1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "qemu/units.h"
21#include "qemu/error-report.h"
22#include "qapi/error.h"
23#include "hw/boards.h"
24#include "hw/qdev-properties.h"
25#include "hw/riscv/numa.h"
26#include "sysemu/device_tree.h"
27
28static bool numa_enabled(const MachineState *ms)
29{
30 return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
31}
32
33int riscv_socket_count(const MachineState *ms)
34{
35 return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
36}
37
38int riscv_socket_first_hartid(const MachineState *ms, int socket_id)
39{
40 int i, first_hartid = ms->smp.cpus;
41
42 if (!numa_enabled(ms)) {
43 return (!socket_id) ? 0 : -1;
44 }
45
46 for (i = 0; i < ms->smp.cpus; i++) {
47 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
48 continue;
49 }
50 if (i < first_hartid) {
51 first_hartid = i;
52 }
53 }
54
55 return (first_hartid < ms->smp.cpus) ? first_hartid : -1;
56}
57
58int riscv_socket_last_hartid(const MachineState *ms, int socket_id)
59{
60 int i, last_hartid = -1;
61
62 if (!numa_enabled(ms)) {
63 return (!socket_id) ? ms->smp.cpus - 1 : -1;
64 }
65
66 for (i = 0; i < ms->smp.cpus; i++) {
67 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
68 continue;
69 }
70 if (i > last_hartid) {
71 last_hartid = i;
72 }
73 }
74
75 return (last_hartid < ms->smp.cpus) ? last_hartid : -1;
76}
77
78int riscv_socket_hart_count(const MachineState *ms, int socket_id)
79{
80 int first_hartid, last_hartid;
81
82 if (!numa_enabled(ms)) {
83 return (!socket_id) ? ms->smp.cpus : -1;
84 }
85
86 first_hartid = riscv_socket_first_hartid(ms, socket_id);
87 if (first_hartid < 0) {
88 return -1;
89 }
90
91 last_hartid = riscv_socket_last_hartid(ms, socket_id);
92 if (last_hartid < 0) {
93 return -1;
94 }
95
96 if (first_hartid > last_hartid) {
97 return -1;
98 }
99
100 return last_hartid - first_hartid + 1;
101}
102
103bool riscv_socket_check_hartids(const MachineState *ms, int socket_id)
104{
105 int i, first_hartid, last_hartid;
106
107 if (!numa_enabled(ms)) {
108 return (!socket_id) ? true : false;
109 }
110
111 first_hartid = riscv_socket_first_hartid(ms, socket_id);
112 if (first_hartid < 0) {
113 return false;
114 }
115
116 last_hartid = riscv_socket_last_hartid(ms, socket_id);
117 if (last_hartid < 0) {
118 return false;
119 }
120
121 for (i = first_hartid; i <= last_hartid; i++) {
122 if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
123 return false;
124 }
125 }
126
127 return true;
128}
129
130uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
131{
132 int i;
133 uint64_t mem_offset = 0;
134
135 if (!numa_enabled(ms)) {
136 return 0;
137 }
138
139 for (i = 0; i < ms->numa_state->num_nodes; i++) {
140 if (i == socket_id) {
141 break;
142 }
143 mem_offset += ms->numa_state->nodes[i].node_mem;
144 }
145
146 return (i == socket_id) ? mem_offset : 0;
147}
148
149uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
150{
151 if (!numa_enabled(ms)) {
152 return (!socket_id) ? ms->ram_size : 0;
153 }
154
155 return (socket_id < ms->numa_state->num_nodes) ?
156 ms->numa_state->nodes[socket_id].node_mem : 0;
157}
158
159void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name,
160 int socket_id)
161{
162 if (numa_enabled(ms)) {
163 qemu_fdt_setprop_cell(ms->fdt, node_name, "numa-node-id", socket_id);
164 }
165}
166
167void riscv_socket_fdt_write_distance_matrix(const MachineState *ms)
168{
169 int i, j, idx;
170 uint32_t *dist_matrix, dist_matrix_size;
171
172 if (numa_enabled(ms) && ms->numa_state->have_numa_distance) {
173 dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms);
174 dist_matrix_size *= (3 * sizeof(uint32_t));
175 dist_matrix = g_malloc0(dist_matrix_size);
176
177 for (i = 0; i < riscv_socket_count(ms); i++) {
178 for (j = 0; j < riscv_socket_count(ms); j++) {
179 idx = (i * riscv_socket_count(ms) + j) * 3;
180 dist_matrix[idx + 0] = cpu_to_be32(i);
181 dist_matrix[idx + 1] = cpu_to_be32(j);
182 dist_matrix[idx + 2] =
183 cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
184 }
185 }
186
187 qemu_fdt_add_subnode(ms->fdt, "/distance-map");
188 qemu_fdt_setprop_string(ms->fdt, "/distance-map", "compatible",
189 "numa-distance-map-v1");
190 qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix",
191 dist_matrix, dist_matrix_size);
192 g_free(dist_matrix);
193 }
194}
195
196CpuInstanceProperties
197riscv_numa_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
198{
199 MachineClass *mc = MACHINE_GET_CLASS(ms);
200 const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
201
202 assert(cpu_index < possible_cpus->len);
203 return possible_cpus->cpus[cpu_index].props;
204}
205
206int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
207{
208 int64_t nidx = 0;
209
210 if (ms->numa_state->num_nodes > ms->smp.cpus) {
211 error_report("Number of NUMA nodes (%d)"
212 " cannot exceed the number of available CPUs (%d).",
213 ms->numa_state->num_nodes, ms->smp.max_cpus);
214 exit(EXIT_FAILURE);
215 }
216 if (ms->numa_state->num_nodes) {
217 nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
218 if (ms->numa_state->num_nodes <= nidx) {
219 nidx = ms->numa_state->num_nodes - 1;
220 }
221 }
222
223 return nidx;
224}
225
226const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
227{
228 int n;
229 unsigned int max_cpus = ms->smp.max_cpus;
230
231 if (ms->possible_cpus) {
232 assert(ms->possible_cpus->len == max_cpus);
233 return ms->possible_cpus;
234 }
235
236 ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
237 sizeof(CPUArchId) * max_cpus);
238 ms->possible_cpus->len = max_cpus;
239 for (n = 0; n < ms->possible_cpus->len; n++) {
240 ms->possible_cpus->cpus[n].type = ms->cpu_type;
241 ms->possible_cpus->cpus[n].arch_id = n;
242 ms->possible_cpus->cpus[n].props.has_core_id = true;
243 ms->possible_cpus->cpus[n].props.core_id = n;
244 }
245
246 return ms->possible_cpus;
247}
248