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