ae23c9
From 72cc005ad139d9d5d4bf2cb7402cf730c6726fd3 Mon Sep 17 00:00:00 2001
ae23c9
From: Cornelia Huck <cohuck@redhat.com>
ae23c9
Date: Wed, 17 Apr 2019 13:57:37 +0100
ae23c9
Subject: [PATCH 20/24] s390x/pci: Fix hotplugging of PCI bridges
ae23c9
ae23c9
RH-Author: Cornelia Huck <cohuck@redhat.com>
ae23c9
Message-id: <20190417135741.25297-21-cohuck@redhat.com>
ae23c9
Patchwork-id: 85801
ae23c9
O-Subject: [RHEL-8.1.0 qemu-kvm PATCH v2 20/24] s390x/pci: Fix hotplugging of PCI bridges
ae23c9
Bugzilla: 1699070
ae23c9
RH-Acked-by: David Hildenbrand <david@redhat.com>
ae23c9
RH-Acked-by: Thomas Huth <thuth@redhat.com>
ae23c9
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
ae23c9
ae23c9
From: David Hildenbrand <david@redhat.com>
ae23c9
ae23c9
When hotplugging a PCI bridge right now to the root port, we resolve
ae23c9
pci_get_bus(pdev)->parent_dev, which results in a SEGFAULT. Hotplugging
ae23c9
really only works right now when hotplugging to another bridge.
ae23c9
ae23c9
Instead, we have to properly check if we are already at the root.
ae23c9
ae23c9
Let's cleanup the code while at it a bit and factor out updating the
ae23c9
subordinate bus number into a separate function. The check for
ae23c9
"old_nr < nr" is right now not strictly necessary, but makes it more
ae23c9
obvious what is actually going on.
ae23c9
ae23c9
Most probably fixing up the topology is not our responsibility when
ae23c9
hotplugging. The guest has to sort this out. But let's keep it for now
ae23c9
and only fix current code to not crash.
ae23c9
ae23c9
Reviewed-by: Thomas Huth <thuth@redhat.com>
ae23c9
Signed-off-by: David Hildenbrand <david@redhat.com>
ae23c9
Message-Id: <20190130155733.32742-3-david@redhat.com>
ae23c9
Reviewed-by: Collin Walling <walling@linux.ibm.com>
ae23c9
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
ae23c9
(cherry picked from commit 150f462538a6f3b78efe785c911669375032b0d2)
ae23c9
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 hw/s390x/s390-pci-bus.c | 28 +++++++++++++++++++---------
ae23c9
 1 file changed, 19 insertions(+), 9 deletions(-)
ae23c9
ae23c9
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
ae23c9
index 309ad79..a0f7245 100644
ae23c9
--- a/hw/s390x/s390-pci-bus.c
ae23c9
+++ b/hw/s390x/s390-pci-bus.c
ae23c9
@@ -881,6 +881,21 @@ static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
ae23c9
     }
ae23c9
 }
ae23c9
 
ae23c9
+static void s390_pci_update_subordinate(PCIDevice *dev, uint32_t nr)
ae23c9
+{
ae23c9
+    uint32_t old_nr;
ae23c9
+
ae23c9
+    pci_default_write_config(dev, PCI_SUBORDINATE_BUS, nr, 1);
ae23c9
+    while (!pci_bus_is_root(pci_get_bus(dev))) {
ae23c9
+        dev = pci_get_bus(dev)->parent_dev;
ae23c9
+
ae23c9
+        old_nr = pci_default_read_config(dev, PCI_SUBORDINATE_BUS, 1);
ae23c9
+        if (old_nr < nr) {
ae23c9
+            pci_default_write_config(dev, PCI_SUBORDINATE_BUS, nr, 1);
ae23c9
+        }
ae23c9
+    }
ae23c9
+}
ae23c9
+
ae23c9
 static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
ae23c9
                               Error **errp)
ae23c9
 {
ae23c9
@@ -889,26 +904,21 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
ae23c9
     S390PCIBusDevice *pbdev = NULL;
ae23c9
 
ae23c9
     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
ae23c9
-        BusState *bus;
ae23c9
         PCIBridge *pb = PCI_BRIDGE(dev);
ae23c9
-        PCIDevice *pdev = PCI_DEVICE(dev);
ae23c9
 
ae23c9
+        pdev = PCI_DEVICE(dev);
ae23c9
         pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
ae23c9
         pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
ae23c9
 
ae23c9
-        bus = BUS(&pb->sec_bus);
ae23c9
-        qbus_set_hotplug_handler(bus, DEVICE(s), errp);
ae23c9
+        qbus_set_hotplug_handler(BUS(&pb->sec_bus), DEVICE(s), errp);
ae23c9
 
ae23c9
         if (dev->hotplugged) {
ae23c9
             pci_default_write_config(pdev, PCI_PRIMARY_BUS,
ae23c9
                                      pci_dev_bus_num(pdev), 1);
ae23c9
             s->bus_no += 1;
ae23c9
             pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1);
ae23c9
-            do {
ae23c9
-                pdev = pci_get_bus(pdev)->parent_dev;
ae23c9
-                pci_default_write_config(pdev, PCI_SUBORDINATE_BUS,
ae23c9
-                                         s->bus_no, 1);
ae23c9
-            } while (pci_get_bus(pdev) && pci_dev_bus_num(pdev));
ae23c9
+
ae23c9
+            s390_pci_update_subordinate(pdev, s->bus_no);
ae23c9
         }
ae23c9
     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
ae23c9
         pdev = PCI_DEVICE(dev);
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9