Inherit bus numbers from the previous kernel during a Live Update when
one or more PCI devices are being preserved. This is necessary so that
preserved devices can DMA through the IOMMU during a Live Update
(changing bus numbers would break IOMMU translation).

Signed-off-by: David Matlack <[email protected]>
---
 drivers/pci/probe.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index af6356c5a156..ca6e5f79debb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1351,6 +1351,20 @@ static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 
*sec, u8 *sub)
        return true;
 }
 
+static bool pci_assign_all_busses(void)
+{
+       /*
+        * During a Live Update where devices are preserved by the previous
+        * kernel, inherit all bus numbers assigned by the previous kernel. Bus
+        * numbers must remain stable for preserved devices so that they can
+        * perform DMA during the Live Update uninterrupted.
+        */
+       if (pci_liveupdate_incoming_nr_devices())
+               return false;
+
+       return pcibios_assign_all_busses();
+}
+
 /*
  * pci_scan_bridge_extend() - Scan buses behind a bridge
  * @bus: Parent bus the bridge is on
@@ -1378,6 +1392,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
                                  int max, unsigned int available_buses,
                                  int pass)
 {
+       bool assign_all_busses = pci_assign_all_busses();
        struct pci_bus *child;
        int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
        u32 buses, i, j = 0;
@@ -1424,7 +1439,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
                              bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
 
-       if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
+       if ((secondary || subordinate) && !assign_all_busses &&
            !is_cardbus && !broken) {
                unsigned int cmax, buses;
 
@@ -1467,7 +1482,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
                 * do in the second pass.
                 */
                if (!pass) {
-                       if (pcibios_assign_all_busses() || broken || is_cardbus)
+                       if (assign_all_busses || broken || is_cardbus)
 
                                /*
                                 * Temporarily disable forwarding of the
@@ -1542,7 +1557,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
                                                        max+i+1))
                                        break;
                                while (parent->parent) {
-                                       if ((!pcibios_assign_all_busses()) &&
+                                       if (!assign_all_busses &&
                                            (parent->busn_res.end > max) &&
                                            (parent->busn_res.end <= max+i)) {
                                                j = 1;
-- 
2.53.0.rc1.225.gd81095ad13-goog


Reply via email to