Commit d1c82f7c authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170120-v2' into staging



First set of s390x patches for 2.9:
- rework of the zpci code, giving us proper multibus support
- introduction of the 2.9 machine
- fixes and improvements

# gpg: Signature made Fri 20 Jan 2017 09:11:58 GMT
# gpg:                using RSA key 0xDECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck/tags/s390x-20170120-v2:
  virtio-ccw: fix ring sizing
  s390x/pci: merge msix init functions
  s390x/pci: handle PCIBridge bus number
  s390x/pci: use hashtable to look up zpci via fh
  s390x/pci: PCI multibus bridge handling
  s390x/pci: optimize calling s390_get_phb()
  s390x/pci: change the device array to a list
  s390x/pci: dynamically allocate iommu
  s390x/pci: make S390PCIIOMMU inherit Object
  s390x/kvm: use kvm_gsi_routing_enabled in flic
  s390x: add compat machine for 2.9
  s390x: remove double compat statement

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents db655a96 8c797e75
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
        .addr = (uint64_t)&adapter,
    };

    if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
    if (!kvm_gsi_routing_enabled()) {
        /* nothing to do */
        return 0;
    }
@@ -226,7 +226,7 @@ static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
    int r;

    if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
    if (!kvm_gsi_routing_enabled()) {
        /* nothing to do */
        return 0;
    }
+236 −125
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "s390-pci-bus.h"
#include "s390-pci-inst.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/msi.h"
#include "qemu/error-report.h"

@@ -31,7 +32,7 @@
    do { } while (0)
#endif

static S390pciState *s390_get_phb(void)
S390pciState *s390_get_phb(void)
{
    static S390pciState *phb;

@@ -91,35 +92,25 @@ int chsc_sei_nt2_have_event(void)
    return !QTAILQ_EMPTY(&s->pending_sei);
}

S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev)
S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s,
                                               S390PCIBusDevice *pbdev)
{
    int idx = 0;
    S390PCIBusDevice *dev = NULL;
    S390pciState *s = s390_get_phb();

    if (pbdev) {
        idx = (pbdev->fh & FH_MASK_INDEX) + 1;
    }
    S390PCIBusDevice *ret = pbdev ? QTAILQ_NEXT(pbdev, link) :
        QTAILQ_FIRST(&s->zpci_devs);

    for (; idx < PCI_SLOT_MAX; idx++) {
        dev = s->pbdev[idx];
        if (dev && dev->state != ZPCI_FS_RESERVED) {
            return dev;
        }
    while (ret && ret->state == ZPCI_FS_RESERVED) {
        ret = QTAILQ_NEXT(ret, link);
    }

    return NULL;
    return ret;
}

S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid)
{
    S390PCIBusDevice *pbdev;
    int i;
    S390pciState *s = s390_get_phb();

    for (i = 0; i < PCI_SLOT_MAX; i++) {
        pbdev = s->pbdev[i];
        if (pbdev && pbdev->fid == fid) {
    QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
        if (pbdev->fid == fid) {
            return pbdev;
        }
    }
@@ -130,7 +121,8 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
void s390_pci_sclp_configure(SCCB *sccb)
{
    PciCfgSccb *psccb = (PciCfgSccb *)sccb;
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(),
                                                       be32_to_cpu(psccb->aid));
    uint16_t rc;

    if (be16_to_cpu(sccb->h.length) < 16) {
@@ -162,7 +154,8 @@ out:
void s390_pci_sclp_deconfigure(SCCB *sccb)
{
    PciCfgSccb *psccb = (PciCfgSccb *)sccb;
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(),
                                                       be32_to_cpu(psccb->aid));
    uint16_t rc;

    if (be16_to_cpu(sccb->h.length) < 16) {
@@ -187,8 +180,8 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
        if (pbdev->summary_ind) {
            pci_dereg_irqs(pbdev);
        }
        if (pbdev->iommu_enabled) {
            pci_dereg_ioat(pbdev);
        if (pbdev->iommu->enabled) {
            pci_dereg_ioat(pbdev->iommu);
        }
        pbdev->state = ZPCI_FS_STANDBY;
        rc = SCLP_RC_NORMAL_COMPLETION;
@@ -201,18 +194,11 @@ out:
    psccb->header.response_code = cpu_to_be16(rc);
}

static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid)
static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid)
{
    int i;
    S390PCIBusDevice *pbdev;
    S390pciState *s = s390_get_phb();

    for (i = 0; i < PCI_SLOT_MAX; i++) {
        pbdev = s->pbdev[i];
        if (!pbdev) {
            continue;
        }

    QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
        if (pbdev->uid == uid) {
            return pbdev;
        }
@@ -221,22 +207,16 @@ static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid)
    return NULL;
}

static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target)
static S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
                                                     const char *target)
{
    int i;
    S390PCIBusDevice *pbdev;
    S390pciState *s = s390_get_phb();

    if (!target) {
        return NULL;
    }

    for (i = 0; i < PCI_SLOT_MAX; i++) {
        pbdev = s->pbdev[i];
        if (!pbdev) {
            continue;
        }

    QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
        if (!strcmp(pbdev->target, target)) {
            return pbdev;
        }
@@ -245,19 +225,16 @@ static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target)
    return NULL;
}

