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
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"
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
) {
51 if (i
< first_hartid
) {
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
) {
71 if (i
> last_hartid
) {
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) {
92 last_hartid
= riscv_socket_last_hartid(ms
, socket_id
);
93 if (last_hartid
< 0) {
97 if (first_hartid
> last_hartid
) {
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) {
117 last_hartid
= riscv_socket_last_hartid(ms
, socket_id
);
118 if (last_hartid
< 0) {
122 for (i
= first_hartid
; i
<= last_hartid
; i
++) {
123 if (ms
->possible_cpus
->cpus
[i
].props
.node_id
!= socket_id
) {
131 uint64_t riscv_socket_mem_offset(const MachineState
*ms
, int socket_id
)
134 uint64_t mem_offset
= 0;
136 if (!numa_enabled(ms
)) {
140 for (i
= 0; i
< ms
->numa_state
->num_nodes
; i
++) {
141 if (i
== socket_id
) {
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
)
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
);
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
)
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;
221 const CPUArchIdList
*riscv_numa_possible_cpu_arch_ids(MachineState
*ms
)
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
;