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