qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

numa.c (6685B)


      1 /*
      2  * QEMU RISC-V NUMA Helper
      3  *
      4  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
      5  *
      6  * This program is free software; you can redistribute it and/or modify it
      7  * under the terms and conditions of the GNU General Public License,
      8  * version 2 or later, as published by the Free Software Foundation.
      9  *
     10  * This program is distributed in the hope it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     13  * more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along with
     16  * this program.  If not, see <http://www.gnu.org/licenses/>.
     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 
     28 static bool numa_enabled(const MachineState *ms)
     29 {
     30     return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
     31 }
     32 
     33 int riscv_socket_count(const MachineState *ms)
     34 {
     35     return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
     36 }
     37 
     38 int 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 
     58 int 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 
     78 int 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 
    103 bool 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 
    130 uint64_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 
    149 uint64_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 
    159 void riscv_socket_fdt_write_id(const MachineState *ms, void *fdt,
    160                                const char *node_name, int socket_id)
    161 {
    162     if (numa_enabled(ms)) {
    163         qemu_fdt_setprop_cell(fdt, node_name, "numa-node-id", socket_id);
    164     }
    165 }
    166 
    167 void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt)
    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(fdt, "/distance-map");
    188         qemu_fdt_setprop_string(fdt, "/distance-map", "compatible",
    189                                 "numa-distance-map-v1");
    190         qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
    191                          dist_matrix, dist_matrix_size);
    192         g_free(dist_matrix);
    193     }
    194 }
    195 
    196 CpuInstanceProperties
    197 riscv_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 
    206 int64_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) {
    211         nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
    212         if (ms->numa_state->num_nodes <= nidx) {
    213             nidx = ms->numa_state->num_nodes - 1;
    214         }
    215     }
    216 
    217     return nidx;
    218 }
    219 
    220 const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
    221 {
    222     int n;
    223     unsigned int max_cpus = ms->smp.max_cpus;
    224 
    225     if (ms->possible_cpus) {
    226         assert(ms->possible_cpus->len == max_cpus);
    227         return ms->possible_cpus;
    228     }
    229 
    230     ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
    231                                   sizeof(CPUArchId) * max_cpus);
    232     ms->possible_cpus->len = max_cpus;
    233     for (n = 0; n < ms->possible_cpus->len; n++) {
    234         ms->possible_cpus->cpus[n].type = ms->cpu_type;
    235         ms->possible_cpus->cpus[n].arch_id = n;
    236         ms->possible_cpus->cpus[n].props.has_core_id = true;
    237         ms->possible_cpus->cpus[n].props.core_id = n;
    238     }
    239 
    240     return ms->possible_cpus;
    241 }