Commit c52e53f4 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.0-20180622' into staging



ppc patch queue 2018-06-22

Another assorted patch of patches for ppc and spapr.
    * Rework of guest pagesize handling for ppc, which avoids guest
      visibly different behaviour between accelerators
    * A number of Pnv cleanups, working towards more complete POWER9
      support
    * Migration of VPA data, a significant bugfix

# gpg: Signature made Fri 22 Jun 2018 05:23:16 BST
# gpg:                using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-3.0-20180622: (23 commits)
  spapr: Don't rewrite mmu capabilities in KVM mode
  spapr: Limit available pagesizes to provide a consistent guest environment
  target/ppc: Add ppc_hash64_filter_pagesizes()
  spapr: Use maximum page size capability to simplify memory backend checking
  spapr: Maximum (HPT) pagesize property
  pseries: Update SLOF firmware image to qemu-slof-20180621
  target/ppc: Add missing opcode for icbt on PPC440
  ppc4xx_i2c: Implement directcntl register
  ppc4xx_i2c: Remove unimplemented sdata and intr registers
  sm501: Fix hardware cursor color conversion
  fpu_helper.c: fix helper_fpscr_clrbit() function
  spapr: remove unused spapr_irq routines
  spapr: split the IRQ allocation sequence
  target/ppc: Add kvmppc_hpt_needs_host_contiguous_pages() helper
  spapr: Add cpu_apply hook to capabilities
  spapr: Compute effective capability values earlier
  target/ppc: Allow cpu compatiblity checks based on type, not instance
  ppc/pnv: consolidate the creation of the ISA bus device tree
  ppc/pnv: introduce Pnv8Chip and Pnv9Chip models
  spapr_cpu_core: migrate VPA related state
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 45eb6fb6 e5ca28ec
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
CONFIG_BITBANG_I2C=y

# For Macs
CONFIG_MAC=y
+1 −0
Original line number Diff line number Diff line
@@ -19,3 +19,4 @@ CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
CONFIG_BITBANG_I2C=y
+3 −3
Original line number Diff line number Diff line
@@ -652,9 +652,9 @@ static inline void get_hwc_palette(SM501State *state, int crt, uint8_t *palette)
        } else {
            rgb565 = color_reg & 0xFFFF;
        }
        palette[i * 3 + 0] = (rgb565 << 3) & 0xf8; /* red */
        palette[i * 3 + 1] = (rgb565 >> 3) & 0xfc; /* green */
        palette[i * 3 + 2] = (rgb565 >> 8) & 0xf8; /* blue */
        palette[i * 3 + 0] = ((rgb565 >> 11) * 527 + 23) >> 6; /* r */
        palette[i * 3 + 1] = (((rgb565 >> 5) & 0x3f) * 259 + 33) >> 6; /* g */
        palette[i * 3 + 2] = ((rgb565 & 0x1f) * 527 + 23) >> 6; /* b */
    }
}

+14 −16
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 *
 * Copyright (c) 2007 Jocelyn Mayer
 * Copyright (c) 2012 François Revol
 * Copyright (c) 2016 BALATON Zoltan
 * Copyright (c) 2016-2018 BALATON Zoltan
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
@@ -30,6 +30,7 @@
#include "cpu.h"
#include "hw/hw.h"
#include "hw/i2c/ppc4xx_i2c.h"
#include "bitbang_i2c.h"

#define PPC4xx_I2C_MEM_SIZE 18

@@ -46,6 +47,11 @@

#define IIC_XTCNTLSS_SRST   (1 << 0)

#define IIC_DIRECTCNTL_SDAC (1 << 3)
#define IIC_DIRECTCNTL_SCLC (1 << 2)
#define IIC_DIRECTCNTL_MSDA (1 << 1)
#define IIC_DIRECTCNTL_MSCL (1 << 0)

static void ppc4xx_i2c_reset(DeviceState *s)
{
    PPC4xxI2CState *i2c = PPC4xx_I2C(s);
@@ -63,7 +69,6 @@ static void ppc4xx_i2c_reset(DeviceState *s)
    i2c->mdcntl = 0;
    i2c->sts = 0;
    i2c->extsts = 0x8f;
    i2c->sdata = 0;
    i2c->lsadr = 0;
    i2c->hsadr = 0;
    i2c->clkdiv = 0;
@@ -71,7 +76,6 @@ static void ppc4xx_i2c_reset(DeviceState *s)
    i2c->xfrcnt = 0;
    i2c->xtcntlss = 0;
    i2c->directcntl = 0xf;
    i2c->intr = 0;
}

