qemu

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

ppc440_pcix.c (15230B)


      1 /*
      2  * Emulation of the ibm,plb-pcix PCI controller
      3  * This is found in some 440 SoCs e.g. the 460EX.
      4  *
      5  * Copyright (c) 2016-2018 BALATON Zoltan
      6  *
      7  * Derived from ppc4xx_pci.c and pci-host/ppce500.c
      8  *
      9  * This program is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License, version 2, as
     11  * published by the Free Software Foundation.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
     20  */
     21 
     22 #include "qemu/osdep.h"
     23 #include "qemu/error-report.h"
     24 #include "qemu/log.h"
     25 #include "qemu/module.h"
     26 #include "hw/irq.h"
     27 #include "hw/ppc/ppc.h"
     28 #include "hw/ppc/ppc4xx.h"
     29 #include "hw/pci/pci.h"
     30 #include "hw/pci/pci_host.h"
     31 #include "trace.h"
     32 #include "qom/object.h"
     33 
     34 struct PLBOutMap {
     35     uint64_t la;
     36     uint64_t pcia;
     37     uint32_t sa;
     38     MemoryRegion mr;
     39 };
     40 
     41 struct PLBInMap {
     42     uint64_t sa;
     43     uint64_t la;
     44     MemoryRegion mr;
     45 };
     46 
     47 #define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
     48 OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST_BRIDGE)
     49 
     50 #define PPC440_PCIX_NR_POMS 3
     51 #define PPC440_PCIX_NR_PIMS 3
     52 
     53 struct PPC440PCIXState {
     54     PCIHostState parent_obj;
     55 
     56     PCIDevice *dev;
     57     struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
     58     struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
     59     uint32_t sts;
     60     qemu_irq irq;
     61     AddressSpace bm_as;
     62     MemoryRegion bm;
     63 
     64     MemoryRegion container;
     65     MemoryRegion iomem;
     66     MemoryRegion busmem;
     67 };
     68 
     69 #define PPC440_REG_BASE     0x80000
     70 #define PPC440_REG_SIZE     0xff
     71 
     72 #define PCIC0_CFGADDR       0x0
     73 #define PCIC0_CFGDATA       0x4
     74 
     75 #define PCIX0_POM0LAL       0x68
     76 #define PCIX0_POM0LAH       0x6c
     77 #define PCIX0_POM0SA        0x70
     78 #define PCIX0_POM0PCIAL     0x74
     79 #define PCIX0_POM0PCIAH     0x78
     80 #define PCIX0_POM1LAL       0x7c
     81 #define PCIX0_POM1LAH       0x80
     82 #define PCIX0_POM1SA        0x84
     83 #define PCIX0_POM1PCIAL     0x88
     84 #define PCIX0_POM1PCIAH     0x8c
     85 #define PCIX0_POM2SA        0x90
     86 
     87 #define PCIX0_PIM0SAL       0x98
     88 #define PCIX0_PIM0LAL       0x9c
     89 #define PCIX0_PIM0LAH       0xa0
     90 #define PCIX0_PIM1SA        0xa4
     91 #define PCIX0_PIM1LAL       0xa8
     92 #define PCIX0_PIM1LAH       0xac
     93 #define PCIX0_PIM2SAL       0xb0
     94 #define PCIX0_PIM2LAL       0xb4
     95 #define PCIX0_PIM2LAH       0xb8
     96 #define PCIX0_PIM0SAH       0xf8
     97 #define PCIX0_PIM2SAH       0xfc
     98 
     99 #define PCIX0_STS           0xe0
    100 
    101 #define PCI_ALL_SIZE        (PPC440_REG_BASE + PPC440_REG_SIZE)
    102 
    103 static void ppc440_pcix_clear_region(MemoryRegion *parent,
    104                                      MemoryRegion *mem)
    105 {
    106     if (memory_region_is_mapped(mem)) {
    107         memory_region_del_subregion(parent, mem);
    108         object_unparent(OBJECT(mem));
    109     }
    110 }
    111 
    112 /* DMA mapping */
    113 static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
    114 {
    115     MemoryRegion *mem = &s->pim[idx].mr;
    116     char *name;
    117     uint64_t size;
    118 
    119     /* Before we modify anything, unmap and destroy the region */
    120     ppc440_pcix_clear_region(&s->bm, mem);
    121 
    122     if (!(s->pim[idx].sa & 1)) {
    123         /* Not enabled, nothing to do */
    124         return;
    125     }
    126 
    127     name = g_strdup_printf("PCI Inbound Window %d", idx);
    128     size = ~(s->pim[idx].sa & ~7ULL) + 1;
    129     memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
    130                              s->pim[idx].la, size);
    131     memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
    132     g_free(name);
    133 
    134     trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
    135 }
    136 
    137 /* BAR mapping */
    138 static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
    139 {
    140     MemoryRegion *mem = &s->pom[idx].mr;
    141     MemoryRegion *address_space_mem = get_system_memory();
    142     char *name;
    143     uint32_t size;
    144 
    145     /* Before we modify anything, unmap and destroy the region */
    146     ppc440_pcix_clear_region(address_space_mem, mem);
    147 
    148     if (!(s->pom[idx].sa & 1)) {
    149         /* Not enabled, nothing to do */
    150         return;
    151     }
    152 
    153     name = g_strdup_printf("PCI Outbound Window %d", idx);
    154     size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
    155     if (!size) {
    156         size = 0xffffffff;
    157     }
    158     memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
    159                              s->pom[idx].pcia, size);
    160     memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
    161     g_free(name);
    162 
    163     trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
    164 }
    165 
    166 static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
    167                                    uint64_t val, unsigned size)
    168 {
    169     struct PPC440PCIXState *s = opaque;
    170 
    171     trace_ppc440_pcix_reg_write(addr, val, size);
    172     switch (addr) {
    173     case PCI_VENDOR_ID ... PCI_MAX_LAT:
    174         stl_le_p(s->dev->config + addr, val);
    175         break;
    176 
    177     case PCIX0_POM0LAL:
    178         s->pom[0].la &= 0xffffffff00000000ULL;
    179         s->pom[0].la |= val;
    180         ppc440_pcix_update_pom(s, 0);
    181         break;
    182     case PCIX0_POM0LAH:
    183         s->pom[0].la &= 0xffffffffULL;
    184         s->pom[0].la |= val << 32;
    185         ppc440_pcix_update_pom(s, 0);
    186         break;
    187     case PCIX0_POM0SA:
    188         s->pom[0].sa = val;
    189         ppc440_pcix_update_pom(s, 0);
    190         break;
    191     case PCIX0_POM0PCIAL:
    192         s->pom[0].pcia &= 0xffffffff00000000ULL;
    193         s->pom[0].pcia |= val;
    194         ppc440_pcix_update_pom(s, 0);
    195         break;
    196     case PCIX0_POM0PCIAH:
    197         s->pom[0].pcia &= 0xffffffffULL;
    198         s->pom[0].pcia |= val << 32;
    199         ppc440_pcix_update_pom(s, 0);
    200         break;
    201     case PCIX0_POM1LAL:
    202         s->pom[1].la &= 0xffffffff00000000ULL;
    203         s->pom[1].la |= val;
    204         ppc440_pcix_update_pom(s, 1);
    205         break;
    206     case PCIX0_POM1LAH:
    207         s->pom[1].la &= 0xffffffffULL;
    208         s->pom[1].la |= val << 32;
    209         ppc440_pcix_update_pom(s, 1);
    210         break;
    211     case PCIX0_POM1SA:
    212         s->pom[1].sa = val;
    213         ppc440_pcix_update_pom(s, 1);
    214         break;
    215     case PCIX0_POM1PCIAL:
    216         s->pom[1].pcia &= 0xffffffff00000000ULL;
    217         s->pom[1].pcia |= val;
    218         ppc440_pcix_update_pom(s, 1);
    219         break;
    220     case PCIX0_POM1PCIAH:
    221         s->pom[1].pcia &= 0xffffffffULL;
    222         s->pom[1].pcia |= val << 32;
    223         ppc440_pcix_update_pom(s, 1);
    224         break;
    225     case PCIX0_POM2SA:
    226         s->pom[2].sa = val;
    227         break;
    228 
    229     case PCIX0_PIM0SAL:
    230         s->pim[0].sa &= 0xffffffff00000000ULL;
    231         s->pim[0].sa |= val;
    232         ppc440_pcix_update_pim(s, 0);
    233         break;
    234     case PCIX0_PIM0LAL:
    235         s->pim[0].la &= 0xffffffff00000000ULL;
    236         s->pim[0].la |= val;
    237         ppc440_pcix_update_pim(s, 0);
    238         break;
    239     case PCIX0_PIM0LAH:
    240         s->pim[0].la &= 0xffffffffULL;
    241         s->pim[0].la |= val << 32;
    242         ppc440_pcix_update_pim(s, 0);
    243         break;
    244     case PCIX0_PIM1SA:
    245         s->pim[1].sa = val;
    246         ppc440_pcix_update_pim(s, 1);
    247         break;
    248     case PCIX0_PIM1LAL:
    249         s->pim[1].la &= 0xffffffff00000000ULL;
    250         s->pim[1].la |= val;
    251         ppc440_pcix_update_pim(s, 1);
    252         break;
    253     case PCIX0_PIM1LAH:
    254         s->pim[1].la &= 0xffffffffULL;
    255         s->pim[1].la |= val << 32;
    256         ppc440_pcix_update_pim(s, 1);
    257         break;
    258     case PCIX0_PIM2SAL:
    259         s->pim[2].sa &= 0xffffffff00000000ULL;
    260         s->pim[2].sa |= val;
    261         ppc440_pcix_update_pim(s, 2);
    262         break;
    263     case PCIX0_PIM2LAL:
    264         s->pim[2].la &= 0xffffffff00000000ULL;
    265         s->pim[2].la |= val;
    266         ppc440_pcix_update_pim(s, 2);
    267         break;
    268     case PCIX0_PIM2LAH:
    269         s->pim[2].la &= 0xffffffffULL;
    270         s->pim[2].la |= val << 32;
    271         ppc440_pcix_update_pim(s, 2);
    272         break;
    273 
    274     case PCIX0_STS:
    275         s->sts = val;
    276         break;
    277 
    278     case PCIX0_PIM0SAH:
    279         s->pim[0].sa &= 0xffffffffULL;
    280         s->pim[0].sa |= val << 32;
    281         ppc440_pcix_update_pim(s, 0);
    282         break;
    283     case PCIX0_PIM2SAH:
    284         s->pim[2].sa &= 0xffffffffULL;
    285         s->pim[2].sa |= val << 32;
    286         ppc440_pcix_update_pim(s, 2);
    287         break;
    288 
    289     default:
    290         qemu_log_mask(LOG_UNIMP,
    291                       "%s: unhandled PCI internal register 0x%"HWADDR_PRIx"\n",
    292                       __func__, addr);
    293         break;
    294     }
    295 }
    296 
    297 static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
    298                                      unsigned size)
    299 {
    300     struct PPC440PCIXState *s = opaque;
    301     uint32_t val;
    302 
    303     switch (addr) {
    304     case PCI_VENDOR_ID ... PCI_MAX_LAT:
    305         val = ldl_le_p(s->dev->config + addr);
    306         break;
    307 
    308     case PCIX0_POM0LAL:
    309         val = s->pom[0].la;
    310         break;
    311     case PCIX0_POM0LAH:
    312         val = s->pom[0].la >> 32;
    313         break;
    314     case PCIX0_POM0SA:
    315         val = s->pom[0].sa;
    316         break;
    317     case PCIX0_POM0PCIAL:
    318         val = s->pom[0].pcia;
    319         break;
    320     case PCIX0_POM0PCIAH:
    321         val = s->pom[0].pcia >> 32;
    322         break;
    323     case PCIX0_POM1LAL:
    324         val = s->pom[1].la;
    325         break;
    326     case PCIX0_POM1LAH:
    327         val = s->pom[1].la >> 32;
    328         break;
    329     case PCIX0_POM1SA:
    330         val = s->pom[1].sa;
    331         break;
    332     case PCIX0_POM1PCIAL:
    333         val = s->pom[1].pcia;
    334         break;
    335     case PCIX0_POM1PCIAH:
    336         val = s->pom[1].pcia >> 32;
    337         break;
    338     case PCIX0_POM2SA:
    339         val = s->pom[2].sa;
    340         break;
    341 
    342     case PCIX0_PIM0SAL:
    343         val = s->pim[0].sa;
    344         break;
    345     case PCIX0_PIM0LAL:
    346         val = s->pim[0].la;
    347         break;
    348     case PCIX0_PIM0LAH:
    349         val = s->pim[0].la >> 32;
    350         break;
    351     case PCIX0_PIM1SA:
    352         val = s->pim[1].sa;
    353         break;
    354     case PCIX0_PIM1LAL:
    355         val = s->pim[1].la;
    356         break;
    357     case PCIX0_PIM1LAH:
    358         val = s->pim[1].la >> 32;
    359         break;
    360     case PCIX0_PIM2SAL:
    361         val = s->pim[2].sa;
    362         break;
    363     case PCIX0_PIM2LAL:
    364         val = s->pim[2].la;
    365         break;
    366     case PCIX0_PIM2LAH:
    367         val = s->pim[2].la >> 32;
    368         break;
    369 
    370     case PCIX0_STS:
    371         val = s->sts;
    372         break;
    373 
    374     case PCIX0_PIM0SAH:
    375         val = s->pim[0].sa  >> 32;
    376         break;
    377     case PCIX0_PIM2SAH:
    378         val = s->pim[2].sa  >> 32;
    379         break;
    380 
    381     default:
    382         qemu_log_mask(LOG_UNIMP,
    383                       "%s: invalid PCI internal register 0x%" HWADDR_PRIx "\n",
    384                       __func__, addr);
    385         val = 0;
    386     }
    387 
    388     trace_ppc440_pcix_reg_read(addr, val);
    389     return val;
    390 }
    391 
    392 static const MemoryRegionOps pci_reg_ops = {
    393     .read = ppc440_pcix_reg_read4,
    394     .write = ppc440_pcix_reg_write4,
    395     .endianness = DEVICE_LITTLE_ENDIAN,
    396 };
    397 
    398 static void ppc440_pcix_reset(DeviceState *dev)
    399 {
    400     struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
    401     int i;
    402 
    403     for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
    404         ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
    405     }
    406     for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
    407         ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
    408     }
    409     memset(s->pom, 0, sizeof(s->pom));
    410     memset(s->pim, 0, sizeof(s->pim));
    411     for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
    412         s->pim[i].sa = 0xffffffff00000000ULL;
    413     }
    414     s->sts = 0;
    415 }
    416 
    417 /*
    418  * All four IRQ[ABCD] pins from all slots are tied to a single board
    419  * IRQ, so our mapping function here maps everything to IRQ 0.
    420  * The code in pci_change_irq_level() tracks the number of times
    421  * the mapped IRQ is asserted and deasserted, so if multiple devices
    422  * assert an IRQ at the same time the behaviour is correct.
    423  *
    424  * This may need further refactoring for boards that use multiple IRQ lines.
    425  */
    426 static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
    427 {
    428     trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, 0);
    429     return 0;
    430 }
    431 
    432 static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
    433 {
    434     qemu_irq *pci_irq = opaque;
    435 
    436     trace_ppc440_pcix_set_irq(irq_num);
    437     if (irq_num < 0) {
    438         error_report("%s: PCI irq %d", __func__, irq_num);
    439         return;
    440     }
    441     qemu_set_irq(*pci_irq, level);
    442 }
    443 
    444 static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
    445 {
    446     PPC440PCIXState *s = opaque;
    447 
    448     return &s->bm_as;
    449 }
    450 
    451 /*
    452  * Some guests on sam460ex write all kinds of garbage here such as
    453  * missing enable bit and low bits set and still expect this to work
    454  * (apparently it does on real hardware because these boot there) so
    455  * we have to override these ops here and fix it up
    456  */
    457 static void pci_host_config_write(void *opaque, hwaddr addr,
    458                                   uint64_t val, unsigned len)
    459 {
    460     PCIHostState *s = opaque;
    461 
    462     if (addr != 0 || len != 4) {
    463         return;
    464     }
    465     s->config_reg = (val & 0xfffffffcULL) | (1UL << 31);
    466 }
    467 
    468 static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
    469                                      unsigned len)
    470 {
    471     PCIHostState *s = opaque;
    472     uint32_t val = s->config_reg;
    473 
    474     return val;
    475 }
    476 
    477 const MemoryRegionOps ppc440_pcix_host_conf_ops = {
    478     .read = pci_host_config_read,
    479     .write = pci_host_config_write,
    480     .endianness = DEVICE_LITTLE_ENDIAN,
    481 };
    482 
    483 static void ppc440_pcix_realize(DeviceState *dev, Error **errp)
    484 {
    485     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    486     PPC440PCIXState *s;
    487     PCIHostState *h;
    488 
    489     h = PCI_HOST_BRIDGE(dev);
    490     s = PPC440_PCIX_HOST_BRIDGE(dev);
    491 
    492     sysbus_init_irq(sbd, &s->irq);
    493     memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
    494     h->bus = pci_register_root_bus(dev, NULL, ppc440_pcix_set_irq,
    495                          ppc440_pcix_map_irq, &s->irq, &s->busmem,
    496                          get_system_io(), PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS);
    497 
    498     s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
    499 
    500     memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
    501     memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
    502     address_space_init(&s->bm_as, &s->bm, "pci-bm");
    503     pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
    504 
    505     memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
    506     memory_region_init_io(&h->conf_mem, OBJECT(s), &ppc440_pcix_host_conf_ops,
    507                           h, "pci-conf-idx", 4);
    508     memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops,
    509                           h, "pci-conf-data", 4);
    510     memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
    511                           "pci.reg", PPC440_REG_SIZE);
    512     memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
    513     memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
    514     memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
    515     sysbus_init_mmio(sbd, &s->container);
    516 }
    517 
    518 static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
    519 {
    520     DeviceClass *dc = DEVICE_CLASS(klass);
    521 
    522     dc->realize = ppc440_pcix_realize;
    523     dc->reset = ppc440_pcix_reset;
    524 }
    525 
    526 static const TypeInfo ppc440_pcix_info = {
    527     .name          = TYPE_PPC440_PCIX_HOST_BRIDGE,
    528     .parent        = TYPE_PCI_HOST_BRIDGE,
    529     .instance_size = sizeof(PPC440PCIXState),
    530     .class_init    = ppc440_pcix_class_init,
    531 };
    532 
    533 static void ppc440_pcix_register_types(void)
    534 {
    535     type_register_static(&ppc440_pcix_info);
    536 }
    537 
    538 type_init(ppc440_pcix_register_types)