qemu/hw/pci-host/pnv_phb3_pbcq.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV (POWER8) PHB3 model
   3 *
   4 * Copyright (c) 2014-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_phb3_regs.h"
  16#include "hw/pci-host/pnv_phb3.h"
  17#include "hw/ppc/pnv.h"
  18#include "hw/ppc/pnv_xscom.h"
  19#include "hw/pci/pci_bridge.h"
  20#include "hw/pci/pci_bus.h"
  21
  22#include <libfdt.h>
  23
  24#define phb3_pbcq_error(pbcq, fmt, ...)                                 \
  25    qemu_log_mask(LOG_GUEST_ERROR, "phb3_pbcq[%d:%d]: " fmt "\n",       \
  26                  (pbcq)->phb->chip_id, (pbcq)->phb->phb_id, ## __VA_ARGS__)
  27
  28static uint64_t pnv_pbcq_nest_xscom_read(void *opaque, hwaddr addr,
  29                                         unsigned size)
  30{
  31    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  32    uint32_t offset = addr >> 3;
  33
  34    return pbcq->nest_regs[offset];
  35}
  36
  37static uint64_t pnv_pbcq_pci_xscom_read(void *opaque, hwaddr addr,
  38                                        unsigned size)
  39{
  40    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  41    uint32_t offset = addr >> 3;
  42
  43    return pbcq->pci_regs[offset];
  44}
  45
  46static uint64_t pnv_pbcq_spci_xscom_read(void *opaque, hwaddr addr,
  47                                         unsigned size)
  48{
  49    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  50    uint32_t offset = addr >> 3;
  51
  52    if (offset == PBCQ_SPCI_ASB_DATA) {
  53        return pnv_phb3_reg_read(pbcq->phb,
  54                                 pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR], 8);
  55    }
  56    return pbcq->spci_regs[offset];
  57}
  58
  59static void pnv_pbcq_update_map(PnvPBCQState *pbcq)
  60{
  61    uint64_t bar_en = pbcq->nest_regs[PBCQ_NEST_BAR_EN];
  62    uint64_t bar, mask, size;
  63
  64    /*
  65     * NOTE: This will really not work well if those are remapped
  66     * after the PHB has created its sub regions. We could do better
  67     * if we had a way to resize regions but we don't really care
  68     * that much in practice as the stuff below really only happens
  69     * once early during boot
  70     */
  71
  72    /* Handle unmaps */
  73    if (memory_region_is_mapped(&pbcq->mmbar0) &&
  74        !(bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
  75        memory_region_del_subregion(get_system_memory(), &pbcq->mmbar0);
  76    }
  77    if (memory_region_is_mapped(&pbcq->mmbar1) &&
  78        !(bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
  79        memory_region_del_subregion(get_system_memory(), &pbcq->mmbar1);
  80    }
  81    if (memory_region_is_mapped(&pbcq->phbbar) &&
  82        !(bar_en & PBCQ_NEST_BAR_EN_PHB)) {
  83        memory_region_del_subregion(get_system_memory(), &pbcq->phbbar);
  84    }
  85
  86    /* Update PHB */
  87    pnv_phb3_update_regions(pbcq->phb);
  88
  89    /* Handle maps */
  90    if (!memory_region_is_mapped(&pbcq->mmbar0) &&
  91        (bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
  92        bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] >> 14;
  93        mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0];
  94        size = ((~mask) >> 14) + 1;
  95        memory_region_init(&pbcq->mmbar0, OBJECT(pbcq), "pbcq-mmio0", size);
  96        memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar0);
  97        pbcq->mmio0_base = bar;
  98        pbcq->mmio0_size = size;
  99    }
 100    if (!memory_region_is_mapped(&pbcq->mmbar1) &&
 101        (bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
 102        bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] >> 14;
 103        mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1];
 104        size = ((~mask) >> 14) + 1;
 105        memory_region_init(&pbcq->mmbar1, OBJECT(pbcq), "pbcq-mmio1", size);
 106        memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar1);
 107        pbcq->mmio1_base = bar;
 108        pbcq->mmio1_size = size;
 109    }
 110    if (!memory_region_is_mapped(&pbcq->phbbar)
 111        && (bar_en & PBCQ_NEST_BAR_EN_PHB)) {
 112        bar = pbcq->nest_regs[PBCQ_NEST_PHB_BAR] >> 14;
 113        size = 0x1000;
 114        memory_region_init(&pbcq->phbbar, OBJECT(pbcq), "pbcq-phb", size);
 115        memory_region_add_subregion(get_system_memory(), bar, &pbcq->phbbar);
 116    }
 117
 118    /* Update PHB */
 119    pnv_phb3_update_regions(pbcq->phb);
 120}
 121
 122static void pnv_pbcq_nest_xscom_write(void *opaque, hwaddr addr,
 123                                uint64_t val, unsigned size)
 124{
 125    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
 126    uint32_t reg = addr >> 3;
 127
 128    switch (reg) {
 129    case PBCQ_NEST_MMIO_BAR0:
 130    case PBCQ_NEST_MMIO_BAR1:
 131    case PBCQ_NEST_MMIO_MASK0:
 132    case PBCQ_NEST_MMIO_MASK1:
 133        if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] &
 134            (PBCQ_NEST_BAR_EN_MMIO0 |
 135             PBCQ_NEST_BAR_EN_MMIO1)) {
 136            phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
 137        }
 138        pbcq->nest_regs[reg] = val & 0xffffffffc0000000ull;
 139        break;
 140    case PBCQ_NEST_PHB_BAR:
 141        if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] & PBCQ_NEST_BAR_EN_PHB) {
 142            phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
 143        }
 144        pbcq->nest_regs[reg] = val & 0xfffffffffc000000ull;
 145        break;
 146    case PBCQ_NEST_BAR_EN:
 147        pbcq->nest_regs[reg] = val & 0xf800000000000000ull;
 148        pnv_pbcq_update_map(pbcq);
 149        pnv_phb3_remap_irqs(pbcq->phb);
 150        break;
 151    case PBCQ_NEST_IRSN_COMPARE:
 152    case PBCQ_NEST_IRSN_MASK:
 153        pbcq->nest_regs[reg] = val & PBCQ_NEST_IRSN_COMP;
 154        pnv_phb3_remap_irqs(pbcq->phb);
 155        break;
 156    case PBCQ_NEST_LSI_SRC_ID:
 157        pbcq->nest_regs[reg] = val & PBCQ_NEST_LSI_SRC;
 158        pnv_phb3_remap_irqs(pbcq->phb);
 159        break;
 160    default:
 161        phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
 162                        addr, val);
 163    }
 164}
 165
 166static void pnv_pbcq_pci_xscom_write(void *opaque, hwaddr addr,
 167                                     uint64_t val, unsigned size)
 168{
 169    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
 170    uint32_t reg = addr >> 3;
 171
 172    switch (reg) {
 173    case PBCQ_PCI_BAR2:
 174        pbcq->pci_regs[reg] = val & 0xfffffffffc000000ull;
 175        pnv_pbcq_update_map(pbcq);
 176        break;
 177    default:
 178        phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
 179                        addr, val);
 180    }
 181}
 182
 183static void pnv_pbcq_spci_xscom_write(void *opaque, hwaddr addr,
 184                                uint64_t val, unsigned size)
 185{
 186    PnvPBCQState *pbcq = PNV_PBCQ(opaque);
 187    uint32_t reg = addr >> 3;
 188
 189    switch (reg) {
 190    case PBCQ_SPCI_ASB_ADDR:
 191        pbcq->spci_regs[reg] = val & 0xfff;
 192        break;
 193    case PBCQ_SPCI_ASB_STATUS:
 194        pbcq->spci_regs[reg] &= ~val;
 195        break;
 196    case PBCQ_SPCI_ASB_DATA:
 197        pnv_phb3_reg_write(pbcq->phb, pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR],
 198                           val, 8);
 199        break;
 200    case PBCQ_SPCI_AIB_CAPP_EN:
 201    case PBCQ_SPCI_CAPP_SEC_TMR:
 202        break;
 203    default:
 204        phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
 205                        addr, val);
 206    }
 207}
 208
 209static const MemoryRegionOps pnv_pbcq_nest_xscom_ops = {
 210    .read = pnv_pbcq_nest_xscom_read,
 211    .write = pnv_pbcq_nest_xscom_write,
 212    .valid.min_access_size = 8,
 213    .valid.max_access_size = 8,
 214    .impl.min_access_size = 8,
 215    .impl.max_access_size = 8,
 216    .endianness = DEVICE_BIG_ENDIAN,
 217};
 218
 219static const MemoryRegionOps pnv_pbcq_pci_xscom_ops = {
 220    .read = pnv_pbcq_pci_xscom_read,
 221    .write = pnv_pbcq_pci_xscom_write,
 222    .valid.min_access_size = 8,
 223    .valid.max_access_size = 8,
 224    .impl.min_access_size = 8,
 225    .impl.max_access_size = 8,
 226    .endianness = DEVICE_BIG_ENDIAN,
 227};
 228
 229static const MemoryRegionOps pnv_pbcq_spci_xscom_ops = {
 230    .read = pnv_pbcq_spci_xscom_read,
 231    .write = pnv_pbcq_spci_xscom_write,
 232    .valid.min_access_size = 8,
 233    .valid.max_access_size = 8,
 234    .impl.min_access_size = 8,
 235    .impl.max_access_size = 8,
 236    .endianness = DEVICE_BIG_ENDIAN,
 237};
 238
 239static void pnv_pbcq_default_bars(PnvPBCQState *pbcq)
 240{
 241    uint64_t mm0, mm1, reg;
 242    PnvPHB3 *phb = pbcq->phb;
 243
 244    mm0 = 0x3d00000000000ull + 0x4000000000ull * phb->chip_id +
 245            0x1000000000ull * phb->phb_id;
 246    mm1 = 0x3ff8000000000ull + 0x0200000000ull * phb->chip_id +
 247            0x0080000000ull * phb->phb_id;
 248    reg = 0x3fffe40000000ull + 0x0000400000ull * phb->chip_id +
 249            0x0000100000ull * phb->phb_id;
 250
 251    pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] = mm0 << 14;
 252    pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] = mm1 << 14;
 253    pbcq->nest_regs[PBCQ_NEST_PHB_BAR] = reg << 14;
 254    pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0] = 0x3fff000000000ull << 14;
 255    pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1] = 0x3ffff80000000ull << 14;
 256    pbcq->pci_regs[PBCQ_PCI_BAR2] = reg << 14;
 257}
 258
 259static void pnv_pbcq_realize(DeviceState *dev, Error **errp)
 260{
 261    PnvPBCQState *pbcq = PNV_PBCQ(dev);
 262    PnvPHB3 *phb;
 263    char name[32];
 264
 265    assert(pbcq->phb);
 266    phb = pbcq->phb;
 267
 268    /* TODO: Fix OPAL to do that: establish default BAR values */
 269    pnv_pbcq_default_bars(pbcq);
 270
 271    /* Initialize the XSCOM region for the PBCQ registers */
 272    snprintf(name, sizeof(name), "xscom-pbcq-nest-%d.%d",
 273             phb->chip_id, phb->phb_id);
 274    pnv_xscom_region_init(&pbcq->xscom_nest_regs, OBJECT(dev),
 275                          &pnv_pbcq_nest_xscom_ops, pbcq, name,
 276                          PNV_XSCOM_PBCQ_NEST_SIZE);
 277    snprintf(name, sizeof(name), "xscom-pbcq-pci-%d.%d",
 278             phb->chip_id, phb->phb_id);
 279    pnv_xscom_region_init(&pbcq->xscom_pci_regs, OBJECT(dev),
 280                          &pnv_pbcq_pci_xscom_ops, pbcq, name,
 281                          PNV_XSCOM_PBCQ_PCI_SIZE);
 282    snprintf(name, sizeof(name), "xscom-pbcq-spci-%d.%d",
 283             phb->chip_id, phb->phb_id);
 284    pnv_xscom_region_init(&pbcq->xscom_spci_regs, OBJECT(dev),
 285                          &pnv_pbcq_spci_xscom_ops, pbcq, name,
 286                          PNV_XSCOM_PBCQ_SPCI_SIZE);
 287
 288    /* Populate the XSCOM address space. */
 289    pnv_xscom_add_subregion(phb->chip,
 290                            PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
 291                            &pbcq->xscom_nest_regs);
 292    pnv_xscom_add_subregion(phb->chip,
 293                            PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
 294                            &pbcq->xscom_pci_regs);
 295    pnv_xscom_add_subregion(phb->chip,
 296                            PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
 297                            &pbcq->xscom_spci_regs);
 298}
 299
 300static int pnv_pbcq_dt_xscom(PnvXScomInterface *dev, void *fdt,
 301                             int xscom_offset)
 302{
 303    const char compat[] = "ibm,power8-pbcq";
 304    PnvPHB3 *phb = PNV_PBCQ(dev)->phb;
 305    char *name;
 306    int offset;
 307    uint32_t lpc_pcba = PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id;
 308    uint32_t reg[] = {
 309        cpu_to_be32(lpc_pcba),
 310        cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE),
 311        cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id),
 312        cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE),
 313        cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id),
 314        cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE)
 315    };
 316
 317    name = g_strdup_printf("pbcq@%x", lpc_pcba);
 318    offset = fdt_add_subnode(fdt, xscom_offset, name);
 319    _FDT(offset);
 320    g_free(name);
 321
 322    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
 323
 324    _FDT((fdt_setprop_cell(fdt, offset, "ibm,phb-index", phb->phb_id)));
 325    _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", phb->chip_id)));
 326    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
 327                      sizeof(compat))));
 328    return 0;
 329}
 330
 331static void phb3_pbcq_instance_init(Object *obj)
 332{
 333    PnvPBCQState *pbcq = PNV_PBCQ(obj);
 334
 335    object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
 336                             (Object **)&pbcq->phb,
 337                             object_property_allow_set_link,
 338                             OBJ_PROP_LINK_STRONG);
 339}
 340
 341static void pnv_pbcq_class_init(ObjectClass *klass, void *data)
 342{
 343    DeviceClass *dc = DEVICE_CLASS(klass);
 344    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
 345
 346    xdc->dt_xscom = pnv_pbcq_dt_xscom;
 347
 348    dc->realize = pnv_pbcq_realize;
 349    dc->user_creatable = false;
 350}
 351
 352static const TypeInfo pnv_pbcq_type_info = {
 353    .name          = TYPE_PNV_PBCQ,
 354    .parent        = TYPE_DEVICE,
 355    .instance_size = sizeof(PnvPBCQState),
 356    .instance_init = phb3_pbcq_instance_init,
 357    .class_init    = pnv_pbcq_class_init,
 358    .interfaces    = (InterfaceInfo[]) {
 359        { TYPE_PNV_XSCOM_INTERFACE },
 360        { }
 361    }
 362};
 363
 364static void pnv_pbcq_register_types(void)
 365{
 366    type_register_static(&pnv_pbcq_type_info);
 367}
 368
 369type_init(pnv_pbcq_register_types)
 370