From: Bjorn Helgaas <helgaas@kernel.org>
To: David Matlack <dmatlack@google.com>
Cc: kexec@lists.infradead.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
linux-pci@vger.kernel.org,
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 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: Re: [PATCH v9 06/13] PCI: liveupdate: Preserve bus numbers during Live Update
Date: Fri, 25 Sep 2026 15:04:07 -0500 [thread overview]
Message-ID: <20260925200407.GA2082921@bhelgaas> (raw)
In-Reply-To: <20260918200640.887030-7-dmatlack@google.com>
On Fri, Sep 18, 2026 at 08:06:32PM +0000, David Matlack wrote:
> 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>
Reviewed-by: Bjorn Helgaas <bhelgaas@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-25 20:04 UTC|newest]
Thread overview: 40+ 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-25 19:55 ` Bjorn Helgaas
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-25 19:59 ` Bjorn Helgaas
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-25 20:02 ` Bjorn Helgaas
2026-09-18 20:06 ` [PATCH v9 06/13] PCI: liveupdate: Preserve bus numbers during " David Matlack
2026-09-18 20:13 ` sashiko-bot
2026-09-25 20:04 ` Bjorn Helgaas [this message]
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-21 20:36 ` David Matlack
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
2026-09-22 18:36 ` [PATCH v9 00/13] PCI: liveupdate: PCI core support " Zhu Yanjun
2026-09-22 18:53 ` David Matlack
[not found] ` <d4547411-eeae-46c5-a30b-12d8cdde9329@linux.dev>
2026-09-24 21:59 ` David Matlack
2026-09-25 4:47 ` Zhu Yanjun
2026-09-25 18:59 ` Samiullah Khawaja
2026-09-22 18:54 ` Zhu Yanjun
2026-09-22 21:47 ` Zhu Yanjun
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=20260925200407.GA2082921@bhelgaas \
--to=helgaas@kernel.org \
--cc=ajayachandra@nvidia.com \
--cc=alex@shazbot.org \
--cc=bhelgaas@google.com \
--cc=chrisl@kernel.org \
--cc=corbet@lwn.net \
--cc=dmatlack@google.com \
--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®