All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform
@ 2016-08-31 16:34 Cédric Le Goater
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
                   ` (6 more replies)
  0 siblings, 7 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

Hello,

Here is a new version to address the comments from v1 plus a couple of
improvements, the most important being :

 - PnvChip now has PnvChipClass depending on the cpu model
 - the device tree uses the fdt "rw" routines
 - the XSCOM bus makes its first appearance.    
 - the cores now use real HW ids ! 'cpu_dt_id' is dead, long live
   'cpu_index' 

The patchset is organised the same way, the initial patch provides a
minimal platform with some RAM to load ROMs, firmware, kernel,
initrd. The device tree is built with what is available at reset time.

Then, comes the PnvChip object acting as a container for other devices
required to run a system. First of these is XSCOM, the sideband bus
which gives controls to all the units in the POWER8 chip and then the
cores.

Last is a little fix to dump the cpus from the monitor.

The PowerNV platform provides just enough support to be run under
qemu, so that you can check the qom tree, dump the device tree from
ram, show the cpus, etc. It still lacks quite a few controllers to be
useful.

The next major task is XICS as it does not support real HW ids for the
cpus. There are some initial patches and hacks for that in my dev
branch. If you feel adventurous, you can give it a try here :

   https://github.com/legoater/qemu/commits/powernv-ipmi-2.8

Just add on the command line :

     -smp cores=8

Thanks,

C. 

Benjamin Herrenschmidt (2):
  ppc/pnv: add skeleton PowerNV platform
  ppc/pnv: Add XSCOM infrastructure

Cédric Le Goater (5):
  ppc/pnv: add a PnvChip object
  ppc/pnv: add a core mask to PnvChip
  ppc/pnv: add a PnvCore object
  ppc/pnv: add a XScomDevice to PnvCore
  monitor: fix crash for platforms without a CPU 0

 default-configs/ppc64-softmmu.mak |   1 +
 hw/ppc/Makefile.objs              |   2 +
 hw/ppc/pnv.c                      | 649 ++++++++++++++++++++++++++++++++++++++
 hw/ppc/pnv_core.c                 | 237 ++++++++++++++
 hw/ppc/pnv_xscom.c                | 408 ++++++++++++++++++++++++
 include/hw/ppc/pnv.h              | 119 +++++++
 include/hw/ppc/pnv_core.h         |  60 ++++
 include/hw/ppc/pnv_xscom.h        |  75 +++++
 monitor.c                         |   2 +-
 9 files changed, 1552 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/pnv.c
 create mode 100644 hw/ppc/pnv_core.c
 create mode 100644 hw/ppc/pnv_xscom.c
 create mode 100644 include/hw/ppc/pnv.h
 create mode 100644 include/hw/ppc/pnv_core.h
 create mode 100644 include/hw/ppc/pnv_xscom.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-01 16:31   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
  2016-09-05  2:48   ` [Qemu-devel] " David Gibson
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object Cédric Le Goater
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

The goal is to emulate a PowerNV system at the level of the skiboot
firmware, which loads the OS and provides some runtime services. Power
Systems have a lower firmware (HostBoot) that does low level system
initialization, like DRAM training. This is beyond the scope of what
qemu will address in a PowerNV guest.

No devices yet, not even an interrupt controller. Just to get started,
some RAM to load the skiboot firmware, the kernel and initrd. The
device tree is fully created in the machine reset op.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[clg: - updated for qemu-2.7
      - replaced fprintf by error_report
      - used a common definition of _FDT macro
      - removed VMStateDescription as migration is not yet supported
      - added IBM Copyright statements
      - reworked kernel_filename handling
      - merged PnvSystem and sPowerNVMachineState
      - removed PHANDLE_XICP
      - added ppc_create_page_sizes_prop helper
      - removed nmi support
      - removed kvm support
      - updated powernv machine to version 2.8
      - removed chips and cpus, They will be provided in another patches
      - added a machine reset routine to initialize the device tree (also)
      - french has a squelette and english a skeleton.
      - improved commit log.
      - reworked prototypes parameters
      - added a check on the ram size (thanks to Michael Ellerman)
      - fixed chip-id cell
      - changed MAX_CPUS to 2048
      - simplified memory node creation to one node only
      - removed machine version
      - rewrote the device tree creation with the fdt "rw" routines
      - s/sPowerNVMachineState/PnvMachineState/
      - etc.
]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 Changes since v1:

 - changed MAX_CPUS to 2048
 - simplified memory node creation to one node only
 - removed machine version 
 - rewrote the device tree creation with the fdt "rw" routines
 - s/sPowerNVMachineState/PnvMachineState/
 - block_default_type is back to IF_IDE because of the AHCI device

 default-configs/ppc64-softmmu.mak |   1 +
 hw/ppc/Makefile.objs              |   2 +
 hw/ppc/pnv.c                      | 244 ++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h              |  37 ++++++
 4 files changed, 284 insertions(+)
 create mode 100644 hw/ppc/pnv.c
 create mode 100644 include/hw/ppc/pnv.h

diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index c4be59f638ed..516a6e25aba3 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -40,6 +40,7 @@ CONFIG_I8259=y
 CONFIG_XILINX=y
 CONFIG_XILINX_ETHLITE=y
 CONFIG_PSERIES=y
+CONFIG_POWERNV=y
 CONFIG_PREP=y
 CONFIG_MAC=y
 CONFIG_E500=y
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 99a0d4e581bf..8105db7d5600 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -5,6 +5,8 @@ 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_cpu_core.o
+# IBM PowerNV
+obj-$(CONFIG_POWERNV) += pnv.o
 ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
 obj-y += spapr_pci_vfio.o
 endif
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
new file mode 100644
index 000000000000..70413e3c5740
--- /dev/null
+++ b/hw/ppc/pnv.c
@@ -0,0 +1,244 @@
+/*
+ * QEMU PowerPC PowerNV model
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ * Copyright (c) 2014-2016 BenH, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/numa.h"
+#include "hw/hw.h"
+#include "target-ppc/cpu.h"
+#include "qemu/log.h"
+#include "hw/ppc/fdt.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/pnv.h"
+#include "hw/loader.h"
+#include "exec/address-spaces.h"
+#include "qemu/cutils.h"
+
+#include <libfdt.h>
+
+#define FDT_ADDR                0x01000000
+#define FDT_MAX_SIZE            0x00100000
+
+#define FW_FILE_NAME            "skiboot.lid"
+#define FW_LOAD_ADDR            0x0
+#define FW_MAX_SIZE             0x00400000
+
+#define KERNEL_LOAD_ADDR        0x20000000
+#define INITRD_LOAD_ADDR        0x40000000
+
+/*
+ * On Power Systems E880, the max cpus (threads) should be :
+ *     4 * 4 sockets * 12 cores * 8 threads = 1536
+ * Let's make it 2^11
+ */
+#define MAX_CPUS                2048
+
+static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
+                                         hwaddr size)
+{
+    char *mem_name;
+    uint64_t mem_reg_property[2];
+    int off;
+
+    mem_reg_property[0] = cpu_to_be64(start);
+    mem_reg_property[1] = cpu_to_be64(size);
+
+    mem_name = g_strdup_printf("memory@"TARGET_FMT_lx, start);
+    off = fdt_add_subnode(fdt, 0, mem_name);
+    g_free(mem_name);
+
+    _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+    _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+                       sizeof(mem_reg_property))));
+    _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
+}
+
+
+/*
+ * Memory nodes are created by hostboot, one for each range of memory
+ * that has a different "affinity". In practice, it means one range
+ * per chip.
+ */
+static int powernv_populate_memory(void *fdt)
+{
+    int chip_id = 0;
+    hwaddr chip_ramsize = ram_size;
+    hwaddr chip_start = 0;
+
+    /* Only one chip for the moment */
+    powernv_populate_memory_node(fdt, chip_id, chip_start, chip_ramsize);
+
+    return 0;
+}
+
+static void *powernv_create_fdt(PnvMachineState *pnv,
+                                const char *kernel_cmdline)
+{
+    void *fdt;
+    char *buf;
+    const char plat_compat[] = "qemu,powernv\0ibm,powernv";
+    int off;
+
+    fdt = g_malloc0(FDT_MAX_SIZE);
+    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
+
+    /* Root node */
+    _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
+    _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
+    _FDT((fdt_setprop_string(fdt, 0, "model",
+                             "IBM PowerNV (emulated by qemu)")));
+    _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
+                      sizeof(plat_compat))));
+
+    buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1],
+                          qemu_uuid[2], qemu_uuid[3], qemu_uuid[4],
+                          qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+                          qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
+                          qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
+                          qemu_uuid[14], qemu_uuid[15]);
+    _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
+    g_free(buf);
+
+    off = fdt_add_subnode(fdt, 0, "chosen");
+    if (kernel_cmdline) {
+        _FDT((fdt_setprop_string(fdt, off, "bootargs", kernel_cmdline)));
+    }
+
+    if (pnv->initrd_size) {
+        uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
+        uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
+
+        _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
+                               &start_prop, sizeof(start_prop))));
+        _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
+                               &end_prop, sizeof(end_prop))));
+    }
+
+    /* Memory */
+    powernv_populate_memory(fdt);
+
+    return fdt;
+}
+
+static void ppc_powernv_reset(void)
+{
+    MachineState *machine = MACHINE(qdev_get_machine());
+    PnvMachineState *pnv = POWERNV_MACHINE(machine);
+    void *fdt;
+
+    pnv->fdt_addr = FDT_ADDR;
+
+    qemu_devices_reset();
+
+    fdt = powernv_create_fdt(pnv, machine->kernel_cmdline);
+
+    cpu_physical_memory_write(pnv->fdt_addr, fdt, fdt_totalsize(fdt));
+}
+
+static void ppc_powernv_init(MachineState *machine)
+{
+    PnvMachineState *pnv = POWERNV_MACHINE(machine);
+    ram_addr_t ram_size = machine->ram_size;
+    MemoryRegion *ram;
+    char *fw_filename;
+    long fw_size;
+    long kernel_size;
+
+    /* allocate RAM */
+    if (ram_size < (1 * G_BYTE)) {
+        error_report("Warning: skiboot may not work with < 1GB of RAM");
+    }
+
+    ram = g_new(MemoryRegion, 1);
+    memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
+                                         ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    /* load skiboot firmware  */
+    if (bios_name == NULL) {
+        bios_name = FW_FILE_NAME;
+    }
+
+    fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
+    if (fw_size < 0) {
+        hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
+        exit(1);
+    }
+    g_free(fw_filename);
+
+    /* load kernel */
+    kernel_size = load_image_targphys(machine->kernel_filename,
+                                      KERNEL_LOAD_ADDR, 0x2000000);
+    if (kernel_size < 0) {
+        hw_error("qemu: could not load kernel'%s'\n", machine->kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    if (machine->initrd_filename) {
+        pnv->initrd_base = INITRD_LOAD_ADDR;
+        pnv->initrd_size = load_image_targphys(machine->initrd_filename,
+                                  pnv->initrd_base, 0x10000000); /* 128MB max */
+        if (pnv->initrd_size < 0) {
+            error_report("qemu: could not load initial ram disk '%s'",
+                         machine->initrd_filename);
+            exit(1);
+        }
+    }
+}
+
+static void powernv_machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "IBM PowerNV (Non-Virtualized)";
+    mc->init = ppc_powernv_init;
+    mc->reset = ppc_powernv_reset;
+    mc->max_cpus = MAX_CPUS;
+    mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
+                                      * storage */
+    mc->no_parallel = 1;
+    mc->default_boot_order = NULL;
+    mc->default_ram_size = 1 * G_BYTE;
+}
+
+static const TypeInfo powernv_machine_info = {
+    .name          = TYPE_POWERNV_MACHINE,
+    .parent        = TYPE_MACHINE,
+    .instance_size = sizeof(PnvMachineState),
+    .class_init    = powernv_machine_class_init,
+};
+
+static void powernv_machine_register_types(void)
+{
+    type_register_static(&powernv_machine_info);
+}
+
+type_init(powernv_machine_register_types)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
new file mode 100644
index 000000000000..31a57ed7f465
--- /dev/null
+++ b/include/hw/ppc/pnv.h
@@ -0,0 +1,37 @@
+/*
+ * QEMU PowerNV various definitions
+ *
+ * Copyright (c) 2014-2016 BenH, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _PPC_PNV_H
+#define _PPC_PNV_H
+
+#include "hw/boards.h"
+
+#define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
+#define POWERNV_MACHINE(obj) \
+    OBJECT_CHECK(PnvMachineState, (obj), TYPE_POWERNV_MACHINE)
+
+typedef struct PnvMachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    uint32_t initrd_base;
+    long initrd_size;
+    hwaddr fdt_addr;
+} PnvMachineState;
+
+#endif /* _PPC_PNV_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-01 17:21   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
  2016-09-05  2:58   ` [Qemu-devel] " David Gibson
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure Cédric Le Goater
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

This is is an abstraction of a POWER8 chip which is a set of cores
plus other 'units', like the pervasive unit, the interrupt controller,
the memory controller, the on-chip microcontroller, etc. The whole can
be seen as a socket. It depends on a cpu model and its characteristics,
max cores, specific init are defined in a PnvChipClass.

We start with an near empty PnvChip with only a few cpu constants
which we will grow in the subsequent patches with the controllers
required to run the system.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 Changes since v1:
 
 - introduced a PnvChipClass depending on the cpu model. It also
   provides some chip constants used by devices, like the cpu model hw
   id (f000f), a enum type (not sure this is useful yet), a custom
   realize ops for customization.
 - the num-chips property can be configured on the command line.
 
 Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 

 hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
 2 files changed, 225 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 70413e3c5740..06051268e200 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
     char *fw_filename;
     long fw_size;
     long kernel_size;
+    int i;
+    char *chip_typename;
 
     /* allocate RAM */
     if (ram_size < (1 * G_BYTE)) {
@@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
             exit(1);
         }
     }
+
+    /* Create the processor chips */
+    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
+
+    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
+    for (i = 0; i < pnv->num_chips; i++) {
+        Object *chip = object_new(chip_typename);
+        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
+        object_property_set_bool(chip, true, "realized", &error_abort);
+        pnv->chips[i] = PNV_CHIP(chip);
+    }
+    g_free(chip_typename);
+}
+
+static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
+{
+    ;
+}
+
+static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvChipClass *k = PNV_CHIP_CLASS(klass);
+
+    k->realize = pnv_chip_power8nvl_realize;
+    k->cpu_model = "POWER8NVL";
+    k->chip_type = PNV_CHIP_P8NVL;
+    k->chip_f000f = 0x120d304980000000ull;
+    dc->desc = "PowerNV Chip POWER8NVL";
+}
+
+static const TypeInfo pnv_chip_power8nvl_info = {
+    .name          = TYPE_PNV_CHIP_POWER8NVL,
+    .parent        = TYPE_PNV_CHIP,
+    .instance_size = sizeof(PnvChipPower8NVL),
+    .class_init    = pnv_chip_power8nvl_class_init,
+};
+
+static void pnv_chip_power8_realize(PnvChip *chip, Error **errp)
+{
+    ;
+}
+
+static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvChipClass *k = PNV_CHIP_CLASS(klass);
+
+    k->realize = pnv_chip_power8_realize;
+    k->cpu_model = "POWER8";
+    k->chip_type = PNV_CHIP_P8;
+    k->chip_f000f = 0x220ea04980000000ull;
+    dc->desc = "PowerNV Chip POWER8";
+}
+
+static const TypeInfo pnv_chip_power8_info = {
+    .name          = TYPE_PNV_CHIP_POWER8,
+    .parent        = TYPE_PNV_CHIP,
+    .instance_size = sizeof(PnvChipPower8),
+    .class_init    = pnv_chip_power8_class_init,
+};
+
+static void pnv_chip_power8e_realize(PnvChip *chip, Error **errp)
+{
+    ;
+}
+
+static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvChipClass *k = PNV_CHIP_CLASS(klass);
+
+    k->realize = pnv_chip_power8e_realize;
+    k->cpu_model = "POWER8E";
+    k->chip_type = PNV_CHIP_P8E;
+    k->chip_f000f = 0x221ef04980000000ull;
+    dc->desc = "PowerNV Chip POWER8E";
+}
+
+static const TypeInfo pnv_chip_power8e_info = {
+    .name          = TYPE_PNV_CHIP_POWER8E,
+    .parent        = TYPE_PNV_CHIP,
+    .instance_size = sizeof(PnvChipPower8e),
+    .class_init    = pnv_chip_power8e_class_init,
+};
+
+static void pnv_chip_realize(DeviceState *dev, Error **errp)
+{
+    PnvChip *chip = PNV_CHIP(dev);
+    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+
+    pcc->realize(chip, errp);
+}
+
+static Property pnv_chip_properties[] = {
+    DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_chip_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = pnv_chip_realize;
+    dc->props = pnv_chip_properties;
+    dc->desc = "PowerNV Chip";
+ }
+
+static const TypeInfo pnv_chip_info = {
+    .name          = TYPE_PNV_CHIP,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .class_init    = pnv_chip_class_init,
+    .class_size    = sizeof(PnvChipClass),
+    .abstract      = true,
+};
+
+static char *pnv_get_num_chips(Object *obj, Error **errp)
+{
+    return g_strdup_printf("%d", POWERNV_MACHINE(obj)->num_chips);
+}
+
+static void pnv_set_num_chips(Object *obj, const char *value, Error **errp)
+{
+    PnvMachineState *pnv = POWERNV_MACHINE(obj);
+    int num_chips;
+
+    if (sscanf(value, "%d", &num_chips) != 1) {
+        error_setg(errp, "invalid num_chips property: '%s'", value);
+    }
+
+    /*
+     * FIXME: should we decide on how many chips we can create based
+     * on #cores and Venice vs. Murano vs. Naples chip type etc...,
+     */
+    pnv->num_chips = num_chips;
+}
+
+static void powernv_machine_initfn(Object *obj)
+{
+    PnvMachineState *pnv = POWERNV_MACHINE(obj);
+    pnv->num_chips = 1;
+
+    object_property_add_str(obj, "num-chips", pnv_get_num_chips,
+                            pnv_set_num_chips, NULL);
+    object_property_set_description(obj, "num-chips",
+                                    "Specifies the number of processor chips",
+                                    NULL);
 }
 
 static void powernv_machine_class_init(ObjectClass *oc, void *data)
@@ -233,12 +382,17 @@ static const TypeInfo powernv_machine_info = {
     .name          = TYPE_POWERNV_MACHINE,
     .parent        = TYPE_MACHINE,
     .instance_size = sizeof(PnvMachineState),
+    .instance_init = powernv_machine_initfn,
     .class_init    = powernv_machine_class_init,
 };
 
 static void powernv_machine_register_types(void)
 {
     type_register_static(&powernv_machine_info);
+    type_register_static(&pnv_chip_info);
+    type_register_static(&pnv_chip_power8e_info);
+    type_register_static(&pnv_chip_power8_info);
+    type_register_static(&pnv_chip_power8nvl_info);
 }
 
 type_init(powernv_machine_register_types)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 31a57ed7f465..1f32573dedff 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -20,6 +20,74 @@
 #define _PPC_PNV_H
 
 #include "hw/boards.h"
+#include "hw/sysbus.h"
+
+#define TYPE_PNV_CHIP "powernv-chip"
+#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
+#define PNV_CHIP_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP)
+#define PNV_CHIP_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PnvChipClass, (obj), TYPE_PNV_CHIP)
+
+typedef enum PnvChipType {
+    PNV_CHIP_P8E,   /* AKA Murano (default) */
+    PNV_CHIP_P8,    /* AKA Venice */
+    PNV_CHIP_P8NVL, /* AKA Naples */
+} PnvChipType;
+
+typedef struct PnvChip {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    uint32_t     chip_id;
+} PnvChip;
+
+typedef struct PnvChipClass {
+    /*< private >*/
+    SysBusDeviceClass parent_class;
+    /*< public >*/
+    const char *cpu_model;
+    PnvChipType  chip_type;
+    uint64_t     chip_f000f;
+
+    void (*realize)(PnvChip *dev, Error **errp);
+} PnvChipClass;
+
+#define TYPE_PNV_CHIP "powernv-chip"
+
+#define TYPE_PNV_CHIP_POWER8E "powernv-chip-POWER8E"
+#define PNV_CHIP_POWER8E(obj) \
+    OBJECT_CHECK(PnvChipPower8e, (obj), TYPE_PNV_CHIP_POWER8E)
+
+typedef struct PnvChipPower8e {
+    PnvChip pnv_chip;
+} PnvChipPower8e;
+
+#define TYPE_PNV_CHIP_POWER8 "powernv-chip-POWER8"
+#define PNV_CHIP_POWER8(obj) \
+    OBJECT_CHECK(PnvChipPower8, (obj), TYPE_PNV_CHIP_POWER8)
+
+typedef struct PnvChipPower8 {
+    PnvChip pnv_chip;
+} PnvChipPower8;
+
+#define TYPE_PNV_CHIP_POWER8NVL "powernv-chip-POWER8NVL"
+#define PNV_CHIP_POWER8NVL(obj) \
+    OBJECT_CHECK(PnvChipPower8NVL, (obj), TYPE_PNV_CHIP_POWER8NVL)
+
+typedef struct PnvChipPower8NVL {
+    PnvChip pnv_chip;
+} PnvChipPower8NVL;
+
+/*
+ * This generates a HW chip id depending on an index:
+ *
+ *    0x0, 0x1, 0x10, 0x11, 0x20, 0x21, ...
+ *
+ * Is this correct ?
+ */
+#define CHIP_HWID(i) ((((i) & 0x3e) << 3) | ((i) & 0x1))
 
 #define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
 #define POWERNV_MACHINE(obj) \
@@ -32,6 +100,9 @@ typedef struct PnvMachineState {
     uint32_t initrd_base;
     long initrd_size;
     hwaddr fdt_addr;
+
+    uint32_t  num_chips;
+    PnvChip   **chips;
 } PnvMachineState;
 
 #endif /* _PPC_PNV_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-05  3:39   ` David Gibson
  2016-09-05  4:16   ` [Qemu-devel] [Qemu-ppc] " Sam Bobroff
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

XSCOM is an interface to a sideband bus provided by the POWER8 chip
pervasive unit, which gives access to a number of facilities in the
chip that are needed by the OPAL firmware and to a lesser extent,
Linux. This is among others how the PCI Host bridges get configured
at boot or how the LPC bus is accessed.

This provides a simple bus and device type for devices sitting on
XSCOM along with some facilities to optionally generate corresponding
device-tree nodes

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[clg: updated for qemu-2.7
      ported on new sPowerNVMachineState which was merged with PnvSystem
      removed TRACE_XSCOM
      fixed checkpatch errors
      replaced assert with error_setg in xscom_realize()
      reworked xscom_create
      introduced the use of the chip_class for chip model contants
      ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 They were some discussions on whether we should use a qemu
 address_space instead of the xscom ranges defined in this patch. 
 I gave it try, it is possible but it brings extra unnecessary calls
 and complexity. I think the current solution is better.

 hw/ppc/Makefile.objs       |   2 +-
 hw/ppc/pnv.c               |  11 ++
 hw/ppc/pnv_xscom.c         | 408 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h       |   2 +
 include/hw/ppc/pnv_xscom.h |  75 +++++++++
 5 files changed, 497 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/pnv_xscom.c
 create mode 100644 include/hw/ppc/pnv_xscom.h

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 8105db7d5600..f580e5c41413 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -6,7 +6,7 @@ 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_cpu_core.o
 # IBM PowerNV
-obj-$(CONFIG_POWERNV) += pnv.o
+obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
 ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
 obj-y += spapr_pci_vfio.o
 endif
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 06051268e200..a6e7f66b2c0a 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -39,6 +39,8 @@
 #include "exec/address-spaces.h"
 #include "qemu/cutils.h"
 
+#include "hw/ppc/pnv_xscom.h"
+
 #include <libfdt.h>
 
 #define FDT_ADDR                0x01000000
@@ -103,6 +105,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
     char *buf;
     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
     int off;
+    int i;
 
     fdt = g_malloc0(FDT_MAX_SIZE);
     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
@@ -142,6 +145,11 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
     /* Memory */
     powernv_populate_memory(fdt);
 
+    /* Populate XSCOM for each chip */
+    for (i = 0; i < pnv->num_chips; i++) {
+        xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
+    }
+
     return fdt;
 }
 
@@ -305,6 +313,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
     PnvChip *chip = PNV_CHIP(dev);
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
 
+    /* Set up XSCOM bus */
+    chip->xscom = xscom_create(chip);
+
     pcc->realize(chip, errp);
 }
 
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
new file mode 100644
index 000000000000..7ed3804f4b3a
--- /dev/null
+++ b/hw/ppc/pnv_xscom.c
@@ -0,0 +1,408 @@
+
+/*
+ * QEMU PowerNV XSCOM bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* TODO: Add some infrastructure for "random stuff" and FIRs that
+ * various units might want to deal with without creating actual
+ * XSCOM devices.
+ *
+ * For example, HB LPC XSCOM in the PIBAM
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "monitor/monitor.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "sysemu/device_tree.h"
+#include "hw/ppc/fdt.h"
+
+#include "hw/ppc/pnv_xscom.h"
+
+#include <libfdt.h>
+
+#define TYPE_XSCOM "xscom"
+#define XSCOM(obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM)
+
+#define XSCOM_SIZE        0x800000000ull
+#define XSCOM_BASE(chip)  (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE)
+
+
+typedef struct XScomState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion mem;
+    int32_t chip_id;
+    PnvChipClass *chip_class;
+    XScomBus *bus;
+} XScomState;
+
+static uint32_t xscom_to_pcb_addr(uint64_t addr)
+{
+        addr &= (XSCOM_SIZE - 1);
+        return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
+}
+
+static void xscom_complete(uint64_t hmer_bits)
+{
+    CPUState *cs = current_cpu;
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    cpu_synchronize_state(cs);
+    env->spr[SPR_HMER] |= hmer_bits;
+
+    /* XXX Need a CPU helper to set HMER, also handle gneeration
+     * of HMIs
+     */
+}
+
+static XScomDevice *xscom_find_target(XScomState *s, uint32_t pcb_addr,
+                                      uint32_t *range)
+{
+    BusChild *bc;
+
+    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
+        DeviceState *qd = bc->child;
+        XScomDevice *xd = XSCOM_DEVICE(qd);
+        unsigned int i;
+
+        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
+            if (xd->ranges[i].addr <= pcb_addr &&
+                (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) {
+                *range = i;
+                return xd;
+            }
+        }
+    }
+    return NULL;
+}
+
+static bool xscom_dispatch_read(XScomState *s, uint32_t pcb_addr,
+                                uint64_t *out_val)
+{
+    uint32_t range, offset;
+    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
+    XScomDeviceClass *xc;
+
+    if (!xd) {
+        return false;
+    }
+    xc = XSCOM_DEVICE_GET_CLASS(xd);
+    if (!xc->read) {
+        return false;
+    }
+    offset = pcb_addr - xd->ranges[range].addr;
+    return xc->read(xd, range, offset, out_val);
+}
+
+static bool xscom_dispatch_write(XScomState *s, uint32_t pcb_addr, uint64_t val)
+{
+    uint32_t range, offset;
+    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
+    XScomDeviceClass *xc;
+
+    if (!xd) {
+        return false;
+    }
+    xc = XSCOM_DEVICE_GET_CLASS(xd);
+    if (!xc->write) {
+        return false;
+    }
+    offset = pcb_addr - xd->ranges[range].addr;
+    return xc->write(xd, range, offset, val);
+}
+
+static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
+{
+    XScomState *s = opaque;
+    uint32_t pcba = xscom_to_pcb_addr(addr);
+    uint64_t val;
+
+    assert(width == 8);
+
+    /* Handle some SCOMs here before dispatch */
+    switch (pcba) {
+    case 0xf000f:
+        val = s->chip_class->chip_f000f;
+        break;
+    case 0x1010c00:     /* PIBAM FIR */
+    case 0x1010c03:     /* PIBAM FIR MASK */
+    case 0x2020007:     /* ADU stuff */
+    case 0x2020009:     /* ADU stuff */
+    case 0x202000f:     /* ADU stuff */
+        val = 0;
+        break;
+    case 0x2013f00:     /* PBA stuff */
+    case 0x2013f01:     /* PBA stuff */
+    case 0x2013f02:     /* PBA stuff */
+    case 0x2013f03:     /* PBA stuff */
+    case 0x2013f04:     /* PBA stuff */
+    case 0x2013f05:     /* PBA stuff */
+    case 0x2013f06:     /* PBA stuff */
+    case 0x2013f07:     /* PBA stuff */
+        val = 0;
+        break;
+    default:
+        if (!xscom_dispatch_read(s, pcba, &val)) {
+            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
+            return 0;
+        }
+    }
+
+    xscom_complete(HMER_XSCOM_DONE);
+    return val;
+}
+
+static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
+                        unsigned width)
+{
+    XScomState *s = opaque;
+    uint32_t pcba = xscom_to_pcb_addr(addr);
+
+    assert(width == 8);
+
+    /* Handle some SCOMs here before dispatch */
+    switch (pcba) {
+        /* We ignore writes to these */
+    case 0xf000f:       /* chip id is RO */
+    case 0x1010c00:     /* PIBAM FIR */
+    case 0x1010c01:     /* PIBAM FIR */
+    case 0x1010c02:     /* PIBAM FIR */
+    case 0x1010c03:     /* PIBAM FIR MASK */
+    case 0x1010c04:     /* PIBAM FIR MASK */
+    case 0x1010c05:     /* PIBAM FIR MASK */
+    case 0x2020007:     /* ADU stuff */
+    case 0x2020009:     /* ADU stuff */
+    case 0x202000f:     /* ADU stuff */
+        break;
+    default:
+        if (!xscom_dispatch_write(s, pcba, val)) {
+            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
+            return;
+        }
+    }
+
+    xscom_complete(HMER_XSCOM_DONE);
+}
+
+static const MemoryRegionOps xscom_ops = {
+    .read = xscom_read,
+    .write = xscom_write,
+    .valid.min_access_size = 8,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 8,
+    .impl.max_access_size = 8,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int xscom_init(SysBusDevice *dev)
+{
+    XScomState *s = XSCOM(dev);
+
+    s->chip_id = -1;
+    return 0;
+}
+
+static void xscom_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    XScomState *s = XSCOM(dev);
+    char *name;
+
+    if (s->chip_id < 0) {
+        error_setg(errp, "invalid chip id '%d'", s->chip_id);
+        return;
+    }
+    name = g_strdup_printf("xscom-%x", s->chip_id);
+    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
+    sysbus_init_mmio(sbd, &s->mem);
+    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));
+}
+
+static Property xscom_properties[] = {
+        DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xscom_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = xscom_properties;
+    dc->realize = xscom_realize;
+    k->init = xscom_init;
+}
+
+static const TypeInfo xscom_info = {
+    .name          = TYPE_XSCOM,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(XScomState),
+    .class_init    = xscom_class_init,
+};
+
+static void xscom_bus_class_init(ObjectClass *klass, void *data)
+{
+}
+
+static const TypeInfo xscom_bus_info = {
+    .name = TYPE_XSCOM_BUS,
+    .parent = TYPE_BUS,
+    .class_init = xscom_bus_class_init,
+    .instance_size = sizeof(XScomBus),
+};
+
+XScomBus *xscom_create(PnvChip *chip)
+{
+    DeviceState *dev;
+    XScomState *xdev;
+    BusState *qbus;
+    XScomBus *xb;
+    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+
+    dev = qdev_create(NULL, TYPE_XSCOM);
+    qdev_prop_set_uint32(dev, "chip_id", chip->chip_id);
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+    qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
+    xb = DO_UPCAST(XScomBus, bus, qbus);
+    xb->chip_id = chip->chip_id;
+    xdev = XSCOM(dev);
+    xdev->bus = xb;
+    xdev->chip_class = pcc;
+
+    return xb;
+}
+
+int xscom_populate_fdt(XScomBus *xb, void *fdt, int root_offset)
+{
+    BusChild *bc;
+    char *name;
+    const char compat[] = "ibm,power8-xscom\0ibm,xscom";
+    uint64_t reg[] = { cpu_to_be64(XSCOM_BASE(xb->chip_id)),
+                       cpu_to_be64(XSCOM_SIZE) };
+    int xscom_offset;
+
+    name = g_strdup_printf("xscom@%llx", (unsigned long long)
+                           be64_to_cpu(reg[0]));
+    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
+    _FDT(xscom_offset);
+    g_free(name);
+    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", xb->chip_id)));
+    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
+    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
+    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat,
+                      sizeof(compat))));
+    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
+
+    QTAILQ_FOREACH(bc, &xb->bus.children, sibling) {
+        DeviceState *qd = bc->child;
+        XScomDevice *xd = XSCOM_DEVICE(qd);
+        XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xd);
+        uint32_t reg[MAX_XSCOM_RANGES * 2];
+        unsigned int i, sz = 0;
+        void *cp, *p;
+        int child_offset;
+
+        /* Some XSCOM slaves may not be represented in the DT */
+        if (!xc->dt_name) {
+            continue;
+        }
+        name = g_strdup_printf("%s@%x", xc->dt_name, xd->ranges[0].addr);
+        child_offset = fdt_add_subnode(fdt, xscom_offset, name);
+        _FDT(child_offset);
+        g_free(name);
+        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
+            if (xd->ranges[i].size == 0) {
+                break;
+            }
+            reg[sz++] = cpu_to_be32(xd->ranges[i].addr);
+            reg[sz++] = cpu_to_be32(xd->ranges[i].size);
+        }
+        _FDT((fdt_setprop(fdt, child_offset, "reg", reg, sz * 4)));
+        if (xc->devnode) {
+            _FDT((xc->devnode(xd, fdt, child_offset)));
+        }
+#define MAX_COMPATIBLE_PROP     1024
+        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
+        i = 0;
+        while ((p - cp) < MAX_COMPATIBLE_PROP) {
+            int l;
+            if (xc->dt_compatible[i] == NULL) {
+                break;
+            }
+            l = strlen(xc->dt_compatible[i]);
+            if (l >= (MAX_COMPATIBLE_PROP - i)) {
+                break;
+            }
+            strcpy(p, xc->dt_compatible[i++]);
+            p += l + 1;
+        }
+        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));
+    }
+
+    return 0;
+}
+
+static int xscom_qdev_init(DeviceState *qdev)
+{
+    XScomDevice *xdev = (XScomDevice *)qdev;
+    XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xdev);
+
+    if (xc->init) {
+        return xc->init(xdev);
+    }
+    return 0;
+}
+
+static void xscom_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = xscom_qdev_init;
+    k->bus_type = TYPE_XSCOM_BUS;
+}
+
+static const TypeInfo xscom_dev_info = {
+    .name = TYPE_XSCOM_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(XScomDevice),
+    .abstract = true,
+    .class_size = sizeof(XScomDeviceClass),
+    .class_init = xscom_device_class_init,
+};
+
+static void xscom_register_types(void)
+{
+    type_register_static(&xscom_info);
+    type_register_static(&xscom_bus_info);
+    type_register_static(&xscom_dev_info);
+}
+
+type_init(xscom_register_types)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 1f32573dedff..bc6e1f80096b 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -35,12 +35,14 @@ typedef enum PnvChipType {
     PNV_CHIP_P8NVL, /* AKA Naples */
 } PnvChipType;
 
+typedef struct XScomBus XScomBus;
 typedef struct PnvChip {
     /*< private >*/
     SysBusDevice parent_obj;
 
     /*< public >*/
     uint32_t     chip_id;
+    XScomBus     *xscom;
 } PnvChip;
 
 typedef struct PnvChipClass {
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
new file mode 100644
index 000000000000..386ad21c5aa5
--- /dev/null
+++ b/include/hw/ppc/pnv_xscom.h
@@ -0,0 +1,75 @@
+#ifndef _HW_XSCOM_H
+#define _HW_XSCOM_H
+/*
+ * QEMU PowerNV XSCOM bus definitions
+ *
+ * Copyright (c) 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corp.
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <hw/ppc/pnv.h>
+
+#define TYPE_XSCOM_DEVICE "xscom-device"
+#define XSCOM_DEVICE(obj) \
+     OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE)
+#define XSCOM_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE)
+#define XSCOM_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE)
+
+#define TYPE_XSCOM_BUS "xscom-bus"
+#define XSCOM_BUS(obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS)
+
+typedef struct XScomDevice XScomDevice;
+typedef struct XScomBus XScomBus;
+
+typedef struct XScomDeviceClass {
+    DeviceClass parent_class;
+
+    const char *dt_name;
+    const char **dt_compatible;
+    int (*init)(XScomDevice *dev);
+    int (*devnode)(XScomDevice *dev, void *fdt, int offset);
+
+    /* Actual XScom accesses */
+    bool (*read)(XScomDevice *dev, uint32_t range, uint32_t offset,
+                 uint64_t *out_val);
+    bool (*write)(XScomDevice *dev, uint32_t range, uint32_t offset,
+                  uint64_t val);
+} XScomDeviceClass;
+
+typedef struct XScomRange {
+    uint32_t addr;
+    uint32_t size;
+} XScomRange;
+
+struct XScomDevice {
+    DeviceState qdev;
+#define MAX_XSCOM_RANGES 4
+    struct XScomRange ranges[MAX_XSCOM_RANGES];
+};
+
+struct XScomBus {
+    BusState bus;
+    uint32_t chip_id;
+};
+
+extern XScomBus *xscom_create(PnvChip *chip);
+extern int xscom_populate_fdt(XScomBus *xscom, void *fdt, int offset);
+
+
+#endif /* _HW_XSCOM_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
                   ` (2 preceding siblings ...)
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-02  8:03   ` Cédric Le Goater
  2016-09-05  3:42   ` David Gibson
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object Cédric Le Goater
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

This will be used to build real HW ids for the cores and enforce some
limits on the available cores per chip.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++++
 include/hw/ppc/pnv.h |  2 ++
 2 files changed, 29 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index a6e7f66b2c0a..b6efb5e3ef07 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -236,6 +236,27 @@ static void ppc_powernv_init(MachineState *machine)
     g_free(chip_typename);
 }
 
+/* Allowed core identifiers on a POWER8 Processor Chip :
+ *
+ * <EX0 reserved>
+ *  EX1  - Venice only
+ *  EX2  - Venice only
+ *  EX3  - Venice only
+ *  EX4
+ *  EX5
+ *  EX6
+ * <EX7,8 reserved> <reserved>
+ *  EX9  - Venice only
+ *  EX10 - Venice only
+ *  EX11 - Venice only
+ *  EX12
+ *  EX13
+ *  EX14
+ * <EX15 reserved>
+ */
+#define POWER8E_CORE_MASK  (~0xffff8f8f)
+#define POWER8_CORE_MASK   (~0xffff8181)
+
 static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
 {
     ;
@@ -250,6 +271,8 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
     k->cpu_model = "POWER8NVL";
     k->chip_type = PNV_CHIP_P8NVL;
     k->chip_f000f = 0x120d304980000000ull;
+    k->cores_max = 12;
+    k->cores_mask = POWER8_CORE_MASK;
     dc->desc = "PowerNV Chip POWER8NVL";
 }
 
@@ -274,6 +297,8 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
     k->cpu_model = "POWER8";
     k->chip_type = PNV_CHIP_P8;
     k->chip_f000f = 0x220ea04980000000ull;
+    k->cores_max = 12;
+    k->cores_mask = POWER8_CORE_MASK;
     dc->desc = "PowerNV Chip POWER8";
 }
 
@@ -298,6 +323,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
     k->cpu_model = "POWER8E";
     k->chip_type = PNV_CHIP_P8E;
     k->chip_f000f = 0x221ef04980000000ull;
+    k->cores_max = 6;
+    k->cores_mask = POWER8E_CORE_MASK;
     dc->desc = "PowerNV Chip POWER8E";
 }
 
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index bc6e1f80096b..987bc70245a7 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -49,6 +49,8 @@ typedef struct PnvChipClass {
     /*< private >*/
     SysBusDeviceClass parent_class;
     /*< public >*/
+    uint32_t   cores_max;
+    uint32_t   cores_mask;
     const char *cpu_model;
     PnvChipType  chip_type;
     uint64_t     chip_f000f;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
                   ` (3 preceding siblings ...)
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-05  4:02   ` David Gibson
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore Cédric Le Goater
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0 Cédric Le Goater
  6 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

This is largy inspired by sPAPRCPUCore with some simplification, no
hotplug for instance. But the differences are small and the objects
could possibly be merged.

A set of PnvCore objects is added to the PnvChip and the device
tree is populated looping on these cores.

Real HW cpu ids are now generated depending on the chip cpu model, the
chip id and a core mask. This id is stored in CPUState->cpu_index and
in PnvCore->core_id and it is used to populate the device tree.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 Changes since v1:

 - changed name to PnvCore
 - changed PnvChip core array type to a 'PnvCore *cores'
 - introduced real cpu hw ids using a core mask from the chip
 - reworked powernv_create_core_node() which populates the device tree
 - added missing "ibm,pa-features" property 
 - smp_cpus representing threads, used smp_cores instead to create the
   cores in the chip.
 - removed the use of ppc_get_vcpu_dt_id() 
 - added "POWER8E" and "POWER8NVL" cpu models to exercice the
   PnvChipClass

 hw/ppc/Makefile.objs      |   2 +-
 hw/ppc/pnv.c              | 204 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/pnv_core.c         | 170 ++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h      |   7 ++
 include/hw/ppc/pnv_core.h |  47 +++++++++++
 5 files changed, 429 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/pnv_core.c
 create mode 100644 include/hw/ppc/pnv_core.h

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index f580e5c41413..08c213c40684 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -6,7 +6,7 @@ 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_cpu_core.o
 # IBM PowerNV
-obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
+obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o
 ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
 obj-y += spapr_pci_vfio.o
 endif
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index b6efb5e3ef07..daf9f459ab0e 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -35,6 +35,7 @@
 #include "hw/ppc/fdt.h"
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_core.h"
 #include "hw/loader.h"
 #include "exec/address-spaces.h"
 #include "qemu/cutils.h"
@@ -98,6 +99,136 @@ static int powernv_populate_memory(void *fdt)
     return 0;
 }
 
+/*
+ * The PowerNV cores (and threads) need to use real HW ids and not an
+ * incremental index like it has been done on other platforms. This HW
+ * id is called a PIR and is used in the device tree, in the XSCOM
+ * communication to address cores, in the interrupt servers.
+ */
+static void powernv_create_core_node(PnvCore *pc, void *fdt,
+                                     int cpus_offset, int chip_id)
+{
+    CPUCore *core = CPU_CORE(pc);
+    CPUState *cs = CPU(DEVICE(pc->threads));
+    DeviceClass *dc = DEVICE_GET_CLASS(cs);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    int smt_threads = ppc_get_compat_smt_threads(cpu);
+    CPUPPCState *env = &cpu->env;
+    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
+    uint32_t servers_prop[smt_threads];
+    uint32_t gservers_prop[smt_threads * 2];
+    int i;
+    uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                       0xffffffff, 0xffffffff};
+    uint32_t tbfreq = PNV_TIMEBASE_FREQ;
+    uint32_t cpufreq = 1000000000;
+    uint32_t page_sizes_prop[64];
+    size_t page_sizes_prop_size;
+    const uint8_t pa_features[] = { 24, 0,
+                                    0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
+                                    0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+                                    0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
+    int offset;
+    char *nodename;
+
+    nodename = g_strdup_printf("%s@%x", dc->fw_name, core->core_id);
+    offset = fdt_add_subnode(fdt, cpus_offset, nodename);
+    _FDT(offset);
+    g_free(nodename);
+
+    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip_id)));
+
+    _FDT((fdt_setprop_cell(fdt, offset, "reg", core->core_id)));
+    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", core->core_id)));
+    _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
+
+    _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
+    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
+                            env->dcache_line_size)));
+    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
+                            env->dcache_line_size)));
+    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
+                            env->icache_line_size)));
+    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
+                            env->icache_line_size)));
+
+    if (pcc->l1_dcache_size) {
+        _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
+                               pcc->l1_dcache_size)));
+    } else {
+        error_report("Warning: Unknown L1 dcache size for cpu");
+    }
+    if (pcc->l1_icache_size) {
+        _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
+                               pcc->l1_icache_size)));
+    } else {
+        error_report("Warning: Unknown L1 icache size for cpu");
+    }
+
+    _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
+    _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
+    _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
+    _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
+    _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
+
+    if (env->spr_cb[SPR_PURR].oea_read) {
+        _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
+    }
+
+    if (env->mmu_model & POWERPC_MMU_1TSEG) {
+        _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
+                           segs, sizeof(segs))));
+    }
+
+    /* Advertise VMX/VSX (vector extensions) if available
+     *   0 / no property == no vector extensions
+     *   1               == VMX / Altivec available
+     *   2               == VSX available */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
+
+        _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
+    }
+
+    /* Advertise DFP (Decimal Floating Point) if available
+     *   0 / no property == no DFP
+     *   1               == DFP available */
+    if (env->insns_flags2 & PPC2_DFP) {
+        _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
+    }
+
+    page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
+                                                  sizeof(page_sizes_prop));
+    if (page_sizes_prop_size) {
+        _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
+                           page_sizes_prop, page_sizes_prop_size)));
+    }
+
+    _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
+                       pa_features, sizeof(pa_features))));
+
+    if (cpu->cpu_version) {
+        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
+    }
+
+    /* Build interrupt servers and gservers properties */
+    for (i = 0; i < smt_threads; i++) {
+        servers_prop[i] = cpu_to_be32(core->core_id + i);
+        /* Hack, direct the group queues back to cpu 0
+         *
+         * FIXME: check that we still need this hack with real HW
+         * ids. Probably not.
+         */
+        gservers_prop[i * 2] = cpu_to_be32(core->core_id + i);
+        gservers_prop[i * 2 + 1] = 0;
+    }
+    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
+                       servers_prop, sizeof(servers_prop))));
+    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
+                       gservers_prop, sizeof(gservers_prop))));
+}
+
 static void *powernv_create_fdt(PnvMachineState *pnv,
                                 const char *kernel_cmdline)
 {
@@ -106,6 +237,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
     int off;
     int i;
+    int cpus_offset;
 
     fdt = g_malloc0(FDT_MAX_SIZE);
     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
@@ -150,6 +282,22 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
         xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
     }
 
+    /* cpus */
+    cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
+    _FDT(cpus_offset);
+    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
+    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
+
+    for (i = 0; i < pnv->num_chips; i++) {
+        PnvChip *chip = pnv->chips[i];
+        int j;
+
+        for (j = 0; j < chip->num_cores; j++) {
+            powernv_create_core_node(&chip->cores[j], fdt, cpus_offset,
+                                     chip->chip_id);
+        }
+    }
+
     return fdt;
 }
 
@@ -230,6 +378,11 @@ static void ppc_powernv_init(MachineState *machine)
     for (i = 0; i < pnv->num_chips; i++) {
         Object *chip = object_new(chip_typename);
         object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
+        object_property_set_int(chip, smp_cores, "num-cores", &error_abort);
+        /*
+         * We could set a custom cores_mask for the chip here.
+         */
+
         object_property_set_bool(chip, true, "realized", &error_abort);
         pnv->chips[i] = PNV_CHIP(chip);
     }
@@ -335,19 +488,70 @@ static const TypeInfo pnv_chip_power8e_info = {
     .class_init    = pnv_chip_power8e_class_init,
 };
 
+/*
+ * This is different for POWER9 so we might need a ops in the chip to
+ * calculate the core pirs
+ */
+#define P8_PIR(chip_id, core_id) (((chip_id) << 7) | ((core_id) << 3))
+
 static void pnv_chip_realize(DeviceState *dev, Error **errp)
 {
     PnvChip *chip = PNV_CHIP(dev);
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+    char *typename = pnv_core_typename(pcc->cpu_model);
+    size_t typesize = object_type_get_instance_size(typename);
+    int i, core_hwid;
+
+    if (!object_class_by_name(typename)) {
+        error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
+        return;
+    }
 
     /* Set up XSCOM bus */
     chip->xscom = xscom_create(chip);
 
+    if (chip->num_cores > pcc->cores_max) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: too many cores for chip ! "
+                      "Limiting to %d\n", __func__, pcc->cores_max);
+        chip->num_cores = pcc->cores_max;
+    }
+
+    chip->cores = g_new0(PnvCore, chip->num_cores);
+
+    /* no custom mask for this chip, let's use the default one from
+     * the chip class */
+    if (!chip->cores_mask) {
+        chip->cores_mask = pcc->cores_mask;
+    }
+
+    for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
+             && (i < chip->num_cores); core_hwid++) {
+        PnvCore *pnv_core = &chip->cores[i];
+
+        if (!(chip->cores_mask & (1 << core_hwid))) {
+            continue;
+        }
+
+        object_initialize(pnv_core, typesize, typename);
+        object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
+                                &error_fatal);
+        object_property_set_int(OBJECT(pnv_core),
+                                P8_PIR(chip->chip_id, core_hwid),
+                                CPU_CORE_PROP_CORE_ID, &error_fatal);
+        object_property_set_bool(OBJECT(pnv_core), true, "realized",
+                                 &error_fatal);
+        object_unref(OBJECT(pnv_core));
+        i++;
+    }
+    g_free(typename);
+
     pcc->realize(chip, errp);
 }
 
 static Property pnv_chip_properties[] = {
     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
+    DEFINE_PROP_UINT32("num-cores", PnvChip, num_cores, 1),
+    DEFINE_PROP_UINT32("cores-mask", PnvChip, cores_mask, 0x0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
new file mode 100644
index 000000000000..825aea1194a1
--- /dev/null
+++ b/hw/ppc/pnv_core.c
@@ -0,0 +1,170 @@
+/*
+ * QEMU PowerPC PowerNV CPU Core model
+ *
+ * Copyright (c) IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "target-ppc/cpu.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_core.h"
+
+static void powernv_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    MachineState *machine = MACHINE(qdev_get_machine());
+    PnvMachineState *pnv = POWERNV_MACHINE(machine);
+
+    cpu_reset(cs);
+
+    env->spr[SPR_PIR] = cs->cpu_index;
+    env->spr[SPR_HIOR] = 0;
+    env->gpr[3] = pnv->fdt_addr;
+    env->nip = 0x10;
+    env->msr |= MSR_HVB;
+}
+
+static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* Set time-base frequency to 512 MHz */
+    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
+
+    /* MSR[IP] doesn't exist nowadays */
+    env->msr_mask &= ~(1 << 6);
+
+    qemu_register_reset(powernv_cpu_reset, cpu);
+    powernv_cpu_reset(cpu);
+}
+
+static void pnv_core_realize_child(Object *child, Error **errp)
+{
+    Error *local_err = NULL;
+    CPUState *cs = CPU(child);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+    object_property_set_bool(child, true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    powernv_cpu_init(cpu, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+}
+
+static void pnv_core_realize(DeviceState *dev, Error **errp)
+{
+    PnvCore *pc = PNV_CORE(OBJECT(dev));
+    CPUCore *cc = CPU_CORE(OBJECT(dev));
+    PnvCoreClass *pcc = PNV_CORE_GET_CLASS(OBJECT(dev));
+    const char *typename = object_class_get_name(pcc->cpu_oc);
+    size_t size = object_type_get_instance_size(typename);
+    Error *local_err = NULL;
+    void *obj;
+    int i, j;
+
+    pc->threads = g_malloc0(size * cc->nr_threads);
+    for (i = 0; i < cc->nr_threads; i++) {
+        char id[32];
+        CPUState *cs;
+
+        obj = pc->threads + i * size;
+
+        object_initialize(obj, size, typename);
+        cs = CPU(obj);
+        cs->cpu_index = cc->core_id + i;
+        snprintf(id, sizeof(id), "thread[%d]", i);
+        object_property_add_child(OBJECT(pc), id, obj, &local_err);
+        if (local_err) {
+            goto err;
+        }
+        object_unref(obj);
+    }
+
+    for (j = 0; j < cc->nr_threads; j++) {
+        obj = pc->threads + j * size;
+
+        pnv_core_realize_child(obj, &local_err);
+        if (local_err) {
+            goto err;
+        }
+    }
+    return;
+
+err:
+    while (--i >= 0) {
+        obj = pc->threads + i * size;
+        object_unparent(obj);
+    }
+    g_free(pc->threads);
+    error_propagate(errp, local_err);
+}
+
+/*
+ * Grow this list or merge with SPAPRCoreInfo which is very similar
+ */
+static const char *pnv_core_models[] = { "POWER8E", "POWER8", "POWER8NVL" };
+
+static void pnv_core_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
+
+    dc->realize = pnv_core_realize;
+    pcc->cpu_oc = cpu_class_by_name(TYPE_POWERPC_CPU, data);
+}
+
+static const TypeInfo pnv_core_info = {
+    .name           = TYPE_PNV_CORE,
+    .parent         = TYPE_CPU_CORE,
+    .instance_size  = sizeof(PnvCore),
+    .class_size     = sizeof(PnvCoreClass),
+    .abstract       = true,
+};
+
+static void pnv_core_register_types(void)
+{
+    int i ;
+
+    type_register_static(&pnv_core_info);
+    for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
+        TypeInfo ti = {
+            .parent = TYPE_PNV_CORE,
+            .instance_size = sizeof(PnvCore),
+            .class_init = pnv_core_class_init,
+            .class_data = (void *) pnv_core_models[i],
+        };
+        ti.name = pnv_core_typename(pnv_core_models[i]);
+        type_register(&ti);
+        g_free((void *)ti.name);
+    }
+}
+
+type_init(pnv_core_register_types)
+
+char *pnv_core_typename(const char *model)
+{
+    return g_strdup_printf(TYPE_PNV_CORE "-%s", model);
+}
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 987bc70245a7..8a3846743ccf 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -36,6 +36,7 @@ typedef enum PnvChipType {
 } PnvChipType;
 
 typedef struct XScomBus XScomBus;
+typedef struct PnvCore PnvCore;
 typedef struct PnvChip {
     /*< private >*/
     SysBusDevice parent_obj;
@@ -43,6 +44,10 @@ typedef struct PnvChip {
     /*< public >*/
     uint32_t     chip_id;
     XScomBus     *xscom;
+
+    uint32_t  num_cores;
+    uint32_t  cores_mask;
+    PnvCore   *cores;
 } PnvChip;
 
 typedef struct PnvChipClass {
@@ -109,4 +114,6 @@ typedef struct PnvMachineState {
     PnvChip   **chips;
 } PnvMachineState;
 
+#define PNV_TIMEBASE_FREQ           512000000ULL
+
 #endif /* _PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
new file mode 100644
index 000000000000..832c8756afaa
--- /dev/null
+++ b/include/hw/ppc/pnv_core.h
@@ -0,0 +1,47 @@
+/*
+ * QEMU PowerPC PowerNV CPU Core model
+ *
+ * Copyright (c) 2016 IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _PPC_PNV_CORE_H
+#define _PPC_PNV_CORE_H
+
+#include "hw/cpu/core.h"
+
+#define TYPE_PNV_CORE "powernv-cpu-core"
+#define PNV_CORE(obj) \
+    OBJECT_CHECK(PnvCore, (obj), TYPE_PNV_CORE)
+#define PNV_CORE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PnvCoreClass, (klass), TYPE_PNV_CORE)
+#define PNV_CORE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PnvCoreClass, (obj), TYPE_PNV_CORE)
+
+typedef struct PnvCore {
+    /*< private >*/
+    CPUCore parent_obj;
+
+    /*< public >*/
+    void *threads;
+} PnvCore;
+
+typedef struct PnvCoreClass {
+    DeviceClass parent_class;
+    ObjectClass *cpu_oc;
+} PnvCoreClass;
+
+extern char *pnv_core_typename(const char *model);
+
+#endif /* _PPC_PNV_CORE_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
                   ` (4 preceding siblings ...)
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-05  4:19   ` David Gibson
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0 Cédric Le Goater
  6 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

Now that we are using real HW ids for the cores in PowerNV chips, we
can route the XSCOM accesses to them. We just need to attach a
XScomDevice to each core with the associated ranges in the XSCOM
address space.

To start with, let's install the DTS (Digital Thermal Sensor) handlers
which are easy to handle.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv.c              |  9 +++++++
 hw/ppc/pnv_core.c         | 67 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv_core.h | 13 +++++++++
 3 files changed, 89 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index daf9f459ab0e..a31568415192 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -527,6 +527,7 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
              && (i < chip->num_cores); core_hwid++) {
         PnvCore *pnv_core = &chip->cores[i];
+        DeviceState *qdev;
 
         if (!(chip->cores_mask & (1 << core_hwid))) {
             continue;
@@ -542,6 +543,14 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
                                  &error_fatal);
         object_unref(OBJECT(pnv_core));
         i++;
+
+        /* Attach the core to its XSCOM bus */
+        qdev = qdev_create(&chip->xscom->bus, TYPE_PNV_CORE_XSCOM);
+        qdev_prop_set_uint32(qdev, "core-pir",
+                             P8_PIR(chip->chip_id, core_hwid));
+        qdev_init_nofail(qdev);
+
+        pnv_core->xd = PNV_CORE_XSCOM(qdev);
     }
     g_free(typename);
 
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 825aea1194a1..feba374740dc 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -18,7 +18,9 @@
  */
 #include "qemu/osdep.h"
 #include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "qemu/log.h"
 #include "target-ppc/cpu.h"
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/pnv.h"
@@ -144,10 +146,75 @@ static const TypeInfo pnv_core_info = {
     .abstract       = true,
 };
 
+
+#define DTS_RESULT0     0x50000
+#define DTS_RESULT1     0x50001
+
+static bool pnv_core_xscom_read(XScomDevice *dev, uint32_t range,
+                               uint32_t offset, uint64_t *out_val)
+{
+    switch (offset) {
+    case DTS_RESULT0:
+        *out_val = 0x26f024f023f0000ull;
+        break;
+    case DTS_RESULT1:
+        *out_val = 0x24f000000000000ull;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "Warning: reading reg=0x%08x", offset);
+    }
+
+   return true;
+}
+
+static bool pnv_core_xscom_write(XScomDevice *dev, uint32_t range,
+                                uint32_t offset, uint64_t val)
+{
+    qemu_log_mask(LOG_GUEST_ERROR, "Warning: writing to reg=0x%08x", offset);
+    return true;
+}
+
+#define EX_XSCOM_BASE 0x10000000
+#define EX_XSCOM_SIZE 0x100000
+
+static void pnv_core_xscom_realize(DeviceState *dev, Error **errp)
+{
+    XScomDevice *xd = XSCOM_DEVICE(dev);
+    PnvCoreXScom *pnv_xd = PNV_CORE_XSCOM(dev);
+
+    xd->ranges[0].addr = EX_XSCOM_BASE | P8_PIR2COREID(pnv_xd->core_pir) << 24;
+    xd->ranges[0].size = EX_XSCOM_SIZE;
+}
+
+static Property pnv_core_xscom_properties[] = {
+        DEFINE_PROP_UINT32("core-pir", PnvCoreXScom, core_pir, 0),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_core_xscom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    XScomDeviceClass *xdc = XSCOM_DEVICE_CLASS(klass);
+
+    xdc->read = pnv_core_xscom_read;
+    xdc->write = pnv_core_xscom_write;
+
+    dc->realize = pnv_core_xscom_realize;
+    dc->props = pnv_core_xscom_properties;
+}
+
+static const TypeInfo pnv_core_xscom_type_info = {
+    .name          = TYPE_PNV_CORE_XSCOM,
+    .parent        = TYPE_XSCOM_DEVICE,
+    .instance_size = sizeof(PnvCoreXScom),
+    .class_init    = pnv_core_xscom_class_init,
+};
+
 static void pnv_core_register_types(void)
 {
     int i ;
 
+    type_register_static(&pnv_core_xscom_type_info);
     type_register_static(&pnv_core_info);
     for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
         TypeInfo ti = {
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 832c8756afaa..72936ccfd22f 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -20,6 +20,18 @@
 #define _PPC_PNV_CORE_H
 
 #include "hw/cpu/core.h"
+#include "hw/ppc/pnv_xscom.h"
+
+#define TYPE_PNV_CORE_XSCOM "powernv-cpu-core-xscom"
+#define PNV_CORE_XSCOM(obj) \
+     OBJECT_CHECK(PnvCoreXScom, (obj), TYPE_PNV_CORE_XSCOM)
+
+typedef struct PnvCoreXScom {
+    XScomDevice xd;
+    uint32_t core_pir;
+} PnvCoreXScom;
+
+#define P8_PIR2COREID(pir) (((pir) >> 3) & 0xf)
 
 #define TYPE_PNV_CORE "powernv-cpu-core"
 #define PNV_CORE(obj) \
@@ -35,6 +47,7 @@ typedef struct PnvCore {
 
     /*< public >*/
     void *threads;
+    PnvCoreXScom *xd;
 } PnvCore;
 
 typedef struct PnvCoreClass {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0
  2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
                   ` (5 preceding siblings ...)
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore Cédric Le Goater
@ 2016-08-31 16:34 ` Cédric Le Goater
  2016-09-05  4:27   ` David Gibson
  6 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-08-31 16:34 UTC (permalink / raw)
  To: qemu-ppc
  Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf,
	Cedric Le Goater

On PowerNV, CPU ids start at 0x8 or 0x20, we don't have a CPU 0
anymore. So let's use the first_cpu index to initialize the monitor.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 So that you can dump the cpu list with the monitor :

	(qemu) info cpus
	* CPU #8: nip=0x0000000000000010 thread_id=7742
	  CPU #16: nip=0x0000000000000010 thread_id=7740
	  CPU #24: nip=0x0000000000000010 thread_id=7740
	  CPU #32: nip=0x0000000000000010 thread_id=7740
	  CPU #40: nip=0x0000000000000010 thread_id=7740
	  CPU #48: nip=0x0000000000000010 thread_id=7740
	  CPU #72: nip=0x0000000000000010 thread_id=7740
	  CPU #80: nip=0x0000000000000010 thread_id=7740
	  CPU #136: nip=0x0000000000000010 thread_id=7740
	  CPU #144: nip=0x0000000000000010 thread_id=7740
	  CPU #152: nip=0x0000000000000010 thread_id=7740
	  CPU #160: nip=0x0000000000000010 thread_id=7740
	  CPU #168: nip=0x0000000000000010 thread_id=7740
	  CPU #176: nip=0x0000000000000010 thread_id=7740
	  CPU #200: nip=0x0000000000000010 thread_id=7740
	  CPU #208: nip=0x0000000000000010 thread_id=7740

 monitor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/monitor.c b/monitor.c
index e9009de09a6c..19b8ec14f40e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1027,7 +1027,7 @@ int monitor_set_cpu(int cpu_index)
 CPUState *mon_get_cpu(void)
 {
     if (!cur_mon->mon_cpu) {
-        monitor_set_cpu(0);
+        monitor_set_cpu(first_cpu->cpu_index);
     }
     cpu_synchronize_state(cur_mon->mon_cpu);
     return cur_mon->mon_cpu;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
@ 2016-09-01 16:31   ` Greg Kurz
  2016-09-02  6:32     ` Cédric Le Goater
  2016-09-05  2:48   ` [Qemu-devel] " David Gibson
  1 sibling, 1 reply; 62+ messages in thread
From: Greg Kurz @ 2016-09-01 16:31 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, qemu-devel, David Gibson, Benjamin Herrenschmidt

On Wed, 31 Aug 2016 18:34:09 +0200
Cédric Le Goater <clg@kaod.org> wrote:

> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> The goal is to emulate a PowerNV system at the level of the skiboot
> firmware, which loads the OS and provides some runtime services. Power
> Systems have a lower firmware (HostBoot) that does low level system
> initialization, like DRAM training. This is beyond the scope of what
> qemu will address in a PowerNV guest.
> 
> No devices yet, not even an interrupt controller. Just to get started,
> some RAM to load the skiboot firmware, the kernel and initrd. The
> device tree is fully created in the machine reset op.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: - updated for qemu-2.7
>       - replaced fprintf by error_report
>       - used a common definition of _FDT macro
>       - removed VMStateDescription as migration is not yet supported
>       - added IBM Copyright statements
>       - reworked kernel_filename handling
>       - merged PnvSystem and sPowerNVMachineState
>       - removed PHANDLE_XICP
>       - added ppc_create_page_sizes_prop helper
>       - removed nmi support
>       - removed kvm support
>       - updated powernv machine to version 2.8
>       - removed chips and cpus, They will be provided in another patches
>       - added a machine reset routine to initialize the device tree (also)
>       - french has a squelette and english a skeleton.
>       - improved commit log.
>       - reworked prototypes parameters
>       - added a check on the ram size (thanks to Michael Ellerman)
>       - fixed chip-id cell
>       - changed MAX_CPUS to 2048
>       - simplified memory node creation to one node only
>       - removed machine version
>       - rewrote the device tree creation with the fdt "rw" routines
>       - s/sPowerNVMachineState/PnvMachineState/
>       - etc.
> ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  Changes since v1:
> 
>  - changed MAX_CPUS to 2048
>  - simplified memory node creation to one node only
>  - removed machine version 
>  - rewrote the device tree creation with the fdt "rw" routines
>  - s/sPowerNVMachineState/PnvMachineState/
>  - block_default_type is back to IF_IDE because of the AHCI device
> 
>  default-configs/ppc64-softmmu.mak |   1 +
>  hw/ppc/Makefile.objs              |   2 +
>  hw/ppc/pnv.c                      | 244 ++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h              |  37 ++++++
>  4 files changed, 284 insertions(+)
>  create mode 100644 hw/ppc/pnv.c
>  create mode 100644 include/hw/ppc/pnv.h
> 
> diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
> index c4be59f638ed..516a6e25aba3 100644
> --- a/default-configs/ppc64-softmmu.mak
> +++ b/default-configs/ppc64-softmmu.mak
> @@ -40,6 +40,7 @@ CONFIG_I8259=y
>  CONFIG_XILINX=y
>  CONFIG_XILINX_ETHLITE=y
>  CONFIG_PSERIES=y
> +CONFIG_POWERNV=y
>  CONFIG_PREP=y
>  CONFIG_MAC=y
>  CONFIG_E500=y
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 99a0d4e581bf..8105db7d5600 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -5,6 +5,8 @@ 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_cpu_core.o
> +# IBM PowerNV
> +obj-$(CONFIG_POWERNV) += pnv.o
>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>  obj-y += spapr_pci_vfio.o
>  endif
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> new file mode 100644
> index 000000000000..70413e3c5740
> --- /dev/null
> +++ b/hw/ppc/pnv.c
> @@ -0,0 +1,244 @@
> +/*
> + * QEMU PowerPC PowerNV model
> + *
> + * Copyright (c) 2004-2007 Fabrice Bellard
> + * Copyright (c) 2007 Jocelyn Mayer
> + * Copyright (c) 2010 David Gibson, IBM Corporation.
> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + *
> + */

This file is a new contribution to QEMU. According to the LICENSE file, it should
be released under GPL version 2 or later. If Ben agrees, probably better to have
the same text as in include/hw/ppc/pnv.h below.

> [...]
> --- /dev/null
> +++ b/include/hw/ppc/pnv.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU PowerNV various definitions
> + *
> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object Cédric Le Goater
@ 2016-09-01 17:21   ` Greg Kurz
  2016-09-02  6:34     ` Cédric Le Goater
  2016-09-05  2:58   ` [Qemu-devel] " David Gibson
  1 sibling, 1 reply; 62+ messages in thread
From: Greg Kurz @ 2016-09-01 17:21 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, David Gibson

On Wed, 31 Aug 2016 18:34:10 +0200
Cédric Le Goater <clg@kaod.org> wrote:

> This is is an abstraction of a POWER8 chip which is a set of cores
> plus other 'units', like the pervasive unit, the interrupt controller,
> the memory controller, the on-chip microcontroller, etc. The whole can
> be seen as a socket. It depends on a cpu model and its characteristics,
> max cores, specific init are defined in a PnvChipClass.
> 
> We start with an near empty PnvChip with only a few cpu constants
> which we will grow in the subsequent patches with the controllers
> required to run the system.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  Changes since v1:
>  
>  - introduced a PnvChipClass depending on the cpu model. It also
>    provides some chip constants used by devices, like the cpu model hw
>    id (f000f), a enum type (not sure this is useful yet), a custom
>    realize ops for customization.
>  - the num-chips property can be configured on the command line.
>  
>  Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 
> 
>  hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
>  2 files changed, 225 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 70413e3c5740..06051268e200 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
>      char *fw_filename;
>      long fw_size;
>      long kernel_size;
> +    int i;
> +    char *chip_typename;
>  
>      /* allocate RAM */
>      if (ram_size < (1 * G_BYTE)) {
> @@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
>              exit(1);
>          }
>      }
> +
> +    /* Create the processor chips */
> +    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
> +

You should check that the CPU model is supported by this machine (with
object_class_by_name()) and error out if it is not, or...

> +    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        Object *chip = object_new(chip_typename);

... this call to object_new() will abort.

> +        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
> +        object_property_set_bool(chip, true, "realized", &error_abort);
> +        pnv->chips[i] = PNV_CHIP(chip);
> +    }
> +    g_free(chip_typename);
> +}
> +
> +static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8nvl_realize;
> +    k->cpu_model = "POWER8NVL";
> +    k->chip_type = PNV_CHIP_P8NVL;
> +    k->chip_f000f = 0x120d304980000000ull;
> +    dc->desc = "PowerNV Chip POWER8NVL";
> +}
> +
> +static const TypeInfo pnv_chip_power8nvl_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8NVL,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8NVL),
> +    .class_init    = pnv_chip_power8nvl_class_init,
> +};
> +
> +static void pnv_chip_power8_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8_realize;
> +    k->cpu_model = "POWER8";
> +    k->chip_type = PNV_CHIP_P8;
> +    k->chip_f000f = 0x220ea04980000000ull;
> +    dc->desc = "PowerNV Chip POWER8";
> +}
> +
> +static const TypeInfo pnv_chip_power8_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8),
> +    .class_init    = pnv_chip_power8_class_init,
> +};
> +
> +static void pnv_chip_power8e_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8e_realize;
> +    k->cpu_model = "POWER8E";
> +    k->chip_type = PNV_CHIP_P8E;
> +    k->chip_f000f = 0x221ef04980000000ull;
> +    dc->desc = "PowerNV Chip POWER8E";
> +}
> +
> +static const TypeInfo pnv_chip_power8e_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8E,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8e),
> +    .class_init    = pnv_chip_power8e_class_init,
> +};
> +
> +static void pnv_chip_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvChip *chip = PNV_CHIP(dev);
> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> +
> +    pcc->realize(chip, errp);
> +}
> +
> +static Property pnv_chip_properties[] = {
> +    DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pnv_chip_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = pnv_chip_realize;
> +    dc->props = pnv_chip_properties;
> +    dc->desc = "PowerNV Chip";
> + }
> +
> +static const TypeInfo pnv_chip_info = {
> +    .name          = TYPE_PNV_CHIP,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .class_init    = pnv_chip_class_init,
> +    .class_size    = sizeof(PnvChipClass),
> +    .abstract      = true,
> +};
> +
> +static char *pnv_get_num_chips(Object *obj, Error **errp)
> +{
> +    return g_strdup_printf("%d", POWERNV_MACHINE(obj)->num_chips);
> +}
> +
> +static void pnv_set_num_chips(Object *obj, const char *value, Error **errp)
> +{
> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
> +    int num_chips;
> +
> +    if (sscanf(value, "%d", &num_chips) != 1) {
> +        error_setg(errp, "invalid num_chips property: '%s'", value);
> +    }
> +
> +    /*
> +     * FIXME: should we decide on how many chips we can create based
> +     * on #cores and Venice vs. Murano vs. Naples chip type etc...,
> +     */
> +    pnv->num_chips = num_chips;
> +}
> +
> +static void powernv_machine_initfn(Object *obj)
> +{
> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
> +    pnv->num_chips = 1;
> +
> +    object_property_add_str(obj, "num-chips", pnv_get_num_chips,
> +                            pnv_set_num_chips, NULL);
> +    object_property_set_description(obj, "num-chips",
> +                                    "Specifies the number of processor chips",
> +                                    NULL);
>  }
>  
>  static void powernv_machine_class_init(ObjectClass *oc, void *data)
> @@ -233,12 +382,17 @@ static const TypeInfo powernv_machine_info = {
>      .name          = TYPE_POWERNV_MACHINE,
>      .parent        = TYPE_MACHINE,
>      .instance_size = sizeof(PnvMachineState),
> +    .instance_init = powernv_machine_initfn,
>      .class_init    = powernv_machine_class_init,
>  };
>  
>  static void powernv_machine_register_types(void)
>  {
>      type_register_static(&powernv_machine_info);
> +    type_register_static(&pnv_chip_info);
> +    type_register_static(&pnv_chip_power8e_info);
> +    type_register_static(&pnv_chip_power8_info);
> +    type_register_static(&pnv_chip_power8nvl_info);
>  }
>  
>  type_init(powernv_machine_register_types)
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 31a57ed7f465..1f32573dedff 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -20,6 +20,74 @@
>  #define _PPC_PNV_H
>  
>  #include "hw/boards.h"
> +#include "hw/sysbus.h"
> +
> +#define TYPE_PNV_CHIP "powernv-chip"
> +#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
> +#define PNV_CHIP_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP)
> +#define PNV_CHIP_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvChipClass, (obj), TYPE_PNV_CHIP)
> +
> +typedef enum PnvChipType {
> +    PNV_CHIP_P8E,   /* AKA Murano (default) */
> +    PNV_CHIP_P8,    /* AKA Venice */
> +    PNV_CHIP_P8NVL, /* AKA Naples */
> +} PnvChipType;
> +
> +typedef struct PnvChip {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    uint32_t     chip_id;
> +} PnvChip;
> +
> +typedef struct PnvChipClass {
> +    /*< private >*/
> +    SysBusDeviceClass parent_class;
> +    /*< public >*/
> +    const char *cpu_model;
> +    PnvChipType  chip_type;
> +    uint64_t     chip_f000f;
> +
> +    void (*realize)(PnvChip *dev, Error **errp);
> +} PnvChipClass;
> +
> +#define TYPE_PNV_CHIP "powernv-chip"
> +

This macro is already defined above.


> +#define TYPE_PNV_CHIP_POWER8E "powernv-chip-POWER8E"

What about this ?

#define TYPE_PNV_CHIP_POWER8E TYPE_PNV_CHIP "-POWER8E"

> +#define PNV_CHIP_POWER8E(obj) \
> +    OBJECT_CHECK(PnvChipPower8e, (obj), TYPE_PNV_CHIP_POWER8E)
> +
> +typedef struct PnvChipPower8e {
> +    PnvChip pnv_chip;
> +} PnvChipPower8e;

Why Power8e here and...

> +
> +#define TYPE_PNV_CHIP_POWER8 "powernv-chip-POWER8"
> +#define PNV_CHIP_POWER8(obj) \
> +    OBJECT_CHECK(PnvChipPower8, (obj), TYPE_PNV_CHIP_POWER8)
> +
> +typedef struct PnvChipPower8 {
> +    PnvChip pnv_chip;
> +} PnvChipPower8;
> +
> +#define TYPE_PNV_CHIP_POWER8NVL "powernv-chip-POWER8NVL"
> +#define PNV_CHIP_POWER8NVL(obj) \
> +    OBJECT_CHECK(PnvChipPower8NVL, (obj), TYPE_PNV_CHIP_POWER8NVL)
> +
> +typedef struct PnvChipPower8NVL {
> +    PnvChip pnv_chip;
> +} PnvChipPower8NVL;

... Power8NVL there ?

> +
> +/*
> + * This generates a HW chip id depending on an index:
> + *
> + *    0x0, 0x1, 0x10, 0x11, 0x20, 0x21, ...
> + *
> + * Is this correct ?
> + */
> +#define CHIP_HWID(i) ((((i) & 0x3e) << 3) | ((i) & 0x1))
>  
>  #define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
>  #define POWERNV_MACHINE(obj) \
> @@ -32,6 +100,9 @@ typedef struct PnvMachineState {
>      uint32_t initrd_base;
>      long initrd_size;
>      hwaddr fdt_addr;
> +
> +    uint32_t  num_chips;
> +    PnvChip   **chips;
>  } PnvMachineState;
>  
>  #endif /* _PPC_PNV_H */

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-09-01 16:31   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-09-02  6:32     ` Cédric Le Goater
  2016-09-02  6:39       ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-02  6:32 UTC (permalink / raw)
  To: Greg Kurz; +Cc: qemu-ppc, qemu-devel, David Gibson, Benjamin Herrenschmidt

>> +/*
>> + * QEMU PowerPC PowerNV model
>> + *
>> + * Copyright (c) 2004-2007 Fabrice Bellard
>> + * Copyright (c) 2007 Jocelyn Mayer
>> + * Copyright (c) 2010 David Gibson, IBM Corporation.
>> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + *
>> + */
> 
> This file is a new contribution to QEMU. According to the LICENSE file, it should
> be released under GPL version 2 or later. If Ben agrees, probably better to have
> the same text as in include/hw/ppc/pnv.h below.

Yes. These copyright headers came from the spapr.c, the file on 
which pnv.c was originally based. pnv.c has nearly been completely 
rewritten since.

Ben, 

Is that OK with you ? 

Cheers,
C.



>> [...]
>> --- /dev/null
>> +++ b/include/hw/ppc/pnv.h
>> @@ -0,0 +1,37 @@
>> +/*
>> + * QEMU PowerNV various definitions
>> + *
>> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-01 17:21   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-09-02  6:34     ` Cédric Le Goater
  0 siblings, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-02  6:34 UTC (permalink / raw)
  To: Greg Kurz; +Cc: qemu-ppc, qemu-devel, David Gibson

On 09/01/2016 07:21 PM, Greg Kurz wrote:
> On Wed, 31 Aug 2016 18:34:10 +0200
> Cédric Le Goater <clg@kaod.org> wrote:
> 
>> This is is an abstraction of a POWER8 chip which is a set of cores
>> plus other 'units', like the pervasive unit, the interrupt controller,
>> the memory controller, the on-chip microcontroller, etc. The whole can
>> be seen as a socket. It depends on a cpu model and its characteristics,
>> max cores, specific init are defined in a PnvChipClass.
>>
>> We start with an near empty PnvChip with only a few cpu constants
>> which we will grow in the subsequent patches with the controllers
>> required to run the system.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>
>>  Changes since v1:
>>  
>>  - introduced a PnvChipClass depending on the cpu model. It also
>>    provides some chip constants used by devices, like the cpu model hw
>>    id (f000f), a enum type (not sure this is useful yet), a custom
>>    realize ops for customization.
>>  - the num-chips property can be configured on the command line.
>>  
>>  Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 
>>
>>  hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
>>  2 files changed, 225 insertions(+)
>>
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 70413e3c5740..06051268e200 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
>>      char *fw_filename;
>>      long fw_size;
>>      long kernel_size;
>> +    int i;
>> +    char *chip_typename;
>>  
>>      /* allocate RAM */
>>      if (ram_size < (1 * G_BYTE)) {
>> @@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
>>              exit(1);
>>          }
>>      }
>> +
>> +    /* Create the processor chips */
>> +    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
>> +
> 
> You should check that the CPU model is supported by this machine (with
> object_class_by_name()) and error out if it is not, or...
> 
>> +    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
>> +    for (i = 0; i < pnv->num_chips; i++) {
>> +        Object *chip = object_new(chip_typename);
> 
> ... this call to object_new() will abort.
> 
>> +        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
>> +        object_property_set_bool(chip, true, "realized", &error_abort);
>> +        pnv->chips[i] = PNV_CHIP(chip);
>> +    }
>> +    g_free(chip_typename);
>> +}
>> +
>> +static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
>> +
>> +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8nvl_realize;
>> +    k->cpu_model = "POWER8NVL";
>> +    k->chip_type = PNV_CHIP_P8NVL;
>> +    k->chip_f000f = 0x120d304980000000ull;
>> +    dc->desc = "PowerNV Chip POWER8NVL";
>> +}
>> +
>> +static const TypeInfo pnv_chip_power8nvl_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8NVL,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8NVL),
>> +    .class_init    = pnv_chip_power8nvl_class_init,
>> +};
>> +
>> +static void pnv_chip_power8_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
>> +
>> +static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8_realize;
>> +    k->cpu_model = "POWER8";
>> +    k->chip_type = PNV_CHIP_P8;
>> +    k->chip_f000f = 0x220ea04980000000ull;
>> +    dc->desc = "PowerNV Chip POWER8";
>> +}
>> +
>> +static const TypeInfo pnv_chip_power8_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8),
>> +    .class_init    = pnv_chip_power8_class_init,
>> +};
>> +
>> +static void pnv_chip_power8e_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
>> +
>> +static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8e_realize;
>> +    k->cpu_model = "POWER8E";
>> +    k->chip_type = PNV_CHIP_P8E;
>> +    k->chip_f000f = 0x221ef04980000000ull;
>> +    dc->desc = "PowerNV Chip POWER8E";
>> +}
>> +
>> +static const TypeInfo pnv_chip_power8e_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8E,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8e),
>> +    .class_init    = pnv_chip_power8e_class_init,
>> +};
>> +
>> +static void pnv_chip_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PnvChip *chip = PNV_CHIP(dev);
>> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>> +
>> +    pcc->realize(chip, errp);
>> +}
>> +
>> +static Property pnv_chip_properties[] = {
>> +    DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void pnv_chip_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = pnv_chip_realize;
>> +    dc->props = pnv_chip_properties;
>> +    dc->desc = "PowerNV Chip";
>> + }
>> +
>> +static const TypeInfo pnv_chip_info = {
>> +    .name          = TYPE_PNV_CHIP,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .class_init    = pnv_chip_class_init,
>> +    .class_size    = sizeof(PnvChipClass),
>> +    .abstract      = true,
>> +};
>> +
>> +static char *pnv_get_num_chips(Object *obj, Error **errp)
>> +{
>> +    return g_strdup_printf("%d", POWERNV_MACHINE(obj)->num_chips);
>> +}
>> +
>> +static void pnv_set_num_chips(Object *obj, const char *value, Error **errp)
>> +{
>> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
>> +    int num_chips;
>> +
>> +    if (sscanf(value, "%d", &num_chips) != 1) {
>> +        error_setg(errp, "invalid num_chips property: '%s'", value);
>> +    }
>> +
>> +    /*
>> +     * FIXME: should we decide on how many chips we can create based
>> +     * on #cores and Venice vs. Murano vs. Naples chip type etc...,
>> +     */
>> +    pnv->num_chips = num_chips;
>> +}
>> +
>> +static void powernv_machine_initfn(Object *obj)
>> +{
>> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
>> +    pnv->num_chips = 1;
>> +
>> +    object_property_add_str(obj, "num-chips", pnv_get_num_chips,
>> +                            pnv_set_num_chips, NULL);
>> +    object_property_set_description(obj, "num-chips",
>> +                                    "Specifies the number of processor chips",
>> +                                    NULL);
>>  }
>>  
>>  static void powernv_machine_class_init(ObjectClass *oc, void *data)
>> @@ -233,12 +382,17 @@ static const TypeInfo powernv_machine_info = {
>>      .name          = TYPE_POWERNV_MACHINE,
>>      .parent        = TYPE_MACHINE,
>>      .instance_size = sizeof(PnvMachineState),
>> +    .instance_init = powernv_machine_initfn,
>>      .class_init    = powernv_machine_class_init,
>>  };
>>  
>>  static void powernv_machine_register_types(void)
>>  {
>>      type_register_static(&powernv_machine_info);
>> +    type_register_static(&pnv_chip_info);
>> +    type_register_static(&pnv_chip_power8e_info);
>> +    type_register_static(&pnv_chip_power8_info);
>> +    type_register_static(&pnv_chip_power8nvl_info);
>>  }
>>  
>>  type_init(powernv_machine_register_types)
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 31a57ed7f465..1f32573dedff 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -20,6 +20,74 @@
>>  #define _PPC_PNV_H
>>  
>>  #include "hw/boards.h"
>> +#include "hw/sysbus.h"
>> +
>> +#define TYPE_PNV_CHIP "powernv-chip"
>> +#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
>> +#define PNV_CHIP_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP)
>> +#define PNV_CHIP_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(PnvChipClass, (obj), TYPE_PNV_CHIP)
>> +
>> +typedef enum PnvChipType {
>> +    PNV_CHIP_P8E,   /* AKA Murano (default) */
>> +    PNV_CHIP_P8,    /* AKA Venice */
>> +    PNV_CHIP_P8NVL, /* AKA Naples */
>> +} PnvChipType;
>> +
>> +typedef struct PnvChip {
>> +    /*< private >*/
>> +    SysBusDevice parent_obj;
>> +
>> +    /*< public >*/
>> +    uint32_t     chip_id;
>> +} PnvChip;
>> +
>> +typedef struct PnvChipClass {
>> +    /*< private >*/
>> +    SysBusDeviceClass parent_class;
>> +    /*< public >*/
>> +    const char *cpu_model;
>> +    PnvChipType  chip_type;
>> +    uint64_t     chip_f000f;
>> +
>> +    void (*realize)(PnvChip *dev, Error **errp);
>> +} PnvChipClass;
>> +
>> +#define TYPE_PNV_CHIP "powernv-chip"
>> +
> 
> This macro is already defined above.
>
> 
>> +#define TYPE_PNV_CHIP_POWER8E "powernv-chip-POWER8E"
> 
> What about this ?
> 
> #define TYPE_PNV_CHIP_POWER8E TYPE_PNV_CHIP "-POWER8E"

I thought of doing that and forgot :)

>> +#define PNV_CHIP_POWER8E(obj) \
>> +    OBJECT_CHECK(PnvChipPower8e, (obj), TYPE_PNV_CHIP_POWER8E)
>> +
>> +typedef struct PnvChipPower8e {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8e;
> 
> Why Power8e here and...

yes. I will change the names to be in sync with the cpu names 
and will probably do the same with enum PnvChipType. 

Thanks,

C.

>> +
>> +#define TYPE_PNV_CHIP_POWER8 "powernv-chip-POWER8"
>> +#define PNV_CHIP_POWER8(obj) \
>> +    OBJECT_CHECK(PnvChipPower8, (obj), TYPE_PNV_CHIP_POWER8)
>> +
>> +typedef struct PnvChipPower8 {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8;
>> +
>> +#define TYPE_PNV_CHIP_POWER8NVL "powernv-chip-POWER8NVL"
>> +#define PNV_CHIP_POWER8NVL(obj) \
>> +    OBJECT_CHECK(PnvChipPower8NVL, (obj), TYPE_PNV_CHIP_POWER8NVL)
>> +
>> +typedef struct PnvChipPower8NVL {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8NVL;
> 
> ... Power8NVL there ?
> 
>> +
>> +/*
>> + * This generates a HW chip id depending on an index:
>> + *
>> + *    0x0, 0x1, 0x10, 0x11, 0x20, 0x21, ...
>> + *
>> + * Is this correct ?
>> + */
>> +#define CHIP_HWID(i) ((((i) & 0x3e) << 3) | ((i) & 0x1))
>>  
>>  #define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
>>  #define POWERNV_MACHINE(obj) \
>> @@ -32,6 +100,9 @@ typedef struct PnvMachineState {
>>      uint32_t initrd_base;
>>      long initrd_size;
>>      hwaddr fdt_addr;
>> +
>> +    uint32_t  num_chips;
>> +    PnvChip   **chips;
>>  } PnvMachineState;
>>  
>>  #endif /* _PPC_PNV_H */
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-09-02  6:32     ` Cédric Le Goater
@ 2016-09-02  6:39       ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-02  6:39 UTC (permalink / raw)
  To: Cédric Le Goater, Greg Kurz; +Cc: qemu-ppc, qemu-devel, David Gibson

On Fri, 2016-09-02 at 08:32 +0200, Cédric Le Goater wrote:
> > This file is a new contribution to QEMU. According to the LICENSE
> file, it should
> > be released under GPL version 2 or later. If Ben agrees, probably
> better to have
> > the same text as in include/hw/ppc/pnv.h below.
> 
> Yes. These copyright headers came from the spapr.c, the file on 
> which pnv.c was originally based. pnv.c has nearly been completely 
> rewritten since.
> 
> Ben, 
> 
> Is that OK with you ? 

Sure.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
@ 2016-09-02  8:03   ` Cédric Le Goater
  2016-09-05  3:42   ` David Gibson
  1 sibling, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-02  8:03 UTC (permalink / raw)
  To: qemu-ppc; +Cc: David Gibson, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 08/31/2016 06:34 PM, Cédric Le Goater wrote:
> This will be used to build real HW ids for the cores and enforce some
> limits on the available cores per chip.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h |  2 ++
>  2 files changed, 29 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index a6e7f66b2c0a..b6efb5e3ef07 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -236,6 +236,27 @@ static void ppc_powernv_init(MachineState *machine)
>      g_free(chip_typename);
>  }
>  
> +/* Allowed core identifiers on a POWER8 Processor Chip :
> + *
> + * <EX0 reserved>
> + *  EX1  - Venice only
> + *  EX2  - Venice only
> + *  EX3  - Venice only
> + *  EX4
> + *  EX5
> + *  EX6
> + * <EX7,8 reserved> <reserved>
> + *  EX9  - Venice only
> + *  EX10 - Venice only
> + *  EX11 - Venice only
> + *  EX12
> + *  EX13
> + *  EX14
> + * <EX15 reserved>
> + */
> +#define POWER8E_CORE_MASK  (~0xffff8f8f)
> +#define POWER8_CORE_MASK   (~0xffff8181)
> +
>  static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
>  {
>      ;
> @@ -250,6 +271,8 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8NVL";
>      k->chip_type = PNV_CHIP_P8NVL;
>      k->chip_f000f = 0x120d304980000000ull;
> +    k->cores_max = 12;
> +    k->cores_mask = POWER8_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8NVL";
>  }
>  
> @@ -274,6 +297,8 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8";
>      k->chip_type = PNV_CHIP_P8;
>      k->chip_f000f = 0x220ea04980000000ull;
> +    k->cores_max = 12;
> +    k->cores_mask = POWER8_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8";
>  }
>  
> @@ -298,6 +323,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8E";
>      k->chip_type = PNV_CHIP_P8E;
>      k->chip_f000f = 0x221ef04980000000ull;
> +    k->cores_max = 6;
> +    k->cores_mask = POWER8E_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8E";
>  }
>  
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index bc6e1f80096b..987bc70245a7 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -49,6 +49,8 @@ typedef struct PnvChipClass {
>      /*< private >*/
>      SysBusDeviceClass parent_class;
>      /*< public >*/
> +    uint32_t   cores_max;
> +    uint32_t   cores_mask;

This 'cores_mask' attribute needs to be a uint64_t for POWER9. The 
core chiplet ids are in the range : [ 0x20 - 0x37 ]

I will change that in the next version and include a PnvChipPower9
class as the cpu_model was merged in David's branch.

Cheers,
C. 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
  2016-09-01 16:31   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-09-05  2:48   ` David Gibson
  2016-09-05  6:06     ` Cédric Le Goater
  1 sibling, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  2:48 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 14599 bytes --]

On Wed, Aug 31, 2016 at 06:34:09PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> The goal is to emulate a PowerNV system at the level of the skiboot
> firmware, which loads the OS and provides some runtime services. Power
> Systems have a lower firmware (HostBoot) that does low level system
> initialization, like DRAM training. This is beyond the scope of what
> qemu will address in a PowerNV guest.
> 
> No devices yet, not even an interrupt controller. Just to get started,
> some RAM to load the skiboot firmware, the kernel and initrd. The
> device tree is fully created in the machine reset op.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: - updated for qemu-2.7
>       - replaced fprintf by error_report
>       - used a common definition of _FDT macro
>       - removed VMStateDescription as migration is not yet supported
>       - added IBM Copyright statements
>       - reworked kernel_filename handling
>       - merged PnvSystem and sPowerNVMachineState
>       - removed PHANDLE_XICP
>       - added ppc_create_page_sizes_prop helper
>       - removed nmi support
>       - removed kvm support
>       - updated powernv machine to version 2.8
>       - removed chips and cpus, They will be provided in another patches
>       - added a machine reset routine to initialize the device tree (also)
>       - french has a squelette and english a skeleton.
>       - improved commit log.
>       - reworked prototypes parameters
>       - added a check on the ram size (thanks to Michael Ellerman)
>       - fixed chip-id cell
>       - changed MAX_CPUS to 2048
>       - simplified memory node creation to one node only
>       - removed machine version
>       - rewrote the device tree creation with the fdt "rw" routines
>       - s/sPowerNVMachineState/PnvMachineState/
>       - etc.
> ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  Changes since v1:
> 
>  - changed MAX_CPUS to 2048
>  - simplified memory node creation to one node only
>  - removed machine version 
>  - rewrote the device tree creation with the fdt "rw" routines
>  - s/sPowerNVMachineState/PnvMachineState/
>  - block_default_type is back to IF_IDE because of the AHCI device
> 
>  default-configs/ppc64-softmmu.mak |   1 +
>  hw/ppc/Makefile.objs              |   2 +
>  hw/ppc/pnv.c                      | 244 ++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h              |  37 ++++++
>  4 files changed, 284 insertions(+)
>  create mode 100644 hw/ppc/pnv.c
>  create mode 100644 include/hw/ppc/pnv.h
> 
> diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
> index c4be59f638ed..516a6e25aba3 100644
> --- a/default-configs/ppc64-softmmu.mak
> +++ b/default-configs/ppc64-softmmu.mak
> @@ -40,6 +40,7 @@ CONFIG_I8259=y
>  CONFIG_XILINX=y
>  CONFIG_XILINX_ETHLITE=y
>  CONFIG_PSERIES=y
> +CONFIG_POWERNV=y
>  CONFIG_PREP=y
>  CONFIG_MAC=y
>  CONFIG_E500=y
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 99a0d4e581bf..8105db7d5600 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -5,6 +5,8 @@ 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_cpu_core.o
> +# IBM PowerNV
> +obj-$(CONFIG_POWERNV) += pnv.o
>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>  obj-y += spapr_pci_vfio.o
>  endif
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> new file mode 100644
> index 000000000000..70413e3c5740
> --- /dev/null
> +++ b/hw/ppc/pnv.c
> @@ -0,0 +1,244 @@
> +/*
> + * QEMU PowerPC PowerNV model
> + *
> + * Copyright (c) 2004-2007 Fabrice Bellard
> + * Copyright (c) 2007 Jocelyn Mayer
> + * Copyright (c) 2010 David Gibson, IBM Corporation.
> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + *
> + */
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/numa.h"
> +#include "hw/hw.h"
> +#include "target-ppc/cpu.h"
> +#include "qemu/log.h"
> +#include "hw/ppc/fdt.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/ppc/pnv.h"
> +#include "hw/loader.h"
> +#include "exec/address-spaces.h"
> +#include "qemu/cutils.h"
> +
> +#include <libfdt.h>
> +
> +#define FDT_ADDR                0x01000000
> +#define FDT_MAX_SIZE            0x00100000
> +
> +#define FW_FILE_NAME            "skiboot.lid"
> +#define FW_LOAD_ADDR            0x0
> +#define FW_MAX_SIZE             0x00400000
> +
> +#define KERNEL_LOAD_ADDR        0x20000000
> +#define INITRD_LOAD_ADDR        0x40000000
> +
> +/*
> + * On Power Systems E880, the max cpus (threads) should be :
> + *     4 * 4 sockets * 12 cores * 8 threads = 1536
> + * Let's make it 2^11
> + */
> +#define MAX_CPUS                2048
> +
> +static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
> +                                         hwaddr size)
> +{
> +    char *mem_name;
> +    uint64_t mem_reg_property[2];
> +    int off;
> +
> +    mem_reg_property[0] = cpu_to_be64(start);
> +    mem_reg_property[1] = cpu_to_be64(size);
> +
> +    mem_name = g_strdup_printf("memory@"TARGET_FMT_lx, start);
> +    off = fdt_add_subnode(fdt, 0, mem_name);
> +    g_free(mem_name);
> +
> +    _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
> +    _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
> +                       sizeof(mem_reg_property))));
> +    _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
> +}
> +
> +
> +/*
> + * Memory nodes are created by hostboot, one for each range of memory
> + * that has a different "affinity". In practice, it means one range
> + * per chip.
> + */
> +static int powernv_populate_memory(void *fdt)
> +{
> +    int chip_id = 0;
> +    hwaddr chip_ramsize = ram_size;
> +    hwaddr chip_start = 0;
> +
> +    /* Only one chip for the moment */
> +    powernv_populate_memory_node(fdt, chip_id, chip_start, chip_ramsize);
> +
> +    return 0;
> +}
> +
> +static void *powernv_create_fdt(PnvMachineState *pnv,
> +                                const char *kernel_cmdline)
> +{
> +    void *fdt;
> +    char *buf;
> +    const char plat_compat[] = "qemu,powernv\0ibm,powernv";
> +    int off;
> +
> +    fdt = g_malloc0(FDT_MAX_SIZE);
> +    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> +
> +    /* Root node */
> +    _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
> +    _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
> +    _FDT((fdt_setprop_string(fdt, 0, "model",
> +                             "IBM PowerNV (emulated by qemu)")));
> +    _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
> +                      sizeof(plat_compat))));
> +
> +    buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1],
> +                          qemu_uuid[2], qemu_uuid[3], qemu_uuid[4],
> +                          qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
> +                          qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
> +                          qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
> +                          qemu_uuid[14], qemu_uuid[15]);
> +    _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
> +    g_free(buf);
> +
> +    off = fdt_add_subnode(fdt, 0, "chosen");
> +    if (kernel_cmdline) {
> +        _FDT((fdt_setprop_string(fdt, off, "bootargs", kernel_cmdline)));
> +    }
> +
> +    if (pnv->initrd_size) {
> +        uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
> +        uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
> +
> +        _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
> +                               &start_prop, sizeof(start_prop))));
> +        _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
> +                               &end_prop, sizeof(end_prop))));
> +    }
> +
> +    /* Memory */
> +    powernv_populate_memory(fdt);
> +
> +    return fdt;
> +}
> +
> +static void ppc_powernv_reset(void)
> +{
> +    MachineState *machine = MACHINE(qdev_get_machine());
> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
> +    void *fdt;
> +
> +    pnv->fdt_addr = FDT_ADDR;

Not sure there's any point to pnv->fdt_addr, since it will always have
the value FDT_ADDR.  Only worth changing if you're doing a respin for
other reasons though.

> +
> +    qemu_devices_reset();
> +
> +    fdt = powernv_create_fdt(pnv, machine->kernel_cmdline);
> +
> +    cpu_physical_memory_write(pnv->fdt_addr, fdt, fdt_totalsize(fdt));
> +}
> +
> +static void ppc_powernv_init(MachineState *machine)
> +{
> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
> +    ram_addr_t ram_size = machine->ram_size;
> +    MemoryRegion *ram;
> +    char *fw_filename;
> +    long fw_size;
> +    long kernel_size;
> +
> +    /* allocate RAM */
> +    if (ram_size < (1 * G_BYTE)) {
> +        error_report("Warning: skiboot may not work with < 1GB of RAM");
> +    }
> +
> +    ram = g_new(MemoryRegion, 1);
> +    memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
> +                                         ram_size);
> +    memory_region_add_subregion(get_system_memory(), 0, ram);
> +
> +    /* load skiboot firmware  */
> +    if (bios_name == NULL) {
> +        bios_name = FW_FILE_NAME;
> +    }
> +
> +    fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> +
> +    fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
> +    if (fw_size < 0) {
> +        hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
> +        exit(1);
> +    }
> +    g_free(fw_filename);
> +
> +    /* load kernel */
> +    kernel_size = load_image_targphys(machine->kernel_filename,
> +                                      KERNEL_LOAD_ADDR, 0x2000000);
> +    if (kernel_size < 0) {
> +        hw_error("qemu: could not load kernel'%s'\n", machine->kernel_filename);
> +        exit(1);
> +    }
> +
> +    /* load initrd */
> +    if (machine->initrd_filename) {
> +        pnv->initrd_base = INITRD_LOAD_ADDR;
> +        pnv->initrd_size = load_image_targphys(machine->initrd_filename,
> +                                  pnv->initrd_base, 0x10000000); /* 128MB max */
> +        if (pnv->initrd_size < 0) {
> +            error_report("qemu: could not load initial ram disk '%s'",
> +                         machine->initrd_filename);
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void powernv_machine_class_init(ObjectClass *oc, void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "IBM PowerNV (Non-Virtualized)";
> +    mc->init = ppc_powernv_init;
> +    mc->reset = ppc_powernv_reset;
> +    mc->max_cpus = MAX_CPUS;
> +    mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
> +                                      * storage */
> +    mc->no_parallel = 1;
> +    mc->default_boot_order = NULL;
> +    mc->default_ram_size = 1 * G_BYTE;
> +}
> +
> +static const TypeInfo powernv_machine_info = {
> +    .name          = TYPE_POWERNV_MACHINE,
> +    .parent        = TYPE_MACHINE,
> +    .instance_size = sizeof(PnvMachineState),
> +    .class_init    = powernv_machine_class_init,
> +};
> +
> +static void powernv_machine_register_types(void)
> +{
> +    type_register_static(&powernv_machine_info);
> +}
> +
> +type_init(powernv_machine_register_types)
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> new file mode 100644
> index 000000000000..31a57ed7f465
> --- /dev/null
> +++ b/include/hw/ppc/pnv.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU PowerNV various definitions
> + *
> + * Copyright (c) 2014-2016 BenH, IBM Corporation.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef _PPC_PNV_H
> +#define _PPC_PNV_H
> +
> +#include "hw/boards.h"
> +
> +#define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
> +#define POWERNV_MACHINE(obj) \
> +    OBJECT_CHECK(PnvMachineState, (obj), TYPE_POWERNV_MACHINE)
> +
> +typedef struct PnvMachineState {
> +    /*< private >*/
> +    MachineState parent_obj;
> +
> +    uint32_t initrd_base;
> +    long initrd_size;
> +    hwaddr fdt_addr;
> +} PnvMachineState;
> +
> +#endif /* _PPC_PNV_H */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object Cédric Le Goater
  2016-09-01 17:21   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-09-05  2:58   ` David Gibson
  2016-09-05  6:59     ` Benjamin Herrenschmidt
  2016-09-05  7:56     ` Cédric Le Goater
  1 sibling, 2 replies; 62+ messages in thread
From: David Gibson @ 2016-09-05  2:58 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 10816 bytes --]

On Wed, Aug 31, 2016 at 06:34:10PM +0200, Cédric Le Goater wrote:
> This is is an abstraction of a POWER8 chip which is a set of cores
> plus other 'units', like the pervasive unit, the interrupt controller,
> the memory controller, the on-chip microcontroller, etc. The whole can
> be seen as a socket. It depends on a cpu model and its characteristics,
> max cores, specific init are defined in a PnvChipClass.
> 
> We start with an near empty PnvChip with only a few cpu constants
> which we will grow in the subsequent patches with the controllers
> required to run the system.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  Changes since v1:
>  
>  - introduced a PnvChipClass depending on the cpu model. It also
>    provides some chip constants used by devices, like the cpu model hw
>    id (f000f), a enum type (not sure this is useful yet), a custom
>    realize ops for customization.
>  - the num-chips property can be configured on the command line.
>  
>  Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 
> 
>  hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
>  2 files changed, 225 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 70413e3c5740..06051268e200 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
>      char *fw_filename;
>      long fw_size;
>      long kernel_size;
> +    int i;
> +    char *chip_typename;
>  
>      /* allocate RAM */
>      if (ram_size < (1 * G_BYTE)) {
> @@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
>              exit(1);
>          }
>      }
> +
> +    /* Create the processor chips */
> +    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
> +
> +    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        Object *chip = object_new(chip_typename);
> +        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
> +        object_property_set_bool(chip, true, "realized", &error_abort);

I'm guessing these could fail due to bad user supplied parameters, not
just internal bugs.  In which case this should be &error_fatal rather
than &error_abort.

> +        pnv->chips[i] = PNV_CHIP(chip);
> +    }
> +    g_free(chip_typename);
> +}
> +
> +static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}

I don't think you should need to define an empty realize function.  Or
is this just a placeholder for things future patches will add?

> +
> +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8nvl_realize;
> +    k->cpu_model = "POWER8NVL";
> +    k->chip_type = PNV_CHIP_P8NVL;

With the new chip class per cpu class, does this chip_type field serve
any purpose any more?

> +    k->chip_f000f = 0x120d304980000000ull;

A comment somewhere explaining what this cryptic value is would be nice.

> +    dc->desc = "PowerNV Chip POWER8NVL";
> +}
> +
> +static const TypeInfo pnv_chip_power8nvl_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8NVL,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8NVL),
> +    .class_init    = pnv_chip_power8nvl_class_init,
> +};
> +
> +static void pnv_chip_power8_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8_realize;
> +    k->cpu_model = "POWER8";
> +    k->chip_type = PNV_CHIP_P8;
> +    k->chip_f000f = 0x220ea04980000000ull;
> +    dc->desc = "PowerNV Chip POWER8";
> +}

It might be worth using some macros to compactify the definition of
each of the chip variants.

> +
> +static const TypeInfo pnv_chip_power8_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8),
> +    .class_init    = pnv_chip_power8_class_init,
> +};
> +
> +static void pnv_chip_power8e_realize(PnvChip *chip, Error **errp)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->realize = pnv_chip_power8e_realize;
> +    k->cpu_model = "POWER8E";
> +    k->chip_type = PNV_CHIP_P8E;
> +    k->chip_f000f = 0x221ef04980000000ull;
> +    dc->desc = "PowerNV Chip POWER8E";
> +}
> +
> +static const TypeInfo pnv_chip_power8e_info = {
> +    .name          = TYPE_PNV_CHIP_POWER8E,
> +    .parent        = TYPE_PNV_CHIP,
> +    .instance_size = sizeof(PnvChipPower8e),
> +    .class_init    = pnv_chip_power8e_class_init,
> +};
> +
> +static void pnv_chip_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvChip *chip = PNV_CHIP(dev);
> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> +
> +    pcc->realize(chip, errp);
> +}
> +
> +static Property pnv_chip_properties[] = {
> +    DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pnv_chip_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = pnv_chip_realize;
> +    dc->props = pnv_chip_properties;
> +    dc->desc = "PowerNV Chip";
> + }
> +
> +static const TypeInfo pnv_chip_info = {
> +    .name          = TYPE_PNV_CHIP,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .class_init    = pnv_chip_class_init,
> +    .class_size    = sizeof(PnvChipClass),
> +    .abstract      = true,
> +};
> +
> +static char *pnv_get_num_chips(Object *obj, Error **errp)
> +{
> +    return g_strdup_printf("%d", POWERNV_MACHINE(obj)->num_chips);
> +}
> +
> +static void pnv_set_num_chips(Object *obj, const char *value, Error **errp)
> +{
> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
> +    int num_chips;
> +
> +    if (sscanf(value, "%d", &num_chips) != 1) {
> +        error_setg(errp, "invalid num_chips property: '%s'", value);
> +    }
> +
> +    /*
> +     * FIXME: should we decide on how many chips we can create based
> +     * on #cores and Venice vs. Murano vs. Naples chip type etc...,
> +     */
> +    pnv->num_chips = num_chips;
> +}
> +
> +static void powernv_machine_initfn(Object *obj)
> +{
> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
> +    pnv->num_chips = 1;
> +
> +    object_property_add_str(obj, "num-chips", pnv_get_num_chips,
> +                            pnv_set_num_chips, NULL);
> +    object_property_set_description(obj, "num-chips",
> +                                    "Specifies the number of processor chips",
> +                                    NULL);
>  }
>  
>  static void powernv_machine_class_init(ObjectClass *oc, void *data)
> @@ -233,12 +382,17 @@ static const TypeInfo powernv_machine_info = {
>      .name          = TYPE_POWERNV_MACHINE,
>      .parent        = TYPE_MACHINE,
>      .instance_size = sizeof(PnvMachineState),
> +    .instance_init = powernv_machine_initfn,
>      .class_init    = powernv_machine_class_init,
>  };
>  
>  static void powernv_machine_register_types(void)
>  {
>      type_register_static(&powernv_machine_info);
> +    type_register_static(&pnv_chip_info);
> +    type_register_static(&pnv_chip_power8e_info);
> +    type_register_static(&pnv_chip_power8_info);
> +    type_register_static(&pnv_chip_power8nvl_info);
>  }
>  
>  type_init(powernv_machine_register_types)
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 31a57ed7f465..1f32573dedff 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -20,6 +20,74 @@
>  #define _PPC_PNV_H
>  
>  #include "hw/boards.h"
> +#include "hw/sysbus.h"
> +
> +#define TYPE_PNV_CHIP "powernv-chip"
> +#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
> +#define PNV_CHIP_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP)
> +#define PNV_CHIP_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvChipClass, (obj), TYPE_PNV_CHIP)
> +
> +typedef enum PnvChipType {
> +    PNV_CHIP_P8E,   /* AKA Murano (default) */
> +    PNV_CHIP_P8,    /* AKA Venice */
> +    PNV_CHIP_P8NVL, /* AKA Naples */
> +} PnvChipType;
> +
> +typedef struct PnvChip {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    uint32_t     chip_id;
> +} PnvChip;
> +
> +typedef struct PnvChipClass {
> +    /*< private >*/
> +    SysBusDeviceClass parent_class;
> +    /*< public >*/
> +    const char *cpu_model;
> +    PnvChipType  chip_type;
> +    uint64_t     chip_f000f;
> +
> +    void (*realize)(PnvChip *dev, Error **errp);
> +} PnvChipClass;
> +
> +#define TYPE_PNV_CHIP "powernv-chip"
> +
> +#define TYPE_PNV_CHIP_POWER8E "powernv-chip-POWER8E"
> +#define PNV_CHIP_POWER8E(obj) \
> +    OBJECT_CHECK(PnvChipPower8e, (obj), TYPE_PNV_CHIP_POWER8E)
> +
> +typedef struct PnvChipPower8e {
> +    PnvChip pnv_chip;
> +} PnvChipPower8e;
> +
> +#define TYPE_PNV_CHIP_POWER8 "powernv-chip-POWER8"
> +#define PNV_CHIP_POWER8(obj) \
> +    OBJECT_CHECK(PnvChipPower8, (obj), TYPE_PNV_CHIP_POWER8)
> +
> +typedef struct PnvChipPower8 {
> +    PnvChip pnv_chip;
> +} PnvChipPower8;
> +
> +#define TYPE_PNV_CHIP_POWER8NVL "powernv-chip-POWER8NVL"
> +#define PNV_CHIP_POWER8NVL(obj) \
> +    OBJECT_CHECK(PnvChipPower8NVL, (obj), TYPE_PNV_CHIP_POWER8NVL)
> +
> +typedef struct PnvChipPower8NVL {
> +    PnvChip pnv_chip;
> +} PnvChipPower8NVL;
> +
> +/*
> + * This generates a HW chip id depending on an index:
> + *
> + *    0x0, 0x1, 0x10, 0x11, 0x20, 0x21, ...
> + *
> + * Is this correct ?
> + */
> +#define CHIP_HWID(i) ((((i) & 0x3e) << 3) | ((i) & 0x1))
>  
>  #define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
>  #define POWERNV_MACHINE(obj) \
> @@ -32,6 +100,9 @@ typedef struct PnvMachineState {
>      uint32_t initrd_base;
>      long initrd_size;
>      hwaddr fdt_addr;
> +
> +    uint32_t  num_chips;
> +    PnvChip   **chips;
>  } PnvMachineState;
>  
>  #endif /* _PPC_PNV_H */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure Cédric Le Goater
@ 2016-09-05  3:39   ` David Gibson
  2016-09-05  7:11     ` Benjamin Herrenschmidt
  2016-09-06 14:42     ` Cédric Le Goater
  2016-09-05  4:16   ` [Qemu-devel] [Qemu-ppc] " Sam Bobroff
  1 sibling, 2 replies; 62+ messages in thread
From: David Gibson @ 2016-09-05  3:39 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 22435 bytes --]

On Wed, Aug 31, 2016 at 06:34:11PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> XSCOM is an interface to a sideband bus provided by the POWER8 chip
> pervasive unit, which gives access to a number of facilities in the
> chip that are needed by the OPAL firmware and to a lesser extent,
> Linux. This is among others how the PCI Host bridges get configured
> at boot or how the LPC bus is accessed.
> 
> This provides a simple bus and device type for devices sitting on
> XSCOM along with some facilities to optionally generate corresponding
> device-tree nodes
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: updated for qemu-2.7
>       ported on new sPowerNVMachineState which was merged with PnvSystem
>       removed TRACE_XSCOM
>       fixed checkpatch errors
>       replaced assert with error_setg in xscom_realize()
>       reworked xscom_create
>       introduced the use of the chip_class for chip model contants
>       ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  They were some discussions on whether we should use a qemu
>  address_space instead of the xscom ranges defined in this patch. 
>  I gave it try, it is possible but it brings extra unnecessary calls
>  and complexity. I think the current solution is better.
> 
>  hw/ppc/Makefile.objs       |   2 +-
>  hw/ppc/pnv.c               |  11 ++
>  hw/ppc/pnv_xscom.c         | 408 +++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h       |   2 +
>  include/hw/ppc/pnv_xscom.h |  75 +++++++++
>  5 files changed, 497 insertions(+), 1 deletion(-)
>  create mode 100644 hw/ppc/pnv_xscom.c
>  create mode 100644 include/hw/ppc/pnv_xscom.h
> 
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 8105db7d5600..f580e5c41413 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -6,7 +6,7 @@ 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_cpu_core.o
>  # IBM PowerNV
> -obj-$(CONFIG_POWERNV) += pnv.o
> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>  obj-y += spapr_pci_vfio.o
>  endif
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 06051268e200..a6e7f66b2c0a 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -39,6 +39,8 @@
>  #include "exec/address-spaces.h"
>  #include "qemu/cutils.h"
>  
> +#include "hw/ppc/pnv_xscom.h"
> +
>  #include <libfdt.h>
>  
>  #define FDT_ADDR                0x01000000
> @@ -103,6 +105,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>      char *buf;
>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
>      int off;
> +    int i;
>  
>      fdt = g_malloc0(FDT_MAX_SIZE);
>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> @@ -142,6 +145,11 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>      /* Memory */
>      powernv_populate_memory(fdt);
>  
> +    /* Populate XSCOM for each chip */
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
> +    }

There will be a bunch of per-chip things in the fdt - I suggest a
common function to do all the fdt creation for a single chip.  Since
you've moved to using the fdt_rw functions exclusively, you don't have
the sequence constraints that would have made that awkward previously.

>      return fdt;
>  }
>  
> @@ -305,6 +313,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>      PnvChip *chip = PNV_CHIP(dev);
>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>  
> +    /* Set up XSCOM bus */
> +    chip->xscom = xscom_create(chip);

So, this creates the xscom as a new device object, unfortunately doing
that from another object's realize() violations QOM lifetime rules as
I understand them.  I think - I have to admit I'm pretty confused on
this topic myself.

You could construct the scom from chip init, then realize it from chip
realize, but I think using object_new() (via qdev_create()) from
another object's init also breaks the rules.  You are however allowed
to allocate the scom state statically within the chip and use
object_initialize() instead, AIUI.

Alternatively.. it might be simpler to just drop the SCOM as a
separate device.  I think you could just hang the scom bus directly
off the chip object.  IIUC the scom is basically the only chip-level
control mechanism, so this does make a certain amount of sense.

>      pcc->realize(chip, errp);
>  }
>  
> diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
> new file mode 100644
> index 000000000000..7ed3804f4b3a
> --- /dev/null
> +++ b/hw/ppc/pnv_xscom.c
> @@ -0,0 +1,408 @@
> +
> +/*
> + * QEMU PowerNV XSCOM bus definitions
> + *
> + * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
> + * Based on the s390 virtio bus code:
> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/* TODO: Add some infrastructure for "random stuff" and FIRs that
> + * various units might want to deal with without creating actual
> + * XSCOM devices.
> + *
> + * For example, HB LPC XSCOM in the PIBAM
> + */
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/hw.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/boards.h"
> +#include "monitor/monitor.h"
> +#include "hw/loader.h"
> +#include "elf.h"
> +#include "hw/sysbus.h"
> +#include "sysemu/kvm.h"
> +#include "sysemu/device_tree.h"
> +#include "hw/ppc/fdt.h"
> +
> +#include "hw/ppc/pnv_xscom.h"
> +
> +#include <libfdt.h>
> +
> +#define TYPE_XSCOM "xscom"
> +#define XSCOM(obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM)
> +
> +#define XSCOM_SIZE        0x800000000ull
> +#define XSCOM_BASE(chip)  (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE)
> +
> +
> +typedef struct XScomState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +    /*< public >*/
> +
> +    MemoryRegion mem;
> +    int32_t chip_id;

Merging scom and chip would avoid the duplication of this field too.

> +    PnvChipClass *chip_class;
> +    XScomBus *bus;
> +} XScomState;
> +
> +static uint32_t xscom_to_pcb_addr(uint64_t addr)
> +{
> +        addr &= (XSCOM_SIZE - 1);
> +        return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
> +}
> +
> +static void xscom_complete(uint64_t hmer_bits)
> +{
> +    CPUState *cs = current_cpu;
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    CPUPPCState *env = &cpu->env;
> +
> +    cpu_synchronize_state(cs);
> +    env->spr[SPR_HMER] |= hmer_bits;
> +
> +    /* XXX Need a CPU helper to set HMER, also handle gneeration
> +     * of HMIs
> +     */
> +}
> +
> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t pcb_addr,
> +                                      uint32_t *range)
> +{
> +    BusChild *bc;
> +
> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> +        DeviceState *qd = bc->child;
> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> +        unsigned int i;
> +
> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> +            if (xd->ranges[i].addr <= pcb_addr &&
> +                (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) {
> +                *range = i;
> +                return xd;
> +            }
> +        }
> +    }

Hmm.. you could set up a SCOM local address space using the
infrastructure in memory.c, rather than doing your own dispatch.

> +    return NULL;
> +}
> +
> +static bool xscom_dispatch_read(XScomState *s, uint32_t pcb_addr,
> +                                uint64_t *out_val)
> +{
> +    uint32_t range, offset;
> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> +    XScomDeviceClass *xc;
> +
> +    if (!xd) {
> +        return false;
> +    }
> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> +    if (!xc->read) {
> +        return false;
> +    }
> +    offset = pcb_addr - xd->ranges[range].addr;
> +    return xc->read(xd, range, offset, out_val);
> +}
> +
> +static bool xscom_dispatch_write(XScomState *s, uint32_t pcb_addr, uint64_t val)
> +{
> +    uint32_t range, offset;
> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> +    XScomDeviceClass *xc;
> +
> +    if (!xd) {
> +        return false;
> +    }
> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> +    if (!xc->write) {
> +        return false;
> +    }
> +    offset = pcb_addr - xd->ranges[range].addr;
> +    return xc->write(xd, range, offset, val);
> +}
> +
> +static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
> +{
> +    XScomState *s = opaque;
> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> +    uint64_t val;
> +
> +    assert(width == 8);
> +
> +    /* Handle some SCOMs here before dispatch */
> +    switch (pcba) {
> +    case 0xf000f:
> +        val = s->chip_class->chip_f000f;
> +        break;
> +    case 0x1010c00:     /* PIBAM FIR */
> +    case 0x1010c03:     /* PIBAM FIR MASK */
> +    case 0x2020007:     /* ADU stuff */
> +    case 0x2020009:     /* ADU stuff */
> +    case 0x202000f:     /* ADU stuff */
> +        val = 0;
> +        break;
> +    case 0x2013f00:     /* PBA stuff */
> +    case 0x2013f01:     /* PBA stuff */
> +    case 0x2013f02:     /* PBA stuff */
> +    case 0x2013f03:     /* PBA stuff */
> +    case 0x2013f04:     /* PBA stuff */
> +    case 0x2013f05:     /* PBA stuff */
> +    case 0x2013f06:     /* PBA stuff */
> +    case 0x2013f07:     /* PBA stuff */
> +        val = 0;
> +        break;
> +    default:
> +        if (!xscom_dispatch_read(s, pcba, &val)) {
> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> +            return 0;
> +        }
> +    }
> +
> +    xscom_complete(HMER_XSCOM_DONE);
> +    return val;
> +}
> +
> +static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
> +                        unsigned width)
> +{
> +    XScomState *s = opaque;
> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> +
> +    assert(width == 8);
> +
> +    /* Handle some SCOMs here before dispatch */
> +    switch (pcba) {
> +        /* We ignore writes to these */
> +    case 0xf000f:       /* chip id is RO */
> +    case 0x1010c00:     /* PIBAM FIR */
> +    case 0x1010c01:     /* PIBAM FIR */
> +    case 0x1010c02:     /* PIBAM FIR */
> +    case 0x1010c03:     /* PIBAM FIR MASK */
> +    case 0x1010c04:     /* PIBAM FIR MASK */
> +    case 0x1010c05:     /* PIBAM FIR MASK */
> +    case 0x2020007:     /* ADU stuff */
> +    case 0x2020009:     /* ADU stuff */
> +    case 0x202000f:     /* ADU stuff */
> +        break;
> +    default:
> +        if (!xscom_dispatch_write(s, pcba, val)) {
> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> +            return;
> +        }
> +    }
> +
> +    xscom_complete(HMER_XSCOM_DONE);
> +}
> +
> +static const MemoryRegionOps xscom_ops = {
> +    .read = xscom_read,
> +    .write = xscom_write,
> +    .valid.min_access_size = 8,
> +    .valid.max_access_size = 8,
> +    .impl.min_access_size = 8,
> +    .impl.max_access_size = 8,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +};
> +
> +static int xscom_init(SysBusDevice *dev)
> +{
> +    XScomState *s = XSCOM(dev);
> +
> +    s->chip_id = -1;
> +    return 0;
> +}
> +
> +static void xscom_realize(DeviceState *dev, Error **errp)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    XScomState *s = XSCOM(dev);
> +    char *name;
> +
> +    if (s->chip_id < 0) {
> +        error_setg(errp, "invalid chip id '%d'", s->chip_id);
> +        return;
> +    }
> +    name = g_strdup_printf("xscom-%x", s->chip_id);
> +    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
> +    sysbus_init_mmio(sbd, &s->mem);
> +    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));
> +}
> +
> +static Property xscom_properties[] = {
> +        DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0),
> +        DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void xscom_class_init(ObjectClass *klass, void *data)
> +{
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = xscom_properties;
> +    dc->realize = xscom_realize;
> +    k->init = xscom_init;
> +}
> +
> +static const TypeInfo xscom_info = {
> +    .name          = TYPE_XSCOM,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(XScomState),
> +    .class_init    = xscom_class_init,
> +};
> +
> +static void xscom_bus_class_init(ObjectClass *klass, void *data)
> +{
> +}
> +
> +static const TypeInfo xscom_bus_info = {
> +    .name = TYPE_XSCOM_BUS,
> +    .parent = TYPE_BUS,
> +    .class_init = xscom_bus_class_init,
> +    .instance_size = sizeof(XScomBus),
> +};
> +
> +XScomBus *xscom_create(PnvChip *chip)
> +{
> +    DeviceState *dev;
> +    XScomState *xdev;
> +    BusState *qbus;
> +    XScomBus *xb;
> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> +
> +    dev = qdev_create(NULL, TYPE_XSCOM);
> +    qdev_prop_set_uint32(dev, "chip_id", chip->chip_id);
> +    qdev_init_nofail(dev);
> +
> +    /* Create bus on bridge device */
> +    qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
> +    xb = DO_UPCAST(XScomBus, bus, qbus);
> +    xb->chip_id = chip->chip_id;
> +    xdev = XSCOM(dev);
> +    xdev->bus = xb;
> +    xdev->chip_class = pcc;
> +
> +    return xb;
> +}
> +
> +int xscom_populate_fdt(XScomBus *xb, void *fdt, int root_offset)

What is the root_offset parameter for, since it is always 0?

> +{
> +    BusChild *bc;
> +    char *name;
> +    const char compat[] = "ibm,power8-xscom\0ibm,xscom";
> +    uint64_t reg[] = { cpu_to_be64(XSCOM_BASE(xb->chip_id)),
> +                       cpu_to_be64(XSCOM_SIZE) };
> +    int xscom_offset;
> +
> +    name = g_strdup_printf("xscom@%llx", (unsigned long long)
> +                           be64_to_cpu(reg[0]));

Nit: in qemu the PRIx64 etc. macros are usually preferred to (unsigned
long long) casts of this type.

> +    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
> +    _FDT(xscom_offset);
> +    g_free(name);
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", xb->chip_id)));
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat,
> +                      sizeof(compat))));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
> +
> +    QTAILQ_FOREACH(bc, &xb->bus.children, sibling) {
> +        DeviceState *qd = bc->child;
> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> +        XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xd);
> +        uint32_t reg[MAX_XSCOM_RANGES * 2];
> +        unsigned int i, sz = 0;
> +        void *cp, *p;
> +        int child_offset;
> +
> +        /* Some XSCOM slaves may not be represented in the DT */
> +        if (!xc->dt_name) {
> +            continue;
> +        }
> +        name = g_strdup_printf("%s@%x", xc->dt_name, xd->ranges[0].addr);
> +        child_offset = fdt_add_subnode(fdt, xscom_offset, name);
> +        _FDT(child_offset);
> +        g_free(name);
> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> +            if (xd->ranges[i].size == 0) {
> +                break;
> +            }
> +            reg[sz++] = cpu_to_be32(xd->ranges[i].addr);
> +            reg[sz++] = cpu_to_be32(xd->ranges[i].size);
> +        }
> +        _FDT((fdt_setprop(fdt, child_offset, "reg", reg, sz * 4)));

Use of fdt_appendprop() might make this a little neater.

> +        if (xc->devnode) {
> +            _FDT((xc->devnode(xd, fdt, child_offset)));
> +        }
> +#define MAX_COMPATIBLE_PROP     1024
> +        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
> +        i = 0;
> +        while ((p - cp) < MAX_COMPATIBLE_PROP) {
> +            int l;
> +            if (xc->dt_compatible[i] == NULL) {
> +                break;
> +            }
> +            l = strlen(xc->dt_compatible[i]);
> +            if (l >= (MAX_COMPATIBLE_PROP - i)) {
> +                break;
> +            }
> +            strcpy(p, xc->dt_compatible[i++]);
> +            p += l + 1;
> +        }
> +        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));

Might it be easier to just require the individual scom device to set
the compatible property from its ->devnode callback?  That way it can
just
	const char compat = "foo\0bar\0baz";
	fdt_setprop(..., compat, sizeof(compat));

and avoid this fiddling around with arrays.

> +    }
> +
> +    return 0;
> +}
> +
> +static int xscom_qdev_init(DeviceState *qdev)
> +{
> +    XScomDevice *xdev = (XScomDevice *)qdev;
> +    XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xdev);
> +
> +    if (xc->init) {
> +        return xc->init(xdev);
> +    }
> +    return 0;
> +}
> +
> +static void xscom_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *k = DEVICE_CLASS(klass);
> +    k->init = xscom_qdev_init;
> +    k->bus_type = TYPE_XSCOM_BUS;
> +}
> +
> +static const TypeInfo xscom_dev_info = {
> +    .name = TYPE_XSCOM_DEVICE,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(XScomDevice),
> +    .abstract = true,
> +    .class_size = sizeof(XScomDeviceClass),
> +    .class_init = xscom_device_class_init,
> +};
> +
> +static void xscom_register_types(void)
> +{
> +    type_register_static(&xscom_info);
> +    type_register_static(&xscom_bus_info);
> +    type_register_static(&xscom_dev_info);
> +}
> +
> +type_init(xscom_register_types)
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 1f32573dedff..bc6e1f80096b 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -35,12 +35,14 @@ typedef enum PnvChipType {
>      PNV_CHIP_P8NVL, /* AKA Naples */
>  } PnvChipType;
>  
> +typedef struct XScomBus XScomBus;
>  typedef struct PnvChip {
>      /*< private >*/
>      SysBusDevice parent_obj;
>  
>      /*< public >*/
>      uint32_t     chip_id;
> +    XScomBus     *xscom;
>  } PnvChip;
>  
>  typedef struct PnvChipClass {
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> new file mode 100644
> index 000000000000..386ad21c5aa5
> --- /dev/null
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -0,0 +1,75 @@
> +#ifndef _HW_XSCOM_H
> +#define _HW_XSCOM_H
> +/*
> + * QEMU PowerNV XSCOM bus definitions
> + *
> + * Copyright (c) 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corp.
> + * Based on the s390 virtio bus definitions:
> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <hw/ppc/pnv.h>
> +
> +#define TYPE_XSCOM_DEVICE "xscom-device"
> +#define XSCOM_DEVICE(obj) \
> +     OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE)
> +#define XSCOM_DEVICE_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE)
> +#define XSCOM_DEVICE_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE)
> +
> +#define TYPE_XSCOM_BUS "xscom-bus"
> +#define XSCOM_BUS(obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS)
> +
> +typedef struct XScomDevice XScomDevice;
> +typedef struct XScomBus XScomBus;
> +
> +typedef struct XScomDeviceClass {
> +    DeviceClass parent_class;
> +
> +    const char *dt_name;
> +    const char **dt_compatible;
> +    int (*init)(XScomDevice *dev);
> +    int (*devnode)(XScomDevice *dev, void *fdt, int offset);
> +
> +    /* Actual XScom accesses */
> +    bool (*read)(XScomDevice *dev, uint32_t range, uint32_t offset,
> +                 uint64_t *out_val);
> +    bool (*write)(XScomDevice *dev, uint32_t range, uint32_t offset,
> +                  uint64_t val);
> +} XScomDeviceClass;
> +
> +typedef struct XScomRange {
> +    uint32_t addr;
> +    uint32_t size;
> +} XScomRange;
> +
> +struct XScomDevice {
> +    DeviceState qdev;
> +#define MAX_XSCOM_RANGES 4
> +    struct XScomRange ranges[MAX_XSCOM_RANGES];
> +};
> +
> +struct XScomBus {
> +    BusState bus;
> +    uint32_t chip_id;
> +};
> +
> +extern XScomBus *xscom_create(PnvChip *chip);
> +extern int xscom_populate_fdt(XScomBus *xscom, void *fdt, int offset);
> +
> +
> +#endif /* _HW_XSCOM_H */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
  2016-09-02  8:03   ` Cédric Le Goater
@ 2016-09-05  3:42   ` David Gibson
  2016-09-05 11:13     ` Cédric Le Goater
  1 sibling, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  3:42 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 2974 bytes --]

On Wed, Aug 31, 2016 at 06:34:12PM +0200, Cédric Le Goater wrote:
> This will be used to build real HW ids for the cores and enforce some
> limits on the available cores per chip.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h |  2 ++
>  2 files changed, 29 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index a6e7f66b2c0a..b6efb5e3ef07 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -236,6 +236,27 @@ static void ppc_powernv_init(MachineState *machine)
>      g_free(chip_typename);
>  }
>  
> +/* Allowed core identifiers on a POWER8 Processor Chip :
> + *
> + * <EX0 reserved>
> + *  EX1  - Venice only
> + *  EX2  - Venice only
> + *  EX3  - Venice only
> + *  EX4
> + *  EX5
> + *  EX6
> + * <EX7,8 reserved> <reserved>
> + *  EX9  - Venice only
> + *  EX10 - Venice only
> + *  EX11 - Venice only
> + *  EX12
> + *  EX13
> + *  EX14
> + * <EX15 reserved>
> + */
> +#define POWER8E_CORE_MASK  (~0xffff8f8f)
> +#define POWER8_CORE_MASK   (~0xffff8181)
> +
>  static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
>  {
>      ;
> @@ -250,6 +271,8 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8NVL";
>      k->chip_type = PNV_CHIP_P8NVL;
>      k->chip_f000f = 0x120d304980000000ull;
> +    k->cores_max = 12;

Is it worth having this cores_max field, since AFAICT you can
calculate it as hweight(~cores_mask)?

> +    k->cores_mask = POWER8_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8NVL";
>  }
>  
> @@ -274,6 +297,8 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8";
>      k->chip_type = PNV_CHIP_P8;
>      k->chip_f000f = 0x220ea04980000000ull;
> +    k->cores_max = 12;
> +    k->cores_mask = POWER8_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8";
>  }
>  
> @@ -298,6 +323,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>      k->cpu_model = "POWER8E";
>      k->chip_type = PNV_CHIP_P8E;
>      k->chip_f000f = 0x221ef04980000000ull;
> +    k->cores_max = 6;
> +    k->cores_mask = POWER8E_CORE_MASK;
>      dc->desc = "PowerNV Chip POWER8E";
>  }
>  
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index bc6e1f80096b..987bc70245a7 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -49,6 +49,8 @@ typedef struct PnvChipClass {
>      /*< private >*/
>      SysBusDeviceClass parent_class;
>      /*< public >*/
> +    uint32_t   cores_max;
> +    uint32_t   cores_mask;
>      const char *cpu_model;
>      PnvChipType  chip_type;
>      uint64_t     chip_f000f;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object Cédric Le Goater
@ 2016-09-05  4:02   ` David Gibson
  2016-09-06  6:14     ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  4:02 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 22235 bytes --]

On Wed, Aug 31, 2016 at 06:34:13PM +0200, Cédric Le Goater wrote:
> This is largy inspired by sPAPRCPUCore with some simplification, no
> hotplug for instance. But the differences are small and the objects
> could possibly be merged.
> 
> A set of PnvCore objects is added to the PnvChip and the device
> tree is populated looping on these cores.
> 
> Real HW cpu ids are now generated depending on the chip cpu model, the
> chip id and a core mask. This id is stored in CPUState->cpu_index and
> in PnvCore->core_id and it is used to populate the device tree.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  Changes since v1:
> 
>  - changed name to PnvCore
>  - changed PnvChip core array type to a 'PnvCore *cores'
>  - introduced real cpu hw ids using a core mask from the chip
>  - reworked powernv_create_core_node() which populates the device tree
>  - added missing "ibm,pa-features" property 
>  - smp_cpus representing threads, used smp_cores instead to create the
>    cores in the chip.
>  - removed the use of ppc_get_vcpu_dt_id() 
>  - added "POWER8E" and "POWER8NVL" cpu models to exercice the
>    PnvChipClass
> 
>  hw/ppc/Makefile.objs      |   2 +-
>  hw/ppc/pnv.c              | 204 ++++++++++++++++++++++++++++++++++++++++++++++
>  hw/ppc/pnv_core.c         | 170 ++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h      |   7 ++
>  include/hw/ppc/pnv_core.h |  47 +++++++++++
>  5 files changed, 429 insertions(+), 1 deletion(-)
>  create mode 100644 hw/ppc/pnv_core.c
>  create mode 100644 include/hw/ppc/pnv_core.h
> 
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index f580e5c41413..08c213c40684 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -6,7 +6,7 @@ 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_cpu_core.o
>  # IBM PowerNV
> -obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o
>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>  obj-y += spapr_pci_vfio.o
>  endif
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index b6efb5e3ef07..daf9f459ab0e 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -35,6 +35,7 @@
>  #include "hw/ppc/fdt.h"
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/pnv.h"
> +#include "hw/ppc/pnv_core.h"
>  #include "hw/loader.h"
>  #include "exec/address-spaces.h"
>  #include "qemu/cutils.h"
> @@ -98,6 +99,136 @@ static int powernv_populate_memory(void *fdt)
>      return 0;
>  }
>  
> +/*
> + * The PowerNV cores (and threads) need to use real HW ids and not an
> + * incremental index like it has been done on other platforms. This HW
> + * id is called a PIR and is used in the device tree, in the XSCOM
> + * communication to address cores, in the interrupt servers.
> + */
> +static void powernv_create_core_node(PnvCore *pc, void *fdt,
> +                                     int cpus_offset, int chip_id)
> +{
> +    CPUCore *core = CPU_CORE(pc);
> +    CPUState *cs = CPU(DEVICE(pc->threads));
> +    DeviceClass *dc = DEVICE_GET_CLASS(cs);
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    int smt_threads = ppc_get_compat_smt_threads(cpu);
> +    CPUPPCState *env = &cpu->env;
> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
> +    uint32_t servers_prop[smt_threads];
> +    uint32_t gservers_prop[smt_threads * 2];
> +    int i;
> +    uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
> +                       0xffffffff, 0xffffffff};
> +    uint32_t tbfreq = PNV_TIMEBASE_FREQ;
> +    uint32_t cpufreq = 1000000000;
> +    uint32_t page_sizes_prop[64];
> +    size_t page_sizes_prop_size;
> +    const uint8_t pa_features[] = { 24, 0,
> +                                    0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
> +                                    0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
> +                                    0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
> +                                    0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
> +    int offset;
> +    char *nodename;
> +
> +    nodename = g_strdup_printf("%s@%x", dc->fw_name, core->core_id);
> +    offset = fdt_add_subnode(fdt, cpus_offset, nodename);
> +    _FDT(offset);
> +    g_free(nodename);
> +
> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip_id)));
> +
> +    _FDT((fdt_setprop_cell(fdt, offset, "reg", core->core_id)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", core->core_id)));
> +    _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
> +
> +    _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
> +                            env->dcache_line_size)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
> +                            env->dcache_line_size)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
> +                            env->icache_line_size)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
> +                            env->icache_line_size)));
> +
> +    if (pcc->l1_dcache_size) {
> +        _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
> +                               pcc->l1_dcache_size)));
> +    } else {
> +        error_report("Warning: Unknown L1 dcache size for cpu");
> +    }
> +    if (pcc->l1_icache_size) {
> +        _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
> +                               pcc->l1_icache_size)));
> +    } else {
> +        error_report("Warning: Unknown L1 icache size for cpu");
> +    }
> +
> +    _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
> +    _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
> +    _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
> +
> +    if (env->spr_cb[SPR_PURR].oea_read) {
> +        _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
> +    }
> +
> +    if (env->mmu_model & POWERPC_MMU_1TSEG) {
> +        _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
> +                           segs, sizeof(segs))));
> +    }
> +
> +    /* Advertise VMX/VSX (vector extensions) if available
> +     *   0 / no property == no vector extensions
> +     *   1               == VMX / Altivec available
> +     *   2               == VSX available */
> +    if (env->insns_flags & PPC_ALTIVEC) {
> +        uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
> +
> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
> +    }
> +
> +    /* Advertise DFP (Decimal Floating Point) if available
> +     *   0 / no property == no DFP
> +     *   1               == DFP available */
> +    if (env->insns_flags2 & PPC2_DFP) {
> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
> +    }
> +
> +    page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
> +                                                  sizeof(page_sizes_prop));
> +    if (page_sizes_prop_size) {
> +        _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
> +                           page_sizes_prop, page_sizes_prop_size)));
> +    }
> +
> +    _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
> +                       pa_features, sizeof(pa_features))));
> +
> +    if (cpu->cpu_version) {
> +        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
> +    }
> +
> +    /* Build interrupt servers and gservers properties */
> +    for (i = 0; i < smt_threads; i++) {
> +        servers_prop[i] = cpu_to_be32(core->core_id + i);
> +        /* Hack, direct the group queues back to cpu 0
> +         *
> +         * FIXME: check that we still need this hack with real HW
> +         * ids. Probably not.
> +         */
> +        gservers_prop[i * 2] = cpu_to_be32(core->core_id + i);
> +        gservers_prop[i * 2 + 1] = 0;

I'm not sure the group servers concept even makes sense in the case of
powernv.  In powernv, doesn't the guest control the "real" xics,
including the link registers, and therefore can configure its own
groups, rather than being limited to what firmware has set up as for
PAPR?

> +    }
> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
> +                       servers_prop, sizeof(servers_prop))));
> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
> +                       gservers_prop, sizeof(gservers_prop))));
> +}
> +
>  static void *powernv_create_fdt(PnvMachineState *pnv,
>                                  const char *kernel_cmdline)
>  {
> @@ -106,6 +237,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
>      int off;
>      int i;
> +    int cpus_offset;
>  
>      fdt = g_malloc0(FDT_MAX_SIZE);
>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> @@ -150,6 +282,22 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>          xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
>      }
>  
> +    /* cpus */
> +    cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
> +    _FDT(cpus_offset);
> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
> +
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        PnvChip *chip = pnv->chips[i];
> +        int j;
> +
> +        for (j = 0; j < chip->num_cores; j++) {
> +            powernv_create_core_node(&chip->cores[j], fdt, cpus_offset,
> +                                     chip->chip_id);
> +        }
> +    }
> +
>      return fdt;
>  }
>  
> @@ -230,6 +378,11 @@ static void ppc_powernv_init(MachineState *machine)
>      for (i = 0; i < pnv->num_chips; i++) {
>          Object *chip = object_new(chip_typename);
>          object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
> +        object_property_set_int(chip, smp_cores, "num-cores", &error_abort);

This should probably be &error_fatal, again.

> +        /*
> +         * We could set a custom cores_mask for the chip here.
> +         */
> +
>          object_property_set_bool(chip, true, "realized", &error_abort);
>          pnv->chips[i] = PNV_CHIP(chip);
>      }
> @@ -335,19 +488,70 @@ static const TypeInfo pnv_chip_power8e_info = {
>      .class_init    = pnv_chip_power8e_class_init,
>  };
>  
> +/*
> + * This is different for POWER9 so we might need a ops in the chip to
> + * calculate the core pirs
> + */
> +#define P8_PIR(chip_id, core_id) (((chip_id) << 7) | ((core_id) << 3))
> +
>  static void pnv_chip_realize(DeviceState *dev, Error **errp)
>  {
>      PnvChip *chip = PNV_CHIP(dev);
>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> +    char *typename = pnv_core_typename(pcc->cpu_model);
> +    size_t typesize = object_type_get_instance_size(typename);
> +    int i, core_hwid;
> +
> +    if (!object_class_by_name(typename)) {
> +        error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
> +        return;
> +    }
>  
>      /* Set up XSCOM bus */
>      chip->xscom = xscom_create(chip);
>  
> +    if (chip->num_cores > pcc->cores_max) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: too many cores for chip ! "
> +                      "Limiting to %d\n", __func__, pcc->cores_max);
> +        chip->num_cores = pcc->cores_max;
> +    }
> +
> +    chip->cores = g_new0(PnvCore, chip->num_cores);
> +
> +    /* no custom mask for this chip, let's use the default one from
> +     * the chip class */
> +    if (!chip->cores_mask) {
> +        chip->cores_mask = pcc->cores_mask;
> +    }
> +
> +    for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
> +             && (i < chip->num_cores); core_hwid++) {
> +        PnvCore *pnv_core = &chip->cores[i];


Unfortunately, as with spapr core creating its threads you'll need
some fancier pointer manipulation to handle the possibility of
subtypes of PnvCore with a different instance size.  That doesn't
happen now, but it can in theory.

> +
> +        if (!(chip->cores_mask & (1 << core_hwid))) {
> +            continue;
> +        }
> +
> +        object_initialize(pnv_core, typesize, typename);
> +        object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
> +                                &error_fatal);
> +        object_property_set_int(OBJECT(pnv_core),
> +                                P8_PIR(chip->chip_id, core_hwid),
> +                                CPU_CORE_PROP_CORE_ID, &error_fatal);
> +        object_property_set_bool(OBJECT(pnv_core), true, "realized",
> +                                 &error_fatal);
> +        object_unref(OBJECT(pnv_core));
> +        i++;
> +    }
> +    g_free(typename);
> +
>      pcc->realize(chip, errp);
>  }
>  
>  static Property pnv_chip_properties[] = {
>      DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
> +    DEFINE_PROP_UINT32("num-cores", PnvChip, num_cores, 1),

I suggest renaming this to "nr-cores" to match "nr-threads" inside the
core object.

> +    DEFINE_PROP_UINT32("cores-mask", PnvChip, cores_mask, 0x0),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> new file mode 100644
> index 000000000000..825aea1194a1
> --- /dev/null
> +++ b/hw/ppc/pnv_core.c
> @@ -0,0 +1,170 @@
> +/*
> + * QEMU PowerPC PowerNV CPU Core model
> + *
> + * Copyright (c) IBM Corporation.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * as published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +#include "qemu/osdep.h"
> +#include "sysemu/sysemu.h"
> +#include "qapi/error.h"
> +#include "target-ppc/cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/ppc/pnv.h"
> +#include "hw/ppc/pnv_core.h"
> +
> +static void powernv_cpu_reset(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +    MachineState *machine = MACHINE(qdev_get_machine());
> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
> +
> +    cpu_reset(cs);
> +
> +    env->spr[SPR_PIR] = cs->cpu_index;

This can't work.  Your PIR values aren't contiguous, but cpu_index
values must be (until you get hotplug).

> +    env->spr[SPR_HIOR] = 0;
> +    env->gpr[3] = pnv->fdt_addr;

Is the fdt address injected for all CPUs, or only the boot CPU?

> +    env->nip = 0x10;
> +    env->msr |= MSR_HVB;
> +}
> +
> +static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    /* Set time-base frequency to 512 MHz */
> +    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
> +
> +    /* MSR[IP] doesn't exist nowadays */
> +    env->msr_mask &= ~(1 << 6);
> +
> +    qemu_register_reset(powernv_cpu_reset, cpu);
> +    powernv_cpu_reset(cpu);
> +}
> +
> +static void pnv_core_realize_child(Object *child, Error **errp)
> +{
> +    Error *local_err = NULL;
> +    CPUState *cs = CPU(child);
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +
> +    object_property_set_bool(child, true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    powernv_cpu_init(cpu, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +}
> +
> +static void pnv_core_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvCore *pc = PNV_CORE(OBJECT(dev));
> +    CPUCore *cc = CPU_CORE(OBJECT(dev));
> +    PnvCoreClass *pcc = PNV_CORE_GET_CLASS(OBJECT(dev));
> +    const char *typename = object_class_get_name(pcc->cpu_oc);
> +    size_t size = object_type_get_instance_size(typename);
> +    Error *local_err = NULL;
> +    void *obj;
> +    int i, j;
> +
> +    pc->threads = g_malloc0(size * cc->nr_threads);
> +    for (i = 0; i < cc->nr_threads; i++) {
> +        char id[32];
> +        CPUState *cs;
> +
> +        obj = pc->threads + i * size;
> +
> +        object_initialize(obj, size, typename);
> +        cs = CPU(obj);
> +        cs->cpu_index = cc->core_id + i;
> +        snprintf(id, sizeof(id), "thread[%d]", i);
> +        object_property_add_child(OBJECT(pc), id, obj, &local_err);
> +        if (local_err) {
> +            goto err;
> +        }
> +        object_unref(obj);
> +    }
> +
> +    for (j = 0; j < cc->nr_threads; j++) {
> +        obj = pc->threads + j * size;
> +
> +        pnv_core_realize_child(obj, &local_err);
> +        if (local_err) {
> +            goto err;
> +        }
> +    }
> +    return;
> +
> +err:
> +    while (--i >= 0) {
> +        obj = pc->threads + i * size;
> +        object_unparent(obj);
> +    }
> +    g_free(pc->threads);
> +    error_propagate(errp, local_err);
> +}
> +
> +/*
> + * Grow this list or merge with SPAPRCoreInfo which is very similar
> + */
> +static const char *pnv_core_models[] = { "POWER8E", "POWER8", "POWER8NVL" };
> +
> +static void pnv_core_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
> +
> +    dc->realize = pnv_core_realize;
> +    pcc->cpu_oc = cpu_class_by_name(TYPE_POWERPC_CPU, data);
> +}
> +
> +static const TypeInfo pnv_core_info = {
> +    .name           = TYPE_PNV_CORE,
> +    .parent         = TYPE_CPU_CORE,
> +    .instance_size  = sizeof(PnvCore),
> +    .class_size     = sizeof(PnvCoreClass),
> +    .abstract       = true,
> +};
> +
> +static void pnv_core_register_types(void)
> +{
> +    int i ;
> +
> +    type_register_static(&pnv_core_info);
> +    for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
> +        TypeInfo ti = {
> +            .parent = TYPE_PNV_CORE,
> +            .instance_size = sizeof(PnvCore),
> +            .class_init = pnv_core_class_init,
> +            .class_data = (void *) pnv_core_models[i],
> +        };
> +        ti.name = pnv_core_typename(pnv_core_models[i]);
> +        type_register(&ti);
> +        g_free((void *)ti.name);
> +    }
> +}
> +
> +type_init(pnv_core_register_types)
> +
> +char *pnv_core_typename(const char *model)
> +{
> +    return g_strdup_printf(TYPE_PNV_CORE "-%s", model);
> +}
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 987bc70245a7..8a3846743ccf 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -36,6 +36,7 @@ typedef enum PnvChipType {
>  } PnvChipType;
>  
>  typedef struct XScomBus XScomBus;
> +typedef struct PnvCore PnvCore;
>  typedef struct PnvChip {
>      /*< private >*/
>      SysBusDevice parent_obj;
> @@ -43,6 +44,10 @@ typedef struct PnvChip {
>      /*< public >*/
>      uint32_t     chip_id;
>      XScomBus     *xscom;
> +
> +    uint32_t  num_cores;
> +    uint32_t  cores_mask;
> +    PnvCore   *cores;
>  } PnvChip;
>  
>  typedef struct PnvChipClass {
> @@ -109,4 +114,6 @@ typedef struct PnvMachineState {
>      PnvChip   **chips;
>  } PnvMachineState;
>  
> +#define PNV_TIMEBASE_FREQ           512000000ULL
> +
>  #endif /* _PPC_PNV_H */
> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> new file mode 100644
> index 000000000000..832c8756afaa
> --- /dev/null
> +++ b/include/hw/ppc/pnv_core.h
> @@ -0,0 +1,47 @@
> +/*
> + * QEMU PowerPC PowerNV CPU Core model
> + *
> + * Copyright (c) 2016 IBM Corporation.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * as published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef _PPC_PNV_CORE_H
> +#define _PPC_PNV_CORE_H
> +
> +#include "hw/cpu/core.h"
> +
> +#define TYPE_PNV_CORE "powernv-cpu-core"
> +#define PNV_CORE(obj) \
> +    OBJECT_CHECK(PnvCore, (obj), TYPE_PNV_CORE)
> +#define PNV_CORE_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvCoreClass, (klass), TYPE_PNV_CORE)
> +#define PNV_CORE_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvCoreClass, (obj), TYPE_PNV_CORE)
> +
> +typedef struct PnvCore {
> +    /*< private >*/
> +    CPUCore parent_obj;
> +
> +    /*< public >*/
> +    void *threads;
> +} PnvCore;
> +
> +typedef struct PnvCoreClass {
> +    DeviceClass parent_class;
> +    ObjectClass *cpu_oc;
> +} PnvCoreClass;
> +
> +extern char *pnv_core_typename(const char *model);
> +
> +#endif /* _PPC_PNV_CORE_H */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure Cédric Le Goater
  2016-09-05  3:39   ` David Gibson
@ 2016-09-05  4:16   ` Sam Bobroff
  2016-09-06 14:51     ` Cédric Le Goater
  1 sibling, 1 reply; 62+ messages in thread
From: Sam Bobroff @ 2016-09-05  4:16 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, David Gibson

On Wed, Aug 31, 2016 at 06:34:11PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> XSCOM is an interface to a sideband bus provided by the POWER8 chip
> pervasive unit, which gives access to a number of facilities in the
> chip that are needed by the OPAL firmware and to a lesser extent,
> Linux. This is among others how the PCI Host bridges get configured
> at boot or how the LPC bus is accessed.
> 
> This provides a simple bus and device type for devices sitting on
> XSCOM along with some facilities to optionally generate corresponding
> device-tree nodes
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: updated for qemu-2.7
>       ported on new sPowerNVMachineState which was merged with PnvSystem
>       removed TRACE_XSCOM
>       fixed checkpatch errors
>       replaced assert with error_setg in xscom_realize()
>       reworked xscom_create
>       introduced the use of the chip_class for chip model contants
>       ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> 
>  They were some discussions on whether we should use a qemu
>  address_space instead of the xscom ranges defined in this patch. 
>  I gave it try, it is possible but it brings extra unnecessary calls
>  and complexity. I think the current solution is better.
> 
>  hw/ppc/Makefile.objs       |   2 +-
>  hw/ppc/pnv.c               |  11 ++
>  hw/ppc/pnv_xscom.c         | 408 +++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv.h       |   2 +
>  include/hw/ppc/pnv_xscom.h |  75 +++++++++
>  5 files changed, 497 insertions(+), 1 deletion(-)
>  create mode 100644 hw/ppc/pnv_xscom.c
>  create mode 100644 include/hw/ppc/pnv_xscom.h
> 
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 8105db7d5600..f580e5c41413 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -6,7 +6,7 @@ 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_cpu_core.o
>  # IBM PowerNV
> -obj-$(CONFIG_POWERNV) += pnv.o
> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>  obj-y += spapr_pci_vfio.o
>  endif
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 06051268e200..a6e7f66b2c0a 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -39,6 +39,8 @@
>  #include "exec/address-spaces.h"
>  #include "qemu/cutils.h"
>  
> +#include "hw/ppc/pnv_xscom.h"
> +
>  #include <libfdt.h>
>  
>  #define FDT_ADDR                0x01000000
> @@ -103,6 +105,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>      char *buf;
>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
>      int off;
> +    int i;
>  
>      fdt = g_malloc0(FDT_MAX_SIZE);
>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> @@ -142,6 +145,11 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>      /* Memory */
>      powernv_populate_memory(fdt);
>  
> +    /* Populate XSCOM for each chip */
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
> +    }
> +
>      return fdt;
>  }
>  
> @@ -305,6 +313,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>      PnvChip *chip = PNV_CHIP(dev);
>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>  
> +    /* Set up XSCOM bus */
> +    chip->xscom = xscom_create(chip);
> +
>      pcc->realize(chip, errp);
>  }
>  
> diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
> new file mode 100644
> index 000000000000..7ed3804f4b3a
> --- /dev/null
> +++ b/hw/ppc/pnv_xscom.c
> @@ -0,0 +1,408 @@
> +
> +/*
> + * QEMU PowerNV XSCOM bus definitions
> + *
> + * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
> + * Based on the s390 virtio bus code:
> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/* TODO: Add some infrastructure for "random stuff" and FIRs that
> + * various units might want to deal with without creating actual
> + * XSCOM devices.
> + *
> + * For example, HB LPC XSCOM in the PIBAM
> + */
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/hw.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/boards.h"
> +#include "monitor/monitor.h"
> +#include "hw/loader.h"
> +#include "elf.h"
> +#include "hw/sysbus.h"
> +#include "sysemu/kvm.h"
> +#include "sysemu/device_tree.h"
> +#include "hw/ppc/fdt.h"
> +
> +#include "hw/ppc/pnv_xscom.h"
> +
> +#include <libfdt.h>
> +
> +#define TYPE_XSCOM "xscom"
> +#define XSCOM(obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM)
> +
> +#define XSCOM_SIZE        0x800000000ull
> +#define XSCOM_BASE(chip)  (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE)
> +
> +
> +typedef struct XScomState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +    /*< public >*/
> +
> +    MemoryRegion mem;
> +    int32_t chip_id;
> +    PnvChipClass *chip_class;
> +    XScomBus *bus;
> +} XScomState;
> +
> +static uint32_t xscom_to_pcb_addr(uint64_t addr)
> +{
> +        addr &= (XSCOM_SIZE - 1);
> +        return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
> +}
> +
> +static void xscom_complete(uint64_t hmer_bits)
> +{
> +    CPUState *cs = current_cpu;
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    CPUPPCState *env = &cpu->env;
> +
> +    cpu_synchronize_state(cs);
> +    env->spr[SPR_HMER] |= hmer_bits;
> +
> +    /* XXX Need a CPU helper to set HMER, also handle gneeration
> +     * of HMIs
> +     */
> +}
> +
> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t pcb_addr,
> +                                      uint32_t *range)
> +{
> +    BusChild *bc;
> +
> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> +        DeviceState *qd = bc->child;
> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> +        unsigned int i;
> +
> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> +            if (xd->ranges[i].addr <= pcb_addr &&
> +                (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) {
> +                *range = i;
> +                return xd;
> +            }
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static bool xscom_dispatch_read(XScomState *s, uint32_t pcb_addr,
> +                                uint64_t *out_val)
> +{
> +    uint32_t range, offset;
> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> +    XScomDeviceClass *xc;
> +
> +    if (!xd) {
> +        return false;
> +    }
> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> +    if (!xc->read) {
> +        return false;
> +    }
> +    offset = pcb_addr - xd->ranges[range].addr;
> +    return xc->read(xd, range, offset, out_val);
> +}
> +
> +static bool xscom_dispatch_write(XScomState *s, uint32_t pcb_addr, uint64_t val)
> +{
> +    uint32_t range, offset;
> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> +    XScomDeviceClass *xc;
> +
> +    if (!xd) {
> +        return false;
> +    }
> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> +    if (!xc->write) {
> +        return false;
> +    }
> +    offset = pcb_addr - xd->ranges[range].addr;
> +    return xc->write(xd, range, offset, val);
> +}
> +
> +static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
> +{
> +    XScomState *s = opaque;
> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> +    uint64_t val;
> +
> +    assert(width == 8);
> +
> +    /* Handle some SCOMs here before dispatch */
> +    switch (pcba) {
> +    case 0xf000f:
> +        val = s->chip_class->chip_f000f;
> +        break;
> +    case 0x1010c00:     /* PIBAM FIR */
> +    case 0x1010c03:     /* PIBAM FIR MASK */
> +    case 0x2020007:     /* ADU stuff */
> +    case 0x2020009:     /* ADU stuff */
> +    case 0x202000f:     /* ADU stuff */
> +        val = 0;
> +        break;
> +    case 0x2013f00:     /* PBA stuff */
> +    case 0x2013f01:     /* PBA stuff */
> +    case 0x2013f02:     /* PBA stuff */
> +    case 0x2013f03:     /* PBA stuff */
> +    case 0x2013f04:     /* PBA stuff */
> +    case 0x2013f05:     /* PBA stuff */
> +    case 0x2013f06:     /* PBA stuff */
> +    case 0x2013f07:     /* PBA stuff */
> +        val = 0;
> +        break;
> +    default:
> +        if (!xscom_dispatch_read(s, pcba, &val)) {
> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> +            return 0;
> +        }
> +    }
> +
> +    xscom_complete(HMER_XSCOM_DONE);
> +    return val;
> +}
> +
> +static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
> +                        unsigned width)
> +{
> +    XScomState *s = opaque;
> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> +
> +    assert(width == 8);
> +
> +    /* Handle some SCOMs here before dispatch */
> +    switch (pcba) {
> +        /* We ignore writes to these */
> +    case 0xf000f:       /* chip id is RO */
> +    case 0x1010c00:     /* PIBAM FIR */
> +    case 0x1010c01:     /* PIBAM FIR */
> +    case 0x1010c02:     /* PIBAM FIR */
> +    case 0x1010c03:     /* PIBAM FIR MASK */
> +    case 0x1010c04:     /* PIBAM FIR MASK */
> +    case 0x1010c05:     /* PIBAM FIR MASK */
> +    case 0x2020007:     /* ADU stuff */
> +    case 0x2020009:     /* ADU stuff */
> +    case 0x202000f:     /* ADU stuff */
> +        break;
> +    default:
> +        if (!xscom_dispatch_write(s, pcba, val)) {
> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> +            return;
> +        }
> +    }
> +
> +    xscom_complete(HMER_XSCOM_DONE);
> +}
> +
> +static const MemoryRegionOps xscom_ops = {
> +    .read = xscom_read,
> +    .write = xscom_write,
> +    .valid.min_access_size = 8,
> +    .valid.max_access_size = 8,
> +    .impl.min_access_size = 8,
> +    .impl.max_access_size = 8,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +};
> +
> +static int xscom_init(SysBusDevice *dev)
> +{
> +    XScomState *s = XSCOM(dev);
> +
> +    s->chip_id = -1;
> +    return 0;
> +}
> +
> +static void xscom_realize(DeviceState *dev, Error **errp)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    XScomState *s = XSCOM(dev);
> +    char *name;
> +
> +    if (s->chip_id < 0) {
> +        error_setg(errp, "invalid chip id '%d'", s->chip_id);
> +        return;
> +    }
> +    name = g_strdup_printf("xscom-%x", s->chip_id);
> +    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
> +    sysbus_init_mmio(sbd, &s->mem);
> +    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));
> +}
> +
> +static Property xscom_properties[] = {
> +        DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0),
> +        DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void xscom_class_init(ObjectClass *klass, void *data)
> +{
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = xscom_properties;
> +    dc->realize = xscom_realize;
> +    k->init = xscom_init;
> +}
> +
> +static const TypeInfo xscom_info = {
> +    .name          = TYPE_XSCOM,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(XScomState),
> +    .class_init    = xscom_class_init,
> +};
> +
> +static void xscom_bus_class_init(ObjectClass *klass, void *data)
> +{
> +}
> +
> +static const TypeInfo xscom_bus_info = {
> +    .name = TYPE_XSCOM_BUS,
> +    .parent = TYPE_BUS,
> +    .class_init = xscom_bus_class_init,
> +    .instance_size = sizeof(XScomBus),
> +};
> +
> +XScomBus *xscom_create(PnvChip *chip)
> +{
> +    DeviceState *dev;
> +    XScomState *xdev;
> +    BusState *qbus;
> +    XScomBus *xb;
> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> +
> +    dev = qdev_create(NULL, TYPE_XSCOM);
> +    qdev_prop_set_uint32(dev, "chip_id", chip->chip_id);
> +    qdev_init_nofail(dev);
> +
> +    /* Create bus on bridge device */
> +    qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
> +    xb = DO_UPCAST(XScomBus, bus, qbus);
> +    xb->chip_id = chip->chip_id;
> +    xdev = XSCOM(dev);
> +    xdev->bus = xb;
> +    xdev->chip_class = pcc;
> +
> +    return xb;
> +}
> +
> +int xscom_populate_fdt(XScomBus *xb, void *fdt, int root_offset)
> +{
> +    BusChild *bc;
> +    char *name;
> +    const char compat[] = "ibm,power8-xscom\0ibm,xscom";
> +    uint64_t reg[] = { cpu_to_be64(XSCOM_BASE(xb->chip_id)),
> +                       cpu_to_be64(XSCOM_SIZE) };
> +    int xscom_offset;
> +
> +    name = g_strdup_printf("xscom@%llx", (unsigned long long)
> +                           be64_to_cpu(reg[0]));
> +    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
> +    _FDT(xscom_offset);
> +    g_free(name);
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", xb->chip_id)));
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat,
> +                      sizeof(compat))));
> +    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
> +
> +    QTAILQ_FOREACH(bc, &xb->bus.children, sibling) {
> +        DeviceState *qd = bc->child;
> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> +        XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xd);
> +        uint32_t reg[MAX_XSCOM_RANGES * 2];
> +        unsigned int i, sz = 0;
> +        void *cp, *p;
> +        int child_offset;
> +
> +        /* Some XSCOM slaves may not be represented in the DT */
> +        if (!xc->dt_name) {
> +            continue;
> +        }
> +        name = g_strdup_printf("%s@%x", xc->dt_name, xd->ranges[0].addr);
> +        child_offset = fdt_add_subnode(fdt, xscom_offset, name);
> +        _FDT(child_offset);
> +        g_free(name);
> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> +            if (xd->ranges[i].size == 0) {
> +                break;
> +            }
> +            reg[sz++] = cpu_to_be32(xd->ranges[i].addr);
> +            reg[sz++] = cpu_to_be32(xd->ranges[i].size);
> +        }
> +        _FDT((fdt_setprop(fdt, child_offset, "reg", reg, sz * 4)));
> +        if (xc->devnode) {
> +            _FDT((xc->devnode(xd, fdt, child_offset)));
> +        }
> +#define MAX_COMPATIBLE_PROP     1024
> +        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
> +        i = 0;
> +        while ((p - cp) < MAX_COMPATIBLE_PROP) {
> +            int l;
> +            if (xc->dt_compatible[i] == NULL) {
> +                break;
> +            }
> +            l = strlen(xc->dt_compatible[i]);
> +            if (l >= (MAX_COMPATIBLE_PROP - i)) {

The use of 'i' above doesn't look right. Should the check be more like this?
               if ((l + 1) >= (MAX_COMPATIBLE_PROP - (p - cp))) {

> +                break;
> +            }
> +            strcpy(p, xc->dt_compatible[i++]);
> +            p += l + 1;
> +        }
> +        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));
> +    }
> +
> +    return 0;
> +}
> +
> +static int xscom_qdev_init(DeviceState *qdev)
> +{
> +    XScomDevice *xdev = (XScomDevice *)qdev;
> +    XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xdev);
> +
> +    if (xc->init) {
> +        return xc->init(xdev);
> +    }
> +    return 0;
> +}
> +
> +static void xscom_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *k = DEVICE_CLASS(klass);
> +    k->init = xscom_qdev_init;
> +    k->bus_type = TYPE_XSCOM_BUS;
> +}
> +
> +static const TypeInfo xscom_dev_info = {
> +    .name = TYPE_XSCOM_DEVICE,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(XScomDevice),
> +    .abstract = true,
> +    .class_size = sizeof(XScomDeviceClass),
> +    .class_init = xscom_device_class_init,
> +};
> +
> +static void xscom_register_types(void)
> +{
> +    type_register_static(&xscom_info);
> +    type_register_static(&xscom_bus_info);
> +    type_register_static(&xscom_dev_info);
> +}
> +
> +type_init(xscom_register_types)
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 1f32573dedff..bc6e1f80096b 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -35,12 +35,14 @@ typedef enum PnvChipType {
>      PNV_CHIP_P8NVL, /* AKA Naples */
>  } PnvChipType;
>  
> +typedef struct XScomBus XScomBus;
>  typedef struct PnvChip {
>      /*< private >*/
>      SysBusDevice parent_obj;
>  
>      /*< public >*/
>      uint32_t     chip_id;
> +    XScomBus     *xscom;
>  } PnvChip;
>  
>  typedef struct PnvChipClass {
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> new file mode 100644
> index 000000000000..386ad21c5aa5
> --- /dev/null
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -0,0 +1,75 @@
> +#ifndef _HW_XSCOM_H
> +#define _HW_XSCOM_H
> +/*
> + * QEMU PowerNV XSCOM bus definitions
> + *
> + * Copyright (c) 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corp.
> + * Based on the s390 virtio bus definitions:
> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <hw/ppc/pnv.h>
> +
> +#define TYPE_XSCOM_DEVICE "xscom-device"
> +#define XSCOM_DEVICE(obj) \
> +     OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE)
> +#define XSCOM_DEVICE_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE)
> +#define XSCOM_DEVICE_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE)
> +
> +#define TYPE_XSCOM_BUS "xscom-bus"
> +#define XSCOM_BUS(obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS)
> +
> +typedef struct XScomDevice XScomDevice;
> +typedef struct XScomBus XScomBus;
> +
> +typedef struct XScomDeviceClass {
> +    DeviceClass parent_class;
> +
> +    const char *dt_name;
> +    const char **dt_compatible;
> +    int (*init)(XScomDevice *dev);
> +    int (*devnode)(XScomDevice *dev, void *fdt, int offset);
> +
> +    /* Actual XScom accesses */
> +    bool (*read)(XScomDevice *dev, uint32_t range, uint32_t offset,
> +                 uint64_t *out_val);
> +    bool (*write)(XScomDevice *dev, uint32_t range, uint32_t offset,
> +                  uint64_t val);
> +} XScomDeviceClass;
> +
> +typedef struct XScomRange {
> +    uint32_t addr;
> +    uint32_t size;
> +} XScomRange;
> +
> +struct XScomDevice {
> +    DeviceState qdev;
> +#define MAX_XSCOM_RANGES 4
> +    struct XScomRange ranges[MAX_XSCOM_RANGES];
> +};
> +
> +struct XScomBus {
> +    BusState bus;
> +    uint32_t chip_id;
> +};
> +
> +extern XScomBus *xscom_create(PnvChip *chip);
> +extern int xscom_populate_fdt(XScomBus *xscom, void *fdt, int offset);
> +
> +
> +#endif /* _HW_XSCOM_H */
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore Cédric Le Goater
@ 2016-09-05  4:19   ` David Gibson
  2016-09-06 13:54     ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  4:19 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 6733 bytes --]

On Wed, Aug 31, 2016 at 06:34:14PM +0200, Cédric Le Goater wrote:
> Now that we are using real HW ids for the cores in PowerNV chips, we
> can route the XSCOM accesses to them. We just need to attach a
> XScomDevice to each core with the associated ranges in the XSCOM
> address space.
> 
> To start with, let's install the DTS (Digital Thermal Sensor) handlers
> which are easy to handle.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/ppc/pnv.c              |  9 +++++++
>  hw/ppc/pnv_core.c         | 67 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/pnv_core.h | 13 +++++++++
>  3 files changed, 89 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index daf9f459ab0e..a31568415192 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -527,6 +527,7 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>      for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
>               && (i < chip->num_cores); core_hwid++) {
>          PnvCore *pnv_core = &chip->cores[i];
> +        DeviceState *qdev;
>  
>          if (!(chip->cores_mask & (1 << core_hwid))) {
>              continue;
> @@ -542,6 +543,14 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>                                   &error_fatal);
>          object_unref(OBJECT(pnv_core));
>          i++;
> +
> +        /* Attach the core to its XSCOM bus */
> +        qdev = qdev_create(&chip->xscom->bus, TYPE_PNV_CORE_XSCOM);

Again, I think this breaks QOM lifetime rules.

> +        qdev_prop_set_uint32(qdev, "core-pir",
> +                             P8_PIR(chip->chip_id, core_hwid));
> +        qdev_init_nofail(qdev);

qdev_init_nofail() - which will abort on failure - shouldn't be used
in a realize() function, which has a way to gracefully report errors.


So, in terms of the lifetime thing.  I think one permitted solution is
to embed the scom device state in the core device state and use
object_initialize().

Alternatively, since SCOM is by its nature a sideband bus, I wonder if
it would make sense to have ScomDevice be a QOM interface, rather than
a full QOM class.  That way the core device itself (and other devices
with SCOM control) could present the SCOM device interface and be
placed directly on the SCOM bus without having to introduce an extra
object.  It will probably make accessing the object innards in
response to SCOM requests more straightforward as well.

I'm not entirely sure if sharing just an interface will be sufficient
for devices under a bus, but it's worth investigating.

> +
> +        pnv_core->xd = PNV_CORE_XSCOM(qdev);
>      }
>      g_free(typename);
>  
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 825aea1194a1..feba374740dc 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -18,7 +18,9 @@
>   */
>  #include "qemu/osdep.h"
>  #include "sysemu/sysemu.h"
> +#include "qemu/error-report.h"
>  #include "qapi/error.h"
> +#include "qemu/log.h"
>  #include "target-ppc/cpu.h"
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/pnv.h"
> @@ -144,10 +146,75 @@ static const TypeInfo pnv_core_info = {
>      .abstract       = true,
>  };
>  
> +
> +#define DTS_RESULT0     0x50000
> +#define DTS_RESULT1     0x50001
> +
> +static bool pnv_core_xscom_read(XScomDevice *dev, uint32_t range,
> +                               uint32_t offset, uint64_t *out_val)
> +{
> +    switch (offset) {
> +    case DTS_RESULT0:
> +        *out_val = 0x26f024f023f0000ull;
> +        break;
> +    case DTS_RESULT1:
> +        *out_val = 0x24f000000000000ull;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "Warning: reading reg=0x%08x", offset);

Can't you just return false here and let the caller handle the error reporting?

> +    }
> +
> +   return true;
> +}
> +
> +static bool pnv_core_xscom_write(XScomDevice *dev, uint32_t range,
> +                                uint32_t offset, uint64_t val)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR, "Warning: writing to reg=0x%08x", offset);
> +    return true;
> +}
> +
> +#define EX_XSCOM_BASE 0x10000000
> +#define EX_XSCOM_SIZE 0x100000
> +
> +static void pnv_core_xscom_realize(DeviceState *dev, Error **errp)
> +{
> +    XScomDevice *xd = XSCOM_DEVICE(dev);
> +    PnvCoreXScom *pnv_xd = PNV_CORE_XSCOM(dev);
> +
> +    xd->ranges[0].addr = EX_XSCOM_BASE | P8_PIR2COREID(pnv_xd->core_pir) << 24;
> +    xd->ranges[0].size = EX_XSCOM_SIZE;
> +}
> +
> +static Property pnv_core_xscom_properties[] = {
> +        DEFINE_PROP_UINT32("core-pir", PnvCoreXScom, core_pir, 0),
> +        DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pnv_core_xscom_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    XScomDeviceClass *xdc = XSCOM_DEVICE_CLASS(klass);
> +
> +    xdc->read = pnv_core_xscom_read;
> +    xdc->write = pnv_core_xscom_write;
> +
> +    dc->realize = pnv_core_xscom_realize;
> +    dc->props = pnv_core_xscom_properties;
> +}
> +
> +static const TypeInfo pnv_core_xscom_type_info = {
> +    .name          = TYPE_PNV_CORE_XSCOM,
> +    .parent        = TYPE_XSCOM_DEVICE,
> +    .instance_size = sizeof(PnvCoreXScom),
> +    .class_init    = pnv_core_xscom_class_init,
> +};
> +
>  static void pnv_core_register_types(void)
>  {
>      int i ;
>  
> +    type_register_static(&pnv_core_xscom_type_info);
>      type_register_static(&pnv_core_info);
>      for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
>          TypeInfo ti = {
> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> index 832c8756afaa..72936ccfd22f 100644
> --- a/include/hw/ppc/pnv_core.h
> +++ b/include/hw/ppc/pnv_core.h
> @@ -20,6 +20,18 @@
>  #define _PPC_PNV_CORE_H
>  
>  #include "hw/cpu/core.h"
> +#include "hw/ppc/pnv_xscom.h"
> +
> +#define TYPE_PNV_CORE_XSCOM "powernv-cpu-core-xscom"
> +#define PNV_CORE_XSCOM(obj) \
> +     OBJECT_CHECK(PnvCoreXScom, (obj), TYPE_PNV_CORE_XSCOM)
> +
> +typedef struct PnvCoreXScom {
> +    XScomDevice xd;
> +    uint32_t core_pir;
> +} PnvCoreXScom;
> +
> +#define P8_PIR2COREID(pir) (((pir) >> 3) & 0xf)
>  
>  #define TYPE_PNV_CORE "powernv-cpu-core"
>  #define PNV_CORE(obj) \
> @@ -35,6 +47,7 @@ typedef struct PnvCore {
>  
>      /*< public >*/
>      void *threads;
> +    PnvCoreXScom *xd;
>  } PnvCore;
>  
>  typedef struct PnvCoreClass {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0
  2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0 Cédric Le Goater
@ 2016-09-05  4:27   ` David Gibson
  2016-09-06  6:28     ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  4:27 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 2122 bytes --]

On Wed, Aug 31, 2016 at 06:34:15PM +0200, Cédric Le Goater wrote:
> On PowerNV, CPU ids start at 0x8 or 0x20, we don't have a CPU 0
> anymore. So let's use the first_cpu index to initialize the monitor.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

So we need a patch like this - amongst other fixes - in order to allow
unplug of cpu 0.  I'm not really sure whether to push it ahead now, or
gather it up with other no-cpu-0 fixes and send them as a batch.

> ---
> 
>  So that you can dump the cpu list with the monitor :
> 
> 	(qemu) info cpus
> 	* CPU #8: nip=0x0000000000000010 thread_id=7742
> 	  CPU #16: nip=0x0000000000000010 thread_id=7740
> 	  CPU #24: nip=0x0000000000000010 thread_id=7740
> 	  CPU #32: nip=0x0000000000000010 thread_id=7740
> 	  CPU #40: nip=0x0000000000000010 thread_id=7740
> 	  CPU #48: nip=0x0000000000000010 thread_id=7740
> 	  CPU #72: nip=0x0000000000000010 thread_id=7740
> 	  CPU #80: nip=0x0000000000000010 thread_id=7740
> 	  CPU #136: nip=0x0000000000000010 thread_id=7740
> 	  CPU #144: nip=0x0000000000000010 thread_id=7740
> 	  CPU #152: nip=0x0000000000000010 thread_id=7740
> 	  CPU #160: nip=0x0000000000000010 thread_id=7740
> 	  CPU #168: nip=0x0000000000000010 thread_id=7740
> 	  CPU #176: nip=0x0000000000000010 thread_id=7740
> 	  CPU #200: nip=0x0000000000000010 thread_id=7740
> 	  CPU #208: nip=0x0000000000000010 thread_id=7740
> 
>  monitor.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/monitor.c b/monitor.c
> index e9009de09a6c..19b8ec14f40e 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -1027,7 +1027,7 @@ int monitor_set_cpu(int cpu_index)
>  CPUState *mon_get_cpu(void)
>  {
>      if (!cur_mon->mon_cpu) {
> -        monitor_set_cpu(0);
> +        monitor_set_cpu(first_cpu->cpu_index);
>      }
>      cpu_synchronize_state(cur_mon->mon_cpu);
>      return cur_mon->mon_cpu;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform
  2016-09-05  2:48   ` [Qemu-devel] " David Gibson
@ 2016-09-05  6:06     ` Cédric Le Goater
  0 siblings, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-05  6:06 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

>> +static void ppc_powernv_reset(void)
>> +{
>> +    MachineState *machine = MACHINE(qdev_get_machine());
>> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
>> +    void *fdt;
>> +
>> +    pnv->fdt_addr = FDT_ADDR;
> 
> Not sure there's any point to pnv->fdt_addr, since it will always have
> the value FDT_ADDR.  Only worth changing if you're doing a respin for
> other reasons though.

Yes, you are probably right. I will take a look.

I have a new version with some basic core and xscom support for P9,
booting up to the interrupt setting in skiboot. So I was already 
planning for v3.

Thanks,

C.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  2:58   ` [Qemu-devel] " David Gibson
@ 2016-09-05  6:59     ` Benjamin Herrenschmidt
  2016-09-05  7:41       ` Cédric Le Goater
  2016-09-05  7:41       ` David Gibson
  2016-09-05  7:56     ` Cédric Le Goater
  1 sibling, 2 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-05  6:59 UTC (permalink / raw)
  To: David Gibson, Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Mon, 2016-09-05 at 12:58 +1000, David Gibson wrote:
> 
> With the new chip class per cpu class, does this chip_type field
> serve
> any purpose any more?
> 
> > +    k->chip_f000f = 0x120d304980000000ull;
> 
> A comment somewhere explaining what this cryptic value is would be
> nice.

It's snapshot from an actual chip ;-) Some of the fields we know about
such as the actual chip "type" and DD version but some are obscure even
to us :-)

Cheers,
Ben.
`

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-05  3:39   ` David Gibson
@ 2016-09-05  7:11     ` Benjamin Herrenschmidt
  2016-09-06  0:48       ` David Gibson
  2016-09-06 14:42     ` Cédric Le Goater
  1 sibling, 1 reply; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-05  7:11 UTC (permalink / raw)
  To: David Gibson, Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Mon, 2016-09-05 at 13:39 +1000, David Gibson wrote:
> > +static XScomDevice *xscom_find_target(XScomState *s, uint32_t
> pcb_addr,
> > +                                      uint32_t *range)
> > +{
> > +    BusChild *bc;
> > +
> > +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> > +        DeviceState *qd = bc->child;
> > +        XScomDevice *xd = XSCOM_DEVICE(qd);
> > +        unsigned int i;
> > +
> > +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> > +            if (xd->ranges[i].addr <= pcb_addr &&
> > +                (xd->ranges[i].addr + xd->ranges[i].size) >
> pcb_addr) {
> > +                *range = i;
> > +                return xd;
> > +            }
> > +        }
> > +    }
> 
> Hmm.. you could set up a SCOM local address space using the
> infrastructure in memory.c, rather than doing your own dispatch.

There are pros and cons to this approach. The memory.c stuff comes with
quite a lot of baggage, not all of it very shinny to be honest ;-) I
still *hate* how it forces upon us a whole 128-bit integer arithmetic
library just so that it can represent 1_0000_0000_0000_0000 ... 

It would be make more sense to use inclusive start/end instead and
stick to 64-bits.

That being said, we could do that. We'd have to shift the XSCOM
addresses left by 3 since each address is an 8 bytes reigster and
forbid non-8-bytes accesses.

Ben.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  6:59     ` Benjamin Herrenschmidt
@ 2016-09-05  7:41       ` Cédric Le Goater
  2016-09-05  8:28         ` Benjamin Herrenschmidt
  2016-09-05  7:41       ` David Gibson
  1 sibling, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-05  7:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/05/2016 08:59 AM, Benjamin Herrenschmidt wrote:
> On Mon, 2016-09-05 at 12:58 +1000, David Gibson wrote:
>>
>> With the new chip class per cpu class, does this chip_type field
>> serve
>> any purpose any more?
>>
>>> +    k->chip_f000f = 0x120d304980000000ull;
>>
>> A comment somewhere explaining what this cryptic value is would be
>> nice.
> 
> It's snapshot from an actual chip ;-) Some of the fields we know about
> such as the actual chip "type" and DD version but some are obscure even
> to us :-)

yeah. I have not found a clear definition of all the bits.

I will try to make a macro with what I can collect from the 
specs and the code.

Cheers,

C.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  6:59     ` Benjamin Herrenschmidt
  2016-09-05  7:41       ` Cédric Le Goater
@ 2016-09-05  7:41       ` David Gibson
  2016-09-05  9:10         ` Cédric Le Goater
  1 sibling, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-05  7:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 861 bytes --]

On Mon, Sep 05, 2016 at 04:59:23PM +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2016-09-05 at 12:58 +1000, David Gibson wrote:
> > 
> > With the new chip class per cpu class, does this chip_type field
> > serve
> > any purpose any more?
> > 
> > > +    k->chip_f000f = 0x120d304980000000ull;
> > 
> > A comment somewhere explaining what this cryptic value is would be
> > nice.
> 
> It's snapshot from an actual chip ;-) Some of the fields we know about
> such as the actual chip "type" and DD version but some are obscure even
> to us :-)

Sorry, I actually meant what does "chip_f000f" mean, rather than what
does the value inside there mean.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  2:58   ` [Qemu-devel] " David Gibson
  2016-09-05  6:59     ` Benjamin Herrenschmidt
@ 2016-09-05  7:56     ` Cédric Le Goater
  2016-09-06  0:52       ` David Gibson
  1 sibling, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-05  7:56 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 04:58 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:10PM +0200, Cédric Le Goater wrote:
>> This is is an abstraction of a POWER8 chip which is a set of cores
>> plus other 'units', like the pervasive unit, the interrupt controller,
>> the memory controller, the on-chip microcontroller, etc. The whole can
>> be seen as a socket. It depends on a cpu model and its characteristics,
>> max cores, specific init are defined in a PnvChipClass.
>>
>> We start with an near empty PnvChip with only a few cpu constants
>> which we will grow in the subsequent patches with the controllers
>> required to run the system.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>
>>  Changes since v1:
>>  
>>  - introduced a PnvChipClass depending on the cpu model. It also
>>    provides some chip constants used by devices, like the cpu model hw
>>    id (f000f), a enum type (not sure this is useful yet), a custom
>>    realize ops for customization.
>>  - the num-chips property can be configured on the command line.
>>  
>>  Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 
>>
>>  hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
>>  2 files changed, 225 insertions(+)
>>
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 70413e3c5740..06051268e200 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
>>      char *fw_filename;
>>      long fw_size;
>>      long kernel_size;
>> +    int i;
>> +    char *chip_typename;
>>  
>>      /* allocate RAM */
>>      if (ram_size < (1 * G_BYTE)) {
>> @@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
>>              exit(1);
>>          }
>>      }
>> +
>> +    /* Create the processor chips */
>> +    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
>> +
>> +    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
>> +    for (i = 0; i < pnv->num_chips; i++) {
>> +        Object *chip = object_new(chip_typename);
>> +        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
>> +        object_property_set_bool(chip, true, "realized", &error_abort);
> 
> I'm guessing these could fail due to bad user supplied parameters, not
> just internal bugs.  In which case this should be &error_fatal rather
> than &error_abort.

yes.

> 
>> +        pnv->chips[i] = PNV_CHIP(chip);
>> +    }
>> +    g_free(chip_typename);
>> +}
>> +
>> +static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
> 
> I don't think you should need to define an empty realize function.  
> Or is this just a placeholder for things future patches will add?

yes that was the plan but maybe this is a little early. chip_type
proved to be useful enough for the moment in the full patchset 
I maintain.

P9 will use a xive object when available and not a xics. I think 
this is when the real big difference will show up. So I should 
make realize() optional.

>> +
>> +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8nvl_realize;
>> +    k->cpu_model = "POWER8NVL";
>> +    k->chip_type = PNV_CHIP_P8NVL;
> 
> With the new chip class per cpu class, does this chip_type field serve
> any purpose any more?

It does look a bit redundant, I agree. But it is useful for xscom 
address translation (P9 is a little different), for xscom devices 
in general, for core id to pir conversion. It also does for lpc_irq 
support, which applies  to P8NVL (and upper I suppose). 

Let's keep it for the moment as it serves its purpose, which is 
to handle small differences without too much cost. If this is 
going too far, I will propose a set of ops per chip type.  

>> +    k->chip_f000f = 0x120d304980000000ull;
> 
> A comment somewhere explaining what this cryptic value is would be nice.

yeah. I will make a macro of it with the bits I know about :/

>> +    dc->desc = "PowerNV Chip POWER8NVL";
>> +}
>> +
>> +static const TypeInfo pnv_chip_power8nvl_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8NVL,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8NVL),
>> +    .class_init    = pnv_chip_power8nvl_class_init,
>> +};
>> +
>> +static void pnv_chip_power8_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
>> +
>> +static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8_realize;
>> +    k->cpu_model = "POWER8";
>> +    k->chip_type = PNV_CHIP_P8;
>> +    k->chip_f000f = 0x220ea04980000000ull;
>> +    dc->desc = "PowerNV Chip POWER8";
>> +}
> 
> It might be worth using some macros to compactify the definition of
> each of the chip variants.

yes. we have four of them now. It is time do so.

Thanks,

C.

>> +
>> +static const TypeInfo pnv_chip_power8_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8),
>> +    .class_init    = pnv_chip_power8_class_init,
>> +};
>> +
>> +static void pnv_chip_power8e_realize(PnvChip *chip, Error **errp)
>> +{
>> +    ;
>> +}
>> +
>> +static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
>> +
>> +    k->realize = pnv_chip_power8e_realize;
>> +    k->cpu_model = "POWER8E";
>> +    k->chip_type = PNV_CHIP_P8E;
>> +    k->chip_f000f = 0x221ef04980000000ull;
>> +    dc->desc = "PowerNV Chip POWER8E";
>> +}
>> +
>> +static const TypeInfo pnv_chip_power8e_info = {
>> +    .name          = TYPE_PNV_CHIP_POWER8E,
>> +    .parent        = TYPE_PNV_CHIP,
>> +    .instance_size = sizeof(PnvChipPower8e),
>> +    .class_init    = pnv_chip_power8e_class_init,
>> +};
>> +
>> +static void pnv_chip_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PnvChip *chip = PNV_CHIP(dev);
>> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>> +
>> +    pcc->realize(chip, errp);
>> +}
>> +
>> +static Property pnv_chip_properties[] = {
>> +    DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void pnv_chip_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = pnv_chip_realize;
>> +    dc->props = pnv_chip_properties;
>> +    dc->desc = "PowerNV Chip";
>> + }
>> +
>> +static const TypeInfo pnv_chip_info = {
>> +    .name          = TYPE_PNV_CHIP,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .class_init    = pnv_chip_class_init,
>> +    .class_size    = sizeof(PnvChipClass),
>> +    .abstract      = true,
>> +};
>> +
>> +static char *pnv_get_num_chips(Object *obj, Error **errp)
>> +{
>> +    return g_strdup_printf("%d", POWERNV_MACHINE(obj)->num_chips);
>> +}
>> +
>> +static void pnv_set_num_chips(Object *obj, const char *value, Error **errp)
>> +{
>> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
>> +    int num_chips;
>> +
>> +    if (sscanf(value, "%d", &num_chips) != 1) {
>> +        error_setg(errp, "invalid num_chips property: '%s'", value);
>> +    }
>> +
>> +    /*
>> +     * FIXME: should we decide on how many chips we can create based
>> +     * on #cores and Venice vs. Murano vs. Naples chip type etc...,
>> +     */
>> +    pnv->num_chips = num_chips;
>> +}
>> +
>> +static void powernv_machine_initfn(Object *obj)
>> +{
>> +    PnvMachineState *pnv = POWERNV_MACHINE(obj);
>> +    pnv->num_chips = 1;
>> +
>> +    object_property_add_str(obj, "num-chips", pnv_get_num_chips,
>> +                            pnv_set_num_chips, NULL);
>> +    object_property_set_description(obj, "num-chips",
>> +                                    "Specifies the number of processor chips",
>> +                                    NULL);
>>  }
>>  
>>  static void powernv_machine_class_init(ObjectClass *oc, void *data)
>> @@ -233,12 +382,17 @@ static const TypeInfo powernv_machine_info = {
>>      .name          = TYPE_POWERNV_MACHINE,
>>      .parent        = TYPE_MACHINE,
>>      .instance_size = sizeof(PnvMachineState),
>> +    .instance_init = powernv_machine_initfn,
>>      .class_init    = powernv_machine_class_init,
>>  };
>>  
>>  static void powernv_machine_register_types(void)
>>  {
>>      type_register_static(&powernv_machine_info);
>> +    type_register_static(&pnv_chip_info);
>> +    type_register_static(&pnv_chip_power8e_info);
>> +    type_register_static(&pnv_chip_power8_info);
>> +    type_register_static(&pnv_chip_power8nvl_info);
>>  }
>>  
>>  type_init(powernv_machine_register_types)
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 31a57ed7f465..1f32573dedff 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -20,6 +20,74 @@
>>  #define _PPC_PNV_H
>>  
>>  #include "hw/boards.h"
>> +#include "hw/sysbus.h"
>> +
>> +#define TYPE_PNV_CHIP "powernv-chip"
>> +#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
>> +#define PNV_CHIP_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP)
>> +#define PNV_CHIP_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(PnvChipClass, (obj), TYPE_PNV_CHIP)
>> +
>> +typedef enum PnvChipType {
>> +    PNV_CHIP_P8E,   /* AKA Murano (default) */
>> +    PNV_CHIP_P8,    /* AKA Venice */
>> +    PNV_CHIP_P8NVL, /* AKA Naples */
>> +} PnvChipType;
>> +
>> +typedef struct PnvChip {
>> +    /*< private >*/
>> +    SysBusDevice parent_obj;
>> +
>> +    /*< public >*/
>> +    uint32_t     chip_id;
>> +} PnvChip;
>> +
>> +typedef struct PnvChipClass {
>> +    /*< private >*/
>> +    SysBusDeviceClass parent_class;
>> +    /*< public >*/
>> +    const char *cpu_model;
>> +    PnvChipType  chip_type;
>> +    uint64_t     chip_f000f;
>> +
>> +    void (*realize)(PnvChip *dev, Error **errp);
>> +} PnvChipClass;
>> +
>> +#define TYPE_PNV_CHIP "powernv-chip"
>> +
>> +#define TYPE_PNV_CHIP_POWER8E "powernv-chip-POWER8E"
>> +#define PNV_CHIP_POWER8E(obj) \
>> +    OBJECT_CHECK(PnvChipPower8e, (obj), TYPE_PNV_CHIP_POWER8E)
>> +
>> +typedef struct PnvChipPower8e {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8e;
>> +
>> +#define TYPE_PNV_CHIP_POWER8 "powernv-chip-POWER8"
>> +#define PNV_CHIP_POWER8(obj) \
>> +    OBJECT_CHECK(PnvChipPower8, (obj), TYPE_PNV_CHIP_POWER8)
>> +
>> +typedef struct PnvChipPower8 {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8;
>> +
>> +#define TYPE_PNV_CHIP_POWER8NVL "powernv-chip-POWER8NVL"
>> +#define PNV_CHIP_POWER8NVL(obj) \
>> +    OBJECT_CHECK(PnvChipPower8NVL, (obj), TYPE_PNV_CHIP_POWER8NVL)
>> +
>> +typedef struct PnvChipPower8NVL {
>> +    PnvChip pnv_chip;
>> +} PnvChipPower8NVL;
>> +
>> +/*
>> + * This generates a HW chip id depending on an index:
>> + *
>> + *    0x0, 0x1, 0x10, 0x11, 0x20, 0x21, ...
>> + *
>> + * Is this correct ?
>> + */
>> +#define CHIP_HWID(i) ((((i) & 0x3e) << 3) | ((i) & 0x1))
>>  
>>  #define TYPE_POWERNV_MACHINE       MACHINE_TYPE_NAME("powernv")
>>  #define POWERNV_MACHINE(obj) \
>> @@ -32,6 +100,9 @@ typedef struct PnvMachineState {
>>      uint32_t initrd_base;
>>      long initrd_size;
>>      hwaddr fdt_addr;
>> +
>> +    uint32_t  num_chips;
>> +    PnvChip   **chips;
>>  } PnvMachineState;
>>  
>>  #endif /* _PPC_PNV_H */
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  7:41       ` Cédric Le Goater
@ 2016-09-05  8:28         ` Benjamin Herrenschmidt
  2016-09-06  0:49           ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-05  8:28 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Mon, 2016-09-05 at 09:41 +0200, Cédric Le Goater wrote:
> yeah. I have not found a clear definition of all the bits.
> 
> I will try to make a macro with what I can collect from the 
> specs and the code.

It's the CFAM stuff, there's some doco internally but nothing
releasable publicly...

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  7:41       ` David Gibson
@ 2016-09-05  9:10         ` Cédric Le Goater
  2016-09-06  0:50           ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-05  9:10 UTC (permalink / raw)
  To: David Gibson, Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/05/2016 09:41 AM, David Gibson wrote:
> On Mon, Sep 05, 2016 at 04:59:23PM +1000, Benjamin Herrenschmidt wrote:
>> On Mon, 2016-09-05 at 12:58 +1000, David Gibson wrote:
>>>
>>> With the new chip class per cpu class, does this chip_type field
>>> serve
>>> any purpose any more?
>>>
>>>> +    k->chip_f000f = 0x120d304980000000ull;
>>>
>>> A comment somewhere explaining what this cryptic value is would be
>>> nice.
>>
>> It's snapshot from an actual chip ;-) Some of the fields we know about
>> such as the actual chip "type" and DD version but some are obscure even
>> to us :-)
> 
> Sorry, I actually meant what does "chip_f000f" mean, rather than what
> does the value inside there mean.

f000f is the xscom address of the register containing this CFAM 
chip id. I will add a chip_cfam_id attribute to the chip object. 
I guess it makes more sense.

Other chips (like the Centaur) have such an ID.

C. 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip
  2016-09-05  3:42   ` David Gibson
@ 2016-09-05 11:13     ` Cédric Le Goater
  2016-09-05 11:30       ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-05 11:13 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 05:42 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:12PM +0200, Cédric Le Goater wrote:
>> This will be used to build real HW ids for the cores and enforce some
>> limits on the available cores per chip.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++++
>>  include/hw/ppc/pnv.h |  2 ++
>>  2 files changed, 29 insertions(+)
>>
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index a6e7f66b2c0a..b6efb5e3ef07 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -236,6 +236,27 @@ static void ppc_powernv_init(MachineState *machine)
>>      g_free(chip_typename);
>>  }
>>  
>> +/* Allowed core identifiers on a POWER8 Processor Chip :
>> + *
>> + * <EX0 reserved>
>> + *  EX1  - Venice only
>> + *  EX2  - Venice only
>> + *  EX3  - Venice only
>> + *  EX4
>> + *  EX5
>> + *  EX6
>> + * <EX7,8 reserved> <reserved>
>> + *  EX9  - Venice only
>> + *  EX10 - Venice only
>> + *  EX11 - Venice only
>> + *  EX12
>> + *  EX13
>> + *  EX14
>> + * <EX15 reserved>
>> + */
>> +#define POWER8E_CORE_MASK  (~0xffff8f8f)
>> +#define POWER8_CORE_MASK   (~0xffff8181)
>> +
>>  static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
>>  {
>>      ;
>> @@ -250,6 +271,8 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>>      k->cpu_model = "POWER8NVL";
>>      k->chip_type = PNV_CHIP_P8NVL;
>>      k->chip_f000f = 0x120d304980000000ull;
>> +    k->cores_max = 12;
> 
> Is it worth having this cores_max field, since AFAICT you can
> calculate it as hweight(~cores_mask)?

Sure. I looked for it and missed it. 

Here is a slightly improved version from Brian Kernighan :

	unsigned int v; // count the number of bits set in v
	unsigned int c; // c accumulates the total bits set in v

	for (c = 0; v; c++)
	{
		v &= v - 1; // clear the least significant bit set
	}

Thanks,

C. 

>> +    k->cores_mask = POWER8_CORE_MASK;
>>      dc->desc = "PowerNV Chip POWER8NVL";
>>  }
>>  
>> @@ -274,6 +297,8 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>>      k->cpu_model = "POWER8";
>>      k->chip_type = PNV_CHIP_P8;
>>      k->chip_f000f = 0x220ea04980000000ull;
>> +    k->cores_max = 12;
>> +    k->cores_mask = POWER8_CORE_MASK;
>>      dc->desc = "PowerNV Chip POWER8";
>>  }
>>  
>> @@ -298,6 +323,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>>      k->cpu_model = "POWER8E";
>>      k->chip_type = PNV_CHIP_P8E;
>>      k->chip_f000f = 0x221ef04980000000ull;
>> +    k->cores_max = 6;
>> +    k->cores_mask = POWER8E_CORE_MASK;
>>      dc->desc = "PowerNV Chip POWER8E";
>>  }
>>  
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index bc6e1f80096b..987bc70245a7 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -49,6 +49,8 @@ typedef struct PnvChipClass {
>>      /*< private >*/
>>      SysBusDeviceClass parent_class;
>>      /*< public >*/
>> +    uint32_t   cores_max;
>> +    uint32_t   cores_mask;
>>      const char *cpu_model;
>>      PnvChipType  chip_type;
>>      uint64_t     chip_f000f;
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip
  2016-09-05 11:13     ` Cédric Le Goater
@ 2016-09-05 11:30       ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-05 11:30 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Mon, 2016-09-05 at 13:13 +0200, Cédric Le Goater wrote:
> > Is it worth having this cores_max field, since AFAICT you can
> > calculate it as hweight(~cores_mask)?
> 
> Sure. I looked for it and missed it. 
> 
> Here is a slightly improved version from Brian Kernighan :
> 
>         unsigned int v; // count the number of bits set in v
>         unsigned int c; // c accumulates the total bits set in v
> 
>         for (c = 0; v; c++)
>         {
>                 v &= v - 1; // clear the least significant bit set
>         }

Use the accessor (ie, hweight). The compiler might turn it into a
popcnt instruction of some sort if the CPU has one :-)

Ben.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-05  7:11     ` Benjamin Herrenschmidt
@ 2016-09-06  0:48       ` David Gibson
  2016-09-06 14:42         ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-06  0:48 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 1882 bytes --]

On Mon, Sep 05, 2016 at 05:11:53PM +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2016-09-05 at 13:39 +1000, David Gibson wrote:
> > > +static XScomDevice *xscom_find_target(XScomState *s, uint32_t
> > pcb_addr,
> > > +                                      uint32_t *range)
> > > +{
> > > +    BusChild *bc;
> > > +
> > > +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> > > +        DeviceState *qd = bc->child;
> > > +        XScomDevice *xd = XSCOM_DEVICE(qd);
> > > +        unsigned int i;
> > > +
> > > +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> > > +            if (xd->ranges[i].addr <= pcb_addr &&
> > > +                (xd->ranges[i].addr + xd->ranges[i].size) >
> > pcb_addr) {
> > > +                *range = i;
> > > +                return xd;
> > > +            }
> > > +        }
> > > +    }
> > 
> > Hmm.. you could set up a SCOM local address space using the
> > infrastructure in memory.c, rather than doing your own dispatch.
> 
> There are pros and cons to this approach. The memory.c stuff comes with
> quite a lot of baggage, not all of it very shinny to be honest ;-) I
> still *hate* how it forces upon us a whole 128-bit integer arithmetic
> library just so that it can represent 1_0000_0000_0000_0000 ... 

Ugh, yeah.  I tried to argue against this when it first came in, but
was overruled.

> It would be make more sense to use inclusive start/end instead and
> stick to 64-bits.
> 
> That being said, we could do that. We'd have to shift the XSCOM
> addresses left by 3 since each address is an 8 bytes reigster and
> forbid non-8-bytes accesses.

Ok.  I'm not particularly fussed either way.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  8:28         ` Benjamin Herrenschmidt
@ 2016-09-06  0:49           ` David Gibson
  2016-09-06  6:21             ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-06  0:49 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

On Mon, Sep 05, 2016 at 06:28:10PM +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2016-09-05 at 09:41 +0200, Cédric Le Goater wrote:
> > yeah. I have not found a clear definition of all the bits.
> > 
> > I will try to make a macro with what I can collect from the 
> > specs and the code.
> 
> It's the CFAM stuff, there's some doco internally but nothing
> releasable publicly...

Right...

My point is that I want a name (and/or coment) saying what the
relevance of this value is to qemu.  Why do we need this cryptic value
sitting here?

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  9:10         ` Cédric Le Goater
@ 2016-09-06  0:50           ` David Gibson
  0 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-06  0:50 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Benjamin Herrenschmidt, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 1254 bytes --]

On Mon, Sep 05, 2016 at 11:10:05AM +0200, Cédric Le Goater wrote:
> On 09/05/2016 09:41 AM, David Gibson wrote:
> > On Mon, Sep 05, 2016 at 04:59:23PM +1000, Benjamin Herrenschmidt wrote:
> >> On Mon, 2016-09-05 at 12:58 +1000, David Gibson wrote:
> >>>
> >>> With the new chip class per cpu class, does this chip_type field
> >>> serve
> >>> any purpose any more?
> >>>
> >>>> +    k->chip_f000f = 0x120d304980000000ull;
> >>>
> >>> A comment somewhere explaining what this cryptic value is would be
> >>> nice.
> >>
> >> It's snapshot from an actual chip ;-) Some of the fields we know about
> >> such as the actual chip "type" and DD version but some are obscure even
> >> to us :-)
> > 
> > Sorry, I actually meant what does "chip_f000f" mean, rather than what
> > does the value inside there mean.
> 
> f000f is the xscom address of the register containing this CFAM 
> chip id. I will add a chip_cfam_id attribute to the chip object. 
> I guess it makes more sense.
> 
> Other chips (like the Centaur) have such an ID.

Ok.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-05  7:56     ` Cédric Le Goater
@ 2016-09-06  0:52       ` David Gibson
  0 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-06  0:52 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 4538 bytes --]

On Mon, Sep 05, 2016 at 09:56:03AM +0200, Cédric Le Goater wrote:
> On 09/05/2016 04:58 AM, David Gibson wrote:
> > On Wed, Aug 31, 2016 at 06:34:10PM +0200, Cédric Le Goater wrote:
> >> This is is an abstraction of a POWER8 chip which is a set of cores
> >> plus other 'units', like the pervasive unit, the interrupt controller,
> >> the memory controller, the on-chip microcontroller, etc. The whole can
> >> be seen as a socket. It depends on a cpu model and its characteristics,
> >> max cores, specific init are defined in a PnvChipClass.
> >>
> >> We start with an near empty PnvChip with only a few cpu constants
> >> which we will grow in the subsequent patches with the controllers
> >> required to run the system.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> >> ---
> >>
> >>  Changes since v1:
> >>  
> >>  - introduced a PnvChipClass depending on the cpu model. It also
> >>    provides some chip constants used by devices, like the cpu model hw
> >>    id (f000f), a enum type (not sure this is useful yet), a custom
> >>    realize ops for customization.
> >>  - the num-chips property can be configured on the command line.
> >>  
> >>  Maybe this object deserves its own file hw/ppc/pnv_chip.c ? 
> >>
> >>  hw/ppc/pnv.c         | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/hw/ppc/pnv.h |  71 ++++++++++++++++++++++++
> >>  2 files changed, 225 insertions(+)
> >>
> >> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> >> index 70413e3c5740..06051268e200 100644
> >> --- a/hw/ppc/pnv.c
> >> +++ b/hw/ppc/pnv.c
> >> @@ -168,6 +168,8 @@ static void ppc_powernv_init(MachineState *machine)
> >>      char *fw_filename;
> >>      long fw_size;
> >>      long kernel_size;
> >> +    int i;
> >> +    char *chip_typename;
> >>  
> >>      /* allocate RAM */
> >>      if (ram_size < (1 * G_BYTE)) {
> >> @@ -212,6 +214,153 @@ static void ppc_powernv_init(MachineState *machine)
> >>              exit(1);
> >>          }
> >>      }
> >> +
> >> +    /* Create the processor chips */
> >> +    chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
> >> +
> >> +    pnv->chips = g_new0(PnvChip *, pnv->num_chips);
> >> +    for (i = 0; i < pnv->num_chips; i++) {
> >> +        Object *chip = object_new(chip_typename);
> >> +        object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
> >> +        object_property_set_bool(chip, true, "realized", &error_abort);
> > 
> > I'm guessing these could fail due to bad user supplied parameters, not
> > just internal bugs.  In which case this should be &error_fatal rather
> > than &error_abort.
> 
> yes.
> 
> > 
> >> +        pnv->chips[i] = PNV_CHIP(chip);
> >> +    }
> >> +    g_free(chip_typename);
> >> +}
> >> +
> >> +static void pnv_chip_power8nvl_realize(PnvChip *chip, Error **errp)
> >> +{
> >> +    ;
> >> +}
> > 
> > I don't think you should need to define an empty realize function.  
> > Or is this just a placeholder for things future patches will add?
> 
> yes that was the plan but maybe this is a little early. chip_type
> proved to be useful enough for the moment in the full patchset 
> I maintain.
> 
> P9 will use a xive object when available and not a xics. I think 
> this is when the real big difference will show up. So I should 
> make realize() optional.
> 
> >> +
> >> +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> >> +
> >> +    k->realize = pnv_chip_power8nvl_realize;
> >> +    k->cpu_model = "POWER8NVL";
> >> +    k->chip_type = PNV_CHIP_P8NVL;
> > 
> > With the new chip class per cpu class, does this chip_type field serve
> > any purpose any more?
> 
> It does look a bit redundant, I agree. But it is useful for xscom 
> address translation (P9 is a little different), for xscom devices 
> in general, for core id to pir conversion. It also does for lpc_irq 
> support, which applies  to P8NVL (and upper I suppose). 
> 
> Let's keep it for the moment as it serves its purpose, which is 
> to handle small differences without too much cost. If this is 
> going too far, I will propose a set of ops per chip type.

Ok, fair enough.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object
  2016-09-05  4:02   ` David Gibson
@ 2016-09-06  6:14     ` Cédric Le Goater
  2016-09-07  1:48       ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06  6:14 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 06:02 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:13PM +0200, Cédric Le Goater wrote:
>> This is largy inspired by sPAPRCPUCore with some simplification, no
>> hotplug for instance. But the differences are small and the objects
>> could possibly be merged.
>>
>> A set of PnvCore objects is added to the PnvChip and the device
>> tree is populated looping on these cores.
>>
>> Real HW cpu ids are now generated depending on the chip cpu model, the
>> chip id and a core mask. This id is stored in CPUState->cpu_index and
>> in PnvCore->core_id and it is used to populate the device tree.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>
>>  Changes since v1:
>>
>>  - changed name to PnvCore
>>  - changed PnvChip core array type to a 'PnvCore *cores'
>>  - introduced real cpu hw ids using a core mask from the chip
>>  - reworked powernv_create_core_node() which populates the device tree
>>  - added missing "ibm,pa-features" property 
>>  - smp_cpus representing threads, used smp_cores instead to create the
>>    cores in the chip.
>>  - removed the use of ppc_get_vcpu_dt_id() 
>>  - added "POWER8E" and "POWER8NVL" cpu models to exercice the
>>    PnvChipClass
>>
>>  hw/ppc/Makefile.objs      |   2 +-
>>  hw/ppc/pnv.c              | 204 ++++++++++++++++++++++++++++++++++++++++++++++
>>  hw/ppc/pnv_core.c         | 170 ++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/pnv.h      |   7 ++
>>  include/hw/ppc/pnv_core.h |  47 +++++++++++
>>  5 files changed, 429 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/ppc/pnv_core.c
>>  create mode 100644 include/hw/ppc/pnv_core.h
>>
>> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
>> index f580e5c41413..08c213c40684 100644
>> --- a/hw/ppc/Makefile.objs
>> +++ b/hw/ppc/Makefile.objs
>> @@ -6,7 +6,7 @@ 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_cpu_core.o
>>  # IBM PowerNV
>> -obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
>> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o
>>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>>  obj-y += spapr_pci_vfio.o
>>  endif
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index b6efb5e3ef07..daf9f459ab0e 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -35,6 +35,7 @@
>>  #include "hw/ppc/fdt.h"
>>  #include "hw/ppc/ppc.h"
>>  #include "hw/ppc/pnv.h"
>> +#include "hw/ppc/pnv_core.h"
>>  #include "hw/loader.h"
>>  #include "exec/address-spaces.h"
>>  #include "qemu/cutils.h"
>> @@ -98,6 +99,136 @@ static int powernv_populate_memory(void *fdt)
>>      return 0;
>>  }
>>  
>> +/*
>> + * The PowerNV cores (and threads) need to use real HW ids and not an
>> + * incremental index like it has been done on other platforms. This HW
>> + * id is called a PIR and is used in the device tree, in the XSCOM
>> + * communication to address cores, in the interrupt servers.
>> + */
>> +static void powernv_create_core_node(PnvCore *pc, void *fdt,
>> +                                     int cpus_offset, int chip_id)
>> +{
>> +    CPUCore *core = CPU_CORE(pc);
>> +    CPUState *cs = CPU(DEVICE(pc->threads));
>> +    DeviceClass *dc = DEVICE_GET_CLASS(cs);
>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>> +    int smt_threads = ppc_get_compat_smt_threads(cpu);
>> +    CPUPPCState *env = &cpu->env;
>> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
>> +    uint32_t servers_prop[smt_threads];
>> +    uint32_t gservers_prop[smt_threads * 2];
>> +    int i;
>> +    uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
>> +                       0xffffffff, 0xffffffff};
>> +    uint32_t tbfreq = PNV_TIMEBASE_FREQ;
>> +    uint32_t cpufreq = 1000000000;
>> +    uint32_t page_sizes_prop[64];
>> +    size_t page_sizes_prop_size;
>> +    const uint8_t pa_features[] = { 24, 0,
>> +                                    0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
>> +                                    0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
>> +                                    0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
>> +                                    0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
>> +    int offset;
>> +    char *nodename;
>> +
>> +    nodename = g_strdup_printf("%s@%x", dc->fw_name, core->core_id);
>> +    offset = fdt_add_subnode(fdt, cpus_offset, nodename);
>> +    _FDT(offset);
>> +    g_free(nodename);
>> +
>> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip_id)));
>> +
>> +    _FDT((fdt_setprop_cell(fdt, offset, "reg", core->core_id)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", core->core_id)));
>> +    _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
>> +
>> +    _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
>> +                            env->dcache_line_size)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
>> +                            env->dcache_line_size)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
>> +                            env->icache_line_size)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
>> +                            env->icache_line_size)));
>> +
>> +    if (pcc->l1_dcache_size) {
>> +        _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
>> +                               pcc->l1_dcache_size)));
>> +    } else {
>> +        error_report("Warning: Unknown L1 dcache size for cpu");
>> +    }
>> +    if (pcc->l1_icache_size) {
>> +        _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
>> +                               pcc->l1_icache_size)));
>> +    } else {
>> +        error_report("Warning: Unknown L1 icache size for cpu");
>> +    }
>> +
>> +    _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
>> +    _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
>> +    _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
>> +
>> +    if (env->spr_cb[SPR_PURR].oea_read) {
>> +        _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
>> +    }
>> +
>> +    if (env->mmu_model & POWERPC_MMU_1TSEG) {
>> +        _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
>> +                           segs, sizeof(segs))));
>> +    }
>> +
>> +    /* Advertise VMX/VSX (vector extensions) if available
>> +     *   0 / no property == no vector extensions
>> +     *   1               == VMX / Altivec available
>> +     *   2               == VSX available */
>> +    if (env->insns_flags & PPC_ALTIVEC) {
>> +        uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
>> +
>> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
>> +    }
>> +
>> +    /* Advertise DFP (Decimal Floating Point) if available
>> +     *   0 / no property == no DFP
>> +     *   1               == DFP available */
>> +    if (env->insns_flags2 & PPC2_DFP) {
>> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
>> +    }
>> +
>> +    page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
>> +                                                  sizeof(page_sizes_prop));
>> +    if (page_sizes_prop_size) {
>> +        _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
>> +                           page_sizes_prop, page_sizes_prop_size)));
>> +    }
>> +
>> +    _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
>> +                       pa_features, sizeof(pa_features))));
>> +
>> +    if (cpu->cpu_version) {
>> +        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
>> +    }
>> +
>> +    /* Build interrupt servers and gservers properties */
>> +    for (i = 0; i < smt_threads; i++) {
>> +        servers_prop[i] = cpu_to_be32(core->core_id + i);
>> +        /* Hack, direct the group queues back to cpu 0
>> +         *
>> +         * FIXME: check that we still need this hack with real HW
>> +         * ids. Probably not.
>> +         */
>> +        gservers_prop[i * 2] = cpu_to_be32(core->core_id + i);
>> +        gservers_prop[i * 2 + 1] = 0;
> 
> I'm not sure the group servers concept even makes sense in the case of
> powernv.  In powernv, doesn't the guest control the "real" xics,
> including the link registers, and therefore can configure its own
> groups, rather than being limited to what firmware has set up as for
> PAPR?

yes. we can remove this property.  
 
>> +    }
>> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
>> +                       servers_prop, sizeof(servers_prop))));
>> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
>> +                       gservers_prop, sizeof(gservers_prop))));
>> +}
>> +
>>  static void *powernv_create_fdt(PnvMachineState *pnv,
>>                                  const char *kernel_cmdline)
>>  {
>> @@ -106,6 +237,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
>>      int off;
>>      int i;
>> +    int cpus_offset;
>>  
>>      fdt = g_malloc0(FDT_MAX_SIZE);
>>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
>> @@ -150,6 +282,22 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>>          xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
>>      }
>>  
>> +    /* cpus */
>> +    cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
>> +    _FDT(cpus_offset);
>> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
>> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
>> +
>> +    for (i = 0; i < pnv->num_chips; i++) {
>> +        PnvChip *chip = pnv->chips[i];
>> +        int j;
>> +
>> +        for (j = 0; j < chip->num_cores; j++) {
>> +            powernv_create_core_node(&chip->cores[j], fdt, cpus_offset,
>> +                                     chip->chip_id);
>> +        }
>> +    }
>> +
>>      return fdt;
>>  }
>>  
>> @@ -230,6 +378,11 @@ static void ppc_powernv_init(MachineState *machine)
>>      for (i = 0; i < pnv->num_chips; i++) {
>>          Object *chip = object_new(chip_typename);
>>          object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
>> +        object_property_set_int(chip, smp_cores, "num-cores", &error_abort);
> 
> This should probably be &error_fatal, again.

ok.

>> +        /*
>> +         * We could set a custom cores_mask for the chip here.
>> +         */
>> +
>>          object_property_set_bool(chip, true, "realized", &error_abort);
>>          pnv->chips[i] = PNV_CHIP(chip);
>>      }
>> @@ -335,19 +488,70 @@ static const TypeInfo pnv_chip_power8e_info = {
>>      .class_init    = pnv_chip_power8e_class_init,
>>  };
>>  
>> +/*
>> + * This is different for POWER9 so we might need a ops in the chip to
>> + * calculate the core pirs
>> + */
>> +#define P8_PIR(chip_id, core_id) (((chip_id) << 7) | ((core_id) << 3))
>> +
>>  static void pnv_chip_realize(DeviceState *dev, Error **errp)
>>  {
>>      PnvChip *chip = PNV_CHIP(dev);
>>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>> +    char *typename = pnv_core_typename(pcc->cpu_model);
>> +    size_t typesize = object_type_get_instance_size(typename);
>> +    int i, core_hwid;
>> +
>> +    if (!object_class_by_name(typename)) {
>> +        error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
>> +        return;
>> +    }
>>  
>>      /* Set up XSCOM bus */
>>      chip->xscom = xscom_create(chip);
>>  
>> +    if (chip->num_cores > pcc->cores_max) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: too many cores for chip ! "
>> +                      "Limiting to %d\n", __func__, pcc->cores_max);
>> +        chip->num_cores = pcc->cores_max;
>> +    }
>> +
>> +    chip->cores = g_new0(PnvCore, chip->num_cores);
>> +
>> +    /* no custom mask for this chip, let's use the default one from
>> +     * the chip class */
>> +    if (!chip->cores_mask) {
>> +        chip->cores_mask = pcc->cores_mask;
>> +    }
>> +
>> +    for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
>> +             && (i < chip->num_cores); core_hwid++) {
>> +        PnvCore *pnv_core = &chip->cores[i];
> 
> 
> Unfortunately, as with spapr core creating its threads you'll need
> some fancier pointer manipulation to handle the possibility of
> subtypes of PnvCore with a different instance size.  
> That doesn't happen now, but it can in theory.

Yes. This is a reason why I preferred to have a Object **cores. I will 
fix that.

I don't really like that :

      void *obj = chip->cores + i * size;

It does not feel "object-oriented". 

>> +
>> +        if (!(chip->cores_mask & (1 << core_hwid))) {
>> +            continue;
>> +        }
>> +
>> +        object_initialize(pnv_core, typesize, typename);
>> +        object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
>> +                                &error_fatal);
>> +        object_property_set_int(OBJECT(pnv_core),
>> +                                P8_PIR(chip->chip_id, core_hwid),
>> +                                CPU_CORE_PROP_CORE_ID, &error_fatal);
>> +        object_property_set_bool(OBJECT(pnv_core), true, "realized",
>> +                                 &error_fatal);
>> +        object_unref(OBJECT(pnv_core));
>> +        i++;
>> +    }
>> +    g_free(typename);
>> +
>>      pcc->realize(chip, errp);
>>  }
>>  
>>  static Property pnv_chip_properties[] = {
>>      DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
>> +    DEFINE_PROP_UINT32("num-cores", PnvChip, num_cores, 1),
> 
> I suggest renaming this to "nr-cores" to match "nr-threads" inside the
> core object.

ok. fine for me. 

>> +    DEFINE_PROP_UINT32("cores-mask", PnvChip, cores_mask, 0x0),
>>      DEFINE_PROP_END_OF_LIST(),
>>  };
>>  
>> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
>> new file mode 100644
>> index 000000000000..825aea1194a1
>> --- /dev/null
>> +++ b/hw/ppc/pnv_core.c
>> @@ -0,0 +1,170 @@
>> +/*
>> + * QEMU PowerPC PowerNV CPU Core model
>> + *
>> + * Copyright (c) IBM Corporation.
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public License
>> + * as published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#include "qemu/osdep.h"
>> +#include "sysemu/sysemu.h"
>> +#include "qapi/error.h"
>> +#include "target-ppc/cpu.h"
>> +#include "hw/ppc/ppc.h"
>> +#include "hw/ppc/pnv.h"
>> +#include "hw/ppc/pnv_core.h"
>> +
>> +static void powernv_cpu_reset(void *opaque)
>> +{
>> +    PowerPCCPU *cpu = opaque;
>> +    CPUState *cs = CPU(cpu);
>> +    CPUPPCState *env = &cpu->env;
>> +    MachineState *machine = MACHINE(qdev_get_machine());
>> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
>> +
>> +    cpu_reset(cs);
>> +
>> +    env->spr[SPR_PIR] = cs->cpu_index;
> 
> This can't work.  Your PIR values aren't contiguous, but cpu_index
> values must be (until you get hotplug).

cpu_index are not contiguous indeed. They are assigned in pnv_core_realize()

        cs->cpu_index = cc->core_id + i;

For this to work, we need the four xics patches Nikunj is working 
on plus some helper routines to assign and find an icp depending on 
cs and not an index anymore.

I will revive the thread with an extra patch.

>> +    env->spr[SPR_HIOR] = 0;
>> +    env->gpr[3] = pnv->fdt_addr;
> 
> Is the fdt address injected for all CPUs, or only the boot CPU?

skiboot will just pick just any boot cpu. My understanding is that 
all need to have the flat device tree address in r3.

Thanks,

C. 

>> +    env->nip = 0x10;
>> +    env->msr |= MSR_HVB;
>> +}
>> +
>> +static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
>> +{
>> +    CPUPPCState *env = &cpu->env;
>> +
>> +    /* Set time-base frequency to 512 MHz */
>> +    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
>> +
>> +    /* MSR[IP] doesn't exist nowadays */
>> +    env->msr_mask &= ~(1 << 6);
>> +
>> +    qemu_register_reset(powernv_cpu_reset, cpu);
>> +    powernv_cpu_reset(cpu);
>> +}
>> +
>> +static void pnv_core_realize_child(Object *child, Error **errp)
>> +{
>> +    Error *local_err = NULL;
>> +    CPUState *cs = CPU(child);
>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>> +
>> +    object_property_set_bool(child, true, "realized", &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +
>> +    powernv_cpu_init(cpu, &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +}
>> +
>> +static void pnv_core_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PnvCore *pc = PNV_CORE(OBJECT(dev));
>> +    CPUCore *cc = CPU_CORE(OBJECT(dev));
>> +    PnvCoreClass *pcc = PNV_CORE_GET_CLASS(OBJECT(dev));
>> +    const char *typename = object_class_get_name(pcc->cpu_oc);
>> +    size_t size = object_type_get_instance_size(typename);
>> +    Error *local_err = NULL;
>> +    void *obj;
>> +    int i, j;
>> +
>> +    pc->threads = g_malloc0(size * cc->nr_threads);
>> +    for (i = 0; i < cc->nr_threads; i++) {
>> +        char id[32];
>> +        CPUState *cs;
>> +
>> +        obj = pc->threads + i * size;
>> +
>> +        object_initialize(obj, size, typename);
>> +        cs = CPU(obj);
>> +        cs->cpu_index = cc->core_id + i;
>> +        snprintf(id, sizeof(id), "thread[%d]", i);
>> +        object_property_add_child(OBJECT(pc), id, obj, &local_err);
>> +        if (local_err) {
>> +            goto err;
>> +        }
>> +        object_unref(obj);
>> +    }
>> +
>> +    for (j = 0; j < cc->nr_threads; j++) {
>> +        obj = pc->threads + j * size;
>> +
>> +        pnv_core_realize_child(obj, &local_err);
>> +        if (local_err) {
>> +            goto err;
>> +        }
>> +    }
>> +    return;
>> +
>> +err:
>> +    while (--i >= 0) {
>> +        obj = pc->threads + i * size;
>> +        object_unparent(obj);
>> +    }
>> +    g_free(pc->threads);
>> +    error_propagate(errp, local_err);
>> +}
>> +
>> +/*
>> + * Grow this list or merge with SPAPRCoreInfo which is very similar
>> + */
>> +static const char *pnv_core_models[] = { "POWER8E", "POWER8", "POWER8NVL" };
>> +
>> +static void pnv_core_class_init(ObjectClass *oc, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(oc);
>> +    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
>> +
>> +    dc->realize = pnv_core_realize;
>> +    pcc->cpu_oc = cpu_class_by_name(TYPE_POWERPC_CPU, data);
>> +}
>> +
>> +static const TypeInfo pnv_core_info = {
>> +    .name           = TYPE_PNV_CORE,
>> +    .parent         = TYPE_CPU_CORE,
>> +    .instance_size  = sizeof(PnvCore),
>> +    .class_size     = sizeof(PnvCoreClass),
>> +    .abstract       = true,
>> +};
>> +
>> +static void pnv_core_register_types(void)
>> +{
>> +    int i ;
>> +
>> +    type_register_static(&pnv_core_info);
>> +    for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
>> +        TypeInfo ti = {
>> +            .parent = TYPE_PNV_CORE,
>> +            .instance_size = sizeof(PnvCore),
>> +            .class_init = pnv_core_class_init,
>> +            .class_data = (void *) pnv_core_models[i],
>> +        };
>> +        ti.name = pnv_core_typename(pnv_core_models[i]);
>> +        type_register(&ti);
>> +        g_free((void *)ti.name);
>> +    }
>> +}
>> +
>> +type_init(pnv_core_register_types)
>> +
>> +char *pnv_core_typename(const char *model)
>> +{
>> +    return g_strdup_printf(TYPE_PNV_CORE "-%s", model);
>> +}
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 987bc70245a7..8a3846743ccf 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -36,6 +36,7 @@ typedef enum PnvChipType {
>>  } PnvChipType;
>>  
>>  typedef struct XScomBus XScomBus;
>> +typedef struct PnvCore PnvCore;
>>  typedef struct PnvChip {
>>      /*< private >*/
>>      SysBusDevice parent_obj;
>> @@ -43,6 +44,10 @@ typedef struct PnvChip {
>>      /*< public >*/
>>      uint32_t     chip_id;
>>      XScomBus     *xscom;
>> +
>> +    uint32_t  num_cores;
>> +    uint32_t  cores_mask;
>> +    PnvCore   *cores;
>>  } PnvChip;
>>  
>>  typedef struct PnvChipClass {
>> @@ -109,4 +114,6 @@ typedef struct PnvMachineState {
>>      PnvChip   **chips;
>>  } PnvMachineState;
>>  
>> +#define PNV_TIMEBASE_FREQ           512000000ULL
>> +
>>  #endif /* _PPC_PNV_H */
>> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
>> new file mode 100644
>> index 000000000000..832c8756afaa
>> --- /dev/null
>> +++ b/include/hw/ppc/pnv_core.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * QEMU PowerPC PowerNV CPU Core model
>> + *
>> + * Copyright (c) 2016 IBM Corporation.
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public License
>> + * as published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef _PPC_PNV_CORE_H
>> +#define _PPC_PNV_CORE_H
>> +
>> +#include "hw/cpu/core.h"
>> +
>> +#define TYPE_PNV_CORE "powernv-cpu-core"
>> +#define PNV_CORE(obj) \
>> +    OBJECT_CHECK(PnvCore, (obj), TYPE_PNV_CORE)
>> +#define PNV_CORE_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(PnvCoreClass, (klass), TYPE_PNV_CORE)
>> +#define PNV_CORE_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(PnvCoreClass, (obj), TYPE_PNV_CORE)
>> +
>> +typedef struct PnvCore {
>> +    /*< private >*/
>> +    CPUCore parent_obj;
>> +
>> +    /*< public >*/
>> +    void *threads;
>> +} PnvCore;
>> +
>> +typedef struct PnvCoreClass {
>> +    DeviceClass parent_class;
>> +    ObjectClass *cpu_oc;
>> +} PnvCoreClass;
>> +
>> +extern char *pnv_core_typename(const char *model);
>> +
>> +#endif /* _PPC_PNV_CORE_H */
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object
  2016-09-06  0:49           ` David Gibson
@ 2016-09-06  6:21             ` Cédric Le Goater
  0 siblings, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06  6:21 UTC (permalink / raw)
  To: David Gibson, Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/06/2016 02:49 AM, David Gibson wrote:
> On Mon, Sep 05, 2016 at 06:28:10PM +1000, Benjamin Herrenschmidt wrote:
>> On Mon, 2016-09-05 at 09:41 +0200, Cédric Le Goater wrote:
>>> yeah. I have not found a clear definition of all the bits.
>>>
>>> I will try to make a macro with what I can collect from the 
>>> specs and the code.
>>
>> It's the CFAM stuff, there's some doco internally but nothing
>> releasable publicly...
> 
> Right...
> 
> My point is that I want a name (and/or coment) saying what the
> relevance of this value is to qemu.  Why do we need this cryptic value
> sitting here?

OK. I will add that. It is mostly important for the FW to identify
the chip model. PVR is for the CPU.

Thanks,

C.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0
  2016-09-05  4:27   ` David Gibson
@ 2016-09-06  6:28     ` Cédric Le Goater
  2016-09-07  1:49       ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06  6:28 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 06:27 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:15PM +0200, Cédric Le Goater wrote:
>> On PowerNV, CPU ids start at 0x8 or 0x20, we don't have a CPU 0
>> anymore. So let's use the first_cpu index to initialize the monitor.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> So we need a patch like this - amongst other fixes - in order to allow
> unplug of cpu 0.  I'm not really sure whether to push it ahead now, or
> gather it up with other no-cpu-0 fixes and send them as a batch.

I think we could send it now as it removes an assumption on the cpu 
number. 

C. 


> 
>> ---
>>
>>  So that you can dump the cpu list with the monitor :
>>
>> 	(qemu) info cpus
>> 	* CPU #8: nip=0x0000000000000010 thread_id=7742
>> 	  CPU #16: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #24: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #32: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #40: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #48: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #72: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #80: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #136: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #144: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #152: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #160: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #168: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #176: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #200: nip=0x0000000000000010 thread_id=7740
>> 	  CPU #208: nip=0x0000000000000010 thread_id=7740
>>
>>  monitor.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/monitor.c b/monitor.c
>> index e9009de09a6c..19b8ec14f40e 100644
>> --- a/monitor.c
>> +++ b/monitor.c
>> @@ -1027,7 +1027,7 @@ int monitor_set_cpu(int cpu_index)
>>  CPUState *mon_get_cpu(void)
>>  {
>>      if (!cur_mon->mon_cpu) {
>> -        monitor_set_cpu(0);
>> +        monitor_set_cpu(first_cpu->cpu_index);
>>      }
>>      cpu_synchronize_state(cur_mon->mon_cpu);
>>      return cur_mon->mon_cpu;
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore
  2016-09-05  4:19   ` David Gibson
@ 2016-09-06 13:54     ` Cédric Le Goater
  2016-09-07  1:51       ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06 13:54 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 06:19 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:14PM +0200, Cédric Le Goater wrote:
>> Now that we are using real HW ids for the cores in PowerNV chips, we
>> can route the XSCOM accesses to them. We just need to attach a
>> XScomDevice to each core with the associated ranges in the XSCOM
>> address space.
>>
>> To start with, let's install the DTS (Digital Thermal Sensor) handlers
>> which are easy to handle.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  hw/ppc/pnv.c              |  9 +++++++
>>  hw/ppc/pnv_core.c         | 67 +++++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/pnv_core.h | 13 +++++++++
>>  3 files changed, 89 insertions(+)
>>
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index daf9f459ab0e..a31568415192 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -527,6 +527,7 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>>      for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
>>               && (i < chip->num_cores); core_hwid++) {
>>          PnvCore *pnv_core = &chip->cores[i];
>> +        DeviceState *qdev;
>>  
>>          if (!(chip->cores_mask & (1 << core_hwid))) {
>>              continue;
>> @@ -542,6 +543,14 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>>                                   &error_fatal);
>>          object_unref(OBJECT(pnv_core));
>>          i++;
>> +
>> +        /* Attach the core to its XSCOM bus */
>> +        qdev = qdev_create(&chip->xscom->bus, TYPE_PNV_CORE_XSCOM);
> 
> Again, I think this breaks QOM lifetime rules.
> 
>> +        qdev_prop_set_uint32(qdev, "core-pir",
>> +                             P8_PIR(chip->chip_id, core_hwid));
>> +        qdev_init_nofail(qdev);
> 
> qdev_init_nofail() - which will abort on failure - shouldn't be used
> in a realize() function, which has a way to gracefully report errors.

yes. I kind of knew that was ugly but the main purpose of the patch 
is the use of scom. So I took the quick and dirty path :)

we should do what you propose below:
 
> So, in terms of the lifetime thing.  I think one permitted solution is
> to embed the scom device state in the core device state and use
> object_initialize().

yes.

> Alternatively, since SCOM is by its nature a sideband bus, I wonder if
> it would make sense to have ScomDevice be a QOM interface, rather than
> a full QOM class.  That way the core device itself (and other devices
> with SCOM control) could present the SCOM device interface and be
> placed directly on the SCOM bus without having to introduce an extra
> object.  

what you are proposing is to have a PnvCore inherit from CPUCore and 
XScomDevice ? I tried that and did not find a way for multi-inheritance. 
But yes, we would get rid of the extra object. At the same time, that 
extra object represents the xscom interface unit in a chiplet which 
exists on real HW.

> It will probably make accessing the object innards in response to 
> SCOM requests more straightforward as well.

The address space is probably the best approach. I have some experimental 
patches which look pretty good :

address-space: xscom-0
  0000000000000000-00000007ffffffff (prio 0, RW): xscom-0
    0000000000b00200-0000000000b0021f (prio 0, RW): lpc-xscom
    0000000120000000-00000001207fffff (prio 0, RW): core-20-xscom
    0000000121000000-00000001217fffff (prio 0, RW): core-21-xscom
    0000000122000000-00000001227fffff (prio 0, RW): core-22-xscom
    0000000123000000-00000001237fffff (prio 0, RW): core-23-xscom
    0000000124000000-00000001247fffff (prio 0, RW): core-24-xscom
    0000000125000000-00000001257fffff (prio 0, RW): core-25-xscom
    0000000126000000-00000001267fffff (prio 0, RW): core-26-xscom
    ....


> I'm not entirely sure if sharing just an interface will be sufficient
> for devices under a bus, but it's worth investigating.

yes. I need to step back a bit and look how I could rework the patchset 
to QOMify the whole. This is really qdev oriented and there are a couple 
of places where fixes are needed. I am seeing that better now. 

The address space should be investigated also.

>> +
>> +        pnv_core->xd = PNV_CORE_XSCOM(qdev);
>>      }
>>      g_free(typename);
>>  
>> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
>> index 825aea1194a1..feba374740dc 100644
>> --- a/hw/ppc/pnv_core.c
>> +++ b/hw/ppc/pnv_core.c
>> @@ -18,7 +18,9 @@
>>   */
>>  #include "qemu/osdep.h"
>>  #include "sysemu/sysemu.h"
>> +#include "qemu/error-report.h"
>>  #include "qapi/error.h"
>> +#include "qemu/log.h"
>>  #include "target-ppc/cpu.h"
>>  #include "hw/ppc/ppc.h"
>>  #include "hw/ppc/pnv.h"
>> @@ -144,10 +146,75 @@ static const TypeInfo pnv_core_info = {
>>      .abstract       = true,
>>  };
>>  
>> +
>> +#define DTS_RESULT0     0x50000
>> +#define DTS_RESULT1     0x50001
>> +
>> +static bool pnv_core_xscom_read(XScomDevice *dev, uint32_t range,
>> +                               uint32_t offset, uint64_t *out_val)
>> +{
>> +    switch (offset) {
>> +    case DTS_RESULT0:
>> +        *out_val = 0x26f024f023f0000ull;
>> +        break;
>> +    case DTS_RESULT1:
>> +        *out_val = 0x24f000000000000ull;
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "Warning: reading reg=0x%08x", offset);
> 
> Can't you just return false here and let the caller handle the error reporting?

yes. 

Thanks,

C. 

>> +    }
>> +
>> +   return true;
>> +}
>> +
>> +static bool pnv_core_xscom_write(XScomDevice *dev, uint32_t range,
>> +                                uint32_t offset, uint64_t val)
>> +{
>> +    qemu_log_mask(LOG_GUEST_ERROR, "Warning: writing to reg=0x%08x", offset);
>> +    return true;
>> +}
>> +
>> +#define EX_XSCOM_BASE 0x10000000
>> +#define EX_XSCOM_SIZE 0x100000
>> +
>> +static void pnv_core_xscom_realize(DeviceState *dev, Error **errp)
>> +{
>> +    XScomDevice *xd = XSCOM_DEVICE(dev);
>> +    PnvCoreXScom *pnv_xd = PNV_CORE_XSCOM(dev);
>> +
>> +    xd->ranges[0].addr = EX_XSCOM_BASE | P8_PIR2COREID(pnv_xd->core_pir) << 24;
>> +    xd->ranges[0].size = EX_XSCOM_SIZE;
>> +}
>> +
>> +static Property pnv_core_xscom_properties[] = {
>> +        DEFINE_PROP_UINT32("core-pir", PnvCoreXScom, core_pir, 0),
>> +        DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void pnv_core_xscom_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    XScomDeviceClass *xdc = XSCOM_DEVICE_CLASS(klass);
>> +
>> +    xdc->read = pnv_core_xscom_read;
>> +    xdc->write = pnv_core_xscom_write;
>> +
>> +    dc->realize = pnv_core_xscom_realize;
>> +    dc->props = pnv_core_xscom_properties;
>> +}
>> +
>> +static const TypeInfo pnv_core_xscom_type_info = {
>> +    .name          = TYPE_PNV_CORE_XSCOM,
>> +    .parent        = TYPE_XSCOM_DEVICE,
>> +    .instance_size = sizeof(PnvCoreXScom),
>> +    .class_init    = pnv_core_xscom_class_init,
>> +};
>> +
>>  static void pnv_core_register_types(void)
>>  {
>>      int i ;
>>  
>> +    type_register_static(&pnv_core_xscom_type_info);
>>      type_register_static(&pnv_core_info);
>>      for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
>>          TypeInfo ti = {
>> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
>> index 832c8756afaa..72936ccfd22f 100644
>> --- a/include/hw/ppc/pnv_core.h
>> +++ b/include/hw/ppc/pnv_core.h
>> @@ -20,6 +20,18 @@
>>  #define _PPC_PNV_CORE_H
>>  
>>  #include "hw/cpu/core.h"
>> +#include "hw/ppc/pnv_xscom.h"
>> +
>> +#define TYPE_PNV_CORE_XSCOM "powernv-cpu-core-xscom"
>> +#define PNV_CORE_XSCOM(obj) \
>> +     OBJECT_CHECK(PnvCoreXScom, (obj), TYPE_PNV_CORE_XSCOM)
>> +
>> +typedef struct PnvCoreXScom {
>> +    XScomDevice xd;
>> +    uint32_t core_pir;
>> +} PnvCoreXScom;
>> +
>> +#define P8_PIR2COREID(pir) (((pir) >> 3) & 0xf)
>>  
>>  #define TYPE_PNV_CORE "powernv-cpu-core"
>>  #define PNV_CORE(obj) \
>> @@ -35,6 +47,7 @@ typedef struct PnvCore {
>>  
>>      /*< public >*/
>>      void *threads;
>> +    PnvCoreXScom *xd;
>>  } PnvCore;
>>  
>>  typedef struct PnvCoreClass {
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-05  3:39   ` David Gibson
  2016-09-05  7:11     ` Benjamin Herrenschmidt
@ 2016-09-06 14:42     ` Cédric Le Goater
  2016-09-06 21:45       ` Benjamin Herrenschmidt
  2016-09-07  1:59       ` David Gibson
  1 sibling, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06 14:42 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

On 09/05/2016 05:39 AM, David Gibson wrote:
> On Wed, Aug 31, 2016 at 06:34:11PM +0200, Cédric Le Goater wrote:
>> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>
>> XSCOM is an interface to a sideband bus provided by the POWER8 chip
>> pervasive unit, which gives access to a number of facilities in the
>> chip that are needed by the OPAL firmware and to a lesser extent,
>> Linux. This is among others how the PCI Host bridges get configured
>> at boot or how the LPC bus is accessed.
>>
>> This provides a simple bus and device type for devices sitting on
>> XSCOM along with some facilities to optionally generate corresponding
>> device-tree nodes
>>
>> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> [clg: updated for qemu-2.7
>>       ported on new sPowerNVMachineState which was merged with PnvSystem
>>       removed TRACE_XSCOM
>>       fixed checkpatch errors
>>       replaced assert with error_setg in xscom_realize()
>>       reworked xscom_create
>>       introduced the use of the chip_class for chip model contants
>>       ]
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>
>>  They were some discussions on whether we should use a qemu
>>  address_space instead of the xscom ranges defined in this patch. 
>>  I gave it try, it is possible but it brings extra unnecessary calls
>>  and complexity. I think the current solution is better.
>>
>>  hw/ppc/Makefile.objs       |   2 +-
>>  hw/ppc/pnv.c               |  11 ++
>>  hw/ppc/pnv_xscom.c         | 408 +++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/ppc/pnv.h       |   2 +
>>  include/hw/ppc/pnv_xscom.h |  75 +++++++++
>>  5 files changed, 497 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/ppc/pnv_xscom.c
>>  create mode 100644 include/hw/ppc/pnv_xscom.h
>>
>> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
>> index 8105db7d5600..f580e5c41413 100644
>> --- a/hw/ppc/Makefile.objs
>> +++ b/hw/ppc/Makefile.objs
>> @@ -6,7 +6,7 @@ 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_cpu_core.o
>>  # IBM PowerNV
>> -obj-$(CONFIG_POWERNV) += pnv.o
>> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
>>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
>>  obj-y += spapr_pci_vfio.o
>>  endif
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 06051268e200..a6e7f66b2c0a 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -39,6 +39,8 @@
>>  #include "exec/address-spaces.h"
>>  #include "qemu/cutils.h"
>>  
>> +#include "hw/ppc/pnv_xscom.h"
>> +
>>  #include <libfdt.h>
>>  
>>  #define FDT_ADDR                0x01000000
>> @@ -103,6 +105,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>>      char *buf;
>>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
>>      int off;
>> +    int i;
>>  
>>      fdt = g_malloc0(FDT_MAX_SIZE);
>>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
>> @@ -142,6 +145,11 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
>>      /* Memory */
>>      powernv_populate_memory(fdt);
>>  
>> +    /* Populate XSCOM for each chip */
>> +    for (i = 0; i < pnv->num_chips; i++) {
>> +        xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
>> +    }
> 
> There will be a bunch of per-chip things in the fdt - I suggest a
> common function to do all the fdt creation for a single chip.  Since
> you've moved to using the fdt_rw functions exclusively, you don't have
> the sequence constraints that would have made that awkward previously.

ok.

>>      return fdt;
>>  }
>>  
>> @@ -305,6 +313,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
>>      PnvChip *chip = PNV_CHIP(dev);
>>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>>  
>> +    /* Set up XSCOM bus */
>> +    chip->xscom = xscom_create(chip);
> 
> So, this creates the xscom as a new device object, unfortunately doing
> that from another object's realize() violations QOM lifetime rules as
> I understand them.  I think - I have to admit I'm pretty confused on
> this topic myself.
> 
> You could construct the scom from chip init, then realize it from chip
> realize, but I think using object_new() (via qdev_create()) from
> another object's init also breaks the rules.  You are however allowed
> to allocate the scom state statically within the chip and use
> object_initialize() instead, AIUI.
> 
> Alternatively.. it might be simpler to just drop the SCOM as a
> separate device.  I think you could just hang the scom bus directly
> off the chip object.  IIUC the scom is basically the only chip-level
> control mechanism, so this does make a certain amount of sense.

yes. I am exposing more and more stuff of the chip object under the 
xscom object so we should merge them. I agree. We will still need 
some XScomDevice of some sort.

>>      pcc->realize(chip, errp);
>>  }
>>  
>> diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
>> new file mode 100644
>> index 000000000000..7ed3804f4b3a
>> --- /dev/null
>> +++ b/hw/ppc/pnv_xscom.c
>> @@ -0,0 +1,408 @@
>> +
>> +/*
>> + * QEMU PowerNV XSCOM bus definitions
>> + *
>> + * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
>> + * Based on the s390 virtio bus code:
>> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +/* TODO: Add some infrastructure for "random stuff" and FIRs that
>> + * various units might want to deal with without creating actual
>> + * XSCOM devices.
>> + *
>> + * For example, HB LPC XSCOM in the PIBAM
>> + */
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "hw/hw.h"
>> +#include "sysemu/sysemu.h"
>> +#include "hw/boards.h"
>> +#include "monitor/monitor.h"
>> +#include "hw/loader.h"
>> +#include "elf.h"
>> +#include "hw/sysbus.h"
>> +#include "sysemu/kvm.h"
>> +#include "sysemu/device_tree.h"
>> +#include "hw/ppc/fdt.h"
>> +
>> +#include "hw/ppc/pnv_xscom.h"
>> +
>> +#include <libfdt.h>
>> +
>> +#define TYPE_XSCOM "xscom"
>> +#define XSCOM(obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM)
>> +
>> +#define XSCOM_SIZE        0x800000000ull
>> +#define XSCOM_BASE(chip)  (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE)
>> +
>> +
>> +typedef struct XScomState {
>> +    /*< private >*/
>> +    SysBusDevice parent_obj;
>> +    /*< public >*/
>> +
>> +    MemoryRegion mem;
>> +    int32_t chip_id;
> 
> Merging scom and chip would avoid the duplication of this field too.

yes.

>> +    PnvChipClass *chip_class;
>> +    XScomBus *bus;
>> +} XScomState;
>> +
>> +static uint32_t xscom_to_pcb_addr(uint64_t addr)
>> +{
>> +        addr &= (XSCOM_SIZE - 1);
>> +        return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
>> +}
>> +
>> +static void xscom_complete(uint64_t hmer_bits)
>> +{
>> +    CPUState *cs = current_cpu;
>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>> +    CPUPPCState *env = &cpu->env;
>> +
>> +    cpu_synchronize_state(cs);
>> +    env->spr[SPR_HMER] |= hmer_bits;
>> +
>> +    /* XXX Need a CPU helper to set HMER, also handle gneeration
>> +     * of HMIs
>> +     */
>> +}
>> +
>> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t pcb_addr,
>> +                                      uint32_t *range)
>> +{
>> +    BusChild *bc;
>> +
>> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
>> +        DeviceState *qd = bc->child;
>> +        XScomDevice *xd = XSCOM_DEVICE(qd);
>> +        unsigned int i;
>> +
>> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
>> +            if (xd->ranges[i].addr <= pcb_addr &&
>> +                (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) {
>> +                *range = i;
>> +                return xd;
>> +            }
>> +        }
>> +    }
> 
> Hmm.. you could set up a SCOM local address space using the
> infrastructure in memory.c, rather than doing your own dispatch.

I need to study this option a little deeper. 

> 
>> +    return NULL;
>> +}
>> +
>> +static bool xscom_dispatch_read(XScomState *s, uint32_t pcb_addr,
>> +                                uint64_t *out_val)
>> +{
>> +    uint32_t range, offset;
>> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
>> +    XScomDeviceClass *xc;
>> +
>> +    if (!xd) {
>> +        return false;
>> +    }
>> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
>> +    if (!xc->read) {
>> +        return false;
>> +    }
>> +    offset = pcb_addr - xd->ranges[range].addr;
>> +    return xc->read(xd, range, offset, out_val);
>> +}
>> +
>> +static bool xscom_dispatch_write(XScomState *s, uint32_t pcb_addr, uint64_t val)
>> +{
>> +    uint32_t range, offset;
>> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
>> +    XScomDeviceClass *xc;
>> +
>> +    if (!xd) {
>> +        return false;
>> +    }
>> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
>> +    if (!xc->write) {
>> +        return false;
>> +    }
>> +    offset = pcb_addr - xd->ranges[range].addr;
>> +    return xc->write(xd, range, offset, val);
>> +}
>> +
>> +static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
>> +{
>> +    XScomState *s = opaque;
>> +    uint32_t pcba = xscom_to_pcb_addr(addr);
>> +    uint64_t val;
>> +
>> +    assert(width == 8);
>> +
>> +    /* Handle some SCOMs here before dispatch */
>> +    switch (pcba) {
>> +    case 0xf000f:
>> +        val = s->chip_class->chip_f000f;
>> +        break;
>> +    case 0x1010c00:     /* PIBAM FIR */
>> +    case 0x1010c03:     /* PIBAM FIR MASK */
>> +    case 0x2020007:     /* ADU stuff */
>> +    case 0x2020009:     /* ADU stuff */
>> +    case 0x202000f:     /* ADU stuff */
>> +        val = 0;
>> +        break;
>> +    case 0x2013f00:     /* PBA stuff */
>> +    case 0x2013f01:     /* PBA stuff */
>> +    case 0x2013f02:     /* PBA stuff */
>> +    case 0x2013f03:     /* PBA stuff */
>> +    case 0x2013f04:     /* PBA stuff */
>> +    case 0x2013f05:     /* PBA stuff */
>> +    case 0x2013f06:     /* PBA stuff */
>> +    case 0x2013f07:     /* PBA stuff */
>> +        val = 0;
>> +        break;
>> +    default:
>> +        if (!xscom_dispatch_read(s, pcba, &val)) {
>> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
>> +            return 0;
>> +        }
>> +    }
>> +
>> +    xscom_complete(HMER_XSCOM_DONE);
>> +    return val;
>> +}
>> +
>> +static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
>> +                        unsigned width)
>> +{
>> +    XScomState *s = opaque;
>> +    uint32_t pcba = xscom_to_pcb_addr(addr);
>> +
>> +    assert(width == 8);
>> +
>> +    /* Handle some SCOMs here before dispatch */
>> +    switch (pcba) {
>> +        /* We ignore writes to these */
>> +    case 0xf000f:       /* chip id is RO */
>> +    case 0x1010c00:     /* PIBAM FIR */
>> +    case 0x1010c01:     /* PIBAM FIR */
>> +    case 0x1010c02:     /* PIBAM FIR */
>> +    case 0x1010c03:     /* PIBAM FIR MASK */
>> +    case 0x1010c04:     /* PIBAM FIR MASK */
>> +    case 0x1010c05:     /* PIBAM FIR MASK */
>> +    case 0x2020007:     /* ADU stuff */
>> +    case 0x2020009:     /* ADU stuff */
>> +    case 0x202000f:     /* ADU stuff */
>> +        break;
>> +    default:
>> +        if (!xscom_dispatch_write(s, pcba, val)) {
>> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
>> +            return;
>> +        }
>> +    }
>> +
>> +    xscom_complete(HMER_XSCOM_DONE);
>> +}
>> +
>> +static const MemoryRegionOps xscom_ops = {
>> +    .read = xscom_read,
>> +    .write = xscom_write,
>> +    .valid.min_access_size = 8,
>> +    .valid.max_access_size = 8,
>> +    .impl.min_access_size = 8,
>> +    .impl.max_access_size = 8,
>> +    .endianness = DEVICE_BIG_ENDIAN,
>> +};
>> +
>> +static int xscom_init(SysBusDevice *dev)
>> +{
>> +    XScomState *s = XSCOM(dev);
>> +
>> +    s->chip_id = -1;
>> +    return 0;
>> +}
>> +
>> +static void xscom_realize(DeviceState *dev, Error **errp)
>> +{
>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> +    XScomState *s = XSCOM(dev);
>> +    char *name;
>> +
>> +    if (s->chip_id < 0) {
>> +        error_setg(errp, "invalid chip id '%d'", s->chip_id);
>> +        return;
>> +    }
>> +    name = g_strdup_printf("xscom-%x", s->chip_id);
>> +    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
>> +    sysbus_init_mmio(sbd, &s->mem);
>> +    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));
>> +}
>> +
>> +static Property xscom_properties[] = {
>> +        DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0),
>> +        DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void xscom_class_init(ObjectClass *klass, void *data)
>> +{
>> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->props = xscom_properties;
>> +    dc->realize = xscom_realize;
>> +    k->init = xscom_init;
>> +}
>> +
>> +static const TypeInfo xscom_info = {
>> +    .name          = TYPE_XSCOM,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(XScomState),
>> +    .class_init    = xscom_class_init,
>> +};
>> +
>> +static void xscom_bus_class_init(ObjectClass *klass, void *data)
>> +{
>> +}
>> +
>> +static const TypeInfo xscom_bus_info = {
>> +    .name = TYPE_XSCOM_BUS,
>> +    .parent = TYPE_BUS,
>> +    .class_init = xscom_bus_class_init,
>> +    .instance_size = sizeof(XScomBus),
>> +};
>> +
>> +XScomBus *xscom_create(PnvChip *chip)
>> +{
>> +    DeviceState *dev;
>> +    XScomState *xdev;
>> +    BusState *qbus;
>> +    XScomBus *xb;
>> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
>> +
>> +    dev = qdev_create(NULL, TYPE_XSCOM);
>> +    qdev_prop_set_uint32(dev, "chip_id", chip->chip_id);
>> +    qdev_init_nofail(dev);
>> +
>> +    /* Create bus on bridge device */
>> +    qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
>> +    xb = DO_UPCAST(XScomBus, bus, qbus);
>> +    xb->chip_id = chip->chip_id;
>> +    xdev = XSCOM(dev);
>> +    xdev->bus = xb;
>> +    xdev->chip_class = pcc;
>> +
>> +    return xb;
>> +}
>> +
>> +int xscom_populate_fdt(XScomBus *xb, void *fdt, int root_offset)
> 
> What is the root_offset parameter for, since it is always 0?

yes ...

>> +{
>> +    BusChild *bc;
>> +    char *name;
>> +    const char compat[] = "ibm,power8-xscom\0ibm,xscom";
>> +    uint64_t reg[] = { cpu_to_be64(XSCOM_BASE(xb->chip_id)),
>> +                       cpu_to_be64(XSCOM_SIZE) };
>> +    int xscom_offset;
>> +
>> +    name = g_strdup_printf("xscom@%llx", (unsigned long long)
>> +                           be64_to_cpu(reg[0]));
> 
> Nit: in qemu the PRIx64 etc. macros are usually preferred to (unsigned
> long long) casts of this type.

sure.

>> +    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
>> +    _FDT(xscom_offset);
>> +    g_free(name);
>> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", xb->chip_id)));
>> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
>> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
>> +    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
>> +    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat,
>> +                      sizeof(compat))));
>> +    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
>> +
>> +    QTAILQ_FOREACH(bc, &xb->bus.children, sibling) {
>> +        DeviceState *qd = bc->child;
>> +        XScomDevice *xd = XSCOM_DEVICE(qd);
>> +        XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xd);
>> +        uint32_t reg[MAX_XSCOM_RANGES * 2];
>> +        unsigned int i, sz = 0;
>> +        void *cp, *p;
>> +        int child_offset;
>> +
>> +        /* Some XSCOM slaves may not be represented in the DT */
>> +        if (!xc->dt_name) {
>> +            continue;
>> +        }
>> +        name = g_strdup_printf("%s@%x", xc->dt_name, xd->ranges[0].addr);
>> +        child_offset = fdt_add_subnode(fdt, xscom_offset, name);
>> +        _FDT(child_offset);
>> +        g_free(name);
>> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
>> +            if (xd->ranges[i].size == 0) {
>> +                break;
>> +            }
>> +            reg[sz++] = cpu_to_be32(xd->ranges[i].addr);
>> +            reg[sz++] = cpu_to_be32(xd->ranges[i].size);
>> +        }
>> +        _FDT((fdt_setprop(fdt, child_offset, "reg", reg, sz * 4)));
> 
> Use of fdt_appendprop() might make this a little neater.

ok.

>> +        if (xc->devnode) {
>> +            _FDT((xc->devnode(xd, fdt, child_offset)));
>> +        }
>> +#define MAX_COMPATIBLE_PROP     1024
>> +        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
>> +        i = 0;
>> +        while ((p - cp) < MAX_COMPATIBLE_PROP) {
>> +            int l;
>> +            if (xc->dt_compatible[i] == NULL) {
>> +                break;
>> +            }
>> +            l = strlen(xc->dt_compatible[i]);
>> +            if (l >= (MAX_COMPATIBLE_PROP - i)) {
>> +                break;
>> +            }
>> +            strcpy(p, xc->dt_compatible[i++]);
>> +            p += l + 1;
>> +        }
>> +        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));
> 
> Might it be easier to just require the individual scom device to set
> the compatible property from its ->devnode callback?  That way it can
> just
> 	const char compat = "foo\0bar\0baz";
> 	fdt_setprop(..., compat, sizeof(compat));
> 
> and avoid this fiddling around with arrays.

Yes. xscom_populate_fdt() will shrink quite a bit. This is a good idea.

Thanks,

C.

>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int xscom_qdev_init(DeviceState *qdev)
>> +{
>> +    XScomDevice *xdev = (XScomDevice *)qdev;
>> +    XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xdev);
>> +
>> +    if (xc->init) {
>> +        return xc->init(xdev);
>> +    }
>> +    return 0;
>> +}
>> +
>> +static void xscom_device_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *k = DEVICE_CLASS(klass);
>> +    k->init = xscom_qdev_init;
>> +    k->bus_type = TYPE_XSCOM_BUS;
>> +}
>> +
>> +static const TypeInfo xscom_dev_info = {
>> +    .name = TYPE_XSCOM_DEVICE,
>> +    .parent = TYPE_DEVICE,
>> +    .instance_size = sizeof(XScomDevice),
>> +    .abstract = true,
>> +    .class_size = sizeof(XScomDeviceClass),
>> +    .class_init = xscom_device_class_init,
>> +};
>> +
>> +static void xscom_register_types(void)
>> +{
>> +    type_register_static(&xscom_info);
>> +    type_register_static(&xscom_bus_info);
>> +    type_register_static(&xscom_dev_info);
>> +}
>> +
>> +type_init(xscom_register_types)
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 1f32573dedff..bc6e1f80096b 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -35,12 +35,14 @@ typedef enum PnvChipType {
>>      PNV_CHIP_P8NVL, /* AKA Naples */
>>  } PnvChipType;
>>  
>> +typedef struct XScomBus XScomBus;
>>  typedef struct PnvChip {
>>      /*< private >*/
>>      SysBusDevice parent_obj;
>>  
>>      /*< public >*/
>>      uint32_t     chip_id;
>> +    XScomBus     *xscom;
>>  } PnvChip;
>>  
>>  typedef struct PnvChipClass {
>> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
>> new file mode 100644
>> index 000000000000..386ad21c5aa5
>> --- /dev/null
>> +++ b/include/hw/ppc/pnv_xscom.h
>> @@ -0,0 +1,75 @@
>> +#ifndef _HW_XSCOM_H
>> +#define _HW_XSCOM_H
>> +/*
>> + * QEMU PowerNV XSCOM bus definitions
>> + *
>> + * Copyright (c) 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corp.
>> + * Based on the s390 virtio bus definitions:
>> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <hw/ppc/pnv.h>
>> +
>> +#define TYPE_XSCOM_DEVICE "xscom-device"
>> +#define XSCOM_DEVICE(obj) \
>> +     OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE)
>> +#define XSCOM_DEVICE_CLASS(klass) \
>> +     OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE)
>> +#define XSCOM_DEVICE_GET_CLASS(obj) \
>> +     OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE)
>> +
>> +#define TYPE_XSCOM_BUS "xscom-bus"
>> +#define XSCOM_BUS(obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS)
>> +
>> +typedef struct XScomDevice XScomDevice;
>> +typedef struct XScomBus XScomBus;
>> +
>> +typedef struct XScomDeviceClass {
>> +    DeviceClass parent_class;
>> +
>> +    const char *dt_name;
>> +    const char **dt_compatible;
>> +    int (*init)(XScomDevice *dev);
>> +    int (*devnode)(XScomDevice *dev, void *fdt, int offset);
>> +
>> +    /* Actual XScom accesses */
>> +    bool (*read)(XScomDevice *dev, uint32_t range, uint32_t offset,
>> +                 uint64_t *out_val);
>> +    bool (*write)(XScomDevice *dev, uint32_t range, uint32_t offset,
>> +                  uint64_t val);
>> +} XScomDeviceClass;
>> +
>> +typedef struct XScomRange {
>> +    uint32_t addr;
>> +    uint32_t size;
>> +} XScomRange;
>> +
>> +struct XScomDevice {
>> +    DeviceState qdev;
>> +#define MAX_XSCOM_RANGES 4
>> +    struct XScomRange ranges[MAX_XSCOM_RANGES];
>> +};
>> +
>> +struct XScomBus {
>> +    BusState bus;
>> +    uint32_t chip_id;
>> +};
>> +
>> +extern XScomBus *xscom_create(PnvChip *chip);
>> +extern int xscom_populate_fdt(XScomBus *xscom, void *fdt, int offset);
>> +
>> +
>> +#endif /* _HW_XSCOM_H */
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06  0:48       ` David Gibson
@ 2016-09-06 14:42         ` Cédric Le Goater
  2016-09-06 21:47           ` Benjamin Herrenschmidt
  2016-09-07  2:01           ` David Gibson
  0 siblings, 2 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06 14:42 UTC (permalink / raw)
  To: David Gibson, Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/06/2016 02:48 AM, David Gibson wrote:
> On Mon, Sep 05, 2016 at 05:11:53PM +1000, Benjamin Herrenschmidt wrote:
>> On Mon, 2016-09-05 at 13:39 +1000, David Gibson wrote:
>>>> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t
>>> pcb_addr,
>>>> +                                      uint32_t *range)
>>>> +{
>>>> +    BusChild *bc;
>>>> +
>>>> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
>>>> +        DeviceState *qd = bc->child;
>>>> +        XScomDevice *xd = XSCOM_DEVICE(qd);
>>>> +        unsigned int i;
>>>> +
>>>> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
>>>> +            if (xd->ranges[i].addr <= pcb_addr &&
>>>> +                (xd->ranges[i].addr + xd->ranges[i].size) >
>>> pcb_addr) {
>>>> +                *range = i;
>>>> +                return xd;
>>>> +            }
>>>> +        }
>>>> +    }
>>>
>>> Hmm.. you could set up a SCOM local address space using the
>>> infrastructure in memory.c, rather than doing your own dispatch.
>>
>> There are pros and cons to this approach. The memory.c stuff comes with
>> quite a lot of baggage, not all of it very shinny to be honest ;-) I
>> still *hate* how it forces upon us a whole 128-bit integer arithmetic
>> library just so that it can represent 1_0000_0000_0000_0000 ... 
> 
> Ugh, yeah.  I tried to argue against this when it first came in, but
> was overruled.
> 
>> It would be make more sense to use inclusive start/end instead and
>> stick to 64-bits.
>>
>> That being said, we could do that. We'd have to shift the XSCOM
>> addresses left by 3 since each address is an 8 bytes reigster and
>> forbid non-8-bytes accesses.
> 
> Ok.  I'm not particularly fussed either way.


The change does seem too invasive. I can give it a try in next
version.

When a memory region is triggered, the impacted device will have
to convert the address with xscom_to_pcb_addr(). There is some 
dependency on the chip model because the translation is different. 
That would be an extra op in the xscom device model I guess. 

Also, the main purpose of the XscomBus is to loop on the devices 
to populate the device tree. I am wondering if we could just use 
a simple list under the chip for that purpose. 

Thanks,

C. 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-05  4:16   ` [Qemu-devel] [Qemu-ppc] " Sam Bobroff
@ 2016-09-06 14:51     ` Cédric Le Goater
  0 siblings, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-06 14:51 UTC (permalink / raw)
  To: Sam Bobroff; +Cc: qemu-ppc, qemu-devel, David Gibson

Hello Sam,

>> +        }
>> +#define MAX_COMPATIBLE_PROP     1024
>> +        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
>> +        i = 0;
>> +        while ((p - cp) < MAX_COMPATIBLE_PROP) {
>> +            int l;
>> +            if (xc->dt_compatible[i] == NULL) {
>> +                break;
>> +            }
>> +            l = strlen(xc->dt_compatible[i]);
>> +            if (l >= (MAX_COMPATIBLE_PROP - i)) {
> 
> The use of 'i' above doesn't look right. Should the check be more like this?
>                if ((l + 1) >= (MAX_COMPATIBLE_PROP - (p - cp))) {

David just proposed to move the compatible property setting in the
devnode op of the device, and so all this code should disappear at 
the same time.

Thanks,

C. 

>> +                break;
>> +            }
>> +            strcpy(p, xc->dt_compatible[i++]);
>> +            p += l + 1;
>> +        }
>> +        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));
>> +    }
>> +
>> +    return 0;
>> +}
>> +

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 14:42     ` Cédric Le Goater
@ 2016-09-06 21:45       ` Benjamin Herrenschmidt
  2016-09-07  2:02         ` David Gibson
  2016-09-07 16:40         ` Cédric Le Goater
  2016-09-07  1:59       ` David Gibson
  1 sibling, 2 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-06 21:45 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
> > Alternatively.. it might be simpler to just drop the SCOM as a
> > separate device.  I think you could just hang the scom bus directly
> > off the chip object.  IIUC the scom is basically the only chip-
> level
> > control mechanism, so this does make a certain amount of sense.
> 
> yes. I am exposing more and more stuff of the chip object under the 
> xscom object so we should merge them. I agree. We will still need 
> some XScomDevice of some sort.

What you can do is split it this way which matches the HW:

 - The chip object is the XSCOM parent, it owns the XSCOM bus,
and expose functions (methods) to read/write XSCOMs. WE could rename
XSCOM to "PIB" or "PCB" which is the real name of the bus ;-) But that
might confuse things more than help .

 - A separate ADU object on each chip that is a SysDevice and does the
MMIO bridge to XSCOM. It decodes the MMIO range for that chip and calls
the above accessors.

That makes it easy to generate XSCOMs using different mechanisms if we
wish to do so, which could come in handy, such as monitor commands, or
if we ever do cosimulation with a separate BMC, a simulated FSI, all by
just calling the first object's methods.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 14:42         ` Cédric Le Goater
@ 2016-09-06 21:47           ` Benjamin Herrenschmidt
  2016-09-06 21:49             ` Benjamin Herrenschmidt
                               ` (2 more replies)
  2016-09-07  2:01           ` David Gibson
  1 sibling, 3 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-06 21:47 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
> 
> The change does seem too invasive. I can give it a try in next
> version.
> 
> When a memory region is triggered, the impacted device will have
> to convert the address with xscom_to_pcb_addr(). There is some 
> dependency on the chip model because the translation is different. 
> That would be an extra op in the xscom device model I guess. 

No. If you split the XSCOM bus from the MMIO -> XSCOM bridge (the ADU)
then the conversion only happens in the former. You don't directly
route the MMIOs over ! You intercept the MMIOs and use use the
address_space_rw to "generate" the XSCOM accesses on the other side,
like I do for the LPC bus.

We need that anyway because of the way XSCOMs can manipulate the HMER
etc...

> Also, the main purpose of the XscomBus is to loop on the devices 
> to populate the device tree. I am wondering if we could just use 
> a simple list under the chip for that purpose.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:47           ` Benjamin Herrenschmidt
@ 2016-09-06 21:49             ` Benjamin Herrenschmidt
  2016-09-07 15:55               ` Cédric Le Goater
  2016-09-07  2:03             ` David Gibson
  2016-09-07 15:47             ` Cédric Le Goater
  2 siblings, 1 reply; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-06 21:49 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Wed, 2016-09-07 at 07:47 +1000, Benjamin Herrenschmidt wrote:
> d be an extra op in the xscom device model I guess. 
> 
> No. If you split the XSCOM bus from the MMIO -> XSCOM bridge (the
> ADU)
> then the conversion only happens in the former. You don't directly
> route the MMIOs over ! You intercept the MMIOs and use use the
> address_space_rw to "generate" the XSCOM accesses on the other side,
> like I do for the LPC bus.
> 
> We need that anyway because of the way XSCOMs can manipulate the HMER
> etc...
> 
> > 
> > Also, the main purpose of the XscomBus is to loop on the devices 
> > to populate the device tree. I am wondering if we could just use 
> > a simple list under the chip for that purpose.

In fact, if you do the above, you no longer need a XSCOM device...

A number of "devices" can exist below a chip, all they need to have
XSCOMs is to register memory regions that are child of that chip's
xscom_region.

For device-tree, well, we could have a generic interface that anything
that can populate DT has and iterate through them. Or make a "chiplet"
class or something.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object
  2016-09-06  6:14     ` Cédric Le Goater
@ 2016-09-07  1:48       ` David Gibson
  0 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  1:48 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 18159 bytes --]

On Tue, Sep 06, 2016 at 08:14:37AM +0200, Cédric Le Goater wrote:
> On 09/05/2016 06:02 AM, David Gibson wrote:
> > On Wed, Aug 31, 2016 at 06:34:13PM +0200, Cédric Le Goater wrote:
> >> This is largy inspired by sPAPRCPUCore with some simplification, no
> >> hotplug for instance. But the differences are small and the objects
> >> could possibly be merged.
> >>
> >> A set of PnvCore objects is added to the PnvChip and the device
> >> tree is populated looping on these cores.
> >>
> >> Real HW cpu ids are now generated depending on the chip cpu model, the
> >> chip id and a core mask. This id is stored in CPUState->cpu_index and
> >> in PnvCore->core_id and it is used to populate the device tree.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> >> ---
> >>
> >>  Changes since v1:
> >>
> >>  - changed name to PnvCore
> >>  - changed PnvChip core array type to a 'PnvCore *cores'
> >>  - introduced real cpu hw ids using a core mask from the chip
> >>  - reworked powernv_create_core_node() which populates the device tree
> >>  - added missing "ibm,pa-features" property 
> >>  - smp_cpus representing threads, used smp_cores instead to create the
> >>    cores in the chip.
> >>  - removed the use of ppc_get_vcpu_dt_id() 
> >>  - added "POWER8E" and "POWER8NVL" cpu models to exercice the
> >>    PnvChipClass
> >>
> >>  hw/ppc/Makefile.objs      |   2 +-
> >>  hw/ppc/pnv.c              | 204 ++++++++++++++++++++++++++++++++++++++++++++++
> >>  hw/ppc/pnv_core.c         | 170 ++++++++++++++++++++++++++++++++++++++
> >>  include/hw/ppc/pnv.h      |   7 ++
> >>  include/hw/ppc/pnv_core.h |  47 +++++++++++
> >>  5 files changed, 429 insertions(+), 1 deletion(-)
> >>  create mode 100644 hw/ppc/pnv_core.c
> >>  create mode 100644 include/hw/ppc/pnv_core.h
> >>
> >> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> >> index f580e5c41413..08c213c40684 100644
> >> --- a/hw/ppc/Makefile.objs
> >> +++ b/hw/ppc/Makefile.objs
> >> @@ -6,7 +6,7 @@ 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_cpu_core.o
> >>  # IBM PowerNV
> >> -obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
> >> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o
> >>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
> >>  obj-y += spapr_pci_vfio.o
> >>  endif
> >> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> >> index b6efb5e3ef07..daf9f459ab0e 100644
> >> --- a/hw/ppc/pnv.c
> >> +++ b/hw/ppc/pnv.c
> >> @@ -35,6 +35,7 @@
> >>  #include "hw/ppc/fdt.h"
> >>  #include "hw/ppc/ppc.h"
> >>  #include "hw/ppc/pnv.h"
> >> +#include "hw/ppc/pnv_core.h"
> >>  #include "hw/loader.h"
> >>  #include "exec/address-spaces.h"
> >>  #include "qemu/cutils.h"
> >> @@ -98,6 +99,136 @@ static int powernv_populate_memory(void *fdt)
> >>      return 0;
> >>  }
> >>  
> >> +/*
> >> + * The PowerNV cores (and threads) need to use real HW ids and not an
> >> + * incremental index like it has been done on other platforms. This HW
> >> + * id is called a PIR and is used in the device tree, in the XSCOM
> >> + * communication to address cores, in the interrupt servers.
> >> + */
> >> +static void powernv_create_core_node(PnvCore *pc, void *fdt,
> >> +                                     int cpus_offset, int chip_id)
> >> +{
> >> +    CPUCore *core = CPU_CORE(pc);
> >> +    CPUState *cs = CPU(DEVICE(pc->threads));
> >> +    DeviceClass *dc = DEVICE_GET_CLASS(cs);
> >> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >> +    int smt_threads = ppc_get_compat_smt_threads(cpu);
> >> +    CPUPPCState *env = &cpu->env;
> >> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
> >> +    uint32_t servers_prop[smt_threads];
> >> +    uint32_t gservers_prop[smt_threads * 2];
> >> +    int i;
> >> +    uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
> >> +                       0xffffffff, 0xffffffff};
> >> +    uint32_t tbfreq = PNV_TIMEBASE_FREQ;
> >> +    uint32_t cpufreq = 1000000000;
> >> +    uint32_t page_sizes_prop[64];
> >> +    size_t page_sizes_prop_size;
> >> +    const uint8_t pa_features[] = { 24, 0,
> >> +                                    0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
> >> +                                    0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
> >> +                                    0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
> >> +                                    0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
> >> +    int offset;
> >> +    char *nodename;
> >> +
> >> +    nodename = g_strdup_printf("%s@%x", dc->fw_name, core->core_id);
> >> +    offset = fdt_add_subnode(fdt, cpus_offset, nodename);
> >> +    _FDT(offset);
> >> +    g_free(nodename);
> >> +
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip_id)));
> >> +
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "reg", core->core_id)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", core->core_id)));
> >> +    _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
> >> +
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
> >> +                            env->dcache_line_size)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
> >> +                            env->dcache_line_size)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
> >> +                            env->icache_line_size)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
> >> +                            env->icache_line_size)));
> >> +
> >> +    if (pcc->l1_dcache_size) {
> >> +        _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
> >> +                               pcc->l1_dcache_size)));
> >> +    } else {
> >> +        error_report("Warning: Unknown L1 dcache size for cpu");
> >> +    }
> >> +    if (pcc->l1_icache_size) {
> >> +        _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
> >> +                               pcc->l1_icache_size)));
> >> +    } else {
> >> +        error_report("Warning: Unknown L1 icache size for cpu");
> >> +    }
> >> +
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
> >> +    _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
> >> +    _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
> >> +    _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
> >> +
> >> +    if (env->spr_cb[SPR_PURR].oea_read) {
> >> +        _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
> >> +    }
> >> +
> >> +    if (env->mmu_model & POWERPC_MMU_1TSEG) {
> >> +        _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
> >> +                           segs, sizeof(segs))));
> >> +    }
> >> +
> >> +    /* Advertise VMX/VSX (vector extensions) if available
> >> +     *   0 / no property == no vector extensions
> >> +     *   1               == VMX / Altivec available
> >> +     *   2               == VSX available */
> >> +    if (env->insns_flags & PPC_ALTIVEC) {
> >> +        uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
> >> +
> >> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
> >> +    }
> >> +
> >> +    /* Advertise DFP (Decimal Floating Point) if available
> >> +     *   0 / no property == no DFP
> >> +     *   1               == DFP available */
> >> +    if (env->insns_flags2 & PPC2_DFP) {
> >> +        _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
> >> +    }
> >> +
> >> +    page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
> >> +                                                  sizeof(page_sizes_prop));
> >> +    if (page_sizes_prop_size) {
> >> +        _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
> >> +                           page_sizes_prop, page_sizes_prop_size)));
> >> +    }
> >> +
> >> +    _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
> >> +                       pa_features, sizeof(pa_features))));
> >> +
> >> +    if (cpu->cpu_version) {
> >> +        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
> >> +    }
> >> +
> >> +    /* Build interrupt servers and gservers properties */
> >> +    for (i = 0; i < smt_threads; i++) {
> >> +        servers_prop[i] = cpu_to_be32(core->core_id + i);
> >> +        /* Hack, direct the group queues back to cpu 0
> >> +         *
> >> +         * FIXME: check that we still need this hack with real HW
> >> +         * ids. Probably not.
> >> +         */
> >> +        gservers_prop[i * 2] = cpu_to_be32(core->core_id + i);
> >> +        gservers_prop[i * 2 + 1] = 0;
> > 
> > I'm not sure the group servers concept even makes sense in the case of
> > powernv.  In powernv, doesn't the guest control the "real" xics,
> > including the link registers, and therefore can configure its own
> > groups, rather than being limited to what firmware has set up as for
> > PAPR?
> 
> yes. we can remove this property.  
>  
> >> +    }
> >> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
> >> +                       servers_prop, sizeof(servers_prop))));
> >> +    _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
> >> +                       gservers_prop, sizeof(gservers_prop))));
> >> +}
> >> +
> >>  static void *powernv_create_fdt(PnvMachineState *pnv,
> >>                                  const char *kernel_cmdline)
> >>  {
> >> @@ -106,6 +237,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
> >>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
> >>      int off;
> >>      int i;
> >> +    int cpus_offset;
> >>  
> >>      fdt = g_malloc0(FDT_MAX_SIZE);
> >>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> >> @@ -150,6 +282,22 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
> >>          xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
> >>      }
> >>  
> >> +    /* cpus */
> >> +    cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
> >> +    _FDT(cpus_offset);
> >> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
> >> +    _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
> >> +
> >> +    for (i = 0; i < pnv->num_chips; i++) {
> >> +        PnvChip *chip = pnv->chips[i];
> >> +        int j;
> >> +
> >> +        for (j = 0; j < chip->num_cores; j++) {
> >> +            powernv_create_core_node(&chip->cores[j], fdt, cpus_offset,
> >> +                                     chip->chip_id);
> >> +        }
> >> +    }
> >> +
> >>      return fdt;
> >>  }
> >>  
> >> @@ -230,6 +378,11 @@ static void ppc_powernv_init(MachineState *machine)
> >>      for (i = 0; i < pnv->num_chips; i++) {
> >>          Object *chip = object_new(chip_typename);
> >>          object_property_set_int(chip, CHIP_HWID(i), "chip-id", &error_abort);
> >> +        object_property_set_int(chip, smp_cores, "num-cores", &error_abort);
> > 
> > This should probably be &error_fatal, again.
> 
> ok.
> 
> >> +        /*
> >> +         * We could set a custom cores_mask for the chip here.
> >> +         */
> >> +
> >>          object_property_set_bool(chip, true, "realized", &error_abort);
> >>          pnv->chips[i] = PNV_CHIP(chip);
> >>      }
> >> @@ -335,19 +488,70 @@ static const TypeInfo pnv_chip_power8e_info = {
> >>      .class_init    = pnv_chip_power8e_class_init,
> >>  };
> >>  
> >> +/*
> >> + * This is different for POWER9 so we might need a ops in the chip to
> >> + * calculate the core pirs
> >> + */
> >> +#define P8_PIR(chip_id, core_id) (((chip_id) << 7) | ((core_id) << 3))
> >> +
> >>  static void pnv_chip_realize(DeviceState *dev, Error **errp)
> >>  {
> >>      PnvChip *chip = PNV_CHIP(dev);
> >>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> >> +    char *typename = pnv_core_typename(pcc->cpu_model);
> >> +    size_t typesize = object_type_get_instance_size(typename);
> >> +    int i, core_hwid;
> >> +
> >> +    if (!object_class_by_name(typename)) {
> >> +        error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
> >> +        return;
> >> +    }
> >>  
> >>      /* Set up XSCOM bus */
> >>      chip->xscom = xscom_create(chip);
> >>  
> >> +    if (chip->num_cores > pcc->cores_max) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: too many cores for chip ! "
> >> +                      "Limiting to %d\n", __func__, pcc->cores_max);
> >> +        chip->num_cores = pcc->cores_max;
> >> +    }
> >> +
> >> +    chip->cores = g_new0(PnvCore, chip->num_cores);
> >> +
> >> +    /* no custom mask for this chip, let's use the default one from
> >> +     * the chip class */
> >> +    if (!chip->cores_mask) {
> >> +        chip->cores_mask = pcc->cores_mask;
> >> +    }
> >> +
> >> +    for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
> >> +             && (i < chip->num_cores); core_hwid++) {
> >> +        PnvCore *pnv_core = &chip->cores[i];
> > 
> > 
> > Unfortunately, as with spapr core creating its threads you'll need
> > some fancier pointer manipulation to handle the possibility of
> > subtypes of PnvCore with a different instance size.  
> > That doesn't happen now, but it can in theory.
> 
> Yes. This is a reason why I preferred to have a Object **cores. I will 
> fix that.
> 
> I don't really like that :
> 
>       void *obj = chip->cores + i * size;
> 
> It does not feel "object-oriented".

Yeah, it's pretty clunky, but it's what we have for now.

> >> +
> >> +        if (!(chip->cores_mask & (1 << core_hwid))) {
> >> +            continue;
> >> +        }
> >> +
> >> +        object_initialize(pnv_core, typesize, typename);
> >> +        object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
> >> +                                &error_fatal);
> >> +        object_property_set_int(OBJECT(pnv_core),
> >> +                                P8_PIR(chip->chip_id, core_hwid),
> >> +                                CPU_CORE_PROP_CORE_ID, &error_fatal);
> >> +        object_property_set_bool(OBJECT(pnv_core), true, "realized",
> >> +                                 &error_fatal);
> >> +        object_unref(OBJECT(pnv_core));
> >> +        i++;
> >> +    }
> >> +    g_free(typename);
> >> +
> >>      pcc->realize(chip, errp);
> >>  }
> >>  
> >>  static Property pnv_chip_properties[] = {
> >>      DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
> >> +    DEFINE_PROP_UINT32("num-cores", PnvChip, num_cores, 1),
> > 
> > I suggest renaming this to "nr-cores" to match "nr-threads" inside the
> > core object.
> 
> ok. fine for me. 
> 
> >> +    DEFINE_PROP_UINT32("cores-mask", PnvChip, cores_mask, 0x0),
> >>      DEFINE_PROP_END_OF_LIST(),
> >>  };
> >>  
> >> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> >> new file mode 100644
> >> index 000000000000..825aea1194a1
> >> --- /dev/null
> >> +++ b/hw/ppc/pnv_core.c
> >> @@ -0,0 +1,170 @@
> >> +/*
> >> + * QEMU PowerPC PowerNV CPU Core model
> >> + *
> >> + * Copyright (c) IBM Corporation.
> >> + *
> >> + * This library is free software; you can redistribute it and/or
> >> + * modify it under the terms of the GNU Lesser General Public License
> >> + * as published by the Free Software Foundation; either version 2 of
> >> + * the License, or (at your option) any later version.
> >> + *
> >> + * This library is distributed in the hope that it will be useful, but
> >> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> + * Lesser General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU Lesser General Public
> >> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +#include "qemu/osdep.h"
> >> +#include "sysemu/sysemu.h"
> >> +#include "qapi/error.h"
> >> +#include "target-ppc/cpu.h"
> >> +#include "hw/ppc/ppc.h"
> >> +#include "hw/ppc/pnv.h"
> >> +#include "hw/ppc/pnv_core.h"
> >> +
> >> +static void powernv_cpu_reset(void *opaque)
> >> +{
> >> +    PowerPCCPU *cpu = opaque;
> >> +    CPUState *cs = CPU(cpu);
> >> +    CPUPPCState *env = &cpu->env;
> >> +    MachineState *machine = MACHINE(qdev_get_machine());
> >> +    PnvMachineState *pnv = POWERNV_MACHINE(machine);
> >> +
> >> +    cpu_reset(cs);
> >> +
> >> +    env->spr[SPR_PIR] = cs->cpu_index;
> > 
> > This can't work.  Your PIR values aren't contiguous, but cpu_index
> > values must be (until you get hotplug).
> 
> cpu_index are not contiguous indeed. They are assigned in pnv_core_realize()
> 
>         cs->cpu_index = cc->core_id + i;
> 
> For this to work, we need the four xics patches Nikunj is working 
> on plus some helper routines to assign and find an icp depending on 
> cs and not an index anymore.

That's not the only problem with cpu_index being non-contiguous.
Maybe we'll get to a point where that's possible but for the
forseeable future, the cpu_index will need to be contiguous (as long
as all possible cpus are present, anyway).

For now you should, if possible, derive the non-contiguous platform
ids from the contiguous cpu_index when you need them.

> I will revive the thread with an extra patch.
> 
> >> +    env->spr[SPR_HIOR] = 0;
> >> +    env->gpr[3] = pnv->fdt_addr;
> > 
> > Is the fdt address injected for all CPUs, or only the boot CPU?
> 
> skiboot will just pick just any boot cpu. My understanding is that 
> all need to have the flat device tree address in r3.

Ok.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0
  2016-09-06  6:28     ` Cédric Le Goater
@ 2016-09-07  1:49       ` David Gibson
  0 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  1:49 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 2612 bytes --]

On Tue, Sep 06, 2016 at 08:28:48AM +0200, Cédric Le Goater wrote:
> On 09/05/2016 06:27 AM, David Gibson wrote:
> > On Wed, Aug 31, 2016 at 06:34:15PM +0200, Cédric Le Goater wrote:
> >> On PowerNV, CPU ids start at 0x8 or 0x20, we don't have a CPU 0
> >> anymore. So let's use the first_cpu index to initialize the monitor.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> > 
> > So we need a patch like this - amongst other fixes - in order to allow
> > unplug of cpu 0.  I'm not really sure whether to push it ahead now, or
> > gather it up with other no-cpu-0 fixes and send them as a batch.
> 
> I think we could send it now as it removes an assumption on the cpu 
> number.

True enough.  I'll try to queue it once I've sorted out my first 2.8
pull request with the existing backlog.

> 
> C. 
> 
> 
> > 
> >> ---
> >>
> >>  So that you can dump the cpu list with the monitor :
> >>
> >> 	(qemu) info cpus
> >> 	* CPU #8: nip=0x0000000000000010 thread_id=7742
> >> 	  CPU #16: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #24: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #32: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #40: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #48: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #72: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #80: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #136: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #144: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #152: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #160: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #168: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #176: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #200: nip=0x0000000000000010 thread_id=7740
> >> 	  CPU #208: nip=0x0000000000000010 thread_id=7740
> >>
> >>  monitor.c | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/monitor.c b/monitor.c
> >> index e9009de09a6c..19b8ec14f40e 100644
> >> --- a/monitor.c
> >> +++ b/monitor.c
> >> @@ -1027,7 +1027,7 @@ int monitor_set_cpu(int cpu_index)
> >>  CPUState *mon_get_cpu(void)
> >>  {
> >>      if (!cur_mon->mon_cpu) {
> >> -        monitor_set_cpu(0);
> >> +        monitor_set_cpu(first_cpu->cpu_index);
> >>      }
> >>      cpu_synchronize_state(cur_mon->mon_cpu);
> >>      return cur_mon->mon_cpu;
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore
  2016-09-06 13:54     ` Cédric Le Goater
@ 2016-09-07  1:51       ` David Gibson
  0 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  1:51 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 9398 bytes --]

On Tue, Sep 06, 2016 at 03:54:10PM +0200, Cédric Le Goater wrote:
> On 09/05/2016 06:19 AM, David Gibson wrote:
> > On Wed, Aug 31, 2016 at 06:34:14PM +0200, Cédric Le Goater wrote:
> >> Now that we are using real HW ids for the cores in PowerNV chips, we
> >> can route the XSCOM accesses to them. We just need to attach a
> >> XScomDevice to each core with the associated ranges in the XSCOM
> >> address space.
> >>
> >> To start with, let's install the DTS (Digital Thermal Sensor) handlers
> >> which are easy to handle.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> >> ---
> >>  hw/ppc/pnv.c              |  9 +++++++
> >>  hw/ppc/pnv_core.c         | 67 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/hw/ppc/pnv_core.h | 13 +++++++++
> >>  3 files changed, 89 insertions(+)
> >>
> >> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> >> index daf9f459ab0e..a31568415192 100644
> >> --- a/hw/ppc/pnv.c
> >> +++ b/hw/ppc/pnv.c
> >> @@ -527,6 +527,7 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
> >>      for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
> >>               && (i < chip->num_cores); core_hwid++) {
> >>          PnvCore *pnv_core = &chip->cores[i];
> >> +        DeviceState *qdev;
> >>  
> >>          if (!(chip->cores_mask & (1 << core_hwid))) {
> >>              continue;
> >> @@ -542,6 +543,14 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
> >>                                   &error_fatal);
> >>          object_unref(OBJECT(pnv_core));
> >>          i++;
> >> +
> >> +        /* Attach the core to its XSCOM bus */
> >> +        qdev = qdev_create(&chip->xscom->bus, TYPE_PNV_CORE_XSCOM);
> > 
> > Again, I think this breaks QOM lifetime rules.
> > 
> >> +        qdev_prop_set_uint32(qdev, "core-pir",
> >> +                             P8_PIR(chip->chip_id, core_hwid));
> >> +        qdev_init_nofail(qdev);
> > 
> > qdev_init_nofail() - which will abort on failure - shouldn't be used
> > in a realize() function, which has a way to gracefully report errors.
> 
> yes. I kind of knew that was ugly but the main purpose of the patch 
> is the use of scom. So I took the quick and dirty path :)
> 
> we should do what you propose below:
>  
> > So, in terms of the lifetime thing.  I think one permitted solution is
> > to embed the scom device state in the core device state and use
> > object_initialize().
> 
> yes.
> 
> > Alternatively, since SCOM is by its nature a sideband bus, I wonder if
> > it would make sense to have ScomDevice be a QOM interface, rather than
> > a full QOM class.  That way the core device itself (and other devices
> > with SCOM control) could present the SCOM device interface and be
> > placed directly on the SCOM bus without having to introduce an extra
> > object.  
> 
> what you are proposing is to have a PnvCore inherit from CPUCore and 
> XScomDevice ? I tried that and did not find a way for multi-inheritance. 

QOM supports multiple interface inheritance, but not multiple direct
inheritance.  That's why youd need to change XScomDevice from a class
to an interface, as I propose in a different mail.  Not sure if that
will cause other problems with the qbus infrastructure.  Have a look
at say, 'HotplugHandler' for an example of a QOM interface.

> But yes, we would get rid of the extra object. At the same time, that 
> extra object represents the xscom interface unit in a chiplet which 
> exists on real HW.
> 
> > It will probably make accessing the object innards in response to 
> > SCOM requests more straightforward as well.
> 
> The address space is probably the best approach. I have some experimental 
> patches which look pretty good :
> 
> address-space: xscom-0
>   0000000000000000-00000007ffffffff (prio 0, RW): xscom-0
>     0000000000b00200-0000000000b0021f (prio 0, RW): lpc-xscom
>     0000000120000000-00000001207fffff (prio 0, RW): core-20-xscom
>     0000000121000000-00000001217fffff (prio 0, RW): core-21-xscom
>     0000000122000000-00000001227fffff (prio 0, RW): core-22-xscom
>     0000000123000000-00000001237fffff (prio 0, RW): core-23-xscom
>     0000000124000000-00000001247fffff (prio 0, RW): core-24-xscom
>     0000000125000000-00000001257fffff (prio 0, RW): core-25-xscom
>     0000000126000000-00000001267fffff (prio 0, RW): core-26-xscom
>     ....
> 
> 
> > I'm not entirely sure if sharing just an interface will be sufficient
> > for devices under a bus, but it's worth investigating.
> 
> yes. I need to step back a bit and look how I could rework the patchset 
> to QOMify the whole. This is really qdev oriented and there are a couple 
> of places where fixes are needed. I am seeing that better now. 
> 
> The address space should be investigated also.
> 
> >> +
> >> +        pnv_core->xd = PNV_CORE_XSCOM(qdev);
> >>      }
> >>      g_free(typename);
> >>  
> >> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> >> index 825aea1194a1..feba374740dc 100644
> >> --- a/hw/ppc/pnv_core.c
> >> +++ b/hw/ppc/pnv_core.c
> >> @@ -18,7 +18,9 @@
> >>   */
> >>  #include "qemu/osdep.h"
> >>  #include "sysemu/sysemu.h"
> >> +#include "qemu/error-report.h"
> >>  #include "qapi/error.h"
> >> +#include "qemu/log.h"
> >>  #include "target-ppc/cpu.h"
> >>  #include "hw/ppc/ppc.h"
> >>  #include "hw/ppc/pnv.h"
> >> @@ -144,10 +146,75 @@ static const TypeInfo pnv_core_info = {
> >>      .abstract       = true,
> >>  };
> >>  
> >> +
> >> +#define DTS_RESULT0     0x50000
> >> +#define DTS_RESULT1     0x50001
> >> +
> >> +static bool pnv_core_xscom_read(XScomDevice *dev, uint32_t range,
> >> +                               uint32_t offset, uint64_t *out_val)
> >> +{
> >> +    switch (offset) {
> >> +    case DTS_RESULT0:
> >> +        *out_val = 0x26f024f023f0000ull;
> >> +        break;
> >> +    case DTS_RESULT1:
> >> +        *out_val = 0x24f000000000000ull;
> >> +        break;
> >> +    default:
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "Warning: reading reg=0x%08x", offset);
> > 
> > Can't you just return false here and let the caller handle the error reporting?
> 
> yes. 
> 
> Thanks,
> 
> C. 
> 
> >> +    }
> >> +
> >> +   return true;
> >> +}
> >> +
> >> +static bool pnv_core_xscom_write(XScomDevice *dev, uint32_t range,
> >> +                                uint32_t offset, uint64_t val)
> >> +{
> >> +    qemu_log_mask(LOG_GUEST_ERROR, "Warning: writing to reg=0x%08x", offset);
> >> +    return true;
> >> +}
> >> +
> >> +#define EX_XSCOM_BASE 0x10000000
> >> +#define EX_XSCOM_SIZE 0x100000
> >> +
> >> +static void pnv_core_xscom_realize(DeviceState *dev, Error **errp)
> >> +{
> >> +    XScomDevice *xd = XSCOM_DEVICE(dev);
> >> +    PnvCoreXScom *pnv_xd = PNV_CORE_XSCOM(dev);
> >> +
> >> +    xd->ranges[0].addr = EX_XSCOM_BASE | P8_PIR2COREID(pnv_xd->core_pir) << 24;
> >> +    xd->ranges[0].size = EX_XSCOM_SIZE;
> >> +}
> >> +
> >> +static Property pnv_core_xscom_properties[] = {
> >> +        DEFINE_PROP_UINT32("core-pir", PnvCoreXScom, core_pir, 0),
> >> +        DEFINE_PROP_END_OF_LIST(),
> >> +};
> >> +
> >> +static void pnv_core_xscom_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +    XScomDeviceClass *xdc = XSCOM_DEVICE_CLASS(klass);
> >> +
> >> +    xdc->read = pnv_core_xscom_read;
> >> +    xdc->write = pnv_core_xscom_write;
> >> +
> >> +    dc->realize = pnv_core_xscom_realize;
> >> +    dc->props = pnv_core_xscom_properties;
> >> +}
> >> +
> >> +static const TypeInfo pnv_core_xscom_type_info = {
> >> +    .name          = TYPE_PNV_CORE_XSCOM,
> >> +    .parent        = TYPE_XSCOM_DEVICE,
> >> +    .instance_size = sizeof(PnvCoreXScom),
> >> +    .class_init    = pnv_core_xscom_class_init,
> >> +};
> >> +
> >>  static void pnv_core_register_types(void)
> >>  {
> >>      int i ;
> >>  
> >> +    type_register_static(&pnv_core_xscom_type_info);
> >>      type_register_static(&pnv_core_info);
> >>      for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
> >>          TypeInfo ti = {
> >> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> >> index 832c8756afaa..72936ccfd22f 100644
> >> --- a/include/hw/ppc/pnv_core.h
> >> +++ b/include/hw/ppc/pnv_core.h
> >> @@ -20,6 +20,18 @@
> >>  #define _PPC_PNV_CORE_H
> >>  
> >>  #include "hw/cpu/core.h"
> >> +#include "hw/ppc/pnv_xscom.h"
> >> +
> >> +#define TYPE_PNV_CORE_XSCOM "powernv-cpu-core-xscom"
> >> +#define PNV_CORE_XSCOM(obj) \
> >> +     OBJECT_CHECK(PnvCoreXScom, (obj), TYPE_PNV_CORE_XSCOM)
> >> +
> >> +typedef struct PnvCoreXScom {
> >> +    XScomDevice xd;
> >> +    uint32_t core_pir;
> >> +} PnvCoreXScom;
> >> +
> >> +#define P8_PIR2COREID(pir) (((pir) >> 3) & 0xf)
> >>  
> >>  #define TYPE_PNV_CORE "powernv-cpu-core"
> >>  #define PNV_CORE(obj) \
> >> @@ -35,6 +47,7 @@ typedef struct PnvCore {
> >>  
> >>      /*< public >*/
> >>      void *threads;
> >> +    PnvCoreXScom *xd;
> >>  } PnvCore;
> >>  
> >>  typedef struct PnvCoreClass {
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 14:42     ` Cédric Le Goater
  2016-09-06 21:45       ` Benjamin Herrenschmidt
@ 2016-09-07  1:59       ` David Gibson
  2016-09-07  5:27         ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-07  1:59 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Benjamin Herrenschmidt, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 25633 bytes --]

On Tue, Sep 06, 2016 at 04:42:01PM +0200, Cédric Le Goater wrote:
> On 09/05/2016 05:39 AM, David Gibson wrote:
> > On Wed, Aug 31, 2016 at 06:34:11PM +0200, Cédric Le Goater wrote:
> >> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> >>
> >> XSCOM is an interface to a sideband bus provided by the POWER8 chip
> >> pervasive unit, which gives access to a number of facilities in the
> >> chip that are needed by the OPAL firmware and to a lesser extent,
> >> Linux. This is among others how the PCI Host bridges get configured
> >> at boot or how the LPC bus is accessed.
> >>
> >> This provides a simple bus and device type for devices sitting on
> >> XSCOM along with some facilities to optionally generate corresponding
> >> device-tree nodes
> >>
> >> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> >> [clg: updated for qemu-2.7
> >>       ported on new sPowerNVMachineState which was merged with PnvSystem
> >>       removed TRACE_XSCOM
> >>       fixed checkpatch errors
> >>       replaced assert with error_setg in xscom_realize()
> >>       reworked xscom_create
> >>       introduced the use of the chip_class for chip model contants
> >>       ]
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> >> ---
> >>
> >>  They were some discussions on whether we should use a qemu
> >>  address_space instead of the xscom ranges defined in this patch. 
> >>  I gave it try, it is possible but it brings extra unnecessary calls
> >>  and complexity. I think the current solution is better.
> >>
> >>  hw/ppc/Makefile.objs       |   2 +-
> >>  hw/ppc/pnv.c               |  11 ++
> >>  hw/ppc/pnv_xscom.c         | 408 +++++++++++++++++++++++++++++++++++++++++++++
> >>  include/hw/ppc/pnv.h       |   2 +
> >>  include/hw/ppc/pnv_xscom.h |  75 +++++++++
> >>  5 files changed, 497 insertions(+), 1 deletion(-)
> >>  create mode 100644 hw/ppc/pnv_xscom.c
> >>  create mode 100644 include/hw/ppc/pnv_xscom.h
> >>
> >> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> >> index 8105db7d5600..f580e5c41413 100644
> >> --- a/hw/ppc/Makefile.objs
> >> +++ b/hw/ppc/Makefile.objs
> >> @@ -6,7 +6,7 @@ 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_cpu_core.o
> >>  # IBM PowerNV
> >> -obj-$(CONFIG_POWERNV) += pnv.o
> >> +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o
> >>  ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
> >>  obj-y += spapr_pci_vfio.o
> >>  endif
> >> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> >> index 06051268e200..a6e7f66b2c0a 100644
> >> --- a/hw/ppc/pnv.c
> >> +++ b/hw/ppc/pnv.c
> >> @@ -39,6 +39,8 @@
> >>  #include "exec/address-spaces.h"
> >>  #include "qemu/cutils.h"
> >>  
> >> +#include "hw/ppc/pnv_xscom.h"
> >> +
> >>  #include <libfdt.h>
> >>  
> >>  #define FDT_ADDR                0x01000000
> >> @@ -103,6 +105,7 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
> >>      char *buf;
> >>      const char plat_compat[] = "qemu,powernv\0ibm,powernv";
> >>      int off;
> >> +    int i;
> >>  
> >>      fdt = g_malloc0(FDT_MAX_SIZE);
> >>      _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> >> @@ -142,6 +145,11 @@ static void *powernv_create_fdt(PnvMachineState *pnv,
> >>      /* Memory */
> >>      powernv_populate_memory(fdt);
> >>  
> >> +    /* Populate XSCOM for each chip */
> >> +    for (i = 0; i < pnv->num_chips; i++) {
> >> +        xscom_populate_fdt(pnv->chips[i]->xscom, fdt, 0);
> >> +    }
> > 
> > There will be a bunch of per-chip things in the fdt - I suggest a
> > common function to do all the fdt creation for a single chip.  Since
> > you've moved to using the fdt_rw functions exclusively, you don't have
> > the sequence constraints that would have made that awkward previously.
> 
> ok.
> 
> >>      return fdt;
> >>  }
> >>  
> >> @@ -305,6 +313,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
> >>      PnvChip *chip = PNV_CHIP(dev);
> >>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> >>  
> >> +    /* Set up XSCOM bus */
> >> +    chip->xscom = xscom_create(chip);
> > 
> > So, this creates the xscom as a new device object, unfortunately doing
> > that from another object's realize() violations QOM lifetime rules as
> > I understand them.  I think - I have to admit I'm pretty confused on
> > this topic myself.
> > 
> > You could construct the scom from chip init, then realize it from chip
> > realize, but I think using object_new() (via qdev_create()) from
> > another object's init also breaks the rules.  You are however allowed
> > to allocate the scom state statically within the chip and use
> > object_initialize() instead, AIUI.
> > 
> > Alternatively.. it might be simpler to just drop the SCOM as a
> > separate device.  I think you could just hang the scom bus directly
> > off the chip object.  IIUC the scom is basically the only chip-level
> > control mechanism, so this does make a certain amount of sense.
> 
> yes. I am exposing more and more stuff of the chip object under the 
> xscom object so we should merge them. I agree. We will still need 
> some XScomDevice of some sort.
> 
> >>      pcc->realize(chip, errp);
> >>  }
> >>  
> >> diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
> >> new file mode 100644
> >> index 000000000000..7ed3804f4b3a
> >> --- /dev/null
> >> +++ b/hw/ppc/pnv_xscom.c
> >> @@ -0,0 +1,408 @@
> >> +
> >> +/*
> >> + * QEMU PowerNV XSCOM bus definitions
> >> + *
> >> + * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
> >> + * Based on the s390 virtio bus code:
> >> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> >> + *
> >> + * This library is free software; you can redistribute it and/or
> >> + * modify it under the terms of the GNU Lesser General Public
> >> + * License as published by the Free Software Foundation; either
> >> + * version 2 of the License, or (at your option) any later version.
> >> + *
> >> + * This library is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> + * Lesser General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU Lesser General Public
> >> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +/* TODO: Add some infrastructure for "random stuff" and FIRs that
> >> + * various units might want to deal with without creating actual
> >> + * XSCOM devices.
> >> + *
> >> + * For example, HB LPC XSCOM in the PIBAM
> >> + */
> >> +#include "qemu/osdep.h"
> >> +#include "qapi/error.h"
> >> +#include "hw/hw.h"
> >> +#include "sysemu/sysemu.h"
> >> +#include "hw/boards.h"
> >> +#include "monitor/monitor.h"
> >> +#include "hw/loader.h"
> >> +#include "elf.h"
> >> +#include "hw/sysbus.h"
> >> +#include "sysemu/kvm.h"
> >> +#include "sysemu/device_tree.h"
> >> +#include "hw/ppc/fdt.h"
> >> +
> >> +#include "hw/ppc/pnv_xscom.h"
> >> +
> >> +#include <libfdt.h>
> >> +
> >> +#define TYPE_XSCOM "xscom"
> >> +#define XSCOM(obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM)
> >> +
> >> +#define XSCOM_SIZE        0x800000000ull
> >> +#define XSCOM_BASE(chip)  (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE)
> >> +
> >> +
> >> +typedef struct XScomState {
> >> +    /*< private >*/
> >> +    SysBusDevice parent_obj;
> >> +    /*< public >*/
> >> +
> >> +    MemoryRegion mem;
> >> +    int32_t chip_id;
> > 
> > Merging scom and chip would avoid the duplication of this field too.
> 
> yes.
> 
> >> +    PnvChipClass *chip_class;
> >> +    XScomBus *bus;
> >> +} XScomState;
> >> +
> >> +static uint32_t xscom_to_pcb_addr(uint64_t addr)
> >> +{
> >> +        addr &= (XSCOM_SIZE - 1);
> >> +        return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
> >> +}
> >> +
> >> +static void xscom_complete(uint64_t hmer_bits)
> >> +{
> >> +    CPUState *cs = current_cpu;
> >> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >> +    CPUPPCState *env = &cpu->env;
> >> +
> >> +    cpu_synchronize_state(cs);
> >> +    env->spr[SPR_HMER] |= hmer_bits;
> >> +
> >> +    /* XXX Need a CPU helper to set HMER, also handle gneeration
> >> +     * of HMIs
> >> +     */
> >> +}
> >> +
> >> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t pcb_addr,
> >> +                                      uint32_t *range)
> >> +{
> >> +    BusChild *bc;
> >> +
> >> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> >> +        DeviceState *qd = bc->child;
> >> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> >> +        unsigned int i;
> >> +
> >> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> >> +            if (xd->ranges[i].addr <= pcb_addr &&
> >> +                (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) {
> >> +                *range = i;
> >> +                return xd;
> >> +            }
> >> +        }
> >> +    }
> > 
> > Hmm.. you could set up a SCOM local address space using the
> > infrastructure in memory.c, rather than doing your own dispatch.
> 
> I need to study this option a little deeper. 

So.. something I realized a bit later.

The obvious way of changing XScomDevice to a QOM interface isn't
really compatible with using the address space infrastructure.  You'd
have read/write methods in the interface, and since that's not the
same interface as an MR you'd need to do your own address decode /
dispatch as you do above.

That does suggest an alternative approach though.  You could remove
XScomDevice entirely from QOM existence, and just expose the xscom
address space globally, much like address_space_memory.  The
individual devices could just register their own subregions within it.

I'm not sure if the latter is a good idea, though.

> 
> > 
> >> +    return NULL;
> >> +}
> >> +
> >> +static bool xscom_dispatch_read(XScomState *s, uint32_t pcb_addr,
> >> +                                uint64_t *out_val)
> >> +{
> >> +    uint32_t range, offset;
> >> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> >> +    XScomDeviceClass *xc;
> >> +
> >> +    if (!xd) {
> >> +        return false;
> >> +    }
> >> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> >> +    if (!xc->read) {
> >> +        return false;
> >> +    }
> >> +    offset = pcb_addr - xd->ranges[range].addr;
> >> +    return xc->read(xd, range, offset, out_val);
> >> +}
> >> +
> >> +static bool xscom_dispatch_write(XScomState *s, uint32_t pcb_addr, uint64_t val)
> >> +{
> >> +    uint32_t range, offset;
> >> +    struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range);
> >> +    XScomDeviceClass *xc;
> >> +
> >> +    if (!xd) {
> >> +        return false;
> >> +    }
> >> +    xc = XSCOM_DEVICE_GET_CLASS(xd);
> >> +    if (!xc->write) {
> >> +        return false;
> >> +    }
> >> +    offset = pcb_addr - xd->ranges[range].addr;
> >> +    return xc->write(xd, range, offset, val);
> >> +}
> >> +
> >> +static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
> >> +{
> >> +    XScomState *s = opaque;
> >> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> >> +    uint64_t val;
> >> +
> >> +    assert(width == 8);
> >> +
> >> +    /* Handle some SCOMs here before dispatch */
> >> +    switch (pcba) {
> >> +    case 0xf000f:
> >> +        val = s->chip_class->chip_f000f;
> >> +        break;
> >> +    case 0x1010c00:     /* PIBAM FIR */
> >> +    case 0x1010c03:     /* PIBAM FIR MASK */
> >> +    case 0x2020007:     /* ADU stuff */
> >> +    case 0x2020009:     /* ADU stuff */
> >> +    case 0x202000f:     /* ADU stuff */
> >> +        val = 0;
> >> +        break;
> >> +    case 0x2013f00:     /* PBA stuff */
> >> +    case 0x2013f01:     /* PBA stuff */
> >> +    case 0x2013f02:     /* PBA stuff */
> >> +    case 0x2013f03:     /* PBA stuff */
> >> +    case 0x2013f04:     /* PBA stuff */
> >> +    case 0x2013f05:     /* PBA stuff */
> >> +    case 0x2013f06:     /* PBA stuff */
> >> +    case 0x2013f07:     /* PBA stuff */
> >> +        val = 0;
> >> +        break;
> >> +    default:
> >> +        if (!xscom_dispatch_read(s, pcba, &val)) {
> >> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> >> +            return 0;
> >> +        }
> >> +    }
> >> +
> >> +    xscom_complete(HMER_XSCOM_DONE);
> >> +    return val;
> >> +}
> >> +
> >> +static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
> >> +                        unsigned width)
> >> +{
> >> +    XScomState *s = opaque;
> >> +    uint32_t pcba = xscom_to_pcb_addr(addr);
> >> +
> >> +    assert(width == 8);
> >> +
> >> +    /* Handle some SCOMs here before dispatch */
> >> +    switch (pcba) {
> >> +        /* We ignore writes to these */
> >> +    case 0xf000f:       /* chip id is RO */
> >> +    case 0x1010c00:     /* PIBAM FIR */
> >> +    case 0x1010c01:     /* PIBAM FIR */
> >> +    case 0x1010c02:     /* PIBAM FIR */
> >> +    case 0x1010c03:     /* PIBAM FIR MASK */
> >> +    case 0x1010c04:     /* PIBAM FIR MASK */
> >> +    case 0x1010c05:     /* PIBAM FIR MASK */
> >> +    case 0x2020007:     /* ADU stuff */
> >> +    case 0x2020009:     /* ADU stuff */
> >> +    case 0x202000f:     /* ADU stuff */
> >> +        break;
> >> +    default:
> >> +        if (!xscom_dispatch_write(s, pcba, val)) {
> >> +            xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE);
> >> +            return;
> >> +        }
> >> +    }
> >> +
> >> +    xscom_complete(HMER_XSCOM_DONE);
> >> +}
> >> +
> >> +static const MemoryRegionOps xscom_ops = {
> >> +    .read = xscom_read,
> >> +    .write = xscom_write,
> >> +    .valid.min_access_size = 8,
> >> +    .valid.max_access_size = 8,
> >> +    .impl.min_access_size = 8,
> >> +    .impl.max_access_size = 8,
> >> +    .endianness = DEVICE_BIG_ENDIAN,
> >> +};
> >> +
> >> +static int xscom_init(SysBusDevice *dev)
> >> +{
> >> +    XScomState *s = XSCOM(dev);
> >> +
> >> +    s->chip_id = -1;
> >> +    return 0;
> >> +}
> >> +
> >> +static void xscom_realize(DeviceState *dev, Error **errp)
> >> +{
> >> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> >> +    XScomState *s = XSCOM(dev);
> >> +    char *name;
> >> +
> >> +    if (s->chip_id < 0) {
> >> +        error_setg(errp, "invalid chip id '%d'", s->chip_id);
> >> +        return;
> >> +    }
> >> +    name = g_strdup_printf("xscom-%x", s->chip_id);
> >> +    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
> >> +    sysbus_init_mmio(sbd, &s->mem);
> >> +    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));
> >> +}
> >> +
> >> +static Property xscom_properties[] = {
> >> +        DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0),
> >> +        DEFINE_PROP_END_OF_LIST(),
> >> +};
> >> +
> >> +static void xscom_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +
> >> +    dc->props = xscom_properties;
> >> +    dc->realize = xscom_realize;
> >> +    k->init = xscom_init;
> >> +}
> >> +
> >> +static const TypeInfo xscom_info = {
> >> +    .name          = TYPE_XSCOM,
> >> +    .parent        = TYPE_SYS_BUS_DEVICE,
> >> +    .instance_size = sizeof(XScomState),
> >> +    .class_init    = xscom_class_init,
> >> +};
> >> +
> >> +static void xscom_bus_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +}
> >> +
> >> +static const TypeInfo xscom_bus_info = {
> >> +    .name = TYPE_XSCOM_BUS,
> >> +    .parent = TYPE_BUS,
> >> +    .class_init = xscom_bus_class_init,
> >> +    .instance_size = sizeof(XScomBus),
> >> +};
> >> +
> >> +XScomBus *xscom_create(PnvChip *chip)
> >> +{
> >> +    DeviceState *dev;
> >> +    XScomState *xdev;
> >> +    BusState *qbus;
> >> +    XScomBus *xb;
> >> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> >> +
> >> +    dev = qdev_create(NULL, TYPE_XSCOM);
> >> +    qdev_prop_set_uint32(dev, "chip_id", chip->chip_id);
> >> +    qdev_init_nofail(dev);
> >> +
> >> +    /* Create bus on bridge device */
> >> +    qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
> >> +    xb = DO_UPCAST(XScomBus, bus, qbus);
> >> +    xb->chip_id = chip->chip_id;
> >> +    xdev = XSCOM(dev);
> >> +    xdev->bus = xb;
> >> +    xdev->chip_class = pcc;
> >> +
> >> +    return xb;
> >> +}
> >> +
> >> +int xscom_populate_fdt(XScomBus *xb, void *fdt, int root_offset)
> > 
> > What is the root_offset parameter for, since it is always 0?
> 
> yes ...
> 
> >> +{
> >> +    BusChild *bc;
> >> +    char *name;
> >> +    const char compat[] = "ibm,power8-xscom\0ibm,xscom";
> >> +    uint64_t reg[] = { cpu_to_be64(XSCOM_BASE(xb->chip_id)),
> >> +                       cpu_to_be64(XSCOM_SIZE) };
> >> +    int xscom_offset;
> >> +
> >> +    name = g_strdup_printf("xscom@%llx", (unsigned long long)
> >> +                           be64_to_cpu(reg[0]));
> > 
> > Nit: in qemu the PRIx64 etc. macros are usually preferred to (unsigned
> > long long) casts of this type.
> 
> sure.
> 
> >> +    xscom_offset = fdt_add_subnode(fdt, root_offset, name);
> >> +    _FDT(xscom_offset);
> >> +    g_free(name);
> >> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "ibm,chip-id", xb->chip_id)));
> >> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
> >> +    _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
> >> +    _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
> >> +    _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat,
> >> +                      sizeof(compat))));
> >> +    _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
> >> +
> >> +    QTAILQ_FOREACH(bc, &xb->bus.children, sibling) {
> >> +        DeviceState *qd = bc->child;
> >> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> >> +        XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xd);
> >> +        uint32_t reg[MAX_XSCOM_RANGES * 2];
> >> +        unsigned int i, sz = 0;
> >> +        void *cp, *p;
> >> +        int child_offset;
> >> +
> >> +        /* Some XSCOM slaves may not be represented in the DT */
> >> +        if (!xc->dt_name) {
> >> +            continue;
> >> +        }
> >> +        name = g_strdup_printf("%s@%x", xc->dt_name, xd->ranges[0].addr);
> >> +        child_offset = fdt_add_subnode(fdt, xscom_offset, name);
> >> +        _FDT(child_offset);
> >> +        g_free(name);
> >> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> >> +            if (xd->ranges[i].size == 0) {
> >> +                break;
> >> +            }
> >> +            reg[sz++] = cpu_to_be32(xd->ranges[i].addr);
> >> +            reg[sz++] = cpu_to_be32(xd->ranges[i].size);
> >> +        }
> >> +        _FDT((fdt_setprop(fdt, child_offset, "reg", reg, sz * 4)));
> > 
> > Use of fdt_appendprop() might make this a little neater.
> 
> ok.
> 
> >> +        if (xc->devnode) {
> >> +            _FDT((xc->devnode(xd, fdt, child_offset)));
> >> +        }
> >> +#define MAX_COMPATIBLE_PROP     1024
> >> +        cp = p = g_malloc0(MAX_COMPATIBLE_PROP);
> >> +        i = 0;
> >> +        while ((p - cp) < MAX_COMPATIBLE_PROP) {
> >> +            int l;
> >> +            if (xc->dt_compatible[i] == NULL) {
> >> +                break;
> >> +            }
> >> +            l = strlen(xc->dt_compatible[i]);
> >> +            if (l >= (MAX_COMPATIBLE_PROP - i)) {
> >> +                break;
> >> +            }
> >> +            strcpy(p, xc->dt_compatible[i++]);
> >> +            p += l + 1;
> >> +        }
> >> +        _FDT((fdt_setprop(fdt, child_offset, "compatible", cp, p - cp)));
> > 
> > Might it be easier to just require the individual scom device to set
> > the compatible property from its ->devnode callback?  That way it can
> > just
> > 	const char compat = "foo\0bar\0baz";
> > 	fdt_setprop(..., compat, sizeof(compat));
> > 
> > and avoid this fiddling around with arrays.
> 
> Yes. xscom_populate_fdt() will shrink quite a bit. This is a good idea.
> 
> Thanks,
> 
> C.
> 
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int xscom_qdev_init(DeviceState *qdev)
> >> +{
> >> +    XScomDevice *xdev = (XScomDevice *)qdev;
> >> +    XScomDeviceClass *xc = XSCOM_DEVICE_GET_CLASS(xdev);
> >> +
> >> +    if (xc->init) {
> >> +        return xc->init(xdev);
> >> +    }
> >> +    return 0;
> >> +}
> >> +
> >> +static void xscom_device_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *k = DEVICE_CLASS(klass);
> >> +    k->init = xscom_qdev_init;
> >> +    k->bus_type = TYPE_XSCOM_BUS;
> >> +}
> >> +
> >> +static const TypeInfo xscom_dev_info = {
> >> +    .name = TYPE_XSCOM_DEVICE,
> >> +    .parent = TYPE_DEVICE,
> >> +    .instance_size = sizeof(XScomDevice),
> >> +    .abstract = true,
> >> +    .class_size = sizeof(XScomDeviceClass),
> >> +    .class_init = xscom_device_class_init,
> >> +};
> >> +
> >> +static void xscom_register_types(void)
> >> +{
> >> +    type_register_static(&xscom_info);
> >> +    type_register_static(&xscom_bus_info);
> >> +    type_register_static(&xscom_dev_info);
> >> +}
> >> +
> >> +type_init(xscom_register_types)
> >> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> >> index 1f32573dedff..bc6e1f80096b 100644
> >> --- a/include/hw/ppc/pnv.h
> >> +++ b/include/hw/ppc/pnv.h
> >> @@ -35,12 +35,14 @@ typedef enum PnvChipType {
> >>      PNV_CHIP_P8NVL, /* AKA Naples */
> >>  } PnvChipType;
> >>  
> >> +typedef struct XScomBus XScomBus;
> >>  typedef struct PnvChip {
> >>      /*< private >*/
> >>      SysBusDevice parent_obj;
> >>  
> >>      /*< public >*/
> >>      uint32_t     chip_id;
> >> +    XScomBus     *xscom;
> >>  } PnvChip;
> >>  
> >>  typedef struct PnvChipClass {
> >> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> >> new file mode 100644
> >> index 000000000000..386ad21c5aa5
> >> --- /dev/null
> >> +++ b/include/hw/ppc/pnv_xscom.h
> >> @@ -0,0 +1,75 @@
> >> +#ifndef _HW_XSCOM_H
> >> +#define _HW_XSCOM_H
> >> +/*
> >> + * QEMU PowerNV XSCOM bus definitions
> >> + *
> >> + * Copyright (c) 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corp.
> >> + * Based on the s390 virtio bus definitions:
> >> + * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
> >> + *
> >> + * This library is free software; you can redistribute it and/or
> >> + * modify it under the terms of the GNU Lesser General Public
> >> + * License as published by the Free Software Foundation; either
> >> + * version 2 of the License, or (at your option) any later version.
> >> + *
> >> + * This library is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> + * Lesser General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU Lesser General Public
> >> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +#include <hw/ppc/pnv.h>
> >> +
> >> +#define TYPE_XSCOM_DEVICE "xscom-device"
> >> +#define XSCOM_DEVICE(obj) \
> >> +     OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE)
> >> +#define XSCOM_DEVICE_CLASS(klass) \
> >> +     OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE)
> >> +#define XSCOM_DEVICE_GET_CLASS(obj) \
> >> +     OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE)
> >> +
> >> +#define TYPE_XSCOM_BUS "xscom-bus"
> >> +#define XSCOM_BUS(obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS)
> >> +
> >> +typedef struct XScomDevice XScomDevice;
> >> +typedef struct XScomBus XScomBus;
> >> +
> >> +typedef struct XScomDeviceClass {
> >> +    DeviceClass parent_class;
> >> +
> >> +    const char *dt_name;
> >> +    const char **dt_compatible;
> >> +    int (*init)(XScomDevice *dev);
> >> +    int (*devnode)(XScomDevice *dev, void *fdt, int offset);
> >> +
> >> +    /* Actual XScom accesses */
> >> +    bool (*read)(XScomDevice *dev, uint32_t range, uint32_t offset,
> >> +                 uint64_t *out_val);
> >> +    bool (*write)(XScomDevice *dev, uint32_t range, uint32_t offset,
> >> +                  uint64_t val);
> >> +} XScomDeviceClass;
> >> +
> >> +typedef struct XScomRange {
> >> +    uint32_t addr;
> >> +    uint32_t size;
> >> +} XScomRange;
> >> +
> >> +struct XScomDevice {
> >> +    DeviceState qdev;
> >> +#define MAX_XSCOM_RANGES 4
> >> +    struct XScomRange ranges[MAX_XSCOM_RANGES];
> >> +};
> >> +
> >> +struct XScomBus {
> >> +    BusState bus;
> >> +    uint32_t chip_id;
> >> +};
> >> +
> >> +extern XScomBus *xscom_create(PnvChip *chip);
> >> +extern int xscom_populate_fdt(XScomBus *xscom, void *fdt, int offset);
> >> +
> >> +
> >> +#endif /* _HW_XSCOM_H */
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 14:42         ` Cédric Le Goater
  2016-09-06 21:47           ` Benjamin Herrenschmidt
@ 2016-09-07  2:01           ` David Gibson
  1 sibling, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  2:01 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Benjamin Herrenschmidt, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 2874 bytes --]

On Tue, Sep 06, 2016 at 04:42:58PM +0200, Cédric Le Goater wrote:
> On 09/06/2016 02:48 AM, David Gibson wrote:
> > On Mon, Sep 05, 2016 at 05:11:53PM +1000, Benjamin Herrenschmidt wrote:
> >> On Mon, 2016-09-05 at 13:39 +1000, David Gibson wrote:
> >>>> +static XScomDevice *xscom_find_target(XScomState *s, uint32_t
> >>> pcb_addr,
> >>>> +                                      uint32_t *range)
> >>>> +{
> >>>> +    BusChild *bc;
> >>>> +
> >>>> +    QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) {
> >>>> +        DeviceState *qd = bc->child;
> >>>> +        XScomDevice *xd = XSCOM_DEVICE(qd);
> >>>> +        unsigned int i;
> >>>> +
> >>>> +        for (i = 0; i < MAX_XSCOM_RANGES; i++) {
> >>>> +            if (xd->ranges[i].addr <= pcb_addr &&
> >>>> +                (xd->ranges[i].addr + xd->ranges[i].size) >
> >>> pcb_addr) {
> >>>> +                *range = i;
> >>>> +                return xd;
> >>>> +            }
> >>>> +        }
> >>>> +    }
> >>>
> >>> Hmm.. you could set up a SCOM local address space using the
> >>> infrastructure in memory.c, rather than doing your own dispatch.
> >>
> >> There are pros and cons to this approach. The memory.c stuff comes with
> >> quite a lot of baggage, not all of it very shinny to be honest ;-) I
> >> still *hate* how it forces upon us a whole 128-bit integer arithmetic
> >> library just so that it can represent 1_0000_0000_0000_0000 ... 
> > 
> > Ugh, yeah.  I tried to argue against this when it first came in, but
> > was overruled.
> > 
> >> It would be make more sense to use inclusive start/end instead and
> >> stick to 64-bits.
> >>
> >> That being said, we could do that. We'd have to shift the XSCOM
> >> addresses left by 3 since each address is an 8 bytes reigster and
> >> forbid non-8-bytes accesses.
> > 
> > Ok.  I'm not particularly fussed either way.
> 
> 
> The change does seem too invasive. I can give it a try in next
> version.
> 
> When a memory region is triggered, the impacted device will have
> to convert the address with xscom_to_pcb_addr(). There is some 
> dependency on the chip model because the translation is different. 
> That would be an extra op in the xscom device model I guess. 

Actually, I was still thinking of having an MR for the scom interface
unit, which does the xscom_to_pcb_addr() then re-issues the access in
the PCB address space.

But your suggestion might work too.

> Also, the main purpose of the XscomBus is to loop on the devices 
> to populate the device tree. I am wondering if we could just use 
> a simple list under the chip for that purpose. 
> 
> Thanks,
> 
> C. 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:45       ` Benjamin Herrenschmidt
@ 2016-09-07  2:02         ` David Gibson
  2016-09-07 16:40         ` Cédric Le Goater
  1 sibling, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  2:02 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 1802 bytes --]

On Wed, Sep 07, 2016 at 07:45:49AM +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
> > > Alternatively.. it might be simpler to just drop the SCOM as a
> > > separate device.  I think you could just hang the scom bus directly
> > > off the chip object.  IIUC the scom is basically the only chip-
> > level
> > > control mechanism, so this does make a certain amount of sense.
> > 
> > yes. I am exposing more and more stuff of the chip object under the 
> > xscom object so we should merge them. I agree. We will still need 
> > some XScomDevice of some sort.
> 
> What you can do is split it this way which matches the HW:
> 
>  - The chip object is the XSCOM parent, it owns the XSCOM bus,
> and expose functions (methods) to read/write XSCOMs. WE could rename
> XSCOM to "PIB" or "PCB" which is the real name of the bus ;-) But that
> might confuse things more than help .
> 
>  - A separate ADU object on each chip that is a SysDevice and does the
> MMIO bridge to XSCOM. It decodes the MMIO range for that chip and calls
> the above accessors.
> 
> That makes it easy to generate XSCOMs using different mechanisms if we
> wish to do so, which could come in handy, such as monitor commands, or
> if we ever do cosimulation with a separate BMC, a simulated FSI, all by
> just calling the first object's methods.

Not what I had in mind - I still was thinking of having the xscom
access unit do the translation and re-issue into the pcb bus address
space.

But sounds like this other approach could have some advantages.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:47           ` Benjamin Herrenschmidt
  2016-09-06 21:49             ` Benjamin Herrenschmidt
@ 2016-09-07  2:03             ` David Gibson
  2016-09-07 15:47             ` Cédric Le Goater
  2 siblings, 0 replies; 62+ messages in thread
From: David Gibson @ 2016-09-07  2:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 1411 bytes --]

On Wed, Sep 07, 2016 at 07:47:16AM +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
> > 
> > The change does seem too invasive. I can give it a try in next
> > version.
> > 
> > When a memory region is triggered, the impacted device will have
> > to convert the address with xscom_to_pcb_addr(). There is some 
> > dependency on the chip model because the translation is different. 
> > That would be an extra op in the xscom device model I guess. 
> 
> No. If you split the XSCOM bus from the MMIO -> XSCOM bridge (the ADU)
> then the conversion only happens in the former. You don't directly
> route the MMIOs over ! You intercept the MMIOs and use use the
> address_space_rw to "generate" the XSCOM accesses on the other side,
> like I do for the LPC bus.

Oh.. wait.. that is what I had in mind, I think I misinterpreted
something one of you said.

> 
> We need that anyway because of the way XSCOMs can manipulate the HMER
> etc...
> 
> > Also, the main purpose of the XscomBus is to loop on the devices 
> > to populate the device tree. I am wondering if we could just use 
> > a simple list under the chip for that purpose.
> 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07  1:59       ` David Gibson
@ 2016-09-07  5:27         ` Benjamin Herrenschmidt
  2016-09-07  5:46           ` David Gibson
  0 siblings, 1 reply; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-07  5:27 UTC (permalink / raw)
  To: David Gibson, Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Wed, 2016-09-07 at 11:59 +1000, David Gibson wrote:
> 
> That does suggest an alternative approach though.  You could remove
> XScomDevice entirely from QOM existence, and just expose the xscom
> address space globally, much like address_space_memory.  The
> individual devices could just register their own subregions within
> it.
> 
> I'm not sure if the latter is a good idea, though.

Not globally, per chip.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07  5:27         ` Benjamin Herrenschmidt
@ 2016-09-07  5:46           ` David Gibson
  2016-09-07  8:29             ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 62+ messages in thread
From: David Gibson @ 2016-09-07  5:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

[-- Attachment #1: Type: text/plain, Size: 875 bytes --]

On Wed, Sep 07, 2016 at 03:27:46PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2016-09-07 at 11:59 +1000, David Gibson wrote:
> > 
> > That does suggest an alternative approach though.  You could remove
> > XScomDevice entirely from QOM existence, and just expose the xscom
> > address space globally, much like address_space_memory.  The
> > individual devices could just register their own subregions within
> > it.
> > 
> > I'm not sure if the latter is a good idea, though.
> 
> Not globally, per chip.

Right, that's probably better.  Not immediately sure how the
scomdevice would get hold of its chip's scom AS, but we can probably
figure out something.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07  5:46           ` David Gibson
@ 2016-09-07  8:29             ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-07  8:29 UTC (permalink / raw)
  To: David Gibson; +Cc: Cédric Le Goater, qemu-ppc, qemu-devel, Alexander Graf

On Wed, 2016-09-07 at 15:46 +1000, David Gibson wrote:
> Right, that's probably better.  Not immediately sure how the
> scomdevice would get hold of its chip's scom AS, but we can probably
> figure out something.

Passed at instanciation ?

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:47           ` Benjamin Herrenschmidt
  2016-09-06 21:49             ` Benjamin Herrenschmidt
  2016-09-07  2:03             ` David Gibson
@ 2016-09-07 15:47             ` Cédric Le Goater
  2016-09-07 21:53               ` Benjamin Herrenschmidt
  2 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-07 15:47 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/06/2016 11:47 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
>>
>> The change does seem too invasive. I can give it a try in next
>> version.
>>
>> When a memory region is triggered, the impacted device will have
>> to convert the address with xscom_to_pcb_addr(). There is some 
>> dependency on the chip model because the translation is different. 
>> That would be an extra op in the xscom device model I guess. 
> 
> No. If you split the XSCOM bus from the MMIO -> XSCOM bridge (the ADU)
> then the conversion only happens in the former. You don't directly
> route the MMIOs over ! You intercept the MMIOs and use use the
> address_space_rw to "generate" the XSCOM accesses on the other side,
> like I do for the LPC bus.

Yes. That is what I have been experimenting with. The mmio read/write 
ops and the current xscom read/write ops are quite compatible so It
did cost too much to do so : 

+static uint64_t pnv_lpc_xscom_mr_read(void *opaque, hwaddr addr, unsigned size)
+{
+    XScomDevice *xd = XSCOM_DEVICE(opaque);
+    uint64_t val = 0;
+
+    pnv_lpc_xscom_read(xd, 0, xscom_to_pcb_addr(xd->chip_type, addr), &val);
+    return val;
+}
+
+static void pnv_lpc_xscom_mr_write(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    XScomDevice *xd = XSCOM_DEVICE(opaque);
+    pnv_lpc_xscom_write(xd, 0, xscom_to_pcb_addr(xd->chip_type, addr), val);
+}
+
+static const MemoryRegionOps lpc_xscom_mr_ops = {
+    .read = pnv_lpc_xscom_mr_read,
+    .write = pnv_lpc_xscom_mr_write,
+    .valid.min_access_size = 8,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 8,
+    .impl.max_access_size = 8,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
 static void pnv_lpc_realize(DeviceState *dev, Error **errp)
 {
     PnvLpcController *lpc = PNV_LPC_CONTROLLER(dev);
+    XScomBus *bus = XSCOM_BUS(qdev_get_parent_bus(dev));
 
     /* LPC XSCOM address is fixed */
+    memory_region_init_io(&lpc->xd.xscom_mr, OBJECT(dev), &lpc_xscom_mr_ops,
+                          lpc, "lpc-xscom", 4 * 8);
+    memory_region_add_subregion(bus->xscom_mr, 0xb00200, &lpc->xd.xscom_mr);
+
     lpc->xd.ranges[0].addr = 0xb0020;
     lpc->xd.ranges[0].size = 4;


To hack my way through, I have put the address space and the backend 
region under the XscomBus, bc it's easy to capture from the device. 
So that might be a reason to keep this bus/device model.

The xscom_to_pcb_addr() translation should probably done at the upper 
level, at the bridge/ADU level. I think that is what you are asking 
for above. 

As for the mapping, I don't think it should be here. It should be done 
at the chip/bus level which controls the address space, but not in the
devices. 

> We need that anyway because of the way XSCOMs can manipulate the HMER
> etc...

ah. Another thing I need to look at !

Thanks,

C.
 
>> Also, the main purpose of the XscomBus is to loop on the devices 
>> to populate the device tree. I am wondering if we could just use 
>> a simple list under the chip for that purpose.
> 
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:49             ` Benjamin Herrenschmidt
@ 2016-09-07 15:55               ` Cédric Le Goater
  2016-09-07 19:48                 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-07 15:55 UTC (permalink / raw)
  To: benh, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/06/2016 11:49 PM, Benjamin Herrenschmidt wrote:
> On Wed, 2016-09-07 at 07:47 +1000, Benjamin Herrenschmidt wrote:
>> d be an extra op in the xscom device model I guess. 
>>
>> No. If you split the XSCOM bus from the MMIO -> XSCOM bridge (the
>> ADU)
>> then the conversion only happens in the former. You don't directly
>> route the MMIOs over ! You intercept the MMIOs and use use the
>> address_space_rw to "generate" the XSCOM accesses on the other side,
>> like I do for the LPC bus.
>>
>> We need that anyway because of the way XSCOMs can manipulate the HMER
>> etc...
>>
>>>
>>> Also, the main purpose of the XscomBus is to loop on the devices 
>>> to populate the device tree. I am wondering if we could just use 
>>> a simple list under the chip for that purpose.
> 
> In fact, if you do the above, you no longer need a XSCOM device...
> 
> A number of "devices" can exist below a chip, all they need to have
> XSCOMs is to register memory regions that are child of that chip's
> xscom_region.

yes. To hack my way through again, I have added a memory region under
the XScomDevice, but we should have a list like the ranges[] because of 
the PHB3 PCBQs.

> For device-tree, well, we could have a generic interface that anything
> that can populate DT has and iterate through them. Or make a "chiplet"
> class or something.

yes, something like the XScomDeviceClass, which serves well the purpose
anyhow.

Thanks,
C.
 
> Cheers,
> Ben.
> 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-06 21:45       ` Benjamin Herrenschmidt
  2016-09-07  2:02         ` David Gibson
@ 2016-09-07 16:40         ` Cédric Le Goater
  1 sibling, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-07 16:40 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/06/2016 11:45 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2016-09-06 at 16:42 +0200, Cédric Le Goater wrote:
>>> Alternatively.. it might be simpler to just drop the SCOM as a
>>> separate device.  I think you could just hang the scom bus directly
>>> off the chip object.  IIUC the scom is basically the only chip-
>> level
>>> control mechanism, so this does make a certain amount of sense.
>>
>> yes. I am exposing more and more stuff of the chip object under the 
>> xscom object so we should merge them. I agree. We will still need 
>> some XScomDevice of some sort.
> 
> What you can do is split it this way which matches the HW:
> 
>  - The chip object is the XSCOM parent, it owns the XSCOM bus,
> and expose functions (methods) to read/write XSCOMs. WE could rename
> XSCOM to "PIB" or "PCB" which is the real name of the bus ;-) But that
> might confuse things more than help .

Well, "Pervasive" should be mentioned somewhere, it is central to
PowerPC architecture. I will add a comment for the "PIB" (Pervasive 
Interconnect Bus) aka XSCOM bus

>  - A separate ADU object on each chip that is a SysDevice and does the
> MMIO bridge to XSCOM. It decodes the MMIO range for that chip and calls
> the above accessors.

ok. So the ADU is the address space holder. 

> That makes it easy to generate XSCOMs using different mechanisms if we
> wish to do so, which could come in handy, such as monitor commands, 

yes, that will be helpful to trigger some behavior from the command
line.

> or if we ever do cosimulation with a separate BMC, a simulated FSI, 
> all by just calling the first object's methods.

The cosimulation is not a long term goal, for the ipmi-bt part. But 
yes, having a more complete model would be excellent.

Cheers,

C. 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07 15:55               ` Cédric Le Goater
@ 2016-09-07 19:48                 ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-07 19:48 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Wed, 2016-09-07 at 17:55 +0200, Cédric Le Goater wrote:
> 
> yes. To hack my way through again, I have added a memory region under
> the XScomDevice, but we should have a list like the ranges[] because of 
> the PHB3 PCBQs.

You have the parent region in the chip. Then each device can create and attach
memory regions below if it feels like it. No need to have a generic XScomDevice
with a fixed list of regions I think. I mean, you can ... but you don't have to.

> > For device-tree, well, we could have a generic interface that anything
> > that can populate DT has and iterate through them. Or make a "chiplet"
> > class or something.
> 
> yes, something like the XScomDeviceClass, which serves well the purpose
> anyhow.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07 15:47             ` Cédric Le Goater
@ 2016-09-07 21:53               ` Benjamin Herrenschmidt
  2016-09-08  8:52                 ` Cédric Le Goater
  0 siblings, 1 reply; 62+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-07 21:53 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On Wed, 2016-09-07 at 17:47 +0200, Cédric Le Goater wrote:
> 
> +static uint64_t pnv_lpc_xscom_mr_read(void *opaque, hwaddr addr,
> unsigned size)
> +{
> +    XScomDevice *xd = XSCOM_DEVICE(opaque);
> +    uint64_t val = 0;
> +
> +    pnv_lpc_xscom_read(xd, 0, xscom_to_pcb_addr(xd->chip_type,
> addr), &val);
> +    return val;
> +}
> +
> +static void pnv_lpc_xscom_mr_write(void *opaque, hwaddr addr,
> +                                   uint64_t val, unsigned size)
> +{
> +    XScomDevice *xd = XSCOM_DEVICE(opaque);
> +    pnv_lpc_xscom_write(xd, 0, xscom_to_pcb_addr(xd->chip_type,
> addr), val);
> +}
> 

I don't understand. That's not at all why I suggested or I'm missing
something.

What I suggest is that you have a memory region per-chip (which is NOT
hooked onto the main address space) which represents the PCB space.
Calling xscom_region. Hook it up to its own address_space.

Thus, the various devices (LPC, OCC, etc...) all just register a sub-
region of that address space using the PCB addresses directly (well,
shifted left by 3 because it's 8 bytes registers but that's it).

The XSCOM "controller" AKA ADU is the one doing the bridge. It
registers an MMIO region in the main address space (SysBusDevice ?)
and from the MMIO accessors, it does the address mangling, and use
address_space_rw() to trigger accesses onto that chip's xscom_region.

Ben.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure
  2016-09-07 21:53               ` Benjamin Herrenschmidt
@ 2016-09-08  8:52                 ` Cédric Le Goater
  0 siblings, 0 replies; 62+ messages in thread
From: Cédric Le Goater @ 2016-09-08  8:52 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, David Gibson; +Cc: qemu-ppc, qemu-devel, Alexander Graf

On 09/07/2016 11:53 PM, Benjamin Herrenschmidt wrote:
> On Wed, 2016-09-07 at 17:47 +0200, Cédric Le Goater wrote:
>>  
>> +static uint64_t pnv_lpc_xscom_mr_read(void *opaque, hwaddr addr,
>> unsigned size)
>> +{
>> +    XScomDevice *xd = XSCOM_DEVICE(opaque);
>> +    uint64_t val = 0;
>> +
>> +    pnv_lpc_xscom_read(xd, 0, xscom_to_pcb_addr(xd->chip_type,
>> addr), &val);
>> +    return val;
>> +}
>> +
>> +static void pnv_lpc_xscom_mr_write(void *opaque, hwaddr addr,
>> +                                   uint64_t val, unsigned size)
>> +{
>> +    XScomDevice *xd = XSCOM_DEVICE(opaque);
>> +    pnv_lpc_xscom_write(xd, 0, xscom_to_pcb_addr(xd->chip_type,
>> addr), val);
>> +}
>>
> 
> I don't understand. That's not at all why I suggested or I'm missing
> something.

This was a preliminary hack on the full powernv tree to study the 
question. I made the two options cohabitate in the same qemu to see 
what were the issues and possible solutions.

The result is very much what you describe below. I need to start 
from the beginning now, and not the end, to make something cleaner.

> What I suggest is that you have a memory region per-chip (which is NOT
> hooked onto the main address space) which represents the PCB space.
> Calling xscom_region. Hook it up to its own address_space.
>
> Thus, the various devices (LPC, OCC, etc...) all just register a sub-
> region of that address space using the PCB addresses directly (well,
> shifted left by 3 because it's 8 bytes registers but that's it).
> 
> The XSCOM "controller" AKA ADU is the one doing the bridge. It
> registers an MMIO region in the main address space (SysBusDevice ?)
> and from the MMIO accessors, it does the address mangling, and use
> address_space_rw() to trigger accesses onto that chip's xscom_region.

yes. this is what your XSCOM bridge does already.

    name = g_strdup_printf("xscom-%x", s->chip_id);
    memory_region_init_io(&s->mem, OBJECT(s), &xscom_ops, s, name, XSCOM_SIZE);
    sysbus_init_mmio(sbd, &s->mem);
    sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));


Thanks,

C. 

^ permalink raw reply	[flat|nested] 62+ messages in thread

end of thread, other threads:[~2016-09-08  8:52 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-31 16:34 [Qemu-devel] [PATCH v2 0/7] ppc/pnv: add a minimal platform Cédric Le Goater
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 1/7] ppc/pnv: add skeleton PowerNV platform Cédric Le Goater
2016-09-01 16:31   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
2016-09-02  6:32     ` Cédric Le Goater
2016-09-02  6:39       ` Benjamin Herrenschmidt
2016-09-05  2:48   ` [Qemu-devel] " David Gibson
2016-09-05  6:06     ` Cédric Le Goater
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 2/7] ppc/pnv: add a PnvChip object Cédric Le Goater
2016-09-01 17:21   ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
2016-09-02  6:34     ` Cédric Le Goater
2016-09-05  2:58   ` [Qemu-devel] " David Gibson
2016-09-05  6:59     ` Benjamin Herrenschmidt
2016-09-05  7:41       ` Cédric Le Goater
2016-09-05  8:28         ` Benjamin Herrenschmidt
2016-09-06  0:49           ` David Gibson
2016-09-06  6:21             ` Cédric Le Goater
2016-09-05  7:41       ` David Gibson
2016-09-05  9:10         ` Cédric Le Goater
2016-09-06  0:50           ` David Gibson
2016-09-05  7:56     ` Cédric Le Goater
2016-09-06  0:52       ` David Gibson
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 3/7] ppc/pnv: Add XSCOM infrastructure Cédric Le Goater
2016-09-05  3:39   ` David Gibson
2016-09-05  7:11     ` Benjamin Herrenschmidt
2016-09-06  0:48       ` David Gibson
2016-09-06 14:42         ` Cédric Le Goater
2016-09-06 21:47           ` Benjamin Herrenschmidt
2016-09-06 21:49             ` Benjamin Herrenschmidt
2016-09-07 15:55               ` Cédric Le Goater
2016-09-07 19:48                 ` Benjamin Herrenschmidt
2016-09-07  2:03             ` David Gibson
2016-09-07 15:47             ` Cédric Le Goater
2016-09-07 21:53               ` Benjamin Herrenschmidt
2016-09-08  8:52                 ` Cédric Le Goater
2016-09-07  2:01           ` David Gibson
2016-09-06 14:42     ` Cédric Le Goater
2016-09-06 21:45       ` Benjamin Herrenschmidt
2016-09-07  2:02         ` David Gibson
2016-09-07 16:40         ` Cédric Le Goater
2016-09-07  1:59       ` David Gibson
2016-09-07  5:27         ` Benjamin Herrenschmidt
2016-09-07  5:46           ` David Gibson
2016-09-07  8:29             ` Benjamin Herrenschmidt
2016-09-05  4:16   ` [Qemu-devel] [Qemu-ppc] " Sam Bobroff
2016-09-06 14:51     ` Cédric Le Goater
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 4/7] ppc/pnv: add a core mask to PnvChip Cédric Le Goater
2016-09-02  8:03   ` Cédric Le Goater
2016-09-05  3:42   ` David Gibson
2016-09-05 11:13     ` Cédric Le Goater
2016-09-05 11:30       ` Benjamin Herrenschmidt
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 5/7] ppc/pnv: add a PnvCore object Cédric Le Goater
2016-09-05  4:02   ` David Gibson
2016-09-06  6:14     ` Cédric Le Goater
2016-09-07  1:48       ` David Gibson
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 6/7] ppc/pnv: add a XScomDevice to PnvCore Cédric Le Goater
2016-09-05  4:19   ` David Gibson
2016-09-06 13:54     ` Cédric Le Goater
2016-09-07  1:51       ` David Gibson
2016-08-31 16:34 ` [Qemu-devel] [PATCH v2 7/7] monitor: fix crash for platforms without a CPU 0 Cédric Le Goater
2016-09-05  4:27   ` David Gibson
2016-09-06  6:28     ` Cédric Le Goater
2016-09-07  1:49       ` David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.