S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx)
S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx)
{
    S390pciState *s = s390_get_phb();

    return s->pbdev[idx & FH_MASK_INDEX];
    return g_hash_table_lookup(s->zpci_table, &idx);
}

S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh)
S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh)
{
    S390pciState *s = s390_get_phb();
    S390PCIBusDevice *pbdev;
    uint32_t idx = FH_MASK_INDEX & fh;
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_idx(s, idx);

    pbdev = s->pbdev[fh & FH_MASK_INDEX];
    if (pbdev && pbdev->fh == fh) {
        return pbdev;
    }
@@ -377,12 +354,12 @@ out:
    return pte;
}

static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
                                          bool is_write)
{
    uint64_t pte;
    uint32_t flags;
    S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr);
    S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
    IOMMUTLBEntry ret = {
        .target_as = &address_space_memory,
        .iova = 0,
@@ -391,10 +368,10 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
        .perm = IOMMU_NONE,
    };

    switch (pbdev->state) {
    switch (iommu->pbdev->state) {
    case ZPCI_FS_ENABLED:
    case ZPCI_FS_BLOCKED:
        if (!pbdev->iommu_enabled) {
        if (!iommu->enabled) {
            return ret;
        }
        break;
@@ -404,11 +381,11 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,

    DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);

    if (addr < pbdev->pba || addr > pbdev->pal) {
    if (addr < iommu->pba || addr > iommu->pal) {
        return ret;
    }

    pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota),
    pte = s390_guest_io_table_walk(s390_pci_get_table_origin(iommu->g_iota),
                                   addr);
    if (!pte) {
        return ret;
@@ -432,11 +409,48 @@ static const MemoryRegionIOMMUOps s390_iommu_ops = {
    .translate = s390_translate_iommu,
};

static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
                                        int devfn)
{
    uint64_t key = (uintptr_t)bus;
    S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key);
    S390PCIIOMMU *iommu;

    if (!table) {
        table = g_malloc0(sizeof(S390PCIIOMMUTable));
        table->key = key;
        g_hash_table_insert(s->iommu_table, &table->key, table);
    }

    iommu = table->iommu[PCI_SLOT(devfn)];
    if (!iommu) {
        iommu = S390_PCI_IOMMU(object_new(TYPE_S390_PCI_IOMMU));

        char *mr_name = g_strdup_printf("iommu-root-%02x:%02x.%01x",
                                        pci_bus_num(bus),
                                        PCI_SLOT(devfn),
                                        PCI_FUNC(devfn));
        char *as_name = g_strdup_printf("iommu-pci-%02x:%02x.%01x",
                                        pci_bus_num(bus),
                                        PCI_SLOT(devfn),
                                        PCI_FUNC(devfn));
        memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX);
        address_space_init(&iommu->as, &iommu->mr, as_name);
        table->iommu[PCI_SLOT(devfn)] = iommu;

        g_free(mr_name);
        g_free(as_name);
    }

    return iommu;
}