static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c)
@@ -139,9 +143,6 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
                          TYPE_PPC4xx_I2C, __func__);
        }
        break;
    case 2:
        ret = i2c->sdata;
        break;
    case 4:
        ret = i2c->lmadr;
        break;
@@ -181,9 +182,6 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
    case 16:
        ret = i2c->directcntl;
        break;
    case 17:
        ret = i2c->intr;
        break;
    default:
        if (addr < PPC4xx_I2C_MEM_SIZE) {
            qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register 0x%"
@@ -229,9 +227,6 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
            }
        }
        break;
    case 2:
        i2c->sdata = value;
        break;
    case 4:
        i2c->lmadr = value;
        if (i2c_bus_busy(i2c->bus)) {
@@ -300,10 +295,12 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
        i2c->xtcntlss = value;
        break;
    case 16:
        i2c->directcntl = value & 0x7;
        break;
    case 17:
        i2c->intr = value;
        i2c->directcntl = value & (IIC_DIRECTCNTL_SDAC & IIC_DIRECTCNTL_SCLC);
        i2c->directcntl |= (value & IIC_DIRECTCNTL_SCLC ? 1 : 0);
        bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SCL,
                        i2c->directcntl & IIC_DIRECTCNTL_MSCL);
        i2c->directcntl |= bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SDA,
                               (value & IIC_DIRECTCNTL_SDAC) != 0) << 1;
        break;
    default:
        if (addr < PPC4xx_I2C_MEM_SIZE) {
@@ -336,6 +333,7 @@ static void ppc4xx_i2c_init(Object *o)
    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
    s->bus = i2c_init_bus(DEVICE(s), "i2c");
    s->bitbang = bitbang_i2c_init(s->bus);
}

static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
+238 −145
Original line number Diff line number Diff line
@@ -265,18 +265,6 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
    g_free(reg);
}

static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
{
    char *name;
    int offset;

    name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
                           (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
    offset = fdt_path_offset(fdt, name);
    g_free(name);
    return offset;
}

static void pnv_dt_chip(PnvChip *chip, void *fdt)
{
    const char *typename = pnv_chip_core_typename(chip);
@@ -285,16 +273,6 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt)

    pnv_dt_xscom(chip, fdt, 0);

    /* The default LPC bus of a multichip system is on chip 0. It's
     * recognized by the firmware (skiboot) using a "primary"
     * property.
     */
    if (chip->chip_id == 0x0) {
        int lpc_offset = pnv_chip_lpc_offset(chip, fdt);

        _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
    }

    for (i = 0; i < chip->nr_cores; i++) {
        PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);

@@ -418,16 +396,35 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
    return 0;
}

static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset)
static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
{
    char *name;
    int offset;

    name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
                           (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
    offset = fdt_path_offset(fdt, name);
    g_free(name);
    return offset;
}

/* The default LPC bus of a multichip system is on chip 0. It's
 * recognized by the firmware (skiboot) using a "primary" property.
 */
static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
{
    int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
    ForeachPopulateArgs args = {
        .fdt = fdt,
        .offset = lpc_offset,
        .offset = isa_offset,
    };

    _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));

    /* ISA devices are not necessarily parented to the ISA bus so we
     * can not use object_child_foreach() */
    qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args);
    qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
                       &args);
}

static void *pnv_dt_create(MachineState *machine)
@@ -438,7 +435,6 @@ static void *pnv_dt_create(MachineState *machine)
    char *buf;
    int off;
    int i;
    int lpc_offset;

    fdt = g_malloc0(FDT_MAX_SIZE);
    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
@@ -480,8 +476,7 @@ static void *pnv_dt_create(MachineState *machine)
    }

    /* Populate ISA devices on chip 0 */
    lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
    pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset);
    pnv_dt_isa(pnv, fdt);

    if (pnv->bmc) {
        pnv_dt_bmc_sensors(pnv->bmc, fdt);
@@ -529,24 +524,26 @@ static void pnv_reset(void)
    cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
}

