xref: /qemu/hw/riscv/numa.c (revision 83fcaefd9d52670d71e1705b13d3df02d8ee4566)
1*83fcaefdSAnup Patel /*
2*83fcaefdSAnup Patel  * QEMU RISC-V NUMA Helper
3*83fcaefdSAnup Patel  *
4*83fcaefdSAnup Patel  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
5*83fcaefdSAnup Patel  *
6*83fcaefdSAnup Patel  * This program is free software; you can redistribute it and/or modify it
7*83fcaefdSAnup Patel  * under the terms and conditions of the GNU General Public License,
8*83fcaefdSAnup Patel  * version 2 or later, as published by the Free Software Foundation.
9*83fcaefdSAnup Patel  *
10*83fcaefdSAnup Patel  * This program is distributed in the hope it will be useful, but WITHOUT
11*83fcaefdSAnup Patel  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*83fcaefdSAnup Patel  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*83fcaefdSAnup Patel  * more details.
14*83fcaefdSAnup Patel  *
15*83fcaefdSAnup Patel  * You should have received a copy of the GNU General Public License along with
16*83fcaefdSAnup Patel  * this program.  If not, see <http://www.gnu.org/licenses/>.
17*83fcaefdSAnup Patel  */
18*83fcaefdSAnup Patel 
19*83fcaefdSAnup Patel #include "qemu/osdep.h"
20*83fcaefdSAnup Patel #include "qemu/units.h"
21*83fcaefdSAnup Patel #include "qemu/log.h"
22*83fcaefdSAnup Patel #include "qemu/error-report.h"
23*83fcaefdSAnup Patel #include "qapi/error.h"
24*83fcaefdSAnup Patel #include "hw/boards.h"
25*83fcaefdSAnup Patel #include "hw/qdev-properties.h"
26*83fcaefdSAnup Patel #include "hw/riscv/numa.h"
27*83fcaefdSAnup Patel #include "sysemu/device_tree.h"
28*83fcaefdSAnup Patel 
29*83fcaefdSAnup Patel static bool numa_enabled(const MachineState *ms)
30*83fcaefdSAnup Patel {
31*83fcaefdSAnup Patel     return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
32*83fcaefdSAnup Patel }
33*83fcaefdSAnup Patel 
34*83fcaefdSAnup Patel int riscv_socket_count(const MachineState *ms)
35*83fcaefdSAnup Patel {
36*83fcaefdSAnup Patel     return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
37*83fcaefdSAnup Patel }
38*83fcaefdSAnup Patel 
39*83fcaefdSAnup Patel int riscv_socket_first_hartid(const MachineState *ms, int socket_id)
40*83fcaefdSAnup Patel {
41*83fcaefdSAnup Patel     int i, first_hartid = ms->smp.cpus;
42*83fcaefdSAnup Patel 
43*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
44*83fcaefdSAnup Patel         return (!socket_id) ? 0 : -1;
45*83fcaefdSAnup Patel     }
46*83fcaefdSAnup Patel 
47*83fcaefdSAnup Patel     for (i = 0; i < ms->smp.cpus; i++) {
48*83fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
49*83fcaefdSAnup Patel             continue;
50*83fcaefdSAnup Patel         }
51*83fcaefdSAnup Patel         if (i < first_hartid) {
52*83fcaefdSAnup Patel             first_hartid = i;
53*83fcaefdSAnup Patel         }
54*83fcaefdSAnup Patel     }
55*83fcaefdSAnup Patel 
56*83fcaefdSAnup Patel     return (first_hartid < ms->smp.cpus) ? first_hartid : -1;
57*83fcaefdSAnup Patel }
58*83fcaefdSAnup Patel 
59*83fcaefdSAnup Patel int riscv_socket_last_hartid(const MachineState *ms, int socket_id)
60*83fcaefdSAnup Patel {
61*83fcaefdSAnup Patel     int i, last_hartid = -1;
62*83fcaefdSAnup Patel 
63*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
64*83fcaefdSAnup Patel         return (!socket_id) ? ms->smp.cpus - 1 : -1;
65*83fcaefdSAnup Patel     }
66*83fcaefdSAnup Patel 
67*83fcaefdSAnup Patel     for (i = 0; i < ms->smp.cpus; i++) {
68*83fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
69*83fcaefdSAnup Patel             continue;
70*83fcaefdSAnup Patel         }
71*83fcaefdSAnup Patel         if (i > last_hartid) {
72*83fcaefdSAnup Patel             last_hartid = i;
73*83fcaefdSAnup Patel         }
74*83fcaefdSAnup Patel     }
75*83fcaefdSAnup Patel 
76*83fcaefdSAnup Patel     return (last_hartid < ms->smp.cpus) ? last_hartid : -1;
77*83fcaefdSAnup Patel }
78*83fcaefdSAnup Patel 
79*83fcaefdSAnup Patel int riscv_socket_hart_count(const MachineState *ms, int socket_id)
80*83fcaefdSAnup Patel {
81*83fcaefdSAnup Patel     int first_hartid, last_hartid;
82*83fcaefdSAnup Patel 
83*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
84*83fcaefdSAnup Patel         return (!socket_id) ? ms->smp.cpus : -1;
85*83fcaefdSAnup Patel     }
86*83fcaefdSAnup Patel 
87*83fcaefdSAnup Patel     first_hartid = riscv_socket_first_hartid(ms, socket_id);
88*83fcaefdSAnup Patel     if (first_hartid < 0) {
89*83fcaefdSAnup Patel         return -1;
90*83fcaefdSAnup Patel     }
91*83fcaefdSAnup Patel 
92*83fcaefdSAnup Patel     last_hartid = riscv_socket_last_hartid(ms, socket_id);
93*83fcaefdSAnup Patel     if (last_hartid < 0) {
94*83fcaefdSAnup Patel         return -1;
95*83fcaefdSAnup Patel     }
96*83fcaefdSAnup Patel 
97*83fcaefdSAnup Patel     if (first_hartid > last_hartid) {
98*83fcaefdSAnup Patel         return -1;
99*83fcaefdSAnup Patel     }
100*83fcaefdSAnup Patel 
101*83fcaefdSAnup Patel     return last_hartid - first_hartid + 1;
102*83fcaefdSAnup Patel }
103*83fcaefdSAnup Patel 
104*83fcaefdSAnup Patel bool riscv_socket_check_hartids(const MachineState *ms, int socket_id)
105*83fcaefdSAnup Patel {
106*83fcaefdSAnup Patel     int i, first_hartid, last_hartid;
107*83fcaefdSAnup Patel 
108*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
109*83fcaefdSAnup Patel         return (!socket_id) ? true : false;
110*83fcaefdSAnup Patel     }
111*83fcaefdSAnup Patel 
112*83fcaefdSAnup Patel     first_hartid = riscv_socket_first_hartid(ms, socket_id);
113*83fcaefdSAnup Patel     if (first_hartid < 0) {
114*83fcaefdSAnup Patel         return false;
115*83fcaefdSAnup Patel     }
116*83fcaefdSAnup Patel 
117*83fcaefdSAnup Patel     last_hartid = riscv_socket_last_hartid(ms, socket_id);
118*83fcaefdSAnup Patel     if (last_hartid < 0) {
119*83fcaefdSAnup Patel         return false;
120*83fcaefdSAnup Patel     }
121*83fcaefdSAnup Patel 
122*83fcaefdSAnup Patel     for (i = first_hartid; i <= last_hartid; i++) {
123*83fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
124*83fcaefdSAnup Patel             return false;
125*83fcaefdSAnup Patel         }
126*83fcaefdSAnup Patel     }
127*83fcaefdSAnup Patel 
128*83fcaefdSAnup Patel     return true;
129*83fcaefdSAnup Patel }
130*83fcaefdSAnup Patel 
131*83fcaefdSAnup Patel uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
132*83fcaefdSAnup Patel {
133*83fcaefdSAnup Patel     int i;
134*83fcaefdSAnup Patel     uint64_t mem_offset = 0;
135*83fcaefdSAnup Patel 
136*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
137*83fcaefdSAnup Patel         return 0;
138*83fcaefdSAnup Patel     }
139*83fcaefdSAnup Patel 
140*83fcaefdSAnup Patel     for (i = 0; i < ms->numa_state->num_nodes; i++) {
141*83fcaefdSAnup Patel         if (i == socket_id) {
142*83fcaefdSAnup Patel             break;
143*83fcaefdSAnup Patel         }
144*83fcaefdSAnup Patel         mem_offset += ms->numa_state->nodes[i].node_mem;
145*83fcaefdSAnup Patel     }
146*83fcaefdSAnup Patel 
147*83fcaefdSAnup Patel     return (i == socket_id) ? mem_offset : 0;
148*83fcaefdSAnup Patel }
149*83fcaefdSAnup Patel 
150*83fcaefdSAnup Patel uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
151*83fcaefdSAnup Patel {
152*83fcaefdSAnup Patel     if (!numa_enabled(ms)) {
153*83fcaefdSAnup Patel         return (!socket_id) ? ms->ram_size : 0;
154*83fcaefdSAnup Patel     }
155*83fcaefdSAnup Patel 
156*83fcaefdSAnup Patel     return (socket_id < ms->numa_state->num_nodes) ?
157*83fcaefdSAnup Patel             ms->numa_state->nodes[socket_id].node_mem : 0;
158*83fcaefdSAnup Patel }
159*83fcaefdSAnup Patel 
160*83fcaefdSAnup Patel void riscv_socket_fdt_write_id(const MachineState *ms, void *fdt,
161*83fcaefdSAnup Patel                                const char *node_name, int socket_id)
162*83fcaefdSAnup Patel {
163*83fcaefdSAnup Patel     if (numa_enabled(ms)) {
164*83fcaefdSAnup Patel         qemu_fdt_setprop_cell(fdt, node_name, "numa-node-id", socket_id);
165*83fcaefdSAnup Patel     }
166*83fcaefdSAnup Patel }
167*83fcaefdSAnup Patel 
168*83fcaefdSAnup Patel void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt)
169*83fcaefdSAnup Patel {
170*83fcaefdSAnup Patel     int i, j, idx;
171*83fcaefdSAnup Patel     uint32_t *dist_matrix, dist_matrix_size;
172*83fcaefdSAnup Patel 
173*83fcaefdSAnup Patel     if (numa_enabled(ms) && ms->numa_state->have_numa_distance) {
174*83fcaefdSAnup Patel         dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms);
175*83fcaefdSAnup Patel         dist_matrix_size *= (3 * sizeof(uint32_t));
176*83fcaefdSAnup Patel         dist_matrix = g_malloc0(dist_matrix_size);
177*83fcaefdSAnup Patel 
178*83fcaefdSAnup Patel         for (i = 0; i < riscv_socket_count(ms); i++) {
179*83fcaefdSAnup Patel             for (j = 0; j < riscv_socket_count(ms); j++) {
180*83fcaefdSAnup Patel                 idx = (i * riscv_socket_count(ms) + j) * 3;
181*83fcaefdSAnup Patel                 dist_matrix[idx + 0] = cpu_to_be32(i);
182*83fcaefdSAnup Patel                 dist_matrix[idx + 1] = cpu_to_be32(j);
183*83fcaefdSAnup Patel                 dist_matrix[idx + 2] =
184*83fcaefdSAnup Patel                     cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
185*83fcaefdSAnup Patel             }
186*83fcaefdSAnup Patel         }
187*83fcaefdSAnup Patel 
188*83fcaefdSAnup Patel         qemu_fdt_add_subnode(fdt, "/distance-map");
189*83fcaefdSAnup Patel         qemu_fdt_setprop_string(fdt, "/distance-map", "compatible",
190*83fcaefdSAnup Patel                                 "numa-distance-map-v1");
191*83fcaefdSAnup Patel         qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
192*83fcaefdSAnup Patel                          dist_matrix, dist_matrix_size);
193*83fcaefdSAnup Patel         g_free(dist_matrix);
194*83fcaefdSAnup Patel     }
195*83fcaefdSAnup Patel }
196*83fcaefdSAnup Patel 
197*83fcaefdSAnup Patel CpuInstanceProperties
198*83fcaefdSAnup Patel riscv_numa_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
199*83fcaefdSAnup Patel {
200*83fcaefdSAnup Patel     MachineClass *mc = MACHINE_GET_CLASS(ms);
201*83fcaefdSAnup Patel     const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
202*83fcaefdSAnup Patel 
203*83fcaefdSAnup Patel     assert(cpu_index < possible_cpus->len);
204*83fcaefdSAnup Patel     return possible_cpus->cpus[cpu_index].props;
205*83fcaefdSAnup Patel }
206*83fcaefdSAnup Patel 
207*83fcaefdSAnup Patel int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
208*83fcaefdSAnup Patel {
209*83fcaefdSAnup Patel     int64_t nidx = 0;
210*83fcaefdSAnup Patel 
211*83fcaefdSAnup Patel     if (ms->numa_state->num_nodes) {
212*83fcaefdSAnup Patel         nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
213*83fcaefdSAnup Patel         if (ms->numa_state->num_nodes <= nidx) {
214*83fcaefdSAnup Patel             nidx = ms->numa_state->num_nodes - 1;
215*83fcaefdSAnup Patel         }
216*83fcaefdSAnup Patel     }
217*83fcaefdSAnup Patel 
218*83fcaefdSAnup Patel     return nidx;
219*83fcaefdSAnup Patel }
220*83fcaefdSAnup Patel 
221*83fcaefdSAnup Patel const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
222*83fcaefdSAnup Patel {
223*83fcaefdSAnup Patel     int n;
224*83fcaefdSAnup Patel     unsigned int max_cpus = ms->smp.max_cpus;
225*83fcaefdSAnup Patel 
226*83fcaefdSAnup Patel     if (ms->possible_cpus) {
227*83fcaefdSAnup Patel         assert(ms->possible_cpus->len == max_cpus);
228*83fcaefdSAnup Patel         return ms->possible_cpus;
229*83fcaefdSAnup Patel     }
230*83fcaefdSAnup Patel 
231*83fcaefdSAnup Patel     ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
232*83fcaefdSAnup Patel                                   sizeof(CPUArchId) * max_cpus);
233*83fcaefdSAnup Patel     ms->possible_cpus->len = max_cpus;
234*83fcaefdSAnup Patel     for (n = 0; n < ms->possible_cpus->len; n++) {
235*83fcaefdSAnup Patel         ms->possible_cpus->cpus[n].type = ms->cpu_type;
236*83fcaefdSAnup Patel         ms->possible_cpus->cpus[n].arch_id = n;
237*83fcaefdSAnup Patel         ms->possible_cpus->cpus[n].props.has_core_id = true;
238*83fcaefdSAnup Patel         ms->possible_cpus->cpus[n].props.core_id = n;
239*83fcaefdSAnup Patel     }
240*83fcaefdSAnup Patel 
241*83fcaefdSAnup Patel     return ms->possible_cpus;
242*83fcaefdSAnup Patel }
243