qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

pnv_phb3_pbcq.c (12439B)


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