static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{
    S390pciState *s = opaque;
    S390PCIIOMMU *iommu = s390_pci_get_iommu(s, bus, devfn);

    return &s->iommu[PCI_SLOT(devfn)]->as;
    return &iommu->as;
}

static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
@@ -503,34 +517,38 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
    .endianness = DEVICE_LITTLE_ENDIAN,
};

void s390_pci_iommu_enable(S390PCIBusDevice *pbdev)
void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
{
    memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->iommu->mr),
                             &s390_iommu_ops, "iommu-s390", pbdev->pal + 1);
    memory_region_add_subregion(&pbdev->iommu->mr, 0, &pbdev->iommu_mr);
    pbdev->iommu_enabled = true;
    char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
    memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr),
                             &s390_iommu_ops, name, iommu->pal + 1);
    iommu->enabled = true;
    memory_region_add_subregion(&iommu->mr, 0, &iommu->iommu_mr);
    g_free(name);
}

void s390_pci_iommu_disable(S390PCIBusDevice *pbdev)
void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{
    memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->iommu_mr);
    object_unparent(OBJECT(&pbdev->iommu_mr));
    pbdev->iommu_enabled = false;
    iommu->enabled = false;
    memory_region_del_subregion(&iommu->mr, &iommu->iommu_mr);
    object_unparent(OBJECT(&iommu->iommu_mr));
}

static void s390_pcihost_init_as(S390pciState *s)
static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
{
    int i;
    S390PCIIOMMU *iommu;
    uint64_t key = (uintptr_t)bus;
    S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key);
    S390PCIIOMMU *iommu = table ? table->iommu[PCI_SLOT(devfn)] : NULL;

    for (i = 0; i < PCI_SLOT_MAX; i++) {
        iommu = g_malloc0(sizeof(S390PCIIOMMU));
        memory_region_init(&iommu->mr, OBJECT(s),
                           "iommu-root-s390", UINT64_MAX);
        address_space_init(&iommu->as, &iommu->mr, "iommu-pci");

        s->iommu[i] = iommu;
    if (!table || !iommu) {
        return;
    }

    table->iommu[PCI_SLOT(devfn)] = NULL;
    address_space_destroy(&iommu->as);
    object_unparent(OBJECT(&iommu->mr));
    object_unparent(OBJECT(iommu));
    object_unref(OBJECT(iommu));
}

static int s390_pcihost_init(SysBusDevice *dev)
@@ -546,7 +564,6 @@ static int s390_pcihost_init(SysBusDevice *dev)
                         s390_pci_set_irq, s390_pci_map_irq, NULL,
                         get_system_memory(), get_system_io(), 0, 64,
                         TYPE_PCI_BUS);
    s390_pcihost_init_as(s);
    pci_setup_iommu(b, s390_pci_dma_iommu, s);

    bus = BUS(b);
@@ -556,12 +573,18 @@ static int s390_pcihost_init(SysBusDevice *dev)
    s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL));
    qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL);

    s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
                                           NULL, g_free);
    s->zpci_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL);
    s->bus_no = 0;
    QTAILQ_INIT(&s->pending_sei);
    QTAILQ_INIT(&s->zpci_devs);
    return 0;
}

static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
{
    char *name;
    uint8_t pos;
    uint16_t ctrl;
    uint32_t table, pba;
@@ -569,7 +592,7 @@ static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
    pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX);
    if (!pos) {
        pbdev->msix.available = false;
        return 0;
        return -1;
    }

    ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS,
