]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/s390x/s390-pci-bus.c
Use #include "..." for our own headers, <...> for others
[mirror_qemu.git] / hw / s390x / s390-pci-bus.c
index 9e24268fd1776d967338c96640948b0fc9afce71..47ca853bd2176338fb96e95a174493797bbd1e55 100644 (file)
@@ -18,9 +18,9 @@
 #include "cpu.h"
 #include "s390-pci-bus.h"
 #include "s390-pci-inst.h"
-#include <hw/pci/pci_bus.h>
-#include <hw/pci/msi.h>
-#include <qemu/error-report.h>
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/msi.h"
+#include "qemu/error-report.h"
 
 /* #define DEBUG_S390PCI_BUS */
 #ifdef DEBUG_S390PCI_BUS
@@ -91,6 +91,26 @@ int chsc_sei_nt2_have_event(void)
     return !QTAILQ_EMPTY(&s->pending_sei);
 }
 
+S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev)
+{
+    int idx = 0;
+    S390PCIBusDevice *dev = NULL;
+    S390pciState *s = s390_get_phb();
+
+    if (pbdev) {
+        idx = (pbdev->fh & FH_MASK_INDEX) + 1;
+    }
+
+    for (; idx < PCI_SLOT_MAX; idx++) {
+        dev = s->pbdev[idx];
+        if (dev && dev->state != ZPCI_FS_RESERVED) {
+            return dev;
+        }
+    }
+
+    return NULL;
+}
+
 S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
 {
     S390PCIBusDevice *pbdev;
@@ -172,6 +192,10 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
         }
         pbdev->state = ZPCI_FS_STANDBY;
         rc = SCLP_RC_NORMAL_COMPLETION;
+
+        if (pbdev->release_timer) {
+            qdev_unplug(DEVICE(pbdev->pdev), NULL);
+        }
     }
 out:
     psccb->header.response_code = cpu_to_be16(rc);
@@ -454,18 +478,18 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
 {
     S390PCIBusDevice *pbdev;
     uint32_t io_int_word;
-    uint32_t fid = data >> ZPCI_MSI_VEC_BITS;
+    uint32_t idx = data >> ZPCI_MSI_VEC_BITS;
     uint32_t vec = data & ZPCI_MSI_VEC_MASK;
     uint64_t ind_bit;
     uint32_t sum_bit;
     uint32_t e = 0;
 
-    DPRINTF("write_msix data 0x%" PRIx64 " fid %d vec 0x%x\n", data, fid, vec);
+    DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec);
 
-    pbdev = s390_pci_find_dev_by_fid(fid);
+    pbdev = s390_pci_find_dev_by_idx(idx);
     if (!pbdev) {
         e |= (vec << ERR_EVENT_MVN_OFFSET);
-        s390_pci_generate_error_event(ERR_EVENT_NOMSI, 0, fid, addr, e);
+        s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e);
         return;
     }
 
@@ -659,6 +683,23 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
     }
 }
 
+static void s390_pcihost_timer_cb(void *opaque)
+{
+    S390PCIBusDevice *pbdev = opaque;
+
+    if (pbdev->summary_ind) {
+        pci_dereg_irqs(pbdev);
+    }
+    if (pbdev->iommu_enabled) {
+        pci_dereg_ioat(pbdev);
+    }
+
+    pbdev->state = ZPCI_FS_STANDBY;
+    s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
+                                 pbdev->fh, pbdev->fid);
+    qdev_unplug(DEVICE(pbdev), NULL);
+}
+
 static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
                                     DeviceState *dev, Error **errp)
 {
@@ -692,8 +733,20 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
     case ZPCI_FS_STANDBY:
         break;
     default:
-        s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
+        s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST,
                                      pbdev->fh, pbdev->fid);
+        pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                            s390_pcihost_timer_cb,
+                                            pbdev);
+        timer_mod(pbdev->release_timer,
+                  qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + HOT_UNPLUG_TIMEOUT);
+        return;
+    }
+
+    if (pbdev->release_timer && timer_pending(pbdev->release_timer)) {
+        timer_del(pbdev->release_timer);
+        timer_free(pbdev->release_timer);
+        pbdev->release_timer = NULL;
     }
 
     s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,