qemu/hw/s390x/s390-pci-bus.c
<<
>>
Prefs
   1/*
   2 * s390 PCI BUS
   3 *
   4 * Copyright 2014 IBM Corp.
   5 * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com>
   6 *            Hong Bo Li <lihbbj@cn.ibm.com>
   7 *            Yi Min Zhao <zyimin@cn.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or (at
  10 * your option) any later version. See the COPYING file in the top-level
  11 * directory.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qemu-common.h"
  16#include "cpu.h"
  17#include "s390-pci-bus.h"
  18#include <hw/pci/pci_bus.h>
  19#include <hw/pci/msi.h>
  20#include <qemu/error-report.h>
  21
  22/* #define DEBUG_S390PCI_BUS */
  23#ifdef DEBUG_S390PCI_BUS
  24#define DPRINTF(fmt, ...) \
  25    do { fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); } while (0)
  26#else
  27#define DPRINTF(fmt, ...) \
  28    do { } while (0)
  29#endif
  30
  31int chsc_sei_nt2_get_event(void *res)
  32{
  33    ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res;
  34    PciCcdfAvail *accdf;
  35    PciCcdfErr *eccdf;
  36    int rc = 1;
  37    SeiContainer *sei_cont;
  38    S390pciState *s = S390_PCI_HOST_BRIDGE(
  39        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
  40
  41    if (!s) {
  42        return rc;
  43    }
  44
  45    sei_cont = QTAILQ_FIRST(&s->pending_sei);
  46    if (sei_cont) {
  47        QTAILQ_REMOVE(&s->pending_sei, sei_cont, link);
  48        nt2_res->nt = 2;
  49        nt2_res->cc = sei_cont->cc;
  50        nt2_res->length = cpu_to_be16(sizeof(ChscSeiNt2Res));
  51        switch (sei_cont->cc) {
  52        case 1: /* error event */
  53            eccdf = (PciCcdfErr *)nt2_res->ccdf;
  54            eccdf->fid = cpu_to_be32(sei_cont->fid);
  55            eccdf->fh = cpu_to_be32(sei_cont->fh);
  56            eccdf->e = cpu_to_be32(sei_cont->e);
  57            eccdf->faddr = cpu_to_be64(sei_cont->faddr);
  58            eccdf->pec = cpu_to_be16(sei_cont->pec);
  59            break;
  60        case 2: /* availability event */
  61            accdf = (PciCcdfAvail *)nt2_res->ccdf;
  62            accdf->fid = cpu_to_be32(sei_cont->fid);
  63            accdf->fh = cpu_to_be32(sei_cont->fh);
  64            accdf->pec = cpu_to_be16(sei_cont->pec);
  65            break;
  66        default:
  67            abort();
  68        }
  69        g_free(sei_cont);
  70        rc = 0;
  71    }
  72
  73    return rc;
  74}
  75
  76int chsc_sei_nt2_have_event(void)
  77{
  78    S390pciState *s = S390_PCI_HOST_BRIDGE(
  79        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
  80
  81    if (!s) {
  82        return 0;
  83    }
  84
  85    return !QTAILQ_EMPTY(&s->pending_sei);
  86}
  87
  88S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
  89{
  90    S390PCIBusDevice *pbdev;
  91    int i;
  92    S390pciState *s = S390_PCI_HOST_BRIDGE(
  93        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
  94
  95    if (!s) {
  96        return NULL;
  97    }
  98
  99    for (i = 0; i < PCI_SLOT_MAX; i++) {
 100        pbdev = &s->pbdev[i];
 101        if ((pbdev->fh != 0) && (pbdev->fid == fid)) {
 102            return pbdev;
 103        }
 104    }
 105
 106    return NULL;
 107}
 108
 109void s390_pci_sclp_configure(int configure, SCCB *sccb)
 110{
 111    PciCfgSccb *psccb = (PciCfgSccb *)sccb;
 112    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
 113    uint16_t rc;
 114
 115    if (pbdev) {
 116        if ((configure == 1 && pbdev->configured == true) ||
 117            (configure == 0 && pbdev->configured == false)) {
 118            rc = SCLP_RC_NO_ACTION_REQUIRED;
 119        } else {
 120            pbdev->configured = !pbdev->configured;
 121            rc = SCLP_RC_NORMAL_COMPLETION;
 122        }
 123    } else {
 124        DPRINTF("sclp config %d no dev found\n", configure);
 125        rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
 126    }
 127
 128    psccb->header.response_code = cpu_to_be16(rc);
 129}
 130
 131static uint32_t s390_pci_get_pfid(PCIDevice *pdev)
 132{
 133    return PCI_SLOT(pdev->devfn);
 134}
 135
 136static uint32_t s390_pci_get_pfh(PCIDevice *pdev)
 137{
 138    return PCI_SLOT(pdev->devfn) | FH_VIRT;
 139}
 140
 141S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx)
 142{
 143    S390PCIBusDevice *pbdev;
 144    int i;
 145    int j = 0;
 146    S390pciState *s = S390_PCI_HOST_BRIDGE(
 147        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
 148
 149    if (!s) {
 150        return NULL;
 151    }
 152
 153    for (i = 0; i < PCI_SLOT_MAX; i++) {
 154        pbdev = &s->pbdev[i];
 155
 156        if (pbdev->fh == 0) {
 157            continue;
 158        }
 159
 160        if (j == idx) {
 161            return pbdev;
 162        }
 163        j++;
 164    }
 165
 166    return NULL;
 167}
 168
 169S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh)
 170{
 171    S390PCIBusDevice *pbdev;
 172    int i;
 173    S390pciState *s = S390_PCI_HOST_BRIDGE(
 174        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
 175
 176    if (!s || !fh) {
 177        return NULL;
 178    }
 179
 180    for (i = 0; i < PCI_SLOT_MAX; i++) {
 181        pbdev = &s->pbdev[i];
 182        if (pbdev->fh == fh) {
 183            return pbdev;
 184        }
 185    }
 186
 187    return NULL;
 188}
 189
 190static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh,
 191                                    uint32_t fid, uint64_t faddr, uint32_t e)
 192{
 193    SeiContainer *sei_cont;
 194    S390pciState *s = S390_PCI_HOST_BRIDGE(
 195        object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL));
 196
 197    if (!s) {
 198        return;
 199    }
 200
 201    sei_cont = g_malloc0(sizeof(SeiContainer));
 202    sei_cont->fh = fh;
 203    sei_cont->fid = fid;
 204    sei_cont->cc = cc;
 205    sei_cont->pec = pec;
 206    sei_cont->faddr = faddr;
 207    sei_cont->e = e;
 208
 209    QTAILQ_INSERT_TAIL(&s->pending_sei, sei_cont, link);
 210    css_generate_css_crws(0);
 211}
 212
 213static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh,
 214                                         uint32_t fid)
 215{
 216    s390_pci_generate_event(2, pec, fh, fid, 0, 0);
 217}
 218
 219static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh,
 220                                          uint32_t fid, uint64_t faddr,
 221                                          uint32_t e)
 222{
 223    s390_pci_generate_event(1, pec, fh, fid, faddr, e);
 224}
 225
 226static void s390_pci_set_irq(void *opaque, int irq, int level)
 227{
 228    /* nothing to do */
 229}
 230
 231static int s390_pci_map_irq(PCIDevice *pci_dev, int irq_num)
 232{
 233    /* nothing to do */
 234    return 0;
 235}
 236
 237static uint64_t s390_pci_get_table_origin(uint64_t iota)
 238{
 239    return iota & ~ZPCI_IOTA_RTTO_FLAG;
 240}
 241
 242static unsigned int calc_rtx(dma_addr_t ptr)
 243{
 244    return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK;
 245}
 246
 247static unsigned int calc_sx(dma_addr_t ptr)
 248{
 249    return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK;
 250}
 251
 252static unsigned int calc_px(dma_addr_t ptr)
 253{
 254    return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK;
 255}
 256
 257static uint64_t get_rt_sto(uint64_t entry)
 258{
 259    return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX)
 260                ? (entry & ZPCI_RTE_ADDR_MASK)
 261                : 0;
 262}
 263
 264static uint64_t get_st_pto(uint64_t entry)
 265{
 266    return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX)
 267            ? (entry & ZPCI_STE_ADDR_MASK)
 268            : 0;
 269}
 270
 271static uint64_t s390_guest_io_table_walk(uint64_t guest_iota,
 272                                  uint64_t guest_dma_address)
 273{
 274    uint64_t sto_a, pto_a, px_a;
 275    uint64_t sto, pto, pte;
 276    uint32_t rtx, sx, px;
 277
 278    rtx = calc_rtx(guest_dma_address);
 279    sx = calc_sx(guest_dma_address);
 280    px = calc_px(guest_dma_address);
 281
 282    sto_a = guest_iota + rtx * sizeof(uint64_t);
 283    sto = address_space_ldq(&address_space_memory, sto_a,
 284                            MEMTXATTRS_UNSPECIFIED, NULL);
 285    sto = get_rt_sto(sto);
 286    if (!sto) {
 287        pte = 0;
 288        goto out;
 289    }
 290
 291    pto_a = sto + sx * sizeof(uint64_t);
 292    pto = address_space_ldq(&address_space_memory, pto_a,
 293                            MEMTXATTRS_UNSPECIFIED, NULL);
 294    pto = get_st_pto(pto);
 295    if (!pto) {
 296        pte = 0;
 297        goto out;
 298    }
 299
 300    px_a = pto + px * sizeof(uint64_t);
 301    pte = address_space_ldq(&address_space_memory, px_a,
 302                            MEMTXATTRS_UNSPECIFIED, NULL);
 303
 304out:
 305    return pte;
 306}
 307
 308static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
 309                                          bool is_write)
 310{
 311    uint64_t pte;
 312    uint32_t flags;
 313    S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr);
 314    S390pciState *s;
 315    IOMMUTLBEntry ret = {
 316        .target_as = &address_space_memory,
 317        .iova = 0,
 318        .translated_addr = 0,
 319        .addr_mask = ~(hwaddr)0,
 320        .perm = IOMMU_NONE,
 321    };
 322
 323    if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) {
 324        return ret;
 325    }
 326
 327    DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
 328
 329    s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent);
 330    /* s390 does not have an APIC mapped to main storage so we use
 331     * a separate AddressSpace only for msix notifications
 332     */
 333    if (addr == ZPCI_MSI_ADDR) {
 334        ret.target_as = &s->msix_notify_as;
 335        ret.iova = addr;
 336        ret.translated_addr = addr;
 337        ret.addr_mask = 0xfff;
 338        ret.perm = IOMMU_RW;
 339        return ret;
 340    }
 341
 342    if (!pbdev->g_iota) {
 343        pbdev->error_state = true;
 344        pbdev->lgstg_blocked = true;
 345        s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
 346                                      addr, 0);
 347        return ret;
 348    }
 349
 350    if (addr < pbdev->pba || addr > pbdev->pal) {
 351        pbdev->error_state = true;
 352        pbdev->lgstg_blocked = true;
 353        s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
 354                                      addr, 0);
 355        return ret;
 356    }
 357
 358    pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
 359                                   addr);
 360
 361    if (!pte) {
 362        pbdev->error_state = true;
 363        pbdev->lgstg_blocked = true;
 364        s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
 365                                      addr, ERR_EVENT_Q_BIT);
 366        return ret;
 367    }
 368
 369    flags = pte & ZPCI_PTE_FLAG_MASK;
 370    ret.iova = addr;
 371    ret.translated_addr = pte & ZPCI_PTE_ADDR_MASK;
 372    ret.addr_mask = 0xfff;
 373
 374    if (flags & ZPCI_PTE_INVALID) {
 375        ret.perm = IOMMU_NONE;
 376    } else {
 377        ret.perm = IOMMU_RW;
 378    }
 379
 380    return ret;
 381}
 382
 383static const MemoryRegionIOMMUOps s390_iommu_ops = {
 384    .translate = s390_translate_iommu,
 385};
 386
 387static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 388{
 389    S390pciState *s = opaque;
 390
 391    return &s->pbdev[PCI_SLOT(devfn)].as;
 392}
 393
 394static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
 395{
 396    uint8_t ind_old, ind_new;
 397    hwaddr len = 1;
 398    uint8_t *ind_addr;
 399
 400    ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
 401    if (!ind_addr) {
 402        s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0);
 403        return -1;
 404    }
 405    do {
 406        ind_old = *ind_addr;
 407        ind_new = ind_old | to_be_set;
 408    } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
 409    cpu_physical_memory_unmap(ind_addr, len, 1, len);
 410
 411    return ind_old;
 412}
 413
 414static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
 415                                unsigned int size)
 416{
 417    S390PCIBusDevice *pbdev;
 418    uint32_t io_int_word;
 419    uint32_t fid = data >> ZPCI_MSI_VEC_BITS;
 420    uint32_t vec = data & ZPCI_MSI_VEC_MASK;
 421    uint64_t ind_bit;
 422    uint32_t sum_bit;
 423    uint32_t e = 0;
 424
 425    DPRINTF("write_msix data 0x%" PRIx64 " fid %d vec 0x%x\n", data, fid, vec);
 426
 427    pbdev = s390_pci_find_dev_by_fid(fid);
 428    if (!pbdev) {
 429        e |= (vec << ERR_EVENT_MVN_OFFSET);
 430        s390_pci_generate_error_event(ERR_EVENT_NOMSI, 0, fid, addr, e);
 431        return;
 432    }
 433
 434    if (!(pbdev->fh & FH_ENABLED)) {
 435        return;
 436    }
 437
 438    ind_bit = pbdev->routes.adapter.ind_offset;
 439    sum_bit = pbdev->routes.adapter.summary_offset;
 440
 441    set_ind_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8,
 442                   0x80 >> ((ind_bit + vec) % 8));
 443    if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8,
 444                                       0x80 >> (sum_bit % 8))) {
 445        io_int_word = (pbdev->isc << 27) | IO_INT_WORD_AI;
 446        s390_io_interrupt(0, 0, 0, io_int_word);
 447    }
 448}
 449
 450static uint64_t s390_msi_ctrl_read(void *opaque, hwaddr addr, unsigned size)
 451{
 452    return 0xffffffff;
 453}
 454
 455static const MemoryRegionOps s390_msi_ctrl_ops = {
 456    .write = s390_msi_ctrl_write,
 457    .read = s390_msi_ctrl_read,
 458    .endianness = DEVICE_LITTLE_ENDIAN,
 459};
 460
 461void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable)
 462{
 463    pbdev->configured = false;
 464
 465    if (enable) {
 466        uint64_t size = pbdev->pal - pbdev->pba + 1;
 467        memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr),
 468                                 &s390_iommu_ops, "iommu-s390", size);
 469        memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr);
 470    } else {
 471        memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr);
 472    }
 473
 474    pbdev->configured = true;
 475}
 476
 477static void s390_pcihost_init_as(S390pciState *s)
 478{
 479    int i;
 480    S390PCIBusDevice *pbdev;
 481
 482    for (i = 0; i < PCI_SLOT_MAX; i++) {
 483        pbdev = &s->pbdev[i];
 484        memory_region_init(&pbdev->mr, OBJECT(s),
 485                           "iommu-root-s390", UINT64_MAX);
 486        address_space_init(&pbdev->as, &pbdev->mr, "iommu-pci");
 487    }
 488
 489    memory_region_init_io(&s->msix_notify_mr, OBJECT(s),
 490                          &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX);
 491    address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci");
 492}
 493
 494static int s390_pcihost_init(SysBusDevice *dev)
 495{
 496    PCIBus *b;
 497    BusState *bus;
 498    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
 499    S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
 500
 501    DPRINTF("host_init\n");
 502
 503    b = pci_register_bus(DEVICE(dev), NULL,
 504                         s390_pci_set_irq, s390_pci_map_irq, NULL,
 505                         get_system_memory(), get_system_io(), 0, 64,
 506                         TYPE_PCI_BUS);
 507    s390_pcihost_init_as(s);
 508    pci_setup_iommu(b, s390_pci_dma_iommu, s);
 509
 510    bus = BUS(b);
 511    qbus_set_hotplug_handler(bus, DEVICE(dev), NULL);
 512    phb->bus = b;
 513    QTAILQ_INIT(&s->pending_sei);
 514    return 0;
 515}
 516
 517static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
 518{
 519    uint8_t pos;
 520    uint16_t ctrl;
 521    uint32_t table, pba;
 522
 523    pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX);
 524    if (!pos) {
 525        pbdev->msix.available = false;
 526        return 0;
 527    }
 528
 529    ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS,
 530             pci_config_size(pbdev->pdev), sizeof(ctrl));
 531    table = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_TABLE,
 532             pci_config_size(pbdev->pdev), sizeof(table));
 533    pba = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_PBA,
 534             pci_config_size(pbdev->pdev), sizeof(pba));
 535
 536    pbdev->msix.table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
 537    pbdev->msix.table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
 538    pbdev->msix.pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
 539    pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
 540    pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
 541    pbdev->msix.available = true;
 542    return 0;
 543}
 544
 545static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
 546                                  DeviceState *dev, Error **errp)
 547{
 548    PCIDevice *pci_dev = PCI_DEVICE(dev);
 549    S390PCIBusDevice *pbdev;
 550    S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev)
 551                                           ->qbus.parent);
 552
 553    pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
 554
 555    pbdev->fid = s390_pci_get_pfid(pci_dev);
 556    pbdev->pdev = pci_dev;
 557    pbdev->configured = true;
 558    pbdev->fh = s390_pci_get_pfh(pci_dev);
 559
 560    s390_pcihost_setup_msix(pbdev);
 561
 562    if (dev->hotplugged) {
 563        s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
 564                                     pbdev->fh, pbdev->fid);
 565        s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED,
 566                                     pbdev->fh, pbdev->fid);
 567    }
 568}
 569
 570static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
 571                                    DeviceState *dev, Error **errp)
 572{
 573    PCIDevice *pci_dev = PCI_DEVICE(dev);
 574    S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev)
 575                                           ->qbus.parent);
 576    S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)];
 577
 578    if (pbdev->configured) {
 579        pbdev->configured = false;
 580        s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
 581                                     pbdev->fh, pbdev->fid);
 582    }
 583
 584    s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
 585                                 pbdev->fh, pbdev->fid);
 586    pbdev->fh = 0;
 587    pbdev->fid = 0;
 588    pbdev->pdev = NULL;
 589    object_unparent(OBJECT(pci_dev));
 590}
 591
 592static void s390_pcihost_class_init(ObjectClass *klass, void *data)
 593{
 594    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 595    DeviceClass *dc = DEVICE_CLASS(klass);
 596    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
 597
 598    dc->cannot_instantiate_with_device_add_yet = true;
 599    k->init = s390_pcihost_init;
 600    hc->plug = s390_pcihost_hot_plug;
 601    hc->unplug = s390_pcihost_hot_unplug;
 602    msi_nonbroken = true;
 603}
 604
 605static const TypeInfo s390_pcihost_info = {
 606    .name          = TYPE_S390_PCI_HOST_BRIDGE,
 607    .parent        = TYPE_PCI_HOST_BRIDGE,
 608    .instance_size = sizeof(S390pciState),
 609    .class_init    = s390_pcihost_class_init,
 610    .interfaces = (InterfaceInfo[]) {
 611        { TYPE_HOTPLUG_HANDLER },
 612        { }
 613    }
 614};
 615
 616static void s390_pci_register_types(void)
 617{
 618    type_register_static(&s390_pcihost_info);
 619}
 620
 621type_init(s390_pci_register_types)
 622