qemu/hw/pci-host/designware.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2018, Impinj, Inc.
   3 *
   4 * Designware PCIe IP block emulation
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see
  18 * <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qapi/error.h"
  23#include "qemu/module.h"
  24#include "hw/pci/msi.h"
  25#include "hw/pci/pci_bridge.h"
  26#include "hw/pci/pci_host.h"
  27#include "hw/pci/pcie_port.h"
  28#include "hw/pci-host/designware.h"
  29
  30#define DESIGNWARE_PCIE_PORT_LINK_CONTROL          0x710
  31#define DESIGNWARE_PCIE_PHY_DEBUG_R1               0x72C
  32#define DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP  BIT(4)
  33#define DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL   0x80C
  34#define DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE    BIT(17)
  35#define DESIGNWARE_PCIE_MSI_ADDR_LO                0x820
  36#define DESIGNWARE_PCIE_MSI_ADDR_HI                0x824
  37#define DESIGNWARE_PCIE_MSI_INTR0_ENABLE           0x828
  38#define DESIGNWARE_PCIE_MSI_INTR0_MASK             0x82C
  39#define DESIGNWARE_PCIE_MSI_INTR0_STATUS           0x830
  40#define DESIGNWARE_PCIE_ATU_VIEWPORT               0x900
  41#define DESIGNWARE_PCIE_ATU_REGION_INBOUND         BIT(31)
  42#define DESIGNWARE_PCIE_ATU_CR1                    0x904
  43#define DESIGNWARE_PCIE_ATU_TYPE_MEM               (0x0 << 0)
  44#define DESIGNWARE_PCIE_ATU_CR2                    0x908
  45#define DESIGNWARE_PCIE_ATU_ENABLE                 BIT(31)
  46#define DESIGNWARE_PCIE_ATU_LOWER_BASE             0x90C
  47#define DESIGNWARE_PCIE_ATU_UPPER_BASE             0x910
  48#define DESIGNWARE_PCIE_ATU_LIMIT                  0x914
  49#define DESIGNWARE_PCIE_ATU_LOWER_TARGET           0x918
  50#define DESIGNWARE_PCIE_ATU_BUS(x)                 (((x) >> 24) & 0xff)
  51#define DESIGNWARE_PCIE_ATU_DEVFN(x)               (((x) >> 16) & 0xff)
  52#define DESIGNWARE_PCIE_ATU_UPPER_TARGET           0x91C
  53
  54#define DESIGNWARE_PCIE_IRQ_MSI                    3
  55
  56static DesignwarePCIEHost *
  57designware_pcie_root_to_host(DesignwarePCIERoot *root)
  58{
  59    BusState *bus = qdev_get_parent_bus(DEVICE(root));
  60    return DESIGNWARE_PCIE_HOST(bus->parent);
  61}
  62
  63static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
  64                                           uint64_t val, unsigned len)
  65{
  66    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque);
  67    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
  68
  69    root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
  70
  71    if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
  72        qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
  73    }
  74}
  75
  76static const MemoryRegionOps designware_pci_host_msi_ops = {
  77    .write = designware_pcie_root_msi_write,
  78    .endianness = DEVICE_LITTLE_ENDIAN,
  79    .valid = {
  80        .min_access_size = 4,
  81        .max_access_size = 4,
  82    },
  83};
  84
  85static void designware_pcie_root_update_msi_mapping(DesignwarePCIERoot *root)
  86
  87{
  88    MemoryRegion *mem   = &root->msi.iomem;
  89    const uint64_t base = root->msi.base;
  90    const bool enable   = root->msi.intr[0].enable;
  91
  92    memory_region_set_address(mem, base);
  93    memory_region_set_enabled(mem, enable);
  94}
  95
  96static DesignwarePCIEViewport *
  97designware_pcie_root_get_current_viewport(DesignwarePCIERoot *root)
  98{
  99    const unsigned int idx = root->atu_viewport & 0xF;
 100    const unsigned int dir =
 101        !!(root->atu_viewport & DESIGNWARE_PCIE_ATU_REGION_INBOUND);
 102    return &root->viewports[dir][idx];
 103}
 104
 105static uint32_t
 106designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
 107{
 108    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
 109    DesignwarePCIEViewport *viewport =
 110        designware_pcie_root_get_current_viewport(root);
 111
 112    uint32_t val;
 113
 114    switch (address) {
 115    case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
 116        /*
 117         * Linux guest uses this register only to configure number of
 118         * PCIE lane (which in our case is irrelevant) and doesn't
 119         * really care about the value it reads from this register
 120         */
 121        val = 0xDEADBEEF;
 122        break;
 123
 124    case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
 125        /*
 126         * To make sure that any code in guest waiting for speed
 127         * change does not time out we always report
 128         * PORT_LOGIC_SPEED_CHANGE as set
 129         */
 130        val = DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE;
 131        break;
 132
 133    case DESIGNWARE_PCIE_MSI_ADDR_LO:
 134        val = root->msi.base;
 135        break;
 136
 137    case DESIGNWARE_PCIE_MSI_ADDR_HI:
 138        val = root->msi.base >> 32;
 139        break;
 140
 141    case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
 142        val = root->msi.intr[0].enable;
 143        break;
 144
 145    case DESIGNWARE_PCIE_MSI_INTR0_MASK:
 146        val = root->msi.intr[0].mask;
 147        break;
 148
 149    case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
 150        val = root->msi.intr[0].status;
 151        break;
 152
 153    case DESIGNWARE_PCIE_PHY_DEBUG_R1:
 154        val = DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
 155        break;
 156
 157    case DESIGNWARE_PCIE_ATU_VIEWPORT:
 158        val = root->atu_viewport;
 159        break;
 160
 161    case DESIGNWARE_PCIE_ATU_LOWER_BASE:
 162        val = viewport->base;
 163        break;
 164
 165    case DESIGNWARE_PCIE_ATU_UPPER_BASE:
 166        val = viewport->base >> 32;
 167        break;
 168
 169    case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
 170        val = viewport->target;
 171        break;
 172
 173    case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
 174        val = viewport->target >> 32;
 175        break;
 176
 177    case DESIGNWARE_PCIE_ATU_LIMIT:
 178        val = viewport->limit;
 179        break;
 180
 181    case DESIGNWARE_PCIE_ATU_CR1:
 182    case DESIGNWARE_PCIE_ATU_CR2:          /* FALLTHROUGH */
 183        val = viewport->cr[(address - DESIGNWARE_PCIE_ATU_CR1) /
 184                           sizeof(uint32_t)];
 185        break;
 186
 187    default:
 188        val = pci_default_read_config(d, address, len);
 189        break;
 190    }
 191
 192    return val;
 193}
 194
 195static uint64_t designware_pcie_root_data_access(void *opaque, hwaddr addr,
 196                                                 uint64_t *val, unsigned len)
 197{
 198    DesignwarePCIEViewport *viewport = opaque;
 199    DesignwarePCIERoot *root = viewport->root;
 200
 201    const uint8_t busnum = DESIGNWARE_PCIE_ATU_BUS(viewport->target);
 202    const uint8_t devfn  = DESIGNWARE_PCIE_ATU_DEVFN(viewport->target);
 203    PCIBus    *pcibus    = pci_get_bus(PCI_DEVICE(root));
 204    PCIDevice *pcidev    = pci_find_device(pcibus, busnum, devfn);
 205
 206    if (pcidev) {
 207        addr &= pci_config_size(pcidev) - 1;
 208
 209        if (val) {
 210            pci_host_config_write_common(pcidev, addr,
 211                                         pci_config_size(pcidev),
 212                                         *val, len);
 213        } else {
 214            return pci_host_config_read_common(pcidev, addr,
 215                                               pci_config_size(pcidev),
 216                                               len);
 217        }
 218    }
 219
 220    return UINT64_MAX;
 221}
 222
 223static uint64_t designware_pcie_root_data_read(void *opaque, hwaddr addr,
 224                                               unsigned len)
 225{
 226    return designware_pcie_root_data_access(opaque, addr, NULL, len);
 227}
 228
 229static void designware_pcie_root_data_write(void *opaque, hwaddr addr,
 230                                            uint64_t val, unsigned len)
 231{
 232    designware_pcie_root_data_access(opaque, addr, &val, len);
 233}
 234
 235static const MemoryRegionOps designware_pci_host_conf_ops = {
 236    .read = designware_pcie_root_data_read,
 237    .write = designware_pcie_root_data_write,
 238    .endianness = DEVICE_LITTLE_ENDIAN,
 239    .valid = {
 240        .min_access_size = 1,
 241        .max_access_size = 4,
 242    },
 243};
 244
 245static void designware_pcie_update_viewport(DesignwarePCIERoot *root,
 246                                            DesignwarePCIEViewport *viewport)
 247{
 248    const uint64_t target = viewport->target;
 249    const uint64_t base   = viewport->base;
 250    const uint64_t size   = (uint64_t)viewport->limit - base + 1;
 251    const bool enabled    = viewport->cr[1] & DESIGNWARE_PCIE_ATU_ENABLE;
 252
 253    MemoryRegion *current, *other;
 254
 255    if (viewport->cr[0] == DESIGNWARE_PCIE_ATU_TYPE_MEM) {
 256        current = &viewport->mem;
 257        other   = &viewport->cfg;
 258        memory_region_set_alias_offset(current, target);
 259    } else {
 260        current = &viewport->cfg;
 261        other   = &viewport->mem;
 262    }
 263
 264    /*
 265     * An outbound viewport can be reconfigure from being MEM to CFG,
 266     * to account for that we disable the "other" memory region that
 267     * becomes unused due to that fact.
 268     */
 269    memory_region_set_enabled(other, false);
 270    if (enabled) {
 271        memory_region_set_size(current, size);
 272        memory_region_set_address(current, base);
 273    }
 274    memory_region_set_enabled(current, enabled);
 275}
 276
 277static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
 278                                              uint32_t val, int len)
 279{
 280    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
 281    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
 282    DesignwarePCIEViewport *viewport =
 283        designware_pcie_root_get_current_viewport(root);
 284
 285    switch (address) {
 286    case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
 287    case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
 288    case DESIGNWARE_PCIE_PHY_DEBUG_R1:
 289        /* No-op */
 290        break;
 291
 292    case DESIGNWARE_PCIE_MSI_ADDR_LO:
 293        root->msi.base &= 0xFFFFFFFF00000000ULL;
 294        root->msi.base |= val;
 295        designware_pcie_root_update_msi_mapping(root);
 296        break;
 297
 298    case DESIGNWARE_PCIE_MSI_ADDR_HI:
 299        root->msi.base &= 0x00000000FFFFFFFFULL;
 300        root->msi.base |= (uint64_t)val << 32;
 301        designware_pcie_root_update_msi_mapping(root);
 302        break;
 303
 304    case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
 305        root->msi.intr[0].enable = val;
 306        designware_pcie_root_update_msi_mapping(root);
 307        break;
 308
 309    case DESIGNWARE_PCIE_MSI_INTR0_MASK:
 310        root->msi.intr[0].mask = val;
 311        break;
 312
 313    case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
 314        root->msi.intr[0].status ^= val;
 315        if (!root->msi.intr[0].status) {
 316            qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
 317        }
 318        break;
 319
 320    case DESIGNWARE_PCIE_ATU_VIEWPORT:
 321        root->atu_viewport = val;
 322        break;
 323
 324    case DESIGNWARE_PCIE_ATU_LOWER_BASE:
 325        viewport->base &= 0xFFFFFFFF00000000ULL;
 326        viewport->base |= val;
 327        break;
 328
 329    case DESIGNWARE_PCIE_ATU_UPPER_BASE:
 330        viewport->base &= 0x00000000FFFFFFFFULL;
 331        viewport->base |= (uint64_t)val << 32;
 332        break;
 333
 334    case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
 335        viewport->target &= 0xFFFFFFFF00000000ULL;
 336        viewport->target |= val;
 337        break;
 338
 339    case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
 340        viewport->target &= 0x00000000FFFFFFFFULL;
 341        viewport->target |= val;
 342        break;
 343
 344    case DESIGNWARE_PCIE_ATU_LIMIT:
 345        viewport->limit = val;
 346        break;
 347
 348    case DESIGNWARE_PCIE_ATU_CR1:
 349        viewport->cr[0] = val;
 350        break;
 351    case DESIGNWARE_PCIE_ATU_CR2:
 352        viewport->cr[1] = val;
 353        designware_pcie_update_viewport(root, viewport);
 354        break;
 355
 356    default:
 357        pci_bridge_write_config(d, address, val, len);
 358        break;
 359    }
 360}
 361
 362static char *designware_pcie_viewport_name(const char *direction,
 363                                           unsigned int i,
 364                                           const char *type)
 365{
 366    return g_strdup_printf("PCI %s Viewport %u [%s]",
 367                           direction, i, type);
 368}
 369
 370static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
 371{
 372    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
 373    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
 374    MemoryRegion *address_space = &host->pci.memory;
 375    PCIBridge *br = PCI_BRIDGE(dev);
 376    DesignwarePCIEViewport *viewport;
 377    /*
 378     * Dummy values used for initial configuration of MemoryRegions
 379     * that belong to a given viewport
 380     */
 381    const hwaddr dummy_offset = 0;
 382    const uint64_t dummy_size = 4;
 383    size_t i;
 384
 385    br->bus_name  = "dw-pcie";
 386
 387    pci_set_word(dev->config + PCI_COMMAND,
 388                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
 389
 390    pci_config_set_interrupt_pin(dev->config, 1);
 391    pci_bridge_initfn(dev, TYPE_PCIE_BUS);
 392
 393    pcie_port_init_reg(dev);
 394
 395    pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT,
 396                  0, &error_fatal);
 397
 398    msi_nonbroken = true;
 399    msi_init(dev, 0x50, 32, true, true, &error_fatal);
 400
 401    for (i = 0; i < DESIGNWARE_PCIE_NUM_VIEWPORTS; i++) {
 402        MemoryRegion *source, *destination, *mem;
 403        const char *direction;
 404        char *name;
 405
 406        viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][i];
 407        viewport->inbound = true;
 408        viewport->base    = 0x0000000000000000ULL;
 409        viewport->target  = 0x0000000000000000ULL;
 410        viewport->limit   = UINT32_MAX;
 411        viewport->cr[0]   = DESIGNWARE_PCIE_ATU_TYPE_MEM;
 412
 413        source      = &host->pci.address_space_root;
 414        destination = get_system_memory();
 415        direction   = "Inbound";
 416
 417        /*
 418         * Configure MemoryRegion implementing PCI -> CPU memory
 419         * access
 420         */
 421        mem  = &viewport->mem;
 422        name = designware_pcie_viewport_name(direction, i, "MEM");
 423        memory_region_init_alias(mem, OBJECT(root), name, destination,
 424                                 dummy_offset, dummy_size);
 425        memory_region_add_subregion_overlap(source, dummy_offset, mem, -1);
 426        memory_region_set_enabled(mem, false);
 427        g_free(name);
 428
 429        viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_OUTBOUND][i];
 430        viewport->root    = root;
 431        viewport->inbound = false;
 432        viewport->base    = 0x0000000000000000ULL;
 433        viewport->target  = 0x0000000000000000ULL;
 434        viewport->limit   = UINT32_MAX;
 435        viewport->cr[0]   = DESIGNWARE_PCIE_ATU_TYPE_MEM;
 436
 437        destination = &host->pci.memory;
 438        direction   = "Outbound";
 439        source      = get_system_memory();
 440
 441        /*
 442         * Configure MemoryRegion implementing CPU -> PCI memory
 443         * access
 444         */
 445        mem  = &viewport->mem;
 446        name = designware_pcie_viewport_name(direction, i, "MEM");
 447        memory_region_init_alias(mem, OBJECT(root), name, destination,
 448                                 dummy_offset, dummy_size);
 449        memory_region_add_subregion(source, dummy_offset, mem);
 450        memory_region_set_enabled(mem, false);
 451        g_free(name);
 452
 453        /*
 454         * Configure MemoryRegion implementing access to configuration
 455         * space
 456         */
 457        mem  = &viewport->cfg;
 458        name = designware_pcie_viewport_name(direction, i, "CFG");
 459        memory_region_init_io(&viewport->cfg, OBJECT(root),
 460                              &designware_pci_host_conf_ops,
 461                              viewport, name, dummy_size);
 462        memory_region_add_subregion(source, dummy_offset, mem);
 463        memory_region_set_enabled(mem, false);
 464        g_free(name);
 465    }
 466
 467    /*
 468     * If no inbound iATU windows are configured, HW defaults to
 469     * letting inbound TLPs to pass in. We emulate that by exlicitly
 470     * configuring first inbound window to cover all of target's
 471     * address space.
 472     *
 473     * NOTE: This will not work correctly for the case when first
 474     * configured inbound window is window 0
 475     */
 476    viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0];
 477    viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE;
 478    designware_pcie_update_viewport(root, viewport);
 479
 480    memory_region_init_io(&root->msi.iomem, OBJECT(root),
 481                          &designware_pci_host_msi_ops,
 482                          root, "pcie-msi", 0x4);
 483    /*
 484     * We initially place MSI interrupt I/O region a adress 0 and
 485     * disable it. It'll be later moved to correct offset and enabled
 486     * in designware_pcie_root_update_msi_mapping() as a part of
 487     * initialization done by guest OS
 488     */
 489    memory_region_add_subregion(address_space, dummy_offset, &root->msi.iomem);
 490    memory_region_set_enabled(&root->msi.iomem, false);
 491}
 492
 493static void designware_pcie_set_irq(void *opaque, int irq_num, int level)
 494{
 495    DesignwarePCIEHost *host = DESIGNWARE_PCIE_HOST(opaque);
 496
 497    qemu_set_irq(host->pci.irqs[irq_num], level);
 498}
 499
 500static const char *
 501designware_pcie_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus)
 502{
 503    return "0000:00";
 504}
 505
 506static const VMStateDescription vmstate_designware_pcie_msi_bank = {
 507    .name = "designware-pcie-msi-bank",
 508    .version_id = 1,
 509    .minimum_version_id = 1,
 510    .fields = (VMStateField[]) {
 511        VMSTATE_UINT32(enable, DesignwarePCIEMSIBank),
 512        VMSTATE_UINT32(mask, DesignwarePCIEMSIBank),
 513        VMSTATE_UINT32(status, DesignwarePCIEMSIBank),
 514        VMSTATE_END_OF_LIST()
 515    }
 516};
 517
 518static const VMStateDescription vmstate_designware_pcie_msi = {
 519    .name = "designware-pcie-msi",
 520    .version_id = 1,
 521    .minimum_version_id = 1,
 522    .fields = (VMStateField[]) {
 523        VMSTATE_UINT64(base, DesignwarePCIEMSI),
 524        VMSTATE_STRUCT_ARRAY(intr,
 525                             DesignwarePCIEMSI,
 526                             DESIGNWARE_PCIE_NUM_MSI_BANKS,
 527                             1,
 528                             vmstate_designware_pcie_msi_bank,
 529                             DesignwarePCIEMSIBank),
 530        VMSTATE_END_OF_LIST()
 531    }
 532};
 533
 534static const VMStateDescription vmstate_designware_pcie_viewport = {
 535    .name = "designware-pcie-viewport",
 536    .version_id = 1,
 537    .minimum_version_id = 1,
 538    .fields = (VMStateField[]) {
 539        VMSTATE_UINT64(base, DesignwarePCIEViewport),
 540        VMSTATE_UINT64(target, DesignwarePCIEViewport),
 541        VMSTATE_UINT32(limit, DesignwarePCIEViewport),
 542        VMSTATE_UINT32_ARRAY(cr, DesignwarePCIEViewport, 2),
 543        VMSTATE_END_OF_LIST()
 544    }
 545};
 546
 547static const VMStateDescription vmstate_designware_pcie_root = {
 548    .name = "designware-pcie-root",
 549    .version_id = 1,
 550    .minimum_version_id = 1,
 551    .fields = (VMStateField[]) {
 552        VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
 553        VMSTATE_UINT32(atu_viewport, DesignwarePCIERoot),
 554        VMSTATE_STRUCT_2DARRAY(viewports,
 555                               DesignwarePCIERoot,
 556                               2,
 557                               DESIGNWARE_PCIE_NUM_VIEWPORTS,
 558                               1,
 559                               vmstate_designware_pcie_viewport,
 560                               DesignwarePCIEViewport),
 561        VMSTATE_STRUCT(msi,
 562                       DesignwarePCIERoot,
 563                       1,
 564                       vmstate_designware_pcie_msi,
 565                       DesignwarePCIEMSI),
 566        VMSTATE_END_OF_LIST()
 567    }
 568};
 569
 570static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
 571{
 572    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 573    DeviceClass *dc = DEVICE_CLASS(klass);
 574
 575    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 576
 577    k->vendor_id = PCI_VENDOR_ID_SYNOPSYS;
 578    k->device_id = 0xABCD;
 579    k->revision = 0;
 580    k->class_id = PCI_CLASS_BRIDGE_PCI;
 581    k->is_bridge = true;
 582    k->exit = pci_bridge_exitfn;
 583    k->realize = designware_pcie_root_realize;
 584    k->config_read = designware_pcie_root_config_read;
 585    k->config_write = designware_pcie_root_config_write;
 586
 587    dc->reset = pci_bridge_reset;
 588    /*
 589     * PCI-facing part of the host bridge, not usable without the
 590     * host-facing part, which can't be device_add'ed, yet.
 591     */
 592    dc->user_creatable = false;
 593    dc->vmsd = &vmstate_designware_pcie_root;
 594}
 595
 596static uint64_t designware_pcie_host_mmio_read(void *opaque, hwaddr addr,
 597                                               unsigned int size)
 598{
 599    PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
 600    PCIDevice *device = pci_find_device(pci->bus, 0, 0);
 601
 602    return pci_host_config_read_common(device,
 603                                       addr,
 604                                       pci_config_size(device),
 605                                       size);
 606}
 607
 608static void designware_pcie_host_mmio_write(void *opaque, hwaddr addr,
 609                                            uint64_t val, unsigned int size)
 610{
 611    PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
 612    PCIDevice *device = pci_find_device(pci->bus, 0, 0);
 613
 614    return pci_host_config_write_common(device,
 615                                        addr,
 616                                        pci_config_size(device),
 617                                        val, size);
 618}
 619
 620static const MemoryRegionOps designware_pci_mmio_ops = {
 621    .read       = designware_pcie_host_mmio_read,
 622    .write      = designware_pcie_host_mmio_write,
 623    .endianness = DEVICE_LITTLE_ENDIAN,
 624    .impl = {
 625        /*
 626         * Our device would not work correctly if the guest was doing
 627         * unaligned access. This might not be a limitation on the real
 628         * device but in practice there is no reason for a guest to access
 629         * this device unaligned.
 630         */
 631        .min_access_size = 4,
 632        .max_access_size = 4,
 633        .unaligned = false,
 634    },
 635};
 636
 637static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque,
 638                                                    int devfn)
 639{
 640    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(opaque);
 641
 642    return &s->pci.address_space;
 643}
 644
 645static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
 646{
 647    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
 648    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(dev);
 649    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 650    size_t i;
 651
 652    for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) {
 653        sysbus_init_irq(sbd, &s->pci.irqs[i]);
 654    }
 655
 656    memory_region_init_io(&s->mmio,
 657                          OBJECT(s),
 658                          &designware_pci_mmio_ops,
 659                          s,
 660                          "pcie.reg", 4 * 1024);
 661    sysbus_init_mmio(sbd, &s->mmio);
 662
 663    memory_region_init(&s->pci.io, OBJECT(s), "pcie-pio", 16);
 664    memory_region_init(&s->pci.memory, OBJECT(s),
 665                       "pcie-bus-memory",
 666                       UINT64_MAX);
 667
 668    pci->bus = pci_register_root_bus(dev, "pcie",
 669                                     designware_pcie_set_irq,
 670                                     pci_swizzle_map_irq_fn,
 671                                     s,
 672                                     &s->pci.memory,
 673                                     &s->pci.io,
 674                                     0, 4,
 675                                     TYPE_PCIE_BUS);
 676
 677    memory_region_init(&s->pci.address_space_root,
 678                       OBJECT(s),
 679                       "pcie-bus-address-space-root",
 680                       UINT64_MAX);
 681    memory_region_add_subregion(&s->pci.address_space_root,
 682                                0x0, &s->pci.memory);
 683    address_space_init(&s->pci.address_space,
 684                       &s->pci.address_space_root,
 685                       "pcie-bus-address-space");
 686    pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s);
 687
 688    qdev_set_parent_bus(DEVICE(&s->root), BUS(pci->bus));
 689    qdev_init_nofail(DEVICE(&s->root));
 690}
 691
 692static const VMStateDescription vmstate_designware_pcie_host = {
 693    .name = "designware-pcie-host",
 694    .version_id = 1,
 695    .minimum_version_id = 1,
 696    .fields = (VMStateField[]) {
 697        VMSTATE_STRUCT(root,
 698                       DesignwarePCIEHost,
 699                       1,
 700                       vmstate_designware_pcie_root,
 701                       DesignwarePCIERoot),
 702        VMSTATE_END_OF_LIST()
 703    }
 704};
 705
 706static void designware_pcie_host_class_init(ObjectClass *klass, void *data)
 707{
 708    DeviceClass *dc = DEVICE_CLASS(klass);
 709    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
 710
 711    hc->root_bus_path = designware_pcie_host_root_bus_path;
 712    dc->realize = designware_pcie_host_realize;
 713    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 714    dc->fw_name = "pci";
 715    dc->vmsd = &vmstate_designware_pcie_host;
 716}
 717
 718static void designware_pcie_host_init(Object *obj)
 719{
 720    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj);
 721    DesignwarePCIERoot *root = &s->root;
 722
 723    object_initialize_child(obj, "root",  root, sizeof(*root),
 724                            TYPE_DESIGNWARE_PCIE_ROOT, &error_abort, NULL);
 725    qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
 726    qdev_prop_set_bit(DEVICE(root), "multifunction", false);
 727}
 728
 729static const TypeInfo designware_pcie_root_info = {
 730    .name = TYPE_DESIGNWARE_PCIE_ROOT,
 731    .parent = TYPE_PCI_BRIDGE,
 732    .instance_size = sizeof(DesignwarePCIERoot),
 733    .class_init = designware_pcie_root_class_init,
 734    .interfaces = (InterfaceInfo[]) {
 735        { INTERFACE_PCIE_DEVICE },
 736        { }
 737    },
 738};
 739
 740static const TypeInfo designware_pcie_host_info = {
 741    .name       = TYPE_DESIGNWARE_PCIE_HOST,
 742    .parent     = TYPE_PCI_HOST_BRIDGE,
 743    .instance_size = sizeof(DesignwarePCIEHost),
 744    .instance_init = designware_pcie_host_init,
 745    .class_init = designware_pcie_host_class_init,
 746};
 747
 748static void designware_pcie_register(void)
 749{
 750    type_register_static(&designware_pcie_root_info);
 751    type_register_static(&designware_pcie_host_info);
 752}
 753type_init(designware_pcie_register)
 754