qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v3 2/2] target-ppc: Implement rtas_get_sysparm(PROCE


From: Sukadev Bhattiprolu
Subject: [Qemu-devel] [PATCH v3 2/2] target-ppc: Implement rtas_get_sysparm(PROCESSOR_MODULE_INFO)
Date: Fri, 13 Nov 2015 18:13:08 -0800

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 <address@hidden>
---
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/address@hidden/ibm,chip-id";
+    const char *module_pattern = 
"/proc/device-tree/address@hidden/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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]