static ISABus *pnv_isa_create(PnvChip *chip)
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
{
    PnvLpcController *lpc = &chip->lpc;
    ISABus *isa_bus;
    qemu_irq *irqs;
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
    Pnv8Chip *chip8 = PNV8_CHIP(chip);
    return pnv_lpc_isa_create(&chip8->lpc, true, errp);
}

    /* let isa_bus_new() create its own bridge on SysBus otherwise
     * devices speficied on the command line won't find the bus and
     * will fail to create.
     */
    isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
                          &error_fatal);
static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
{
    Pnv8Chip *chip8 = PNV8_CHIP(chip);
    return pnv_lpc_isa_create(&chip8->lpc, false, errp);
}

    irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
{
    return NULL;
}

    isa_bus_irqs(isa_bus, irqs);
    return isa_bus;
static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
{
    return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
}

static void pnv_init(MachineState *machine)
@@ -646,7 +643,7 @@ static void pnv_init(MachineState *machine)
    g_free(chip_typename);

    /* Instantiate ISA bus on chip 0 */
    pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
    pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);

    /* Create serial port */
    serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
@@ -671,6 +668,13 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
    return (chip->chip_id << 7) | (core_id << 3);
}

static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child,
                                           Error **errp)
{
    return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
                      errp);
}

/*
 *    0:48  Reserved - Read as zeroes
 *   49:52  Node ID
@@ -686,6 +690,12 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
    return (chip->chip_id << 8) | (core_id << 2);
}

static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child,
                                           Error **errp)
{
    return NULL;
}

/* Allowed core identifiers on a POWER8 Processor Chip :
 *
 * <EX0 reserved>
@@ -712,6 +722,103 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
 */
#define POWER9_CORE_MASK   (0xffffffffffffffull)

static void pnv_chip_power8_instance_init(Object *obj)
{
    Pnv8Chip *chip8 = PNV8_CHIP(obj);

    object_initialize(&chip8->psi, sizeof(chip8->psi), TYPE_PNV_PSI);
    object_property_add_child(obj, "psi", OBJECT(&chip8->psi), NULL);
    object_property_add_const_link(OBJECT(&chip8->psi), "xics",
                                   OBJECT(qdev_get_machine()), &error_abort);

    object_initialize(&chip8->lpc, sizeof(chip8->lpc), TYPE_PNV_LPC);
    object_property_add_child(obj, "lpc", OBJECT(&chip8->lpc), NULL);
    object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
                                   OBJECT(&chip8->psi), &error_abort);

    object_initialize(&chip8->occ, sizeof(chip8->occ), TYPE_PNV_OCC);
    object_property_add_child(obj, "occ", OBJECT(&chip8->occ), NULL);
    object_property_add_const_link(OBJECT(&chip8->occ), "psi",
                                   OBJECT(&chip8->psi), &error_abort);
}

static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
 {
    PnvChip *chip = PNV_CHIP(chip8);
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
    const char *typename = pnv_chip_core_typename(chip);
    size_t typesize = object_type_get_instance_size(typename);
    int i, j;
    char *name;
    XICSFabric *xi = XICS_FABRIC(qdev_get_machine());

    name = g_strdup_printf("icp-%x", chip->chip_id);
    memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
    sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
    g_free(name);

    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));

    /* Map the ICP registers for each thread */
    for (i = 0; i < chip->nr_cores; i++) {
        PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
        int core_hwid = CPU_CORE(pnv_core)->core_id;

        for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
            uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
            PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));

            memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
                                        &icp->mmio);
        }
    }
}

static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
{
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
    PnvChip *chip = PNV_CHIP(dev);
    Pnv8Chip *chip8 = PNV8_CHIP(dev);
    Error *local_err = NULL;

    pcc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    /* Processor Service Interface (PSI) Host Bridge */
    object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
                            "bar", &error_fatal);
    object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);

    /* Create LPC controller */
    object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
                             &error_fatal);
    pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);

    /* Interrupt Management Area. This is the memory region holding
     * all the Interrupt Control Presenter (ICP) registers */
    pnv_chip_icp_realize(chip8, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    /* Create the simplified OCC model */
    object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
}

