xref: /qemu/hw/riscv/numa.c (revision 74416394)
183fcaefdSAnup Patel /*
283fcaefdSAnup Patel  * QEMU RISC-V NUMA Helper
383fcaefdSAnup Patel  *
483fcaefdSAnup Patel  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
583fcaefdSAnup Patel  *
683fcaefdSAnup Patel  * This program is free software; you can redistribute it and/or modify it
783fcaefdSAnup Patel  * under the terms and conditions of the GNU General Public License,
883fcaefdSAnup Patel  * version 2 or later, as published by the Free Software Foundation.
983fcaefdSAnup Patel  *
1083fcaefdSAnup Patel  * This program is distributed in the hope it will be useful, but WITHOUT
1183fcaefdSAnup Patel  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1283fcaefdSAnup Patel  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1383fcaefdSAnup Patel  * more details.
1483fcaefdSAnup Patel  *
1583fcaefdSAnup Patel  * You should have received a copy of the GNU General Public License along with
1683fcaefdSAnup Patel  * this program.  If not, see <http://www.gnu.org/licenses/>.
1783fcaefdSAnup Patel  */
1883fcaefdSAnup Patel 
1983fcaefdSAnup Patel #include "qemu/osdep.h"
2083fcaefdSAnup Patel #include "qemu/units.h"
2183fcaefdSAnup Patel #include "qemu/error-report.h"
2283fcaefdSAnup Patel #include "qapi/error.h"
2383fcaefdSAnup Patel #include "hw/boards.h"
2483fcaefdSAnup Patel #include "hw/qdev-properties.h"
2583fcaefdSAnup Patel #include "hw/riscv/numa.h"
2683fcaefdSAnup Patel #include "sysemu/device_tree.h"
2783fcaefdSAnup Patel 
numa_enabled(const MachineState * ms)2883fcaefdSAnup Patel static bool numa_enabled(const MachineState *ms)
2983fcaefdSAnup Patel {
3083fcaefdSAnup Patel     return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
3183fcaefdSAnup Patel }
3283fcaefdSAnup Patel 
riscv_socket_count(const MachineState * ms)3383fcaefdSAnup Patel int riscv_socket_count(const MachineState *ms)
3483fcaefdSAnup Patel {
3583fcaefdSAnup Patel     return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
3683fcaefdSAnup Patel }
3783fcaefdSAnup Patel 
riscv_socket_first_hartid(const MachineState * ms,int socket_id)3883fcaefdSAnup Patel int riscv_socket_first_hartid(const MachineState *ms, int socket_id)
3983fcaefdSAnup Patel {
4083fcaefdSAnup Patel     int i, first_hartid = ms->smp.cpus;
4183fcaefdSAnup Patel 
4283fcaefdSAnup Patel     if (!numa_enabled(ms)) {
4383fcaefdSAnup Patel         return (!socket_id) ? 0 : -1;
4483fcaefdSAnup Patel     }
4583fcaefdSAnup Patel 
4683fcaefdSAnup Patel     for (i = 0; i < ms->smp.cpus; i++) {
4783fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
4883fcaefdSAnup Patel             continue;
4983fcaefdSAnup Patel         }
5083fcaefdSAnup Patel         if (i < first_hartid) {
5183fcaefdSAnup Patel             first_hartid = i;
5283fcaefdSAnup Patel         }
5383fcaefdSAnup Patel     }
5483fcaefdSAnup Patel 
5583fcaefdSAnup Patel     return (first_hartid < ms->smp.cpus) ? first_hartid : -1;
5683fcaefdSAnup Patel }
5783fcaefdSAnup Patel 
riscv_socket_last_hartid(const MachineState * ms,int socket_id)5883fcaefdSAnup Patel int riscv_socket_last_hartid(const MachineState *ms, int socket_id)
5983fcaefdSAnup Patel {
6083fcaefdSAnup Patel     int i, last_hartid = -1;
6183fcaefdSAnup Patel 
6283fcaefdSAnup Patel     if (!numa_enabled(ms)) {
6383fcaefdSAnup Patel         return (!socket_id) ? ms->smp.cpus - 1 : -1;
6483fcaefdSAnup Patel     }
6583fcaefdSAnup Patel 
6683fcaefdSAnup Patel     for (i = 0; i < ms->smp.cpus; i++) {
6783fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
6883fcaefdSAnup Patel             continue;
6983fcaefdSAnup Patel         }
7083fcaefdSAnup Patel         if (i > last_hartid) {
7183fcaefdSAnup Patel             last_hartid = i;
7283fcaefdSAnup Patel         }
7383fcaefdSAnup Patel     }
7483fcaefdSAnup Patel 
7583fcaefdSAnup Patel     return (last_hartid < ms->smp.cpus) ? last_hartid : -1;
7683fcaefdSAnup Patel }
7783fcaefdSAnup Patel 
riscv_socket_hart_count(const MachineState * ms,int socket_id)7883fcaefdSAnup Patel int riscv_socket_hart_count(const MachineState *ms, int socket_id)
7983fcaefdSAnup Patel {
8083fcaefdSAnup Patel     int first_hartid, last_hartid;
8183fcaefdSAnup Patel 
8283fcaefdSAnup Patel     if (!numa_enabled(ms)) {
8383fcaefdSAnup Patel         return (!socket_id) ? ms->smp.cpus : -1;
8483fcaefdSAnup Patel     }
8583fcaefdSAnup Patel 
8683fcaefdSAnup Patel     first_hartid = riscv_socket_first_hartid(ms, socket_id);
8783fcaefdSAnup Patel     if (first_hartid < 0) {
8883fcaefdSAnup Patel         return -1;
8983fcaefdSAnup Patel     }
9083fcaefdSAnup Patel 
9183fcaefdSAnup Patel     last_hartid = riscv_socket_last_hartid(ms, socket_id);
9283fcaefdSAnup Patel     if (last_hartid < 0) {
9383fcaefdSAnup Patel         return -1;
9483fcaefdSAnup Patel     }
9583fcaefdSAnup Patel 
9683fcaefdSAnup Patel     if (first_hartid > last_hartid) {
9783fcaefdSAnup Patel         return -1;
9883fcaefdSAnup Patel     }
9983fcaefdSAnup Patel 
10083fcaefdSAnup Patel     return last_hartid - first_hartid + 1;
10183fcaefdSAnup Patel }
10283fcaefdSAnup Patel 
riscv_socket_check_hartids(const MachineState * ms,int socket_id)10383fcaefdSAnup Patel bool riscv_socket_check_hartids(const MachineState *ms, int socket_id)
10483fcaefdSAnup Patel {
10583fcaefdSAnup Patel     int i, first_hartid, last_hartid;
10683fcaefdSAnup Patel 
10783fcaefdSAnup Patel     if (!numa_enabled(ms)) {
10883fcaefdSAnup Patel         return (!socket_id) ? true : false;
10983fcaefdSAnup Patel     }
11083fcaefdSAnup Patel 
11183fcaefdSAnup Patel     first_hartid = riscv_socket_first_hartid(ms, socket_id);
11283fcaefdSAnup Patel     if (first_hartid < 0) {
11383fcaefdSAnup Patel         return false;
11483fcaefdSAnup Patel     }
11583fcaefdSAnup Patel 
11683fcaefdSAnup Patel     last_hartid = riscv_socket_last_hartid(ms, socket_id);
11783fcaefdSAnup Patel     if (last_hartid < 0) {
11883fcaefdSAnup Patel         return false;
11983fcaefdSAnup Patel     }
12083fcaefdSAnup Patel 
12183fcaefdSAnup Patel     for (i = first_hartid; i <= last_hartid; i++) {
12283fcaefdSAnup Patel         if (ms->possible_cpus->cpus[i].props.node_id != socket_id) {
12383fcaefdSAnup Patel             return false;
12483fcaefdSAnup Patel         }
12583fcaefdSAnup Patel     }
12683fcaefdSAnup Patel 
12783fcaefdSAnup Patel     return true;
12883fcaefdSAnup Patel }
12983fcaefdSAnup Patel 
riscv_socket_mem_offset(const MachineState * ms,int socket_id)13083fcaefdSAnup Patel uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
13183fcaefdSAnup Patel {
13283fcaefdSAnup Patel     int i;
13383fcaefdSAnup Patel     uint64_t mem_offset = 0;
13483fcaefdSAnup Patel 
13583fcaefdSAnup Patel     if (!numa_enabled(ms)) {
13683fcaefdSAnup Patel         return 0;
13783fcaefdSAnup Patel     }
13883fcaefdSAnup Patel 
13983fcaefdSAnup Patel     for (i = 0; i < ms->numa_state->num_nodes; i++) {
14083fcaefdSAnup Patel         if (i == socket_id) {
14183fcaefdSAnup Patel             break;
14283fcaefdSAnup Patel         }
14383fcaefdSAnup Patel         mem_offset += ms->numa_state->nodes[i].node_mem;
14483fcaefdSAnup Patel     }
14583fcaefdSAnup Patel 
14683fcaefdSAnup Patel     return (i == socket_id) ? mem_offset : 0;
14783fcaefdSAnup Patel }
14883fcaefdSAnup Patel 
riscv_socket_mem_size(const MachineState * ms,int socket_id)14983fcaefdSAnup Patel uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
15083fcaefdSAnup Patel {
15183fcaefdSAnup Patel     if (!numa_enabled(ms)) {
15283fcaefdSAnup Patel         return (!socket_id) ? ms->ram_size : 0;
15383fcaefdSAnup Patel     }
15483fcaefdSAnup Patel 
15583fcaefdSAnup Patel     return (socket_id < ms->numa_state->num_nodes) ?
15683fcaefdSAnup Patel             ms->numa_state->nodes[socket_id].node_mem : 0;
15783fcaefdSAnup Patel }
15883fcaefdSAnup Patel 
riscv_socket_fdt_write_id(const MachineState * ms,const char * node_name,int socket_id)159fb60b488SDaniel Henrique Barboza void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name,
160fb60b488SDaniel Henrique Barboza                                int socket_id)
16183fcaefdSAnup Patel {
16283fcaefdSAnup Patel     if (numa_enabled(ms)) {
163fb60b488SDaniel Henrique Barboza         qemu_fdt_setprop_cell(ms->fdt, node_name, "numa-node-id", socket_id);
16483fcaefdSAnup Patel     }
16583fcaefdSAnup Patel }
16683fcaefdSAnup Patel 
riscv_socket_fdt_write_distance_matrix(const MachineState * ms)1679c3ee7e8SDaniel Henrique Barboza void riscv_socket_fdt_write_distance_matrix(const MachineState *ms)
16883fcaefdSAnup Patel {
16983fcaefdSAnup Patel     int i, j, idx;
170*74416394SDaniel Henrique Barboza     g_autofree uint32_t *dist_matrix = NULL;
171*74416394SDaniel Henrique Barboza     uint32_t dist_matrix_size;
17283fcaefdSAnup Patel 
17383fcaefdSAnup Patel     if (numa_enabled(ms) && ms->numa_state->have_numa_distance) {
17483fcaefdSAnup Patel         dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms);
17583fcaefdSAnup Patel         dist_matrix_size *= (3 * sizeof(uint32_t));
17683fcaefdSAnup Patel         dist_matrix = g_malloc0(dist_matrix_size);
17783fcaefdSAnup Patel 
17883fcaefdSAnup Patel         for (i = 0; i < riscv_socket_count(ms); i++) {
17983fcaefdSAnup Patel             for (j = 0; j < riscv_socket_count(ms); j++) {
18083fcaefdSAnup Patel                 idx = (i * riscv_socket_count(ms) + j) * 3;
18183fcaefdSAnup Patel                 dist_matrix[idx + 0] = cpu_to_be32(i);
18283fcaefdSAnup Patel                 dist_matrix[idx + 1] = cpu_to_be32(j);
18383fcaefdSAnup Patel                 dist_matrix[idx + 2] =
18483fcaefdSAnup Patel                     cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
18583fcaefdSAnup Patel             }
18683fcaefdSAnup Patel         }
18783fcaefdSAnup Patel 
1889c3ee7e8SDaniel Henrique Barboza         qemu_fdt_add_subnode(ms->fdt, "/distance-map");
1899c3ee7e8SDaniel Henrique Barboza         qemu_fdt_setprop_string(ms->fdt, "/distance-map", "compatible",
19083fcaefdSAnup Patel                                 "numa-distance-map-v1");
1919c3ee7e8SDaniel Henrique Barboza         qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix",
19283fcaefdSAnup Patel                          dist_matrix, dist_matrix_size);
19383fcaefdSAnup Patel     }
19483fcaefdSAnup Patel }
19583fcaefdSAnup Patel 
19683fcaefdSAnup Patel CpuInstanceProperties
riscv_numa_cpu_index_to_props(MachineState * ms,unsigned cpu_index)19783fcaefdSAnup Patel riscv_numa_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
19883fcaefdSAnup Patel {
19983fcaefdSAnup Patel     MachineClass *mc = MACHINE_GET_CLASS(ms);
20083fcaefdSAnup Patel     const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
20183fcaefdSAnup Patel 
20283fcaefdSAnup Patel     assert(cpu_index < possible_cpus->len);
20383fcaefdSAnup Patel     return possible_cpus->cpus[cpu_index].props;
20483fcaefdSAnup Patel }
20583fcaefdSAnup Patel 
riscv_numa_get_default_cpu_node_id(const MachineState * ms,int idx)20683fcaefdSAnup Patel int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
20783fcaefdSAnup Patel {
20883fcaefdSAnup Patel     int64_t nidx = 0;
20983fcaefdSAnup Patel 
210b9cedbf1SYin Wang     if (ms->numa_state->num_nodes > ms->smp.cpus) {
211b9cedbf1SYin Wang         error_report("Number of NUMA nodes (%d)"
212a916dc95SZhao Liu                      " cannot exceed the number of available CPUs (%u).",
213a916dc95SZhao Liu                      ms->numa_state->num_nodes, ms->smp.cpus);
214b9cedbf1SYin Wang         exit(EXIT_FAILURE);
215b9cedbf1SYin Wang     }
21683fcaefdSAnup Patel     if (ms->numa_state->num_nodes) {
21783fcaefdSAnup Patel         nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
21883fcaefdSAnup Patel         if (ms->numa_state->num_nodes <= nidx) {
21983fcaefdSAnup Patel             nidx = ms->numa_state->num_nodes - 1;
22083fcaefdSAnup Patel         }
22183fcaefdSAnup Patel     }
22283fcaefdSAnup Patel 
22383fcaefdSAnup Patel     return nidx;
22483fcaefdSAnup Patel }
22583fcaefdSAnup Patel 
riscv_numa_possible_cpu_arch_ids(MachineState * ms)22683fcaefdSAnup Patel const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
22783fcaefdSAnup Patel {
22883fcaefdSAnup Patel     int n;
22983fcaefdSAnup Patel     unsigned int max_cpus = ms->smp.max_cpus;
23083fcaefdSAnup Patel 
23183fcaefdSAnup Patel     if (ms->possible_cpus) {
23283fcaefdSAnup Patel         assert(ms->possible_cpus->len == max_cpus);
23383fcaefdSAnup Patel         return ms->possible_cpus;
23483fcaefdSAnup Patel     }
23583fcaefdSAnup Patel 
23683fcaefdSAnup Patel     ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
23783fcaefdSAnup Patel                                   sizeof(CPUArchId) * max_cpus);
23883fcaefdSAnup Patel     ms->possible_cpus->len = max_cpus;
23983fcaefdSAnup Patel     for (n = 0; n < ms->possible_cpus->len; n++) {
24083fcaefdSAnup Patel         ms->possible_cpus->cpus[n].type = ms->cpu_type;
24183fcaefdSAnup Patel         ms->possible_cpus->cpus[n].arch_id = n;
24283fcaefdSAnup Patel         ms->possible_cpus->cpus[n].props.has_core_id = true;
24383fcaefdSAnup Patel         ms->possible_cpus->cpus[n].props.core_id = n;
24483fcaefdSAnup Patel     }
24583fcaefdSAnup Patel 
24683fcaefdSAnup Patel     return ms->possible_cpus;
24783fcaefdSAnup Patel }
248