[PATCH v3 04/24] PCI: Inherit bus numbers from previous kernel during Live Update

David Matlack
2026-03-23T23:58:50Z

Inherit bus numbers from the previous kernel during a Live Update when
one or more PCI devices are being preserved, even if pci=assign-busses
is enabled.

During a Live Update, preserved devices will be allowed to continue
performing memory transactions. Thus the kernel cannot change the fabric
topology, including changing bus numbers, since that would requiring
disabling and flushing any memory transactions first.

So if pci=assign-busses is enabled, ignore it during the Live Update and
inherit all bus numbers assigned by the previous kernel. This will not
break users that rely on pci=assign-busses for their system to function
correctly since the system can be assumed to be in a functional state
already if a Live Update is underway. In other words, pci=assign-busses
would establish a functional topology during the initial cold boot, and
then that topology would remain fixed across any subsequent Live
Updates.

Signed-off-by: David Matlack <dmatlack@google.com>
---
.../admin-guide/kernel-parameters.txt | 6 +++-
drivers/pci/liveupdate.c | 5 ++-
drivers/pci/probe.c | 35 ++++++++++++++++---
3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 03a550630644..beff9f3f8e3b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5156,7 +5156,11 @@ Kernel parameters
explicitly which ones they are.
assign-busses [X86] Always assign all PCI bus
numbers ourselves, overriding
- whatever the firmware may have done.
+ whatever the firmware may have done. Ignored
+ during a Live Update, where the kernel must
+ inherit the PCI topology (including bus numbers)
+ to avoid interrupting ongoing memory
+ transactions of preserved devices.
usepirqmask [X86] Honor the possible IRQ mask stored
in the BIOS $PIR table. This is needed on
some systems with broken BIOSes, notably
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index a3dbe06650ff..c1251f4f8438 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -84,7 +84,10 @@
* Update:
*
* * The PCI Segment, Bus, Device, and Function numbers assigned to the device
- * are guaranteed to remain the same across Live Update.
+ * are guaranteed to remain the same across Live Update. Note that this is
+ * true even if pci=assign-busses is set on the command line. The kernel will
+ * always inherit bus numbers assigned by the previous kernel during a Live
+ * Update.
*
* This list will be extended in the future as new support is added.
*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c60222d45659..165056d71e66 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1369,6 +1369,34 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
return true;
}

+static bool pci_assign_all_busses(void)
+{
+ if (!pcibios_assign_all_busses())
+ return false;
+
+ /*
+ * During a Live Update, preserved devices are are allowed to continue
+ * performing memory transactions. Thus the kernel cannot change the
+ * fabric topology, including changing bus numbers, since that would
+ * requiring disabling and flushing any memory transactions first.
+ *
+ * So if pci=assign-busses is enabled, ignore it during the Live Update
+ * and inherit all bus numbers assigned by the previous kernel. This
+ * will not break users that rely on pci=assign-busses for their system
+ * to function correctly since the system can be assumed to be in a
+ * functional state already if a Live Update is underway. In other
+ * words, pci=assign-busses should be used to establish working bus
+ * numbers during the initial cold boot, and then that topology would
+ * then remain fixed across any subsequent Live Updates.
+ */
+ if (pci_liveupdate_incoming_nr_devices()) {
+ pr_info_once("Ignoring pci=assign-busses and inheriting bus numbers during Live Update\n");
+ return false;
+ }
+
+ return true;
+}
+
/*
* pci_scan_bridge_extend() - Scan buses behind a bridge
* @bus: Parent bus the bridge is on
@@ -1396,6 +1424,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int max, unsigned int available_buses,
int pass)
{
+ const bool assign_all_busses = pci_assign_all_busses();
struct pci_bus *child;
u32 buses;
u16 bctl;
@@ -1448,8 +1477,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
goto out;
}

- if ((secondary || subordinate) &&
- !pcibios_assign_all_busses() && !broken) {
+ if ((secondary || subordinate) && !assign_all_busses && !broken) {
unsigned int cmax, buses;

/*
@@ -1491,8 +1519,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)
-
+ if (assign_all_busses || broken)
/*
* Temporarily disable forwarding of the
* configuration cycles on all bridges in
--
2.53.0.983.g0bb29b3bc5-goog