qemu/hw/pci-host/pnv_phb4_pec.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV (POWER9) PHB4 model
   3 *
   4 * Copyright (c) 2018-2020, IBM Corporation.
   5 *
   6 * This code is licensed under the GPL version 2 or later. See the
   7 * COPYING file in the top-level directory.
   8 */
   9#include "qemu/osdep.h"
  10#include "qapi/error.h"
  11#include "qemu-common.h"
  12#include "qemu/log.h"
  13#include "target/ppc/cpu.h"
  14#include "hw/ppc/fdt.h"
  15#include "hw/pci-host/pnv_phb4_regs.h"
  16#include "hw/pci-host/pnv_phb4.h"
  17#include "hw/ppc/pnv_xscom.h"
  18#include "hw/pci/pci_bridge.h"
  19#include "hw/pci/pci_bus.h"
  20#include "hw/ppc/pnv.h"
  21#include "hw/qdev-properties.h"
  22
  23#include <libfdt.h>
  24
  25#define phb_pec_error(pec, fmt, ...)                                    \
  26    qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n",        \
  27                  (pec)->chip_id, (pec)->index, ## __VA_ARGS__)
  28
  29
  30static uint64_t pnv_pec_nest_xscom_read(void *opaque, hwaddr addr,
  31                                        unsigned size)
  32{
  33    PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  34    uint32_t reg = addr >> 3;
  35
  36    /* TODO: add list of allowed registers and error out if not */
  37    return pec->nest_regs[reg];
  38}
  39
  40static void pnv_pec_nest_xscom_write(void *opaque, hwaddr addr,
  41                                     uint64_t val, unsigned size)
  42{
  43    PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  44    uint32_t reg = addr >> 3;
  45
  46    switch (reg) {
  47    case PEC_NEST_PBCQ_HW_CONFIG:
  48    case PEC_NEST_DROP_PRIO_CTRL:
  49    case PEC_NEST_PBCQ_ERR_INJECT:
  50    case PEC_NEST_PCI_NEST_CLK_TRACE_CTL:
  51    case PEC_NEST_PBCQ_PMON_CTRL:
  52    case PEC_NEST_PBCQ_PBUS_ADDR_EXT:
  53    case PEC_NEST_PBCQ_PRED_VEC_TIMEOUT:
  54    case PEC_NEST_CAPP_CTRL:
  55    case PEC_NEST_PBCQ_READ_STK_OVR:
  56    case PEC_NEST_PBCQ_WRITE_STK_OVR:
  57    case PEC_NEST_PBCQ_STORE_STK_OVR:
  58    case PEC_NEST_PBCQ_RETRY_BKOFF_CTRL:
  59        pec->nest_regs[reg] = val;
  60        break;
  61    default:
  62        phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
  63                      addr, val);
  64    }
  65}
  66
  67static const MemoryRegionOps pnv_pec_nest_xscom_ops = {
  68    .read = pnv_pec_nest_xscom_read,
  69    .write = pnv_pec_nest_xscom_write,
  70    .valid.min_access_size = 8,
  71    .valid.max_access_size = 8,
  72    .impl.min_access_size = 8,
  73    .impl.max_access_size = 8,
  74    .endianness = DEVICE_BIG_ENDIAN,
  75};
  76
  77static uint64_t pnv_pec_pci_xscom_read(void *opaque, hwaddr addr,
  78                                       unsigned size)
  79{
  80    PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  81    uint32_t reg = addr >> 3;
  82
  83    /* TODO: add list of allowed registers and error out if not */
  84    return pec->pci_regs[reg];
  85}
  86
  87static void pnv_pec_pci_xscom_write(void *opaque, hwaddr addr,
  88                                    uint64_t val, unsigned size)
  89{
  90    PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  91    uint32_t reg = addr >> 3;
  92
  93    switch (reg) {
  94    case PEC_PCI_PBAIB_HW_CONFIG:
  95    case PEC_PCI_PBAIB_READ_STK_OVR:
  96        pec->pci_regs[reg] = val;
  97        break;
  98    default:
  99        phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
 100                      addr, val);
 101    }
 102}
 103
 104static const MemoryRegionOps pnv_pec_pci_xscom_ops = {
 105    .read = pnv_pec_pci_xscom_read,
 106    .write = pnv_pec_pci_xscom_write,
 107    .valid.min_access_size = 8,
 108    .valid.max_access_size = 8,
 109    .impl.min_access_size = 8,
 110    .impl.max_access_size = 8,
 111    .endianness = DEVICE_BIG_ENDIAN,
 112};
 113
 114static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr,
 115                                            unsigned size)
 116{
 117    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
 118    uint32_t reg = addr >> 3;
 119
 120    /* TODO: add list of allowed registers and error out if not */
 121    return stack->nest_regs[reg];
 122}
 123
 124static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack)
 125{
 126    PnvPhb4PecState *pec = stack->pec;
 127    MemoryRegion *sysmem = pec->system_memory;
 128    uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN];
 129    uint64_t bar, mask, size;
 130    char name[64];
 131
 132    /*
 133     * NOTE: This will really not work well if those are remapped
 134     * after the PHB has created its sub regions. We could do better
 135     * if we had a way to resize regions but we don't really care
 136     * that much in practice as the stuff below really only happens
 137     * once early during boot
 138     */
 139
 140    /* Handle unmaps */
 141    if (memory_region_is_mapped(&stack->mmbar0) &&
 142        !(bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
 143        memory_region_del_subregion(sysmem, &stack->mmbar0);
 144    }
 145    if (memory_region_is_mapped(&stack->mmbar1) &&
 146        !(bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
 147        memory_region_del_subregion(sysmem, &stack->mmbar1);
 148    }
 149    if (memory_region_is_mapped(&stack->phbbar) &&
 150        !(bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
 151        memory_region_del_subregion(sysmem, &stack->phbbar);
 152    }
 153    if (memory_region_is_mapped(&stack->intbar) &&
 154        !(bar_en & PEC_NEST_STK_BAR_EN_INT)) {
 155        memory_region_del_subregion(sysmem, &stack->intbar);
 156    }
 157
 158    /* Update PHB */
 159    pnv_phb4_update_regions(stack);
 160
 161    /* Handle maps */
 162    if (!memory_region_is_mapped(&stack->mmbar0) &&
 163        (bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
 164        bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0] >> 8;
 165        mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0_MASK];
 166        size = ((~mask) >> 8) + 1;
 167        snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio0",
 168                 pec->chip_id, pec->index, stack->stack_no);
 169        memory_region_init(&stack->mmbar0, OBJECT(stack), name, size);
 170        memory_region_add_subregion(sysmem, bar, &stack->mmbar0);
 171        stack->mmio0_base = bar;
 172        stack->mmio0_size = size;
 173    }
 174    if (!memory_region_is_mapped(&stack->mmbar1) &&
 175        (bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
 176        bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1] >> 8;
 177        mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1_MASK];
 178        size = ((~mask) >> 8) + 1;
 179        snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio1",
 180                 pec->chip_id, pec->index, stack->stack_no);
 181        memory_region_init(&stack->mmbar1, OBJECT(stack), name, size);
 182        memory_region_add_subregion(sysmem, bar, &stack->mmbar1);
 183        stack->mmio1_base = bar;
 184        stack->mmio1_size = size;
 185    }
 186    if (!memory_region_is_mapped(&stack->phbbar) &&
 187        (bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
 188        bar = stack->nest_regs[PEC_NEST_STK_PHB_REGS_BAR] >> 8;
 189        size = PNV_PHB4_NUM_REGS << 3;
 190        snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-phb",
 191                 pec->chip_id, pec->index, stack->stack_no);
 192        memory_region_init(&stack->phbbar, OBJECT(stack), name, size);
 193        memory_region_add_subregion(sysmem, bar, &stack->phbbar);
 194    }
 195    if (!memory_region_is_mapped(&stack->intbar) &&
 196        (bar_en & PEC_NEST_STK_BAR_EN_INT)) {
 197        bar = stack->nest_regs[PEC_NEST_STK_INT_BAR] >> 8;
 198        size = PNV_PHB4_MAX_INTs << 16;
 199        snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-int",
 200                 stack->pec->chip_id, stack->pec->index, stack->stack_no);
 201        memory_region_init(&stack->intbar, OBJECT(stack), name, size);
 202        memory_region_add_subregion(sysmem, bar, &stack->intbar);
 203    }
 204
 205    /* Update PHB */
 206    pnv_phb4_update_regions(stack);
 207}
 208
 209static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
 210                                         uint64_t val, unsigned size)
 211{
 212    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
 213    PnvPhb4PecState *pec = stack->pec;
 214    uint32_t reg = addr >> 3;
 215
 216    switch (reg) {
 217    case PEC_NEST_STK_PCI_NEST_FIR:
 218        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val;
 219        break;
 220    case PEC_NEST_STK_PCI_NEST_FIR_CLR:
 221        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val;
 222        break;
 223    case PEC_NEST_STK_PCI_NEST_FIR_SET:
 224        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val;
 225        break;
 226    case PEC_NEST_STK_PCI_NEST_FIR_MSK:
 227        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val;
 228        break;
 229    case PEC_NEST_STK_PCI_NEST_FIR_MSKC:
 230        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val;
 231        break;
 232    case PEC_NEST_STK_PCI_NEST_FIR_MSKS:
 233        stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] |= val;
 234        break;
 235    case PEC_NEST_STK_PCI_NEST_FIR_ACT0:
 236    case PEC_NEST_STK_PCI_NEST_FIR_ACT1:
 237        stack->nest_regs[reg] = val;
 238        break;
 239    case PEC_NEST_STK_PCI_NEST_FIR_WOF:
 240        stack->nest_regs[reg] = 0;
 241        break;
 242    case PEC_NEST_STK_ERR_REPORT_0:
 243    case PEC_NEST_STK_ERR_REPORT_1:
 244    case PEC_NEST_STK_PBCQ_GNRL_STATUS:
 245        /* Flag error ? */
 246        break;
 247    case PEC_NEST_STK_PBCQ_MODE:
 248        stack->nest_regs[reg] = val & 0xff00000000000000ull;
 249        break;
 250    case PEC_NEST_STK_MMIO_BAR0:
 251    case PEC_NEST_STK_MMIO_BAR0_MASK:
 252    case PEC_NEST_STK_MMIO_BAR1:
 253    case PEC_NEST_STK_MMIO_BAR1_MASK:
 254        if (stack->nest_regs[PEC_NEST_STK_BAR_EN] &
 255            (PEC_NEST_STK_BAR_EN_MMIO0 |
 256             PEC_NEST_STK_BAR_EN_MMIO1)) {
 257            phb_pec_error(pec, "Changing enabled BAR unsupported\n");
 258        }
 259        stack->nest_regs[reg] = val & 0xffffffffff000000ull;
 260        break;
 261    case PEC_NEST_STK_PHB_REGS_BAR:
 262        if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) {
 263            phb_pec_error(pec, "Changing enabled BAR unsupported\n");
 264        }
 265        stack->nest_regs[reg] = val & 0xffffffffffc00000ull;
 266        break;
 267    case PEC_NEST_STK_INT_BAR:
 268        if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) {
 269            phb_pec_error(pec, "Changing enabled BAR unsupported\n");
 270        }
 271        stack->nest_regs[reg] = val & 0xfffffff000000000ull;
 272        break;
 273    case PEC_NEST_STK_BAR_EN:
 274        stack->nest_regs[reg] = val & 0xf000000000000000ull;
 275        pnv_pec_stk_update_map(stack);
 276        break;
 277    case PEC_NEST_STK_DATA_FRZ_TYPE:
 278    case PEC_NEST_STK_PBCQ_TUN_BAR:
 279        /* Not used for now */
 280        stack->nest_regs[reg] = val;
 281        break;
 282    default:
 283        qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx
 284                      "=%"PRIx64"\n", addr, val);
 285    }
 286}
 287
 288static const MemoryRegionOps pnv_pec_stk_nest_xscom_ops = {
 289    .read = pnv_pec_stk_nest_xscom_read,
 290    .write = pnv_pec_stk_nest_xscom_write,
 291    .valid.min_access_size = 8,
 292    .valid.max_access_size = 8,
 293    .impl.min_access_size = 8,
 294    .impl.max_access_size = 8,
 295    .endianness = DEVICE_BIG_ENDIAN,
 296};
 297
 298static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr,
 299                                           unsigned size)
 300{
 301    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
 302    uint32_t reg = addr >> 3;
 303
 304    /* TODO: add list of allowed registers and error out if not */
 305    return stack->pci_regs[reg];
 306}
 307
 308static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
 309                                        uint64_t val, unsigned size)
 310{
 311    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
 312    uint32_t reg = addr >> 3;
 313
 314    switch (reg) {
 315    case PEC_PCI_STK_PCI_FIR:
 316        stack->nest_regs[reg] = val;
 317        break;
 318    case PEC_PCI_STK_PCI_FIR_CLR:
 319        stack->nest_regs[PEC_PCI_STK_PCI_FIR] &= val;
 320        break;
 321    case PEC_PCI_STK_PCI_FIR_SET:
 322        stack->nest_regs[PEC_PCI_STK_PCI_FIR] |= val;
 323        break;
 324    case PEC_PCI_STK_PCI_FIR_MSK:
 325        stack->nest_regs[reg] = val;
 326        break;
 327    case PEC_PCI_STK_PCI_FIR_MSKC:
 328        stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val;
 329        break;
 330    case PEC_PCI_STK_PCI_FIR_MSKS:
 331        stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] |= val;
 332        break;
 333    case PEC_PCI_STK_PCI_FIR_ACT0:
 334    case PEC_PCI_STK_PCI_FIR_ACT1:
 335        stack->nest_regs[reg] = val;
 336        break;
 337    case PEC_PCI_STK_PCI_FIR_WOF:
 338        stack->nest_regs[reg] = 0;
 339        break;
 340    case PEC_PCI_STK_ETU_RESET:
 341        stack->nest_regs[reg] = val & 0x8000000000000000ull;
 342        /* TODO: Implement reset */
 343        break;
 344    case PEC_PCI_STK_PBAIB_ERR_REPORT:
 345        break;
 346    case PEC_PCI_STK_PBAIB_TX_CMD_CRED:
 347    case PEC_PCI_STK_PBAIB_TX_DAT_CRED:
 348        stack->nest_regs[reg] = val;
 349        break;
 350    default:
 351        qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx
 352                      "=%"PRIx64"\n", addr, val);
 353    }
 354}
 355
 356static const MemoryRegionOps pnv_pec_stk_pci_xscom_ops = {
 357    .read = pnv_pec_stk_pci_xscom_read,
 358    .write = pnv_pec_stk_pci_xscom_write,
 359    .valid.min_access_size = 8,
 360    .valid.max_access_size = 8,
 361    .impl.min_access_size = 8,
 362    .impl.max_access_size = 8,
 363    .endianness = DEVICE_BIG_ENDIAN,
 364};
 365
 366static void pnv_pec_instance_init(Object *obj)
 367{
 368    PnvPhb4PecState *pec = PNV_PHB4_PEC(obj);
 369    int i;
 370
 371    for (i = 0; i < PHB4_PEC_MAX_STACKS; i++) {
 372        object_initialize_child(obj, "stack[*]", &pec->stacks[i],
 373                                TYPE_PNV_PHB4_PEC_STACK);
 374    }
 375}
 376
 377static void pnv_pec_realize(DeviceState *dev, Error **errp)
 378{
 379    PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
 380    char name[64];
 381    int i;
 382
 383    assert(pec->system_memory);
 384
 385    /* Create stacks */
 386    for (i = 0; i < pec->num_stacks; i++) {
 387        PnvPhb4PecStack *stack = &pec->stacks[i];
 388        Object *stk_obj = OBJECT(stack);
 389
 390        object_property_set_int(stk_obj, "stack-no", i, &error_abort);
 391        object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort);
 392        if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) {
 393            return;
 394        }
 395    }
 396    for (; i < PHB4_PEC_MAX_STACKS; i++) {
 397        object_unparent(OBJECT(&pec->stacks[i]));
 398    }
 399
 400    /* Initialize the XSCOM regions for the PEC registers */
 401    snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest", pec->chip_id,
 402             pec->index);
 403    pnv_xscom_region_init(&pec->nest_regs_mr, OBJECT(dev),
 404                          &pnv_pec_nest_xscom_ops, pec, name,
 405                          PHB4_PEC_NEST_REGS_COUNT);
 406
 407    snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci", pec->chip_id,
 408             pec->index);
 409    pnv_xscom_region_init(&pec->pci_regs_mr, OBJECT(dev),
 410                          &pnv_pec_pci_xscom_ops, pec, name,
 411                          PHB4_PEC_PCI_REGS_COUNT);
 412}
 413
 414static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
 415                            int xscom_offset)
 416{
 417    PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
 418    PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(dev);
 419    uint32_t nbase = pecc->xscom_nest_base(pec);
 420    uint32_t pbase = pecc->xscom_pci_base(pec);
 421    int offset, i;
 422    char *name;
 423    uint32_t reg[] = {
 424        cpu_to_be32(nbase),
 425        cpu_to_be32(pecc->xscom_nest_size),
 426        cpu_to_be32(pbase),
 427        cpu_to_be32(pecc->xscom_pci_size),
 428    };
 429
 430    name = g_strdup_printf("pbcq@%x", nbase);
 431    offset = fdt_add_subnode(fdt, xscom_offset, name);
 432    _FDT(offset);
 433    g_free(name);
 434
 435    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
 436
 437    _FDT((fdt_setprop_cell(fdt, offset, "ibm,pec-index", pec->index)));
 438    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 1)));
 439    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0)));
 440    _FDT((fdt_setprop(fdt, offset, "compatible", pecc->compat,
 441                      pecc->compat_size)));
 442
 443    for (i = 0; i < pec->num_stacks; i++) {
 444        PnvPhb4PecStack *stack = &pec->stacks[i];
 445        PnvPHB4 *phb = &stack->phb;
 446        int stk_offset;
 447
 448        name = g_strdup_printf("stack@%x", i);
 449        stk_offset = fdt_add_subnode(fdt, offset, name);
 450        _FDT(stk_offset);
 451        g_free(name);
 452        _FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat,
 453                          pecc->stk_compat_size)));
 454        _FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i)));
 455        _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb->phb_id)));
 456    }
 457
 458    return 0;
 459}
 460
 461static Property pnv_pec_properties[] = {
 462        DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
 463        DEFINE_PROP_UINT32("num-stacks", PnvPhb4PecState, num_stacks, 0),
 464        DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
 465        DEFINE_PROP_LINK("system-memory", PnvPhb4PecState, system_memory,
 466                     TYPE_MEMORY_REGION, MemoryRegion *),
 467        DEFINE_PROP_END_OF_LIST(),
 468};
 469
 470static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec)
 471{
 472    return PNV9_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
 473}
 474
 475static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
 476{
 477    return PNV9_XSCOM_PEC_NEST_BASE + 0x400 * pec->index;
 478}
 479
 480static void pnv_pec_class_init(ObjectClass *klass, void *data)
 481{
 482    DeviceClass *dc = DEVICE_CLASS(klass);
 483    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
 484    PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
 485    static const char compat[] = "ibm,power9-pbcq";
 486    static const char stk_compat[] = "ibm,power9-phb-stack";
 487
 488    xdc->dt_xscom = pnv_pec_dt_xscom;
 489
 490    dc->realize = pnv_pec_realize;
 491    device_class_set_props(dc, pnv_pec_properties);
 492    dc->user_creatable = false;
 493
 494    pecc->xscom_nest_base = pnv_pec_xscom_nest_base;
 495    pecc->xscom_pci_base  = pnv_pec_xscom_pci_base;
 496    pecc->xscom_nest_size = PNV9_XSCOM_PEC_NEST_SIZE;
 497    pecc->xscom_pci_size  = PNV9_XSCOM_PEC_PCI_SIZE;
 498    pecc->compat = compat;
 499    pecc->compat_size = sizeof(compat);
 500    pecc->stk_compat = stk_compat;
 501    pecc->stk_compat_size = sizeof(stk_compat);
 502}
 503
 504static const TypeInfo pnv_pec_type_info = {
 505    .name          = TYPE_PNV_PHB4_PEC,
 506    .parent        = TYPE_DEVICE,
 507    .instance_size = sizeof(PnvPhb4PecState),
 508    .instance_init = pnv_pec_instance_init,
 509    .class_init    = pnv_pec_class_init,
 510    .class_size    = sizeof(PnvPhb4PecClass),
 511    .interfaces    = (InterfaceInfo[]) {
 512        { TYPE_PNV_XSCOM_INTERFACE },
 513        { }
 514    }
 515};
 516
 517static void pnv_pec_stk_instance_init(Object *obj)
 518{
 519    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj);
 520
 521    object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4);
 522}
 523
 524static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
 525{
 526    PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev);
 527    PnvPhb4PecState *pec = stack->pec;
 528    char name[64];
 529
 530    assert(pec);
 531
 532    /* Initialize the XSCOM regions for the stack registers */
 533    snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest-stack-%d",
 534             pec->chip_id, pec->index, stack->stack_no);
 535    pnv_xscom_region_init(&stack->nest_regs_mr, OBJECT(stack),
 536                          &pnv_pec_stk_nest_xscom_ops, stack, name,
 537                          PHB4_PEC_NEST_STK_REGS_COUNT);
 538
 539    snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d",
 540             pec->chip_id, pec->index, stack->stack_no);
 541    pnv_xscom_region_init(&stack->pci_regs_mr, OBJECT(stack),
 542                          &pnv_pec_stk_pci_xscom_ops, stack, name,
 543                          PHB4_PEC_PCI_STK_REGS_COUNT);
 544
 545    /* PHB pass-through */
 546    snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d-phb",
 547             pec->chip_id, pec->index, stack->stack_no);
 548    pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(&stack->phb),
 549                          &pnv_phb4_xscom_ops, &stack->phb, name, 0x40);
 550
 551    /*
 552     * Let the machine/chip realize the PHB object to customize more
 553     * easily some fields
 554     */
 555}
 556
 557static Property pnv_pec_stk_properties[] = {
 558        DEFINE_PROP_UINT32("stack-no", PnvPhb4PecStack, stack_no, 0),
 559        DEFINE_PROP_LINK("pec", PnvPhb4PecStack, pec, TYPE_PNV_PHB4_PEC,
 560                         PnvPhb4PecState *),
 561        DEFINE_PROP_END_OF_LIST(),
 562};
 563
 564static void pnv_pec_stk_class_init(ObjectClass *klass, void *data)
 565{
 566    DeviceClass *dc = DEVICE_CLASS(klass);
 567
 568    device_class_set_props(dc, pnv_pec_stk_properties);
 569    dc->realize = pnv_pec_stk_realize;
 570    dc->user_creatable = false;
 571
 572    /* TODO: reset regs ? */
 573}
 574
 575static const TypeInfo pnv_pec_stk_type_info = {
 576    .name          = TYPE_PNV_PHB4_PEC_STACK,
 577    .parent        = TYPE_DEVICE,
 578    .instance_size = sizeof(PnvPhb4PecStack),
 579    .instance_init = pnv_pec_stk_instance_init,
 580    .class_init    = pnv_pec_stk_class_init,
 581    .interfaces    = (InterfaceInfo[]) {
 582        { TYPE_PNV_XSCOM_INTERFACE },
 583        { }
 584    }
 585};
 586
 587static void pnv_pec_register_types(void)
 588{
 589    type_register_static(&pnv_pec_type_info);
 590    type_register_static(&pnv_pec_stk_type_info);
 591}
 592
 593type_init(pnv_pec_register_types);
 594