static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
@@ -721,8 +828,13 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
    k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
    k->cores_mask = POWER8E_CORE_MASK;
    k->core_pir = pnv_chip_core_pir_p8;
    k->intc_create = pnv_chip_power8_intc_create;
    k->isa_create = pnv_chip_power8_isa_create;
    k->xscom_base = 0x003fc0000000000ull;
    dc->desc = "PowerNV Chip POWER8E";

    device_class_set_parent_realize(dc, pnv_chip_power8_realize,
                                    &k->parent_realize);
}

static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
@@ -734,8 +846,13 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
    k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
    k->cores_mask = POWER8_CORE_MASK;
    k->core_pir = pnv_chip_core_pir_p8;
    k->intc_create = pnv_chip_power8_intc_create;
    k->isa_create = pnv_chip_power8_isa_create;
    k->xscom_base = 0x003fc0000000000ull;
    dc->desc = "PowerNV Chip POWER8";

    device_class_set_parent_realize(dc, pnv_chip_power8_realize,
                                    &k->parent_realize);
}

static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
@@ -747,8 +864,29 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
    k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
    k->cores_mask = POWER8_CORE_MASK;
    k->core_pir = pnv_chip_core_pir_p8;
    k->intc_create = pnv_chip_power8_intc_create;
    k->isa_create = pnv_chip_power8nvl_isa_create;
    k->xscom_base = 0x003fc0000000000ull;
    dc->desc = "PowerNV Chip POWER8NVL";

    device_class_set_parent_realize(dc, pnv_chip_power8_realize,
                                    &k->parent_realize);
}

static void pnv_chip_power9_instance_init(Object *obj)
{
}

static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
{
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
    Error *local_err = NULL;

    pcc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
}

static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
@@ -760,8 +898,13 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
    k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
    k->cores_mask = POWER9_CORE_MASK;
    k->core_pir = pnv_chip_core_pir_p9;
    k->intc_create = pnv_chip_power9_intc_create;
    k->isa_create = pnv_chip_power9_isa_create;
    k->xscom_base = 0x00603fc00000000ull;
    dc->desc = "PowerNV Chip POWER9";

    device_class_set_parent_realize(dc, pnv_chip_power9_realize,
                                    &k->parent_realize);
}

static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
@@ -794,59 +937,9 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
    }
}

static void pnv_chip_init(Object *obj)
{
    PnvChip *chip = PNV_CHIP(obj);
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);

    chip->xscom_base = pcc->xscom_base;

    object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
    object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);

    object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
    object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
    object_property_add_const_link(OBJECT(&chip->psi), "xics",
                                   OBJECT(qdev_get_machine()), &error_abort);

    object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
    object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
    object_property_add_const_link(OBJECT(&chip->occ), "psi",
                                   OBJECT(&chip->psi), &error_abort);

    /* The LPC controller needs PSI to generate interrupts */
    object_property_add_const_link(OBJECT(&chip->lpc), "psi",
                                   OBJECT(&chip->psi), &error_abort);
}

static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
static void pnv_chip_instance_init(Object *obj)
{
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
    const char *typename = pnv_chip_core_typename(chip);
    size_t typesize = object_type_get_instance_size(typename);
    int i, j;
    char *name;
    XICSFabric *xi = XICS_FABRIC(qdev_get_machine());

    name = g_strdup_printf("icp-%x", chip->chip_id);
    memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
    sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
    g_free(name);

    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));

    /* Map the ICP registers for each thread */
    for (i = 0; i < chip->nr_cores; i++) {
        PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
        int core_hwid = CPU_CORE(pnv_core)->core_id;

        for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
            uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
            PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));

            memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
        }
    }
    PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
}

static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
@@ -892,8 +985,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
        object_property_set_int(OBJECT(pnv_core),
                                pcc->core_pir(chip, core_hwid),
                                "pir", &error_fatal);
        object_property_add_const_link(OBJECT(pnv_core), "xics",
                                       qdev_get_machine(), &error_fatal);
        object_property_add_const_link(OBJECT(pnv_core), "chip",
                                       OBJECT(chip), &error_fatal);
        object_property_set_bool(OBJECT(pnv_core), true, "realized",
                                 &error_fatal);
        object_unref(OBJECT(pnv_core));
