qemu/hw/ppc/ppc440_pcix.c
<<
>>
Prefs
   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
  34struct PLBOutMap {
  35    uint64_t la;
  36    uint64_t pcia;
  37    uint32_t sa;
  38    MemoryRegion mr;
  39};
  40
  41struct PLBInMap {
  42    uint64_t sa;
  43    uint64_t la;
  44    MemoryRegion mr;
  45};
  46
  47#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
  48OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST_BRIDGE)
  49
  50#define PPC440_PCIX_NR_POMS 3
  51#define PPC440_PCIX_NR_PIMS 3
  52
  53struct 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
 103static 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 */
 113static 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 */
 138static 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
 166static 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
 297static 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
 392static const MemoryRegionOps pci_reg_ops = {
 393    .read = ppc440_pcix_reg_read4,
 394    .write = ppc440_pcix_reg_write4,
 395    .endianness = DEVICE_LITTLE_ENDIAN,
 396};
 397
 398static 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 */
 426static 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
 432static 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
 444static 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 */
 457static 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
 468static 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
 477const 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
 483static 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
 518static 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
 526static 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
 533static void ppc440_pcix_register_types(void)
 534{
 535    type_register_static(&ppc440_pcix_info);
 536}
 537
 538type_init(ppc440_pcix_register_types)
 539