From: David Matlack <dmatlack@google.com>
To: kexec@lists.infradead.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
linux-pci@vger.kernel.org
Cc: Adithya Jayachandran <ajayachandra@nvidia.com>,
Alexander Graf <graf@amazon.com>,
Alex Williamson <alex@shazbot.org>,
Bjorn Helgaas <bhelgaas@google.com>, Chris Li <chrisl@kernel.org>,
David Matlack <dmatlack@google.com>,
David Rientjes <rientjes@google.com>,
Jacob Pan <jacob.pan@linux.microsoft.com>,
Jason Gunthorpe <jgg@nvidia.com>,
Jonathan Corbet <corbet@lwn.net>,
Josh Hilke <jrhilke@google.com>,
Leon Romanovsky <leonro@nvidia.com>,
Lukas Wunner <lukas@wunner.de>, Mike Rapoport <rppt@kernel.org>,
Parav Pandit <parav@nvidia.com>,
Pasha Tatashin <pasha.tatashin@soleen.com>,
Pranjal Shrivastava <praan@google.com>,
Pratyush Yadav <pratyush@kernel.org>,
Randy Dunlap <rdunlap@infradead.org>,
Saeed Mahameed <saeedm@nvidia.com>,
Samiullah Khawaja <skhawaja@google.com>,
Shuah Khan <skhan@linuxfoundation.org>,
Vipin Sharma <vipinsh@google.com>, William Tu <witu@nvidia.com>,
Yi Liu <yi.l.liu@intel.com>
Subject: [PATCH v9 06/13] PCI: liveupdate: Preserve bus numbers during Live Update
Date: Fri, 18 Sep 2026 20:06:32 +0000 [thread overview]
Message-ID: <20260918200640.887030-7-dmatlack@google.com> (raw)
In-Reply-To: <20260918200640.887030-1-dmatlack@google.com>
Keep the secondary and subordinate bus numbers that the previous kernel
programmed into bridges, rather than assigning new ones, if the previous
kernel preserved any device across a Live Update. Do this even on
architectures that would otherwise always assign bus numbers themselves,
e.g. when pci=assign-busses is passed.
Preserved devices must be allowed to continue performing memory
transactions across a Live Update, so the kernel cannot change the
fabric topology. Changing the bus numbers of a bridge changes the
RequesterIDs of the devices below it, which would require disabling and
flushing any in-flight memory transactions first.
Apply the policy globally rather than only to the paths that contain
preserved devices. Bus numbers have to be preserved above a preserved
device anyway, since an upstream bridge cannot expand its window. A
global policy matches the scope of pcibios_assign_all_busses(), and
gives an answer that cannot change part way through the two passes of a
bridge scan.
Bridges that do not have bus numbers are still assigned new ones, so
hot-adding a bridge keeps working, both during and after a Live Update.
The two-pass bridge scan guarantees such bridges are only assigned bus
numbers above those already claimed by preserved bridges.
The exception is a bridge that was preserved but comes up without a
valid bus number configuration, e.g. because it was reset during kexec.
Refuse to assign it new bus numbers, since that would silently change
the BDF of every preserved device in its hierarchy. Also refuse to
assign bus numbers to the other bridges on the same bus, since the bus
numbers of the failed bridge can no longer be read from hardware and
handing them out would let an unrelated device inherit the BDF of a
preserved device.
Require that CONFIG_CARDBUS is not enabled to enable
CONFIG_PCI_LIVEUPDATE since preserving bus numbers on PCI-to-CardBus
bridges requires additional work but is not a priority at the moment.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../admin-guide/kernel-parameters.txt | 7 +-
drivers/pci/Kconfig | 2 +-
drivers/pci/liveupdate.c | 114 ++++++++++++++++++
drivers/pci/liveupdate.h | 13 ++
drivers/pci/probe.c | 11 +-
include/linux/pci_liveupdate.h | 5 +
6 files changed, 146 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd2..7eabf6320abf 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5170,7 +5170,12 @@ 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
+ if any device was preserved across a Live
+ Update, where the kernel must preserve 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/Kconfig b/drivers/pci/Kconfig
index 8af20f558086..16fbd4212e0f 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -273,7 +273,7 @@ config VGA_ARB_MAX_GPUS
config PCI_LIVEUPDATE
bool "PCI Live Update Support"
- depends on PCI && LIVEUPDATE && 64BIT
+ depends on PCI && LIVEUPDATE && 64BIT && !CARDBUS
help
Enable PCI core support for preserving PCI devices across Live
Update. This, in combination with support in a device's driver,
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index 825df024eec4..686887a6c8d9 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -148,6 +148,32 @@
* This enables the PCI core and any drivers bound to the bridge to participate
* in the Live Update so that preserved endpoints can continue issuing memory
* transactions during the Live Update.
+ *
+ * BDF Stability
+ * =============
+ *
+ * The PCI core guarantees that preserved devices can be identified by the same
+ * bus, device, and function numbers for as long as they are preserved
+ * (including across kexec). To accomplish this, the PCI core keeps the
+ * secondary and subordinate bus numbers that the previous kernel programmed
+ * into bridges, if the previous kernel preserved any device. This is true even
+ * on architectures that always assign new bus numbers during scanning. The
+ * kernel assumes the previous kernel established a sane bus topology across
+ * kexec.
+ *
+ * Bridges that do not have bus numbers are assigned new ones as usual, so
+ * hot-adding a bridge keeps working, both during and after a Live Update. The
+ * two-pass bridge scan ensures such bridges are only assigned bus numbers above
+ * those already claimed by preserved bridges.
+ *
+ * If a preserved bridge comes up without a valid bus number configuration, e.g.
+ * because it was reset during kexec, the PCI core refuses to assign it new bus
+ * numbers and does not enumerate anything below it. Assigning new bus numbers
+ * would silently change the BDF of every preserved device in its hierarchy. The
+ * PCI core also stops assigning bus numbers to the other bridges on the same
+ * bus, since the bus numbers of the failed bridge can no longer be read from
+ * hardware and handing them to another bridge would let an unrelated device
+ * inherit the BDF of a preserved device.
*/
#define pr_fmt(fmt) "PCI: liveupdate: " fmt
@@ -168,9 +194,13 @@
* struct pci_liveupdate_global - Global state for PCI Live Update support
* @rwsem: Reader/writer semaphore used to protect the incoming and outgoing
* FLBs, and the references to them in struct pci_dev.
+ * @had_incoming: True if the previous kernel preserved at least one PCI device.
+ * Set when the incoming FLB is retrieved and never cleared, so
+ * it stays true after Live Update finishes.
*/
struct pci_liveupdate_global {
struct rw_semaphore rwsem;
+ bool had_incoming;
};
static struct pci_liveupdate_global pci_liveupdate = {
@@ -298,6 +328,14 @@ static int pci_flb_retrieve(struct liveupdate_flb_op_args *args)
ret);
}
+ /*
+ * Remember that the previous kernel preserved devices for the lifetime
+ * of this kernel, even after Live Update finishes and the incoming FLB
+ * is freed. See pci_liveupdate_preserve_bus_numbers().
+ */
+ if (!xa_empty(&incoming->xa))
+ pci_liveupdate.had_incoming = true;
+
args->obj = incoming;
return 0;
}
@@ -606,6 +644,80 @@ static void pci_liveupdate_flb_put_incoming(void)
liveupdate_flb_put_incoming(&pci_liveupdate_flb);
}
+/**
+ * pci_liveupdate_preserve_bus_numbers() - Determine if the PCI core should
+ * preserve bus numbers when scanning
+ * bridges.
+ *
+ * This function is called by the PCI core when it is scanning a bridge. It
+ * determines whether the PCI core should preserve the secondary and subordinate
+ * bus numbers that the previous kernel programmed into that bridge, rather than
+ * assigning new ones. This is necessary to keep RequesterIDs constant for
+ * preserved devices issuing memory transactions.
+ *
+ * Bus numbers are preserved everywhere, and for the lifetime of the kernel, if
+ * the previous kernel preserved any device. Bus numbers have to be preserved
+ * above a preserved device anyway, since an upstream bridge cannot expand its
+ * window. Applying the same policy everywhere matches the scope of
+ * pcibios_assign_all_busses(), and gives an answer that cannot change part way
+ * through the two passes of a bridge scan.
+ *
+ * The incoming FLB is retrieved while setting up the first device, which always
+ * happens before any bridge is scanned, so this returns the same answer for the
+ * entire enumeration.
+ *
+ * Note that this does not prevent the PCI core from assigning bus numbers to
+ * bridges that do not have any, e.g. bridges that are hot-added after the
+ * Live Update. See pci_liveupdate_refuse_bus_numbers() for the one case where
+ * the PCI core must refuse to do so.
+ *
+ * Return: True if bus numbers should be preserved, false otherwise.
+ */
+bool pci_liveupdate_preserve_bus_numbers(void)
+{
+ return pci_liveupdate.had_incoming;
+}
+
+/**
+ * pci_liveupdate_refuse_bus_numbers() - Determine if the PCI core must refuse
+ * to assign bus numbers to the provided
+ * bridge.
+ * @bus: The PCI bus the bus numbers would be assigned from.
+ * @dev: The PCI bridge device the bus numbers would be assigned to.
+ *
+ * This function is called by the PCI core before it assigns bus numbers to a
+ * bridge that does not have any.
+ *
+ * A bridge that was preserved by the previous kernel but came up without a
+ * valid bus number configuration, e.g. because it was reset during kexec, is
+ * left alone by the PCI core and therefore has no child bus once the first pass
+ * of the bridge scan is done.
+ *
+ * The PCI core must not assign bus numbers from @bus while such a bridge is on
+ * it, including to the failed bridge itself. Assigning new bus numbers to the
+ * failed bridge would silently change the BDF of every preserved device in its
+ * hierarchy. Its bus numbers cannot be read from hardware anymore either, so
+ * they cannot be excluded from assignment, and handing them to another bridge
+ * would let an unrelated device inherit the BDF of a preserved device.
+ *
+ * Return: True if @dev must not be assigned bus numbers, false otherwise.
+ */
+bool pci_liveupdate_refuse_bus_numbers(struct pci_bus *bus, struct pci_dev *dev)
+{
+ struct pci_dev *bridge;
+
+ for_each_pci_bridge(bridge, bus) {
+ if (!bridge->liveupdate.was_incoming || bridge->subordinate)
+ continue;
+
+ pci_err(dev, "Not assigning bus numbers, preserved bridge %s lost its bus number configuration\n",
+ pci_name(bridge));
+ return true;
+ }
+
+ return false;
+}
+
void pci_liveupdate_setup_device(struct pci_dev *dev)
{
struct pci_flb_incoming *incoming;
@@ -634,6 +746,8 @@ void pci_liveupdate_setup_device(struct pci_dev *dev)
pci_info(dev, "Device was preserved by previous kernel across Live Update\n");
dev->liveupdate.incoming = dev_ser;
+ dev->liveupdate.was_incoming = true;
+
pci_liveupdate_flb_put_incoming();
}
diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h
index eaaa3559fd77..e5d2a19d2ca2 100644
--- a/drivers/pci/liveupdate.h
+++ b/drivers/pci/liveupdate.h
@@ -13,6 +13,8 @@
#ifdef CONFIG_PCI_LIVEUPDATE
void pci_liveupdate_setup_device(struct pci_dev *dev);
void pci_liveupdate_cleanup_device(struct pci_dev *dev);
+bool pci_liveupdate_preserve_bus_numbers(void);
+bool pci_liveupdate_refuse_bus_numbers(struct pci_bus *bus, struct pci_dev *dev);
#else
static inline void pci_liveupdate_setup_device(struct pci_dev *dev)
{
@@ -21,6 +23,17 @@ static inline void pci_liveupdate_setup_device(struct pci_dev *dev)
static inline void pci_liveupdate_cleanup_device(struct pci_dev *dev)
{
}
+
+static inline bool pci_liveupdate_preserve_bus_numbers(void)
+{
+ return false;
+}
+
+static inline bool pci_liveupdate_refuse_bus_numbers(struct pci_bus *bus,
+ struct pci_dev *dev)
+{
+ return false;
+}
#endif
#endif /* DRIVERS_PCI_LIVEUPDATE_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ad7fdf0d56b6..debe0ad1ef68 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1397,6 +1397,8 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int max, unsigned int available_buses,
int pass)
{
+ bool preserve_bus_numbers = !pcibios_assign_all_busses() ||
+ pci_liveupdate_preserve_bus_numbers();
struct pci_bus *child;
u32 buses;
u16 bctl;
@@ -1449,8 +1451,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) && preserve_bus_numbers && !broken) {
unsigned int cmax, buses;
/*
@@ -1492,8 +1493,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 (!preserve_bus_numbers || broken)
/*
* Temporarily disable forwarding of the
* configuration cycles on all bridges in
@@ -1507,6 +1507,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
goto out;
}
+ if (pci_liveupdate_refuse_bus_numbers(bus, dev))
+ goto out;
+
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h
index 710026ada2d5..d45a5b524909 100644
--- a/include/linux/pci_liveupdate.h
+++ b/include/linux/pci_liveupdate.h
@@ -17,10 +17,15 @@
* struct pci_liveupdate - PCI Live Update state for a struct pci_dev
* @outgoing: State preserved for the next kernel.
* @incoming: State preserved by the previous kernel.
+ * @was_incoming: True if this struct pci_dev was incoming-preserved when it was
+ * set up, i.e. it was matched to state preserved by the previous
+ * kernel. Unlike @incoming, this is never cleared, so it stays
+ * true after the device finishes participating in Live Update.
*/
struct pci_liveupdate {
struct pci_dev_ser *outgoing;
struct pci_dev_ser *incoming;
+ bool was_incoming;
};
struct pci_dev;
--
2.55.0.1082.g2b9226bbc0-goog
next prev parent reply other threads:[~2026-09-18 20:06 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 20:06 [PATCH v9 00/13] PCI: liveupdate: PCI core support for " David Matlack
2026-09-18 20:06 ` [PATCH v9 01/13] PCI: liveupdate: Set up FLB handler for the PCI core David Matlack
2026-09-18 20:15 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 02/13] PCI: liveupdate: Track outgoing preserved PCI devices David Matlack
2026-09-18 20:23 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 03/13] PCI: liveupdate: Track incoming " David Matlack
2026-09-18 20:20 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 04/13] PCI: liveupdate: Document driver binding responsibilities David Matlack
2026-09-18 20:09 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 05/13] PCI: liveupdate: Auto-preserve upstream bridges across Live Update David Matlack
2026-09-18 20:14 ` sashiko-bot
2026-09-18 20:06 ` David Matlack [this message]
2026-09-18 20:13 ` [PATCH v9 06/13] PCI: liveupdate: Preserve bus numbers during " sashiko-bot
2026-09-18 20:06 ` [PATCH v9 07/13] PCI: Refactor matching logic for pci_dev_acs_ops David Matlack
2026-09-18 20:13 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 08/13] PCI: Save and restore the ACS Control register David Matlack
2026-09-18 20:15 ` sashiko-bot
2026-09-19 1:18 ` Alex Williamson
2026-09-18 20:06 ` [PATCH v9 09/13] PCI: liveupdate: Adopt ACS controls in incoming preserved devices David Matlack
2026-09-18 20:13 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 10/13] PCI: liveupdate: Adopt ARI Forwarding Enable on preserved bridges David Matlack
2026-09-18 20:19 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 11/13] PCI: liveupdate: Freeze preservation status during shutdown David Matlack
2026-09-18 20:19 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 12/13] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec David Matlack
2026-09-18 20:17 ` sashiko-bot
2026-09-18 20:06 ` [PATCH v9 13/13] Documentation: PCI: Add documentation for Live Update David Matlack
2026-09-18 20:14 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260918200640.887030-7-dmatlack@google.com \
--to=dmatlack@google.com \
--cc=ajayachandra@nvidia.com \
--cc=alex@shazbot.org \
--cc=bhelgaas@google.com \
--cc=chrisl@kernel.org \
--cc=corbet@lwn.net \
--cc=graf@amazon.com \
--cc=jacob.pan@linux.microsoft.com \
--cc=jgg@nvidia.com \
--cc=jrhilke@google.com \
--cc=kexec@lists.infradead.org \
--cc=leonro@nvidia.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-pci@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=parav@nvidia.com \
--cc=pasha.tatashin@soleen.com \
--cc=praan@google.com \
--cc=pratyush@kernel.org \
--cc=rdunlap@infradead.org \
--cc=rientjes@google.com \
--cc=rppt@kernel.org \
--cc=saeedm@nvidia.com \
--cc=skhan@linuxfoundation.org \
--cc=skhawaja@google.com \
--cc=vipinsh@google.com \
--cc=witu@nvidia.com \
--cc=yi.l.liu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®