@@ -930,37 +1023,6 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
        error_propagate(errp, error);
        return;
    }

    /* Create LPC controller */
    object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
                             &error_fatal);
    pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);

    /* Interrupt Management Area. This is the memory region holding
     * all the Interrupt Control Presenter (ICP) registers */
    pnv_chip_icp_realize(chip, &error);
    if (error) {
        error_propagate(errp, error);
        return;
    }

    /* Processor Service Interface (PSI) Host Bridge */
    object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
                            "bar", &error_fatal);
    object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
    if (error) {
        error_propagate(errp, error);
        return;
    }
    pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);

    /* Create the simplified OCC model */
    object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
    if (error) {
        error_propagate(errp, error);
        return;
    }
    pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
}

static Property pnv_chip_properties[] = {
@@ -988,8 +1050,10 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
    int i;

    for (i = 0; i < pnv->num_chips; i++) {
        if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
            return &pnv->chips[i]->psi.ics;
        Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);

        if (ics_valid_irq(&chip8->psi.ics, irq)) {
            return &chip8->psi.ics;
        }
    }
    return NULL;
@@ -1001,7 +1065,8 @@ static void pnv_ics_resend(XICSFabric *xi)
    int i;

    for (i = 0; i < pnv->num_chips; i++) {
        ics_resend(&pnv->chips[i]->psi.ics);
        Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
        ics_resend(&chip8->psi.ics);
    }
}

@@ -1042,7 +1107,8 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
    }

    for (i = 0; i < pnv->num_chips; i++) {
        ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
        Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
        ics_pic_print_info(&chip8->psi.ics, mon);
    }
}

@@ -1077,7 +1143,7 @@ static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
    pnv->num_chips = num_chips;
}

static void pnv_machine_initfn(Object *obj)
static void pnv_machine_instance_init(Object *obj)
{
    PnvMachineState *pnv = PNV_MACHINE(obj);
    pnv->num_chips = 1;
@@ -1117,11 +1183,18 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
    pnv_machine_class_props_init(oc);
}

#define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \
#define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
    {                                             \
        .name          = type,                    \
        .class_init    = class_initfn,            \
        .parent        = TYPE_PNV_CHIP,          \
        .parent        = TYPE_PNV8_CHIP,          \
    }

#define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
    {                                             \
        .name          = type,                    \
        .class_init    = class_initfn,            \
        .parent        = TYPE_PNV9_CHIP,          \
    }

static const TypeInfo types[] = {
@@ -1129,7 +1202,7 @@ static const TypeInfo types[] = {
        .name          = TYPE_PNV_MACHINE,
        .parent        = TYPE_MACHINE,
        .instance_size = sizeof(PnvMachineState),
        .instance_init = pnv_machine_initfn,
        .instance_init = pnv_machine_instance_init,
        .class_init    = pnv_machine_class_init,
        .interfaces = (InterfaceInfo[]) {
            { TYPE_XICS_FABRIC },
@@ -1141,15 +1214,35 @@ static const TypeInfo types[] = {
        .name          = TYPE_PNV_CHIP,
        .parent        = TYPE_SYS_BUS_DEVICE,
        .class_init    = pnv_chip_class_init,
        .instance_init = pnv_chip_init,
        .instance_init = pnv_chip_instance_init,
        .instance_size = sizeof(PnvChip),
        .class_size    = sizeof(PnvChipClass),
        .abstract      = true,
    },
    DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
    DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
    DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
    DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,

    /*
     * P9 chip and variants
     */
    {
        .name          = TYPE_PNV9_CHIP,
        .parent        = TYPE_PNV_CHIP,
        .instance_init = pnv_chip_power9_instance_init,
        .instance_size = sizeof(Pnv9Chip),
    },
    DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),

    /*
     * P8 chip and variants
     */
    {
        .name          = TYPE_PNV8_CHIP,
        .parent        = TYPE_PNV_CHIP,
        .instance_init = pnv_chip_power8_instance_init,
        .instance_size = sizeof(Pnv8Chip),
    },
    DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
    DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
    DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
                          pnv_chip_power8nvl_class_init),
};

Loading