Merge remote-tracking branch 'remotes/vivier2/tags/trivial-branch-for-6.0-pull-reques...
[qemu/ar7.git] / hw / riscv / numa.c
blob4f92307102fff402332e526c0afaef55f4f4490e
1 /*
2 * QEMU RISC-V NUMA Helper
4 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "qemu/units.h"
21 #include "qemu/log.h"
22 #include "qemu/error-report.h"
23 #include "qapi/error.h"
24 #include "hw/boards.h"
25 #include "hw/qdev-properties.h"
26 #include "hw/riscv/numa.h"
27 #include "sysemu/device_tree.h"
29 static bool numa_enabled(const MachineState *ms)
31 return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
34 int riscv_socket_count(const MachineState *ms)
36 return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
39 int riscv_socket_first_hartid(const MachineState *ms, int socket_id)
41 int i, first_hartid = ms->smp.cpus;
43 if (!numa_enabled(ms)) {
44 return (!socket_id) ? 0 : -1;
47 for (i = 0; i < ms->smp.cpus; i++) {
48 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
49 continue;
51 if (i < first_hartid) {
52 first_hartid = i;
56 return (first_hartid < ms->smp.cpus) ? first_hartid : -1;
59 int riscv_socket_last_hartid(const MachineState *ms, int socket_id)
61 int i, last_hartid = -1;
63 if (!numa_enabled(ms)) {
64 return (!socket_id) ? ms->smp.cpus - 1 : -1;
67 for (i = 0; i < ms->smp.cpus; i++) {
68 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
69 continue;
71 if (i > last_hartid) {
72 last_hartid = i;
76 return (last_hartid < ms->smp.cpus) ? last_hartid : -1;
79 int riscv_socket_hart_count(const MachineState *ms, int socket_id)
81 int first_hartid, last_hartid;
83 if (!numa_enabled(ms)) {
84 return (!socket_id) ? ms->smp.cpus : -1;
87 first_hartid = riscv_socket_first_hartid(ms, socket_id);
88 if (first_hartid < 0) {
89 return -1;
92 last_hartid = riscv_socket_last_hartid(ms, socket_id);
93 if (last_hartid < 0) {
94 return -1;
97 if (first_hartid > last_hartid) {
98 return -1;
101 return last_hartid - first_hartid + 1;
104 bool riscv_socket_check_hartids(const MachineState *ms, int socket_id)
106 int i, first_hartid, last_hartid;
108 if (!numa_enabled(ms)) {
109 return (!socket_id) ? true : false;
112 first_hartid = riscv_socket_first_hartid(ms, socket_id);
113 if (first_hartid < 0) {
114 return false;
117 last_hartid = riscv_socket_last_hartid(ms, socket_id);
118 if (last_hartid < 0) {
119 return false;
122 for (i = first_hartid; i <= last_hartid; i++) {
123 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
124 return false;
128 return true;
131 uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
133 int i;
134 uint64_t mem_offset = 0;
136 if (!numa_enabled(ms)) {
137 return 0;
140 for (i = 0; i < ms->numa_state->num_nodes; i++) {
141 if (i == socket_id) {
142 break;
144 mem_offset += ms->numa_state->nodes[i].node_mem;
147 return (i == socket_id) ? mem_offset : 0;
150 uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
152 if (!numa_enabled(ms)) {
153 return (!socket_id) ? ms->ram_size : 0;
156 return (socket_id < ms->numa_state->num_nodes) ?
157 ms->numa_state->nodes[socket_id].node_mem : 0;
160 void riscv_socket_fdt_write_id(const MachineState *ms, void *fdt,
161 const char *node_name, int socket_id)
163 if (numa_enabled(ms)) {
164 qemu_fdt_setprop_cell(fdt, node_name, "numa-node-id", socket_id);
168 void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt)
170 int i, j, idx;
171 uint32_t *dist_matrix, dist_matrix_size;
173 if (numa_enabled(ms) && ms->numa_state->have_numa_distance) {
174 dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms);
175 dist_matrix_size *= (3 * sizeof(uint32_t));
176 dist_matrix = g_malloc0(dist_matrix_size);
178 for (i = 0; i < riscv_socket_count(ms); i++) {
179 for (j = 0; j < riscv_socket_count(ms); j++) {
180 idx = (i * riscv_socket_count(ms) + j) * 3;
181 dist_matrix[idx + 0] = cpu_to_be32(i);
182 dist_matrix[idx + 1] = cpu_to_be32(j);
183 dist_matrix[idx + 2] =
184 cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
188 qemu_fdt_add_subnode(fdt, "/distance-map");
189 qemu_fdt_setprop_string(fdt, "/distance-map", "compatible",
190 "numa-distance-map-v1");
191 qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
192 dist_matrix, dist_matrix_size);
193 g_free(dist_matrix);
197 CpuInstanceProperties
198 riscv_numa_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
200 MachineClass *mc = MACHINE_GET_CLASS(ms);
201 const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
203 assert(cpu_index < possible_cpus->len);
204 return possible_cpus->cpus[cpu_index].props;
207 int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
209 int64_t nidx = 0;
211 if (ms->numa_state->num_nodes) {
212 nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
213 if (ms->numa_state->num_nodes <= nidx) {
214 nidx = ms->numa_state->num_nodes - 1;
218 return nidx;
221 const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
223 int n;
224 unsigned int max_cpus = ms->smp.max_cpus;
226 if (ms->possible_cpus) {
227 assert(ms->possible_cpus->len == max_cpus);
228 return ms->possible_cpus;
231 ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
232 sizeof(CPUArchId) * max_cpus);
233 ms->possible_cpus->len = max_cpus;
234 for (n = 0; n < ms->possible_cpus->len; n++) {
235 ms->possible_cpus->cpus[n].type = ms->cpu_type;
236 ms->possible_cpus->cpus[n].arch_id = n;
237 ms->possible_cpus->cpus[n].props.has_core_id = true;
238 ms->possible_cpus->cpus[n].props.core_id = n;
241 return ms->possible_cpus;