@@ -585,21 +608,15 @@ static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
    pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
    pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
    pbdev->msix.available = true;
    return 0;
}

static void s390_pci_msix_init(S390PCIBusDevice *pbdev)
{
    char *name;

    name = g_strdup_printf("msix-s390-%04x", pbdev->uid);

    memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
                          &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
    memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR,
                                &pbdev->msix_notify_mr);

    g_free(name);

    return 0;
}

static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
@@ -608,10 +625,10 @@ static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
    object_unparent(OBJECT(&pbdev->msix_notify_mr));
}

static S390PCIBusDevice *s390_pci_device_new(const char *target)
static S390PCIBusDevice *s390_pci_device_new(S390pciState *s,
                                             const char *target)
{
    DeviceState *dev = NULL;
    S390pciState *s = s390_get_phb();

    dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE);
    if (!dev) {
@@ -624,6 +641,24 @@ static S390PCIBusDevice *s390_pci_device_new(const char *target)
    return S390_PCI_DEVICE(dev);
}

static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
{
    uint32_t idx;

    idx = s->next_idx;
    while (s390_pci_find_dev_by_idx(s, idx)) {
        idx = (idx + 1) & FH_MASK_INDEX;
        if (idx == s->next_idx) {
            return false;
        }
    }

    pbdev->idx = idx;
    s->next_idx = (idx + 1) & FH_MASK_INDEX;

    return true;
}

static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
                                  DeviceState *dev, Error **errp)
{
@@ -631,7 +666,28 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
    S390PCIBusDevice *pbdev = NULL;
    S390pciState *s = s390_get_phb();

    if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
        BusState *bus;
        PCIBridge *pb = PCI_BRIDGE(dev);
        PCIDevice *pdev = PCI_DEVICE(dev);

        pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
        pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);

        bus = BUS(&pb->sec_bus);
        qbus_set_hotplug_handler(bus, DEVICE(s), errp);

        if (dev->hotplugged) {
            pci_default_write_config(pdev, PCI_PRIMARY_BUS, s->bus_no, 1);
            s->bus_no += 1;
            pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1);
            do {
                pdev = pdev->bus->parent_dev;
                pci_default_write_config(pdev, PCI_SUBORDINATE_BUS,
                                         s->bus_no, 1);
            } while (pdev->bus && pci_bus_num(pdev->bus));
        }
    } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
        pdev = PCI_DEVICE(dev);

        if (!dev->id) {
@@ -643,9 +699,9 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
                                      PCI_FUNC(pdev->devfn));
        }

        pbdev = s390_pci_find_dev_by_target(dev->id);
        pbdev = s390_pci_find_dev_by_target(s, dev->id);
        if (!pbdev) {
            pbdev = s390_pci_device_new(dev->id);
            pbdev = s390_pci_device_new(s, dev->id);
            if (!pbdev) {
                error_setg(errp, "create zpci device failed");
                return;
@@ -659,29 +715,30 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
        }

        pbdev->pdev = pdev;
        pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)];
        pbdev->iommu = s390_pci_get_iommu(s, pdev->bus, pdev->devfn);
        pbdev->iommu->pbdev = pbdev;
        pbdev->state = ZPCI_FS_STANDBY;

        s390_pci_msix_init(pbdev);
        s390_pci_setup_msix(pbdev);
        if (s390_pci_msix_init(pbdev)) {
            error_setg(errp, "MSI-X support is mandatory "
                       "in the S390 architecture");
            return;
        }

        if (dev->hotplugged) {
            s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
                                         pbdev->fh, pbdev->fid);
        }
    } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
        int idx;

        pbdev = S390_PCI_DEVICE(dev);
        for (idx = 0; idx < PCI_SLOT_MAX; idx++) {
            if (!s->pbdev[idx]) {
                s->pbdev[idx] = pbdev;
                pbdev->fh = idx;
                return;
            }
        }

        if (!s390_pci_alloc_idx(s, pbdev)) {
            error_setg(errp, "no slot for plugging zpci device");
            return;
        }
        pbdev->fh = pbdev->idx;
        QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link);
        g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
    }
}

