Keep track of start and end address of each NUMA node in numa_info structure so that lookup of node by address becomes easier. Add an API numa_get_node() to lookup a node by address.
This is needed by sPAPR PowerPC to support ibm,dynamic-reconfiguration-memory device tree node which is needed for memory hotplug. Signed-off-by: Bharata B Rao <bhar...@linux.vnet.ibm.com> Reviewed-by: David Gibson <da...@gibson.dropbear.id.au> --- This patch was earlier posted as part of sPAPR hotplug patchset here: https://lists.gnu.org/archive/html/qemu-ppc/2015-04/msg00204.html include/sysemu/numa.h | 3 +++ numa.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index 6523b4d..19c0ba3 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -15,11 +15,14 @@ typedef struct node_info { DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS); struct HostMemoryBackend *node_memdev; bool present; + ram_addr_t mem_start; + ram_addr_t mem_end; } NodeInfo; extern NodeInfo numa_info[MAX_NODES]; void parse_numa_opts(MachineClass *mc); void numa_post_machine_init(void); void query_numa_node_mem(uint64_t node_mem[]); extern QemuOptsList qemu_numa_opts; +uint32_t numa_get_node(ram_addr_t addr, Error **errp); #endif diff --git a/numa.c b/numa.c index c975fb2..fdf333b 100644 --- a/numa.c +++ b/numa.c @@ -53,6 +53,63 @@ static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one. int nb_numa_nodes; NodeInfo numa_info[MAX_NODES]; +/* + * Given an address, return the index of the NUMA node to which the + * address belongs to. + */ +uint32_t numa_get_node(ram_addr_t addr, Error **errp) +{ + uint32_t i; + MemoryDeviceInfoList *info_list = NULL; + MemoryDeviceInfoList **prev = &info_list; + MemoryDeviceInfoList *info; + + for (i = 0; i < nb_numa_nodes; i++) { + if (addr >= numa_info[i].mem_start && addr < numa_info[i].mem_end) { + return i; + } + } + + /* + * If this @addr falls under cold or hotplugged memory regions, + * check there too. + */ + qmp_pc_dimm_device_list(qdev_get_machine(), &prev); + for (info = info_list; info; info = info->next) { + MemoryDeviceInfo *value = info->value; + + if (value) { + switch (value->kind) { + case MEMORY_DEVICE_INFO_KIND_DIMM: + if (addr >= value->dimm->addr && + addr < (value->dimm->addr + value->dimm->size)) { + qapi_free_MemoryDeviceInfoList(info_list); + return value->dimm->node; + } + break; + default: + break; + } + } + } + qapi_free_MemoryDeviceInfoList(info_list); + error_setg(errp, "Address 0x" RAM_ADDR_FMT " doesn't belong to any " + "NUMA node", addr); + + return -1; +} + +static void numa_set_mem_address(int nodenr) +{ + if (nodenr) { + numa_info[nodenr].mem_start = numa_info[nodenr-1].mem_end; + } else { + numa_info[nodenr].mem_start = 0; + } + numa_info[nodenr].mem_end = numa_info[nodenr].mem_start + + numa_info[nodenr].node_mem; +} + static void numa_node_parse(NumaNodeOptions *node, QemuOpts *opts, Error **errp) { uint16_t nodenr; @@ -276,6 +333,10 @@ void parse_numa_opts(MachineClass *mc) } for (i = 0; i < nb_numa_nodes; i++) { + numa_set_mem_address(i); + } + + for (i = 0; i < nb_numa_nodes; i++) { if (!bitmap_empty(numa_info[i].node_cpu, MAX_CPUMASK_BITS)) { break; } -- 2.1.0