David, Alexey, Any comments on this patch?
Suka Sukadev Bhattiprolu [suka...@linux.vnet.ibm.com] wrote: | Implement RTAS_SYSPARM_PROCESSOR_MODULE_INFO parameter to rtas_get_sysparm() | call in qemu. This call returns the processor module (socket), chip and core | information as specified in section 7.3.16.17 of LoPAPR v2.7. | | We walk the /proc/device-tree to determine the number of modules(aka sockets), | chips and cores in the _host_ system and return this info to the guest | application that makes the rtas_get_sysparm() call. | | We currently hard code the number of module_types to 1 (we currently don't | have systems with more than one module type) but we should determine that | dynamically somehow later. | | Thanks to input from Nishanth Aravamudan, Alexey Kardashevskiy, David Gibson, | Thomas Huth. | | Signed-off-by: Sukadev Bhattiprolu <suka...@linux.vnet.ibm.com> | --- | Changelog[v3]: | [David Gibson] Use glob() to simplify pattern matching path names. | Move new code into target-ppc/{kvm.c,kvm_ppc.h} to not impact | other targets and avoid creating new files. | [Alexey Kardashevskiy] Fix indentation, error messages; fold new | code into existing files and avoid creating new files for this | parameter; since the keys are integer, use g_direct_hash() and | GINT_TO_POINTER() and avoid allocating/freeing memory. | | Changelog[v2]: | [Alexey Kardashevskiy] Use existing interfaces like ldl_be_p(), | stw_be_phys(), g_hash_table_new_full(), error_report() rather | than re-inventing; fix indentation, function prottypes etc; | Drop the fts() interface (which doesn't seem to be available | on mingw32/mingw64) and use opendir() to walk specific | directories in the directory tree. | --- | hw/ppc/spapr_rtas.c | 31 +++++++++++ | include/hw/ppc/spapr.h | 13 +++++ | target-ppc/kvm.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ | target-ppc/kvm_ppc.h | 8 +++ | 4 files changed, 193 insertions(+) | | diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c | index 34b12a3..44b2537 100644 | --- a/hw/ppc/spapr_rtas.c | +++ b/hw/ppc/spapr_rtas.c | @@ -38,6 +38,7 @@ | | #include <libfdt.h> | #include "hw/ppc/spapr_drc.h" | +#include "kvm_ppc.h" | | /* #define DEBUG_SPAPR */ | | @@ -240,6 +241,36 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, | target_ulong ret = RTAS_OUT_SUCCESS; | | switch (parameter) { | + case RTAS_SYSPARM_PROCESSOR_MODULE_INFO: { | + struct sPAPRRTASModuleInfo modinfo; | + int i, size = sizeof(modinfo), offset = 0; | + | + memset(&modinfo, 0, size); | + if (kvmppc_rtas_get_module_info(&modinfo)) { | + ret = RTAS_OUT_HW_ERROR; | + break; | + } | + | + stw_be_phys(&address_space_memory, buffer+offset, size); | + offset += 2; | + | + stw_be_phys(&address_space_memory, buffer+offset, modinfo.module_types); | + offset += 2; | + | + for (i = 0; i < modinfo.module_types; i++) { | + stw_be_phys(&address_space_memory, buffer+offset, | + modinfo.si[i].sockets); | + offset += 2; | + stw_be_phys(&address_space_memory, buffer+offset, | + modinfo.si[i].chips); | + offset += 2; | + stw_be_phys(&address_space_memory, buffer+offset, | + modinfo.si[i].cores_per_chip); | + offset += 2; | + } | + break; | + } | + | case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: { | char *param_val = g_strdup_printf("MaxEntCap=%d," | "DesMem=%llu," | diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h | index 5baa906..f793465 100644 | --- a/include/hw/ppc/spapr.h | +++ b/include/hw/ppc/spapr.h | @@ -463,6 +463,7 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi); | /* RTAS ibm,get-system-parameter token values */ | #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 | #define RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE 42 | +#define RTAS_SYSPARM_PROCESSOR_MODULE_INFO 43 | #define RTAS_SYSPARM_UUID 48 | | /* RTAS indicator/sensor types | @@ -646,4 +647,16 @@ int spapr_rng_populate_dt(void *fdt); | */ | #define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008 | | +#define SPAPR_MAX_MODULE_TYPES 1 | + | +struct sPAPRRTASSocketInfo { | + unsigned short sockets; | + unsigned short chips; | + unsigned short cores_per_chip; | +}; | +struct sPAPRRTASModuleInfo { | + unsigned short module_types; | + struct sPAPRRTASSocketInfo si[SPAPR_MAX_MODULE_TYPES]; | +}; | + | #endif /* !defined (__HW_SPAPR_H__) */ | diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c | index 9940a90..bbef78c 100644 | --- a/target-ppc/kvm.c | +++ b/target-ppc/kvm.c | @@ -15,6 +15,7 @@ | */ | | #include <dirent.h> | +#include <glob.h> | #include <sys/types.h> | #include <sys/ioctl.h> | #include <sys/mman.h> | @@ -2518,3 +2519,143 @@ int kvmppc_enable_hwrng(void) | | return kvmppc_enable_hcall(kvm_state, H_RANDOM); | } | + | +/* Read an identifier from the file @path and add the identifier | + * to the hash table @gt unless its already in the table. | + */ | +static int kvmppc_hash_file_contents(GHashTable *gt, char *path) | +{ | + uint32_t idx; | + | + idx = kvmppc_read_int_dt(path); | + if (idx == -1) { | + return -1; | + } | + | + if (g_hash_table_contains(gt, GINT_TO_POINTER(idx))) { | + return 0; | + } | + | + if (!g_hash_table_insert(gt, GINT_TO_POINTER(idx), NULL)) { | + fprintf(stderr, "%s() Unable to add key %d\n", __func__, idx); | + return -1; | + } | + | + return 0; | +} | + | +static int kvmppc_glob_count_ids_dt(const char *pattern, int *count) | +{ | + int i, rc; | + glob_t dtglob; | + GHashTable *htbl; | + | + rc = glob(pattern, GLOB_NOSORT, NULL, &dtglob); | + if (rc) { | + fprintf(stderr, "%s() glob(%s) returns %d, errno %d\n", __func__, | + pattern, rc, errno); | + return -1; | + } | + | + rc = -1; | + htbl = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); | + | + for (i = 0; i < dtglob.gl_pathc; i++) { | + if (kvmppc_hash_file_contents(htbl, dtglob.gl_pathv[i])) { | + goto cleanup; | + } | + } | + | + *count = g_hash_table_size(htbl); | + rc = 0; | + | +cleanup: | + globfree(&dtglob); | + g_hash_table_remove_all(htbl); | + g_hash_table_destroy(htbl); | + | + return rc; | +} | + | +/* Each socket's (aka module's) id is contained in the 'ibm,hw-module-id' | + * file in an "xscom" directory (/proc/device-tree/xscom*). Similarly each | + * chip's id is contained in the 'ibm,chip-id' file in an xscom directory. | + * | + * Since a module can have more than one chip and a chip can have more than | + * one core, there are likely to be duplicates in the module and chip ids | + * i.e more than one xscom directory can contain the same module/chip id. | + * | + * Search the xscom directories and count the number of _UNIQUE_ modules | + * and chips in the system. | + * | + * Return 0 if one or more modules and chips each are found. Return -1 | + * otherwise. | + */ | +static int kvmppc_count_sockets_chips_dt(int *num_sockets, int *num_chips) | +{ | + const char *chip_pattern = "/proc/device-tree/xscom@*/ibm,chip-id"; | + const char *module_pattern = "/proc/device-tree/xscom@*/ibm,hw-module-id"; | + | + if (kvmppc_glob_count_ids_dt(module_pattern, num_sockets) | + || kvmppc_glob_count_ids_dt(chip_pattern, num_chips)) { | + return -1; | + } | + | + if (*num_sockets == 0 || *num_chips == 0) { | + return -1; | + } | + | + return 0; | +} | + | +/* Each core in the system is represented by a directory with the prefix | + * 'PowerPC,POWER' in directory /proc/device-tree/cpus/. Process that | + * directory and count the number of cores in the system. | + * | + * Return 0 if one or more cores are found. Return -1 otherwise. | + */ | +static int kvmppc_count_cores_dt(int *num_cores) | +{ | + int rc; | + glob_t dtglob; | + const char *cpus_pattern = "/proc/device-tree/cpus/PowerPC,POWER*"; | + | + rc = glob(cpus_pattern, GLOB_NOSORT, NULL, &dtglob); | + if (rc) { | + fprintf(stderr, "%s() glob(%s) returns %d, errno %d\n", __func__, | + cpus_pattern, rc, errno); | + return -1; | + } | + | + *num_cores = dtglob.gl_pathc; | + globfree(&dtglob); | + | + if (*num_cores == 0) { | + return -1; | + } | + | + return 0; | +} | + | +int kvmppc_rtas_get_module_info(struct sPAPRRTASModuleInfo *modinfo) | +{ | + int cores, chips, sockets; | + | + if (kvmppc_count_sockets_chips_dt(&sockets, &chips) | + || kvmppc_count_cores_dt(&cores)) { | + return -1; | + } | + | + /* TODO: Although the interface allows multiple module types, Power | + * systems currently support only one module type per system - | + * either Single Chip Module(SCM) or Dual Chip Module(DCM), | + * but not both types in the same system. Hard code module_types | + * for now till we can determine it dynamically. | + */ | + modinfo->module_types = 1; | + modinfo->si[0].sockets = sockets; | + modinfo->si[0].chips = chips; | + modinfo->si[0].cores_per_chip = cores / chips; | + | + return 0; | +} | diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h | index 309cbe0..46a2768 100644 | --- a/target-ppc/kvm_ppc.h | +++ b/target-ppc/kvm_ppc.h | @@ -10,6 +10,7 @@ | #define __KVM_PPC_H__ | | #define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU | +#include "hw/ppc/spapr.h" | | #ifdef CONFIG_KVM | | @@ -55,6 +56,7 @@ void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, | target_ulong pte0, target_ulong pte1); | bool kvmppc_has_cap_fixup_hcalls(void); | int kvmppc_enable_hwrng(void); | +int kvmppc_rtas_get_module_info(struct sPAPRRTASModuleInfo *modinfo); | | #else | | @@ -256,6 +258,12 @@ static inline int kvmppc_enable_hwrng(void) | { | return -1; | } | + | +static inline int kvmppc_rtas_get_module_info(struct sPAPRRTASModuleInfo *mi) | +{ | + return -1; | +} | + | #endif | | #ifndef CONFIG_KVM | -- | 2.1.0 |