@@ -692,8 +749,8 @@ static void s390_pcihost_timer_cb(void *opaque)
    if (pbdev->summary_ind) {
        pci_dereg_irqs(pbdev);
    }
    if (pbdev->iommu_enabled) {
        pci_dereg_ioat(pbdev);
    if (pbdev->iommu->enabled) {
        pci_dereg_ioat(pbdev->iommu);
    }

    pbdev->state = ZPCI_FS_STANDBY;
@@ -705,17 +762,20 @@ static void s390_pcihost_timer_cb(void *opaque)
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
{
    int i;
    PCIDevice *pci_dev = NULL;
    PCIBus *bus;
    int32_t devfn;
    S390PCIBusDevice *pbdev = NULL;
    S390pciState *s = s390_get_phb();

    if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
        error_setg(errp, "PCI bridge hot unplug currently not supported");
        return;
    } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
        pci_dev = PCI_DEVICE(dev);

        for (i = 0 ; i < PCI_SLOT_MAX; i++) {
            if (s->pbdev[i] && s->pbdev[i]->pdev == pci_dev) {
                pbdev = s->pbdev[i];
        QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
            if (pbdev->pdev == pci_dev) {
                break;
            }
        }
@@ -749,16 +809,58 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,

    s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
                                 pbdev->fh, pbdev->fid);
    bus = pci_dev->bus;
    devfn = pci_dev->devfn;
    object_unparent(OBJECT(pci_dev));
    s390_pci_msix_free(pbdev);
    s390_pci_iommu_free(s, bus, devfn);
    pbdev->pdev = NULL;
    pbdev->state = ZPCI_FS_RESERVED;
out:
    pbdev->fid = 0;
    s->pbdev[pbdev->fh & FH_MASK_INDEX] = NULL;
    QTAILQ_REMOVE(&s->zpci_devs, pbdev, link);
    g_hash_table_remove(s->zpci_table, &pbdev->idx);
    object_unparent(OBJECT(pbdev));
}

static void s390_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
                                      void *opaque)
{
    S390pciState *s = opaque;
    unsigned int primary = s->bus_no;
    unsigned int subordinate = 0xff;
    PCIBus *sec_bus = NULL;

    if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
         PCI_HEADER_TYPE_BRIDGE)) {
        return;
    }

    (s->bus_no)++;
    pci_default_write_config(pdev, PCI_PRIMARY_BUS, primary, 1);
    pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1);
    pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);

    sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
    if (!sec_bus) {
        return;
    }

    pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, subordinate, 1);
    pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
                        s390_pci_enumerate_bridge, s);
    pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);
}

static void s390_pcihost_reset(DeviceState *dev)
{
    S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
    PCIBus *bus = s->parent_obj.bus;

    s->bus_no = 0;
    pci_for_each_device(bus, pci_bus_num(bus), s390_pci_enumerate_bridge, s);
}

static void s390_pcihost_class_init(ObjectClass *klass, void *data)
{
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
@@ -766,6 +868,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);

    dc->cannot_instantiate_with_device_add_yet = true;
    dc->reset = s390_pcihost_reset;
    k->init = s390_pcihost_init;
    hc->plug = s390_pcihost_hot_plug;
    hc->unplug = s390_pcihost_hot_unplug;
@@ -789,13 +892,13 @@ static const TypeInfo s390_pcibus_info = {
    .instance_size = sizeof(S390PCIBus),
};

