[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 1/1] target-ppc: Support rtas_get_sysparm(PROCESSOR_MO
From: |
Sukadev Bhattiprolu |
Subject: |
[Qemu-ppc] [PATCH 1/1] target-ppc: Support rtas_get_sysparm(PROCESSOR_MODULE_INFO) |
Date: |
Sat, 24 Oct 2015 13:29:16 -0700 |
Implement the RTAS_SYSPARM_PROCESSOR_MODULE_INFO parameter to
rtas_get_sysparm() call in qemu. This call returns the processor
core, chip, socket and module information as specified in
section 7.3.16.18 of PAPR v2.7.
We walk the /proc/device-tree to determine the number of chips,
cores and modules 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, but we
should determine that dynamically somehow later.
Thanks to input from Nishanth Aravamudan.
Signed-off-by: Sukadev Bhattiprolu <address@hidden>
---
hw/ppc/Makefile.objs | 1 +
hw/ppc/spapr_rtas.c | 39 +++++++
hw/ppc/spapr_rtas_modinfo.c | 253 ++++++++++++++++++++++++++++++++++++++++++++
hw/ppc/spapr_rtas_modinfo.h | 16 +++
include/hw/ppc/spapr.h | 1 +
5 files changed, 310 insertions(+)
create mode 100644 hw/ppc/spapr_rtas_modinfo.c
create mode 100644 hw/ppc/spapr_rtas_modinfo.h
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index c1ffc77..57c6b02 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -4,6 +4,7 @@ obj-y += ppc.o ppc_booke.o
obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
+obj-$(CONFIG_PSERIES) += spapr_rtas_modinfo.o
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
obj-y += spapr_pci_vfio.o
endif
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 34b12a3..3356036 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -34,6 +34,8 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "qapi-event.h"
+
+#include "spapr_rtas_modinfo.h"
#include "hw/boards.h"
#include <libfdt.h>
@@ -228,6 +230,16 @@ static void rtas_stop_self(PowerPCCPU *cpu,
sPAPRMachineState *spapr,
env->msr = 0;
}
+static void write_2_rtas_bytes(uint8_t *buf, int *next, int val)
+{
+ int i = *next;
+
+ buf[i++] = (val >> 8) & 0xFF;
+ buf[i++] = val & 0xFF;
+
+ *next = i;
+}
+
static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
sPAPRMachineState *spapr,
uint32_t token, uint32_t nargs,
@@ -240,6 +252,33 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
target_ulong ret = RTAS_OUT_SUCCESS;
switch (parameter) {
+ case RTAS_SYSPARM_PROCESSOR_MODULE_INFO: {
+ int i;
+ int offset = 0;
+ int size;
+ uint8_t *param_val;
+ struct rtas_module_info modinfo;
+
+ if (rtas_get_module_info(&modinfo))
+ break;
+
+ size = sizeof(modinfo);
+ size += (modinfo.module_types - 1) * sizeof(struct rtas_socket_info);
+
+ param_val = g_malloc(size);
+
+ write_2_rtas_bytes(param_val, &offset, modinfo.module_types);
+ for (i = 0; i < modinfo.module_types; i++) {
+ write_2_rtas_bytes(param_val, &offset, modinfo.si[i].sockets);
+ write_2_rtas_bytes(param_val, &offset, modinfo.si[i].chips);
+ write_2_rtas_bytes(param_val, &offset,
modinfo.si[i].cores_per_chip);
+ }
+
+ rtas_st_buffer(buffer, length, param_val, offset);
+ g_free(param_val);
+ break;
+ }
+
case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
char *param_val = g_strdup_printf("MaxEntCap=%d,"
"DesMem=%llu,"
diff --git a/hw/ppc/spapr_rtas_modinfo.c b/hw/ppc/spapr_rtas_modinfo.c
new file mode 100644
index 0000000..0babdf4
--- /dev/null
+++ b/hw/ppc/spapr_rtas_modinfo.c
@@ -0,0 +1,253 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * TODO: <fts.h> doesn't like __USE_FILE_OFFSET64 but hopefully we don't
+ * need to deal with large file offsets in /proc/device-tree. If we
+ * must, we should fall back to walking the tree with opendir().
+ * Another alternative is nftw() but that requires us to use global
+ * variables to keep the counts of chips/cores etc so we need to
+ * serialize access to the globals.
+ */
+#undef __USE_FILE_OFFSET64
+#include <fts.h>
+
+#include <glib.h>
+#include "spapr_rtas_modinfo.h"
+
+/*
+ * Chip IDs and Module IDs can occur more than once in the devcie-tree
+ * (eg: each core in a chip would have same chip id). To count number
+ * of unique chips, track and skip duplicate chip/modules ids that we
+ * may encounter.
+ */
+struct obj {
+ int idx;
+ struct obj *next;
+};
+
+
+/*
+ * Add the given object (chip or module) id to its list if its not
+ * not already there.
+ *
+ * Return 1 if object was added (i.e it was new). Return 0 otherwise.
+ */
+static int add_obj(struct obj **headp, int idx)
+{
+ struct obj *cur;
+
+ cur = *headp;
+ while(cur) {
+ if (cur->idx == idx)
+ return 0;
+ cur = cur->next;
+ }
+
+ cur = g_malloc(sizeof(struct obj));
+ if (!cur) {
+ fprintf(stderr, "%s: Unable to alloc struct obj\n", __func__);
+ return 0;
+ }
+
+ cur->idx = idx;
+ cur->next = NULL;
+
+ if (*headp)
+ (*headp)->next = cur;
+ else
+ *headp = cur;
+
+ return 1;
+}
+
+static void free_obj_list(struct obj *head)
+{
+ struct obj *cur, *prev;
+
+ cur = head;
+ while(cur) {
+ prev = cur;
+ cur = cur->next;
+ g_free(prev);
+ }
+}
+
+static int file_matches(FTSENT *ent, const char *file_name,
+ const char *parent_prefix, int level)
+{
+ char *parent_name;
+
+ if (!S_ISREG(ent->fts_statp->st_mode) || ent->fts_level != level)
+ return 0;
+
+ parent_name = ent->fts_parent->fts_name;
+ if (strncmp(parent_name, parent_prefix, strlen(parent_prefix)))
+ return 0;
+
+ if (strncmp(ent->fts_name, file_name, strlen(file_name)))
+ return 0;
+
+ return 1;
+}
+
+static int file_read_buf(char *file_name, char *buf, int len)
+{
+ int rc;
+ FILE *fp;
+
+ fp = fopen(file_name, "r");
+ if (!fp) {
+ fprintf(stderr, "%s: Error opening %s\n", __func__, file_name);
+ return -1;
+ }
+
+ rc = fread(buf, 1, len, fp);
+ fclose(fp);
+
+ if (rc != len)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Check if @ent corresponds a new CPU module. i.e if @ent corresponds to
+ * a file, 'ibm,hw-module-id' in a directory like (i.e fts_level == 2)
+ *
+ * /proc/device-tree/xscom*
+ *
+ * If it is a module id file, read the module index (one word) in the file
+ * and check if it is a duplicate module index.
+ *
+ * Return 1 if it is a new module index. Return 0 in all other cases.
+ */
+static int is_new_module(struct obj **module_list, FTSENT *ent)
+{
+ int i;
+ int idx;
+ char buf[16];
+
+ if (!file_matches(ent, "ibm,hw-module-id", "xscom", 2))
+ return 0;
+
+ if (file_read_buf(ent->fts_path, buf, sizeof(int)) < 0)
+ return 0;
+
+ idx = 0;
+ for (i = 0; i < 4; i++)
+ idx |= (buf[i] << (3-i));
+
+ return add_obj(module_list, idx);
+}
+
+/*
+ * Check if @ent corresponds a new CPU chip. i.e if @ent corresponds to
+ * a file, 'ibm,chip-id' in a directory like (i.e fts_level == 2)
+ *
+ * /proc/device-tree/xscom*
+ *
+ * If it is a chip id file, read the chip index (one word) in the file
+ * and check if it is a duplicate chip index.
+ *
+ * Return 1 if it is a new chip index. Return 0 in all other cases.
+ */
+static int is_new_chip(struct obj **chip_list, FTSENT *ent)
+{
+ int i;
+ int idx;
+ char buf[16];
+
+ if (!file_matches(ent, "ibm,chip-id", "xscom", 2))
+ return 0;
+
+ if (file_read_buf(ent->fts_path, buf, sizeof(int)) < 0)
+ return 0;
+
+ idx = 0;
+ for (i = 0; i < 4; i++)
+ idx |= (buf[i] << (3-i));
+
+ return add_obj(chip_list, idx);
+}
+
+/*
+ * Check if @ent corresponds a CPU core.
+ *
+ * i.e check if @ent corresponds to 'device_type' file in a directory like
+ *
+ * /proc/device-tree/cpus/PowerPC,POWER*
+ *
+ * (i.e fts_level == 3) and if the file contains the string "cpu".
+ *
+ * Return 1 if file corresponds to a CPU core. Return 0 in all other cases.
+ */
+static int is_cpu_core(FTSENT *ent)
+{
+ int rc;
+ char buf[16];
+
+ if (!file_matches(ent, "device_type", "PowerPC,POWER", 3))
+ return 0;
+
+ rc = file_read_buf(ent->fts_path, buf, 4);
+ if (rc < 0)
+ return 0;
+
+ if (strcmp(buf, "cpu"))
+ return 0;
+
+ return 1;
+}
+
+int rtas_get_module_info(struct rtas_module_info *modinfo)
+{
+ int num_cores;
+ int num_chips;
+ int num_modules;
+ const char *p1 = "/proc/device-tree";
+ char * const argv[] = { (char *)p1, NULL };
+ struct obj *chip_list;
+ struct obj *module_list;
+
+ FTS *handle;
+ FTSENT *ent;
+
+ handle = fts_open(argv, FTS_LOGICAL|FTS_NOCHDIR, NULL);
+ if (!handle) {
+ fprintf(stderr, "fts_open(): Error %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(modinfo, 0, sizeof(struct rtas_module_info));
+
+ num_cores = num_chips = num_modules = 0;
+ chip_list = module_list = NULL;
+
+ while (1) {
+ ent = fts_read(handle);
+ if (!ent)
+ break;
+
+ if (is_cpu_core(ent))
+ num_cores++;
+ else if (is_new_chip(&chip_list, ent))
+ num_chips++;
+ else if (is_new_module(&module_list, ent))
+ num_modules++;
+ }
+
+ modinfo->module_types = 1;
+ modinfo->si[0].sockets = num_modules;
+ modinfo->si[0].chips = num_chips;
+ modinfo->si[0].cores_per_chip = num_cores / num_chips;
+
+ free_obj_list(chip_list);
+ free_obj_list(module_list);
+
+ return 0;
+}
diff --git a/hw/ppc/spapr_rtas_modinfo.h b/hw/ppc/spapr_rtas_modinfo.h
new file mode 100644
index 0000000..65942f1
--- /dev/null
+++ b/hw/ppc/spapr_rtas_modinfo.h
@@ -0,0 +1,16 @@
+
+#ifndef uint16_t
+typedef unsigned short uint16_t;
+#endif
+
+struct rtas_socket_info {
+ uint16_t sockets;
+ uint16_t chips;
+ uint16_t cores_per_chip;
+};
+struct rtas_module_info {
+ uint16_t module_types;
+ struct rtas_socket_info si[1];
+};
+
+extern int rtas_get_module_info(struct rtas_module_info *topo);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 5baa906..cfe7fa2 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
--
2.5.3
- [Qemu-ppc] [PATCH 1/1] target-ppc: Support rtas_get_sysparm(PROCESSOR_MODULE_INFO),
Sukadev Bhattiprolu <=