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 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 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 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 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 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 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 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 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 159*fb60b488SDaniel Henrique Barboza void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, 160*fb60b488SDaniel Henrique Barboza int socket_id) 16183fcaefdSAnup Patel { 16283fcaefdSAnup Patel if (numa_enabled(ms)) { 163*fb60b488SDaniel Henrique Barboza qemu_fdt_setprop_cell(ms->fdt, node_name, "numa-node-id", socket_id); 16483fcaefdSAnup Patel } 16583fcaefdSAnup Patel } 16683fcaefdSAnup Patel 16783fcaefdSAnup Patel void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt) 16883fcaefdSAnup Patel { 16983fcaefdSAnup Patel int i, j, idx; 17083fcaefdSAnup Patel uint32_t *dist_matrix, dist_matrix_size; 17183fcaefdSAnup Patel 17283fcaefdSAnup Patel if (numa_enabled(ms) && ms->numa_state->have_numa_distance) { 17383fcaefdSAnup Patel dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms); 17483fcaefdSAnup Patel dist_matrix_size *= (3 * sizeof(uint32_t)); 17583fcaefdSAnup Patel dist_matrix = g_malloc0(dist_matrix_size); 17683fcaefdSAnup Patel 17783fcaefdSAnup Patel for (i = 0; i < riscv_socket_count(ms); i++) { 17883fcaefdSAnup Patel for (j = 0; j < riscv_socket_count(ms); j++) { 17983fcaefdSAnup Patel idx = (i * riscv_socket_count(ms) + j) * 3; 18083fcaefdSAnup Patel dist_matrix[idx + 0] = cpu_to_be32(i); 18183fcaefdSAnup Patel dist_matrix[idx + 1] = cpu_to_be32(j); 18283fcaefdSAnup Patel dist_matrix[idx + 2] = 18383fcaefdSAnup Patel cpu_to_be32(ms->numa_state->nodes[i].distance[j]); 18483fcaefdSAnup Patel } 18583fcaefdSAnup Patel } 18683fcaefdSAnup Patel 18783fcaefdSAnup Patel qemu_fdt_add_subnode(fdt, "/distance-map"); 18883fcaefdSAnup Patel qemu_fdt_setprop_string(fdt, "/distance-map", "compatible", 18983fcaefdSAnup Patel "numa-distance-map-v1"); 19083fcaefdSAnup Patel qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix", 19183fcaefdSAnup Patel dist_matrix, dist_matrix_size); 19283fcaefdSAnup Patel g_free(dist_matrix); 19383fcaefdSAnup Patel } 19483fcaefdSAnup Patel } 19583fcaefdSAnup Patel 19683fcaefdSAnup Patel CpuInstanceProperties 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 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 21083fcaefdSAnup Patel if (ms->numa_state->num_nodes) { 21183fcaefdSAnup Patel nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes); 21283fcaefdSAnup Patel if (ms->numa_state->num_nodes <= nidx) { 21383fcaefdSAnup Patel nidx = ms->numa_state->num_nodes - 1; 21483fcaefdSAnup Patel } 21583fcaefdSAnup Patel } 21683fcaefdSAnup Patel 21783fcaefdSAnup Patel return nidx; 21883fcaefdSAnup Patel } 21983fcaefdSAnup Patel 22083fcaefdSAnup Patel const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms) 22183fcaefdSAnup Patel { 22283fcaefdSAnup Patel int n; 22383fcaefdSAnup Patel unsigned int max_cpus = ms->smp.max_cpus; 22483fcaefdSAnup Patel 22583fcaefdSAnup Patel if (ms->possible_cpus) { 22683fcaefdSAnup Patel assert(ms->possible_cpus->len == max_cpus); 22783fcaefdSAnup Patel return ms->possible_cpus; 22883fcaefdSAnup Patel } 22983fcaefdSAnup Patel 23083fcaefdSAnup Patel ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + 23183fcaefdSAnup Patel sizeof(CPUArchId) * max_cpus); 23283fcaefdSAnup Patel ms->possible_cpus->len = max_cpus; 23383fcaefdSAnup Patel for (n = 0; n < ms->possible_cpus->len; n++) { 23483fcaefdSAnup Patel ms->possible_cpus->cpus[n].type = ms->cpu_type; 23583fcaefdSAnup Patel ms->possible_cpus->cpus[n].arch_id = n; 23683fcaefdSAnup Patel ms->possible_cpus->cpus[n].props.has_core_id = true; 23783fcaefdSAnup Patel ms->possible_cpus->cpus[n].props.core_id = n; 23883fcaefdSAnup Patel } 23983fcaefdSAnup Patel 24083fcaefdSAnup Patel return ms->possible_cpus; 24183fcaefdSAnup Patel } 242