static uint16_t s390_pci_generate_uid(void)
static uint16_t s390_pci_generate_uid(S390pciState *s)
{
    uint16_t uid = 0;

    do {
        uid++;
        if (!s390_pci_find_dev_by_uid(uid)) {
        if (!s390_pci_find_dev_by_uid(s, uid)) {
            return uid;
        }
    } while (uid < ZPCI_MAX_UID);
@@ -803,12 +906,12 @@ static uint16_t s390_pci_generate_uid(void)
    return UID_UNDEFINED;
}

static uint32_t s390_pci_generate_fid(Error **errp)
static uint32_t s390_pci_generate_fid(S390pciState *s, Error **errp)
{
    uint32_t fid = 0;

    do {
        if (!s390_pci_find_dev_by_fid(fid)) {
        if (!s390_pci_find_dev_by_fid(s, fid)) {
            return fid;
        }
    } while (fid++ != ZPCI_MAX_FID);
@@ -820,25 +923,26 @@ static uint32_t s390_pci_generate_fid(Error **errp)
static void s390_pci_device_realize(DeviceState *dev, Error **errp)
{
    S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev);
    S390pciState *s = s390_get_phb();

    if (!zpci->target) {
        error_setg(errp, "target must be defined");
        return;
    }

    if (s390_pci_find_dev_by_target(zpci->target)) {
    if (s390_pci_find_dev_by_target(s, zpci->target)) {
        error_setg(errp, "target %s already has an associated zpci device",
                   zpci->target);
        return;
    }

    if (zpci->uid == UID_UNDEFINED) {
        zpci->uid = s390_pci_generate_uid();
        zpci->uid = s390_pci_generate_uid(s);
        if (!zpci->uid) {
            error_setg(errp, "no free uid could be found");
            return;
        }
    } else if (s390_pci_find_dev_by_uid(zpci->uid)) {
    } else if (s390_pci_find_dev_by_uid(s, zpci->uid)) {
        error_setg(errp, "uid %u already in use", zpci->uid);
        return;
    }
@@ -846,12 +950,12 @@ static void s390_pci_device_realize(DeviceState *dev, Error **errp)
    if (!zpci->fid_defined) {
        Error *local_error = NULL;

        zpci->fid = s390_pci_generate_fid(&local_error);
        zpci->fid = s390_pci_generate_fid(s, &local_error);
        if (local_error) {
            error_propagate(errp, local_error);
            return;
        }
    } else if (s390_pci_find_dev_by_fid(zpci->fid)) {
    } else if (s390_pci_find_dev_by_fid(s, zpci->fid)) {
        error_setg(errp, "fid %u already in use", zpci->fid);
        return;
    }
@@ -877,8 +981,8 @@ static void s390_pci_device_reset(DeviceState *dev)
    if (pbdev->summary_ind) {
        pci_dereg_irqs(pbdev);
    }
    if (pbdev->iommu_enabled) {
        pci_dereg_ioat(pbdev);
    if (pbdev->iommu->enabled) {
        pci_dereg_ioat(pbdev->iommu);
    }

    pbdev->fmb_addr = 0;
@@ -944,11 +1048,18 @@ static const TypeInfo s390_pci_device_info = {
    .class_init = s390_pci_device_class_init,
};

static TypeInfo s390_pci_iommu_info = {
    .name = TYPE_S390_PCI_IOMMU,
    .parent = TYPE_OBJECT,
    .instance_size = sizeof(S390PCIIOMMU),
};

static void s390_pci_register_types(void)
{
    type_register_static(&s390_pcihost_info);
    type_register_static(&s390_pcibus_info);
    type_register_static(&s390_pci_device_info);
    type_register_static(&s390_pci_iommu_info);
}

type_init(s390_pci_register_types)
+32 −14

File changed.

Preview size limit exceeded, changes collapsed.

+39 −35

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -292,7 +292,7 @@ typedef struct ZpciFib {
} QEMU_PACKED ZpciFib;

int pci_dereg_irqs(S390PCIBusDevice *pbdev);
void pci_dereg_ioat(S390PCIBusDevice *pbdev);
void pci_dereg_ioat(S390PCIIOMMU *iommu);
int clp_service_call(S390CPU *cpu, uint8_t r2);
int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
Loading