PCI: liveupdate: PCI core support for Live Update
Subsystems (6)
v4 cover PCI: liveupdate: PCI core support for Live Update
This series can be found on GitHub:
https://github.com/dmatlack/linux/tree/liveupdate/pci/base/v4
This patch series introduces support in the PCI core for Live Update, enabling drivers to preserve PCI devices across a kexec-based kernel update without interrupting the device. This functionality is critical for minimizing downtime in environments where PCI devices (e.g., those assigned to VMs via VFIO) must continue operating or maintain state across a host kernel upgrade.
This series was split off from the the VFIO driver series [1] to enable more rapid iteration on the PCI core changes, add breathing room to split changes into smaller patches, and add some more functionality.
Series Overview
---------------
This series implements the following to support PCI device preservation across Live Update:
1. Set up a File-Lifecycle-Bound (FLB) handler to track and preserve PCI-specific state (struct pci_ser) across Live Update using Kexec Handover (KHO).
2. Add APIs for drivers to register "outgoing" devices for preservation and for the PCI core to identify "incoming" preserved devices during enumeration.
3. Automatically preserve all upstream bridges for any preserved endpoint. Use reference counting to ensure bridges remain preserved as long as any downstream device is preserved.
4. Inherit secondary/subordinate bus numbers, ARI Forwarding Enable, and Access Control Services (ACS) flags from the previous kernel to ensure a stable routing fabric and consistent IOMMU group assignments during Live Update.
5. Restrict preservation to devices in immutable singleton IOMMU groups. Require that all upstream bridges have the necessary ACS features enabled to prevent IOMMU group changes across the update.
6. Modify the PCI shutdown path to avoid disabling bus mastering on preserved devices and their upstream bridges, allowing memory transactions to continue uninterrupted.
7. Provide comprehensive documentation for the FLB API, device tracking mechanisms, and the division of responsibilities between the PCI core, drivers, and userspace.
This series could be simplified down to fewer patches by limiting preservation support to only devices on a root bus. Supporting devices downstream of bridges could be split off into a follow-up series. However since I got bridge preservation working and the series was less than 15 patches I opted to include it for now.
Dependencies
------------
This series depends on 2 LUO patches to enable refcounting of the incoming FLB so that it is safe for the PCI core to use liveupdate_flb_get_incoming() during enumeration.
https://lore.kernel.org/lkml/[email protected]/
VFIO support for PCI device preservation is built on top of this series. The following branch on GitHub contains all the patches together to enable testing (the LUO FLB changes, this series, and the VFIO patches):
https://github.com/dmatlack/linux/tree/liveupdate/pci/base/v4-with-vfio
Testing
-------
This series was tested in combination with the VFIO patches mentioned in the previous section using the the new VFIO selftests:
- vfio_pci_liveupdate_uapi_test
- vfio_pci_liveupdate_kexec_test
Both tests were ran in ran in a QEMU-based VM environment, using a single virtio-net PCIe device behind a PCI-to-PCI bridge as the test device, and in a baremetal environment on an Intel EMR server, using 8x Intel DSA PCIe devices (each on a host bridge).
Future Work
-----------
After this series we expect to make further improvements to the PCI core support for Live Update. Once these are done we plan to drop the "experimental" verbiage from PCI_LIVEUPDATE Kconfig help message and documentation.
- Ensure bridges with downstream preserved devices stay in D0 across Live Update in case preserved endpoints are doing memory transactions.
- Preserve BARs of all preserved devices to avoid disrupting P2P
Beyond that we also plan to add support for preserving Virtual Functions since that is a major use-case for Cloud environments. This will require keeping SR-IOV enabled on the partent PF across a Live Update.
Changelog
---------
v4:
Enhancements on top of previous series:
- Split "PCI: Add API to track PCI devices preserved across Live Update" from v3 into 4 separate commits to make reviewing easier (FLB setup, outgoing device tracking, incoming device tracking, and documentation for driver binding)
- Use new incoming FLB refcounting to avoid use-after-free bugs during enumeration
- Use an xarray to speed up looking up of incoming preserved devices during enumeration
- Use a per-device bit to indicate when secondary and subordinate bus numbers should be inherited on bridges instead of global data to avoid races between the 2 passes
- Inherit ARI enablement across Live Update
- Automatically preserve bridges upstream of preserved endpoints so so that ACS flags, ARI enablement, and bus mastering can be kept constant on bridges across Live Update
- Avoid clearing bus mastering during shutdown on outgoing preserved device to avoid disrupting memory transcations being performed by preserved devices
- Add a MAINTAINERS entry for the new files to support Live Update in the PCI core
- Add info and debug level logging for various events throughout device preservation
Changes based on review feedback on v3:
- Fix up typos, wording, documentation gaps, and code style (Bjorn)
- Use pci_WARN_ONCE() where possible (Bjorn)
- Require ACS flags to preserve devices behind bridges so that singleton IOMMU group topology is guaranteed to remain across Live Update (Yi)
- Preserve ACS flags (Jason, Alex)
v3: https://lore.kernel.org/kvm/[email protected]/
v2: https://lore.kernel.org/kvm/[email protected]/
v1: https://lore.kernel.org/kvm/[email protected]/
rfc: https://lore.kernel.org/kvm/[email protected]/
[1] https://lore.kernel.org/kvm/[email protected]/
David Matlack (11):
PCI: liveupdate: Set up FLB handler for the PCI core
PCI: liveupdate: Track outgoing preserved PCI devices
PCI: liveupdate: Track incoming preserved PCI devices
PCI: liveupdate: Document driver binding responsibilities
PCI: liveupdate: Inherit bus numbers during Live Update
PCI: liveupdate: Auto-preserve upstream bridges across Live Update
PCI: liveupdate: Inherit ACS flags in incoming preserved devices
PCI: liveupdate: Require preserved devices are in immutable singleton
IOMMU groups
PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
PCI: liveupdate: Do not disable bus mastering on preserved devices
during kexec
Documentation: PCI: Add documentation for Live Update
Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 23 + .../admin-guide/kernel-parameters.txt | 6 +- Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 13 + drivers/iommu/iommu.c | 35 ++ drivers/pci/Kconfig | 14 + drivers/pci/Makefile | 1 + drivers/pci/liveupdate.c | 562 ++++++++++++++++++ drivers/pci/pci-driver.c | 31 +- drivers/pci/pci.c | 22 +- drivers/pci/pci.h | 13 + drivers/pci/probe.c | 25 +- include/linux/iommu.h | 7 + include/linux/kho/abi/pci.h | 62 ++ include/linux/pci.h | 58 ++ 16 files changed, 858 insertions(+), 16 deletions(-) create mode 100644 Documentation/PCI/liveupdate.rst create mode 100644 drivers/pci/liveupdate.c create mode 100644 include/linux/kho/abi/pci.h
base-commit: a13f7eb5b2d5bef886659768680093bec1c0470d
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
PATCH v4 1/11 PCI: liveupdate: Set up FLB handler for the PCI core
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct pci_ser) and preserve it across a Live Update whenever at least one device is preserved.
Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is itended primarily to support preservation of PCI devices bound to VFIO drivers.
This commit enables drivers to register their liveupdate_file_handler with the PCI core so that the PCI core can do its own tracking and enforcement of which devices are preserved.
pci_liveupdate_register_flb(driver_file_handler); pci_liveupdate_unregister_flb(driver_file_handler);
When the first file (with a handler registered with the PCI core) is preserved, the PCI core will be notified to allocate its tracking struct (pci_ser). When the last file is unpreserved (i.e. preservation cancelled) the PCI core will be notified to free struct pci_ser.
This struct is preserved across a Live Update using KHO and can be fetched by the PCI core during early boot (e.g. during device enumeration) so that it knows which devices were preserved.
Note that this commit only allocates struct pci_ser and preserves it across Live Update. A subsequent commit will add an API for drivers to tell the PCI core exactly which devices are being preserved.
--- MAINTAINERS | 12 ++++ drivers/pci/Kconfig | 14 ++++ drivers/pci/Makefile | 1 + drivers/pci/liveupdate.c | 139 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 61 ++++++++++++++++ include/linux/pci.h | 15 ++++ 6 files changed, 242 insertions(+) create mode 100644 drivers/pci/liveupdate.c create mode 100644 include/linux/kho/abi/pci.h
MAINTAINERS +12 -0
@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]> +M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.org +C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h + PCI MSI DRIVER FOR ALTERA MSI IP L: [email protected] S: Orphan
drivers/pci/Kconfig +14 -0
@@ -328,6 +328,20 @@ config VGA_ARB_MAX_GPUS Reserves space in the kernel to maintain resource locking for multiple GPUS. The overhead for each GPU is very small. +config PCI_LIVEUPDATE + bool "PCI Live Update Support (EXPERIMENTAL)" + depends on PCI && LIVEUPDATE + help + Enable PCI core support for preserving PCI devices across Live + Update. This, in combination with support in a device's driver, + enables PCI devices to run and perform memory transactions + uninterrupted during a kexec for Live Update. + + This option should only be enabled by developers working on + implementing this support. + + If unsure, say N. + source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig"
drivers/pci/Makefile +1 -0
@@ -16,6 +16,7 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o obj-$(CONFIG_ACPI) += pci-acpi.o obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o +obj-$(CONFIG_PCI_LIVEUPDATE) += liveupdate.o endif obj-$(CONFIG_OF) += of.o
drivers/pci/liveupdate.c new file +139 -0
139 lines not on this page · raw message
include/linux/kho/abi/pci.h new file +61 -0
61 lines not on this page · raw message
include/linux/pci.h +15 -0
@@ -40,6 +40,7 @@#include <linux/resource_ext.h> #include <linux/msi_api.h> #include <uapi/linux/pci.h> +#include <linux/liveupdate.h> #include <linux/pci_ids.h>
@@ -2876,4 +2877,18 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);WARN_ONCE (condition,"%s %s: " fmt, \ dev_driver_string(&(pdev)->dev), pci_name(pdev), ##arg) +#ifdef CONFIG_PCI_LIVEUPDATE +int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh); +void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh); +#else +static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) +{ +} +#endif +#endif /* LINUX_PCI_H */
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Pratyush Yadav
maintainerRe: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Hi David,
On Thu, Apr 23 2026, David Matlack wrote:
[...]
Quoted 10 lines
MAINTAINERS +2
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]>
MAINTAINERS L: [email protected] · line 20569
Quoted 10 lines
MAINTAINERS +10
-0+M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.org +C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +
Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI. We can figure out the maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update.
Perhaps also add the kexec list here? We plan to use it to maintain the LUO patches, and adding it will make sure we get the patches in case someone updates the file list here but forgets to update it in the LIVE UPDATE entry.
Quoted 3 lines
MAINTAINERS +0
-0PCI MSI DRIVER FOR ALTERA MSI IP L: [email protected] S: Orphan
[...]
Signature · 2 lines
Regards, Pratyush Yadav
Pasha Tatashin
maintainerRe: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 30 lines · Pratyush Yadav
Hi David,
On Thu, Apr 23 2026, David Matlack wrote:
[...]Quoted 10 lines
MAINTAINERS +2
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]>MAINTAINERS L: [email protected] · line 20569
Quoted 10 lines
MAINTAINERS +10
-0+M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.org +C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI. We can figure out the maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update.
Quoted 4 lines
Perhaps also add the kexec list here? We plan to use it to maintain the LUO patches, and adding it will make sure we get the patches in case someone updates the file list here but forgets to update it in the LIVE UPDATE entry.
+1
These files should also be added to the Live Update entry, and the kexec mailing list should be included.
Changes specific to Live Update should be routed through the liveupdate/linux.git tree, while generic PCI changes should go through pci/pci.git. In either case, if liveupdate.c or abi/pci.h are modified, acks are required from the Live Update group.
Pasha
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 13 lines · Pasha Tatashin
Quoted 12 lines · Pratyush Yadav
Hi David,
On Thu, Apr 23 2026, David Matlack wrote:
[...]Quoted 8 lines
MAINTAINERS +0
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
MAINTAINERS +7
-0+PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]> +M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.orgQuoted 8 lines
MAINTAINERS L: [email protected] · line 20569
Quoted 5 lines
MAINTAINERS +5
-0+C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI.
Covering that intersection of Live Update and PCI was exactly my intention with introducing this new PCI LIVE UPDATE entry. This ensures we have maintenance coverage with knowledge of that intersection.
Quoted 3 lines
Quoted 3 lines
We can figure out the
maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update.
Would adding kexec@ here be sufficient or do you want to be CC'd directly?
If you want to be CC'd directly do you think makes more sense to add the Live Update maintainers as Reviewers under PCI LIVE UPDATE, or add drivers/pci/liveupdate.c under LIVE UPDATE?
Quoted 8 lines
Quoted 5 lines
Perhaps also add the kexec list here? We plan to use it to maintain the LUO patches, and adding it will make sure we get the patches in case someone updates the file list here but forgets to update it in the LIVE UPDATE entry.
+1
Quoted 7 lines
These files should also be added to the Live Update entry, and the kexec mailing list should be included.
Changes specific to Live Update should be routed through the liveupdate/linux.git tree, while generic PCI changes should go through pci/pci.git. In either case, if
liveupdate.corabi/pci.hare modified, acks are required from the Live Update group.
Do you want to merge changes to drivers/pci/liveupdate.c through the live update tree or PCI tree? We should probably decide now. I was assuming the PCI tree since its part of PCI core.
As we project this out there are going to be users of the Live Update API across different parts of the kernel: PCI core, IOMMU core, IOMMU drivers, VFIO core, VFIO PCI drivers, and KVM. I don't think it will scale to take all that code through the live update tree.
Pasha Tatashin
maintainerRe: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 61 lines · David Matlack
Quoted 13 lines · Pasha Tatashin
Quoted 12 lines · Pratyush Yadav
Hi David,
On Thu, Apr 23 2026, David Matlack wrote:
[...]Quoted 8 lines
MAINTAINERS +0
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rstQuoted 15 lines
Quoted 7 lines
Quoted 7 lines
MAINTAINERS +7
-0+PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]> +M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.orgQuoted 8 lines
MAINTAINERS L: [email protected] · line 20569
Quoted 5 lines
MAINTAINERS +5
-0+C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI.
Covering that intersection of Live Update and PCI was exactly my intention with introducing this new PCI LIVE UPDATE entry. This ensures we have maintenance coverage with knowledge of that intersection.
Quoted 3 lines
Quoted 3 lines
We can figure out the
maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update.Would adding kexec@ here be sufficient or do you want to be CC'd directly?
If you want to be CC'd directly do you think makes more sense to add the Live Update maintainers as Reviewers under PCI LIVE UPDATE, or add
drivers/pci/liveupdate.cunder LIVE UPDATE?Quoted 8 lines
Quoted 5 lines
Perhaps also add the kexec list here? We plan to use it to maintain the LUO patches, and adding it will make sure we get the patches in case someone updates the file list here but forgets to update it in the LIVE UPDATE entry.
+1
Quoted 7 lines
These files should also be added to the Live Update entry, and the kexec mailing list should be included.
Changes specific to Live Update should be routed through the liveupdate/linux.git tree, while generic PCI changes should go through pci/pci.git. In either case, if
liveupdate.corabi/pci.hare modified, acks are required from the Live Update group.
Quoted 8 lines
Do you want to merge changes to
drivers/pci/liveupdate.cthrough the live update tree or PCI tree? We should probably decide now. I was assuming the PCI tree since its part of PCI core.As we project this out there are going to be users of the Live Update API across different parts of the kernel: PCI core, IOMMU core, IOMMU drivers, VFIO core, VFIO PCI drivers, and KVM. I don't think it will scale to take all that code through the live update tree.
All Live-Update-specific changes should go through the liveupdate tree. The liveupdate tree is the only Linux tree that will cover full Live Update regression testing, and it contains reviewers and maintainers who know the details of the Live Update process, its lifecycle, and its requirements.
The request we are hearing from other subsystem maintainers is that they want to make sure Live Update is isolated enough not to make their lives harder. This means reducing the number of conflicts, the maintenance burden, and testing responsibilities.
Therefore, the "PCI LIVE UPDATE" entry should specify you as a maintainer, "[email protected]" as the list to which all LU changes should be CC'd, and "liveupdate/linux.git" as the git tree against which changes should be applied.
It should also include "[email protected]" so the PCI maintainers are CC'd. In case there are larger changes that touch core PCI and liveupdate.c/abi, we can ACK them, ensuring we are aware of incoming conflicts during the current or next merge cycle.
It should also specify the members of LU group so we can stage the changes.
This is the way we agreed to handle kexec changes: Baoquan He is the maintainer, and without his Reviewed-by tag, we won't take changes to kexec. This is the approach we follow with MM for KHO changes to memblock and memfd preservation, as well as the upcoming hugetlb/guestmemfd preservation.
This is also the approach we should continue using when adding LUO support to other components like PCI, VFIO, IOMMU, and KVM. It keeps life easier for the core component maintainers and ensures we do not regress LU by staging everything in the same tree and sending LU merge requests from a single tree.
Pasha
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 87 lines · Pasha Tatashin
Quoted 61 lines · David Matlack
Quoted 13 lines · Pasha Tatashin
Quoted 12 lines · Pratyush Yadav
Hi David,
On Thu, Apr 23 2026, David Matlack wrote:
[...]Quoted 8 lines
MAINTAINERS +0
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rstQuoted 15 lines
Quoted 7 lines
Quoted 7 lines
MAINTAINERS +7
-0+PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]> +M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.orgQuoted 8 lines
MAINTAINERS L: [email protected] · line 20569
Quoted 5 lines
MAINTAINERS +5
-0+C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI.
Covering that intersection of Live Update and PCI was exactly my intention with introducing this new PCI LIVE UPDATE entry. This ensures we have maintenance coverage with knowledge of that intersection.
Quoted 3 lines
Quoted 3 lines
We can figure out the
maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update.Would adding kexec@ here be sufficient or do you want to be CC'd directly?
If you want to be CC'd directly do you think makes more sense to add the Live Update maintainers as Reviewers under PCI LIVE UPDATE, or add
drivers/pci/liveupdate.cunder LIVE UPDATE?Quoted 8 lines
Quoted 5 lines
Perhaps also add the kexec list here? We plan to use it to maintain the LUO patches, and adding it will make sure we get the patches in case someone updates the file list here but forgets to update it in the LIVE UPDATE entry.
+1
Quoted 7 lines
These files should also be added to the Live Update entry, and the kexec mailing list should be included.
Changes specific to Live Update should be routed through the liveupdate/linux.git tree, while generic PCI changes should go through pci/pci.git. In either case, if
liveupdate.corabi/pci.hare modified, acks are required from the Live Update group.Quoted 8 lines
Do you want to merge changes to
drivers/pci/liveupdate.cthrough the live update tree or PCI tree? We should probably decide now. I was assuming the PCI tree since its part of PCI core.As we project this out there are going to be users of the Live Update API across different parts of the kernel: PCI core, IOMMU core, IOMMU drivers, VFIO core, VFIO PCI drivers, and KVM. I don't think it will scale to take all that code through the live update tree.
All Live-Update-specific changes should go through the liveupdate tree. The liveupdate tree is the only Linux tree that will cover full Live Update regression testing, and it contains reviewers and maintainers who know the details of the Live Update process, its lifecycle, and its requirements.
The request we are hearing from other subsystem maintainers is that they want to make sure Live Update is isolated enough not to make their lives harder. This means reducing the number of conflicts, the maintenance burden, and testing responsibilities.
Therefore, the "PCI LIVE UPDATE" entry should specify you as a maintainer, "[email protected]" as the list to which all LU changes should be CC'd, and "liveupdate/linux.git" as the git tree against which changes should be applied.
Quoted 7 lines
It should also include "[email protected]" so the PCI maintainers are CC'd. In case there are larger changes that touch core PCI and liveupdate.c/abi, we can ACK them, ensuring we are aware of incoming conflicts during the current or next merge cycle.
It should also specify the members of LU group so we can stage the changes.
Sorry what does this mean specifically?
Quoted 11 lines
This is the way we agreed to handle kexec changes: Baoquan He is the maintainer, and without his Reviewed-by tag, we won't take changes to kexec. This is the approach we follow with MM for KHO changes to memblock and memfd preservation, as well as the upcoming hugetlb/guestmemfd preservation.
This is also the approach we should continue using when adding LUO support to other components like PCI, VFIO, IOMMU, and KVM. It keeps life easier for the core component maintainers and ensures we do not regress LU by staging everything in the same tree and sending LU merge requests from a single tree.
Ok it sounds like we are aligned on keeping drivers/pci/liveupdate.c, include/linux/kho/abi/pci.h, and Documentation/PCI/liveupdate.rst in the PCI LIVE UPDATE entry and not duplicating them in the LIVE UPDATE entry.
I think the only open question is what tree to use for the PCI LIVE UPDATE entry, PCI tree or Live Update tree. You are proposing the Live Update tree.
Bjorn are you ok with that approach?
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 55 lines · David Matlack
Quoted 36 lines · Pasha Tatashin
Quoted 35 lines · David Matlack
Quoted 11 lines · Pasha Tatashin
Quoted 10 lines · Pratyush Yadav
On Thu, Apr 23 2026, David Matlack wrote:
[...]Quoted 8 lines
MAINTAINERS +0
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rstQuoted 15 lines
Quoted 7 lines
Quoted 7 lines
MAINTAINERS +7
-0+PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]> +M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.orgQuoted 8 lines
MAINTAINERS L: [email protected] · line 20569
Quoted 5 lines
MAINTAINERS +5
-0+C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +Can we please also add these files under the "LIVE UPDATE" entry. The code here concerns both live update and PCI.
Covering that intersection of Live Update and PCI was exactly my intention with introducing this new PCI LIVE UPDATE entry. This ensures we have maintenance coverage with knowledge of that intersection.
Quoted 3 lines
Quoted 3 lines
We can figure out the
maintenance details as we go along, but I think the live update maintainers should at least get all the patches for PCI live update....
Quoted 11 lines
This is the way we agreed to handle kexec changes: Baoquan He is the maintainer, and without his Reviewed-by tag, we won't take changes to kexec. This is the approach we follow with MM for KHO changes to memblock and memfd preservation, as well as the upcoming hugetlb/guestmemfd preservation.
This is also the approach we should continue using when adding LUO support to other components like PCI, VFIO, IOMMU, and KVM. It keeps life easier for the core component maintainers and ensures we do not regress LU by staging everything in the same tree and sending LU merge requests from a single tree.
Ok it sounds like we are aligned on keeping
drivers/pci/liveupdate.c,include/linux/kho/abi/pci.h, andDocumentation/PCI/liveupdate.rstin the PCI LIVE UPDATE entry and not duplicating them in the LIVE UPDATE entry.
Quoted 5 lines
I think the only open question is what tree to use for the PCI LIVE UPDATE entry, PCI tree or Live Update tree. You are proposing the Live Update tree.
Bjorn are you ok with that approach?
Yes, I think that makes sense, at least to start. In early days, it would probably be a headache to coordinate LU things across multiple trees.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 23 lines · Bjorn Helgaas
Quoted 22 lines · David Matlack
Quoted 11 lines · Pasha Tatashin
This is the way we agreed to handle kexec changes: Baoquan He is the maintainer, and without his Reviewed-by tag, we won't take changes to kexec. This is the approach we follow with MM for KHO changes to memblock and memfd preservation, as well as the upcoming hugetlb/guestmemfd preservation.
This is also the approach we should continue using when adding LUO support to other components like PCI, VFIO, IOMMU, and KVM. It keeps life easier for the core component maintainers and ensures we do not regress LU by staging everything in the same tree and sending LU merge requests from a single tree.
Ok it sounds like we are aligned on keeping
drivers/pci/liveupdate.c,include/linux/kho/abi/pci.h, andDocumentation/PCI/liveupdate.rstin the PCI LIVE UPDATE entry and not duplicating them in the LIVE UPDATE entry.I think the only open question is what tree to use for the PCI LIVE UPDATE entry, PCI tree or Live Update tree. You are proposing the Live Update tree.
Quoted 5 lines
Quoted 1 line
Bjorn are you ok with that approach?
Yes, I think that makes sense, at least to start. In early days, it would probably be a headache to coordinate LU things across multiple trees.
Sounds good. I will swap the trees in v5. Thanks all.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
In reply to David MatlackQuoted 11 lines · David Matlack
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct
pci_ser) and preserve it across a Live Update whenever at least one device is preserved.Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is itended primarily to support preservation of PCI devices bound to VFIO drivers.
s/itended/intended/
MAINTAINERS L: [email protected] · line 20559
Quoted 7 lines
+++ b/MAINTAINERS
MAINTAINERS +2
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]>
I don't think I want to be the primary contact here. I'll see patches regardless since they're on linux-pci.
Quoted 9 lines
MAINTAINERS +9
-0+M: David Matlack <[email protected]> +L: [email protected] +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.org +C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 10 lines · Bjorn Helgaas
MAINTAINERS L: [email protected] · line 20559
Quoted 7 lines
+++ b/MAINTAINERS
MAINTAINERS +2
-0@@ -20555,6 +20555,18 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: Bjorn Helgaas <[email protected]>I don't think I want to be the primary contact here. I'll see patches regardless since they're on linux-pci.
Ack, I will drop this line from v5.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
In reply to David Matlackdrivers/pci/liveupdate.c line 84
Quoted 6 lines · David Matlack
drivers/pci/liveupdate.c new file +6
-0+pr_debug ("Preserving struct pci_ser with room for %u devices\n" , + max_nr_devices); + + ser =kho_alloc_preserve (size); +if (IS_ERR (ser)) +return PTR_ERR (ser);
Should there be a similar pr_debug() in case of failure to denote that above "Preserving ..." message didn't finish, or, maybe just print one pr_debug() after the error check above?
include/linux/kho/abi/pci.h line 38
Quoted 11 lines
include/linux/kho/abi/pci.h new file +11
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @reserved: Reserved (to naturally align struct pci_dev_ser). +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 reserved;
Should this be renamed to 'u8 __padding[2];' instead? This will allow to just change the array length based on the need (0, 1, 2, 3).
Quoted 11 lines
include/linux/kho/abi/pci.h new file +11
-0+} __packed; + +/** +* struct pci_ser - PCI Subsystem Live Update State +* +* This struct tracks state about all devices that are being preserved across +* a Live Update for the next kernel. +* +* @max_nr_devices: The length of the devices[] flexible array. +* @nr_devices: The number of devices that were preserved. +* @devices: Flexible array of pci_dev_ser structs for each device.
include/linux/kho/abi/pci.h line 59
Quoted 10 lines
include/linux/kho/abi/pci.h new file +10
-0+*/ +struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed; + +/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );
Nit: Maybe move this assert to be near to the definition of this struct, easier to find it when editing the struct vs finding it later during build.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 11 lines · Vipin Sharma
drivers/pci/liveupdate.c line 84
Quoted 6 lines · David Matlack
drivers/pci/liveupdate.c new file +6
-0+pr_debug ("Preserving struct pci_ser with room for %u devices\n" , + max_nr_devices); + + ser =kho_alloc_preserve (size); +if (IS_ERR (ser)) +return PTR_ERR (ser);Should there be a similar
pr_debug()in case of failure to denote that above "Preserving ..." message didn't finish, or, maybe just print onepr_debug()after the error check above?
Hm... I guess there could always be more pr_debug()s but I don't want to instrument every error path. I could move it to the success path but I don't see how that makes it any better.
Quoted 15 lines
include/linux/kho/abi/pci.h line 38
Quoted 12 lines
include/linux/kho/abi/pci.h new file +11
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @reserved: Reserved (to naturally align struct pci_dev_ser). +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 reserved;Should this be renamed to 'u8 __padding[2];' instead? This will allow to just change the array length based on the need (0, 1, 2, 3).
Sorry I'm not following what you mean here. What is the reason to rename this field and change it to an array?
Quoted 17 lines
Quoted 17 lines
include/linux/kho/abi/pci.h new file +17
-0+} __packed; + +/** +* struct pci_ser - PCI Subsystem Live Update State +* +* This struct tracks state about all devices that are being preserved across +* a Live Update for the next kernel. +* +* @max_nr_devices: The length of the devices[] flexible array. +* @nr_devices: The number of devices that were preserved. +* @devices: Flexible array of pci_dev_ser structs for each device. +*/ +struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed;
Quoted 8 lines
include/linux/kho/abi/pci.h line 59
Quoted 4 lines
include/linux/kho/abi/pci.h new file +4
-0+ +/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );Nit: Maybe move this assert to be near to the definition of this struct, easier to find it when editing the struct vs finding it later during build.
The combination of these 2 asserts is what guarantees that every element of the devices[] array are naturally aligned, that's why I put them together here.
I can move it up though if you think it's better.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 13 lines · David Matlack
Quoted 11 lines · Vipin Sharma
drivers/pci/liveupdate.c line 84
Quoted 6 lines · David Matlack
drivers/pci/liveupdate.c new file +6
-0+pr_debug ("Preserving struct pci_ser with room for %u devices\n" , + max_nr_devices); + + ser =kho_alloc_preserve (size); +if (IS_ERR (ser)) +return PTR_ERR (ser);Should there be a similar
pr_debug()in case of failure to denote that above "Preserving ..." message didn't finish, or, maybe just print onepr_debug()after the error check above?
Quoted 4 lines
Hm... I guess there could always be more pr_debug()s but I don't want to instrument every error path. I could move it to the success path but I don't see how that makes it any better.
In current way, it is printing that it is preserving pci_ser, but there is no indication did it succeed or not in logs. If we are printing the logs then may be complete picture will be to know what is the action and its result.
I think moving to success path or printing again based on the failure provides assurance of what happened. If this gets printed in happy path, then we will know it succeeded in preserving that struct on kho. Absence means it didn't.
We can also remove pr_debug(), if this is of no value.
Quoted 16 lines
Quoted 15 lines
include/linux/kho/abi/pci.h line 38
Quoted 12 lines
include/linux/kho/abi/pci.h new file +11
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @reserved: Reserved (to naturally align struct pci_dev_ser). +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 reserved;Should this be renamed to 'u8 __padding[2];' instead? This will allow to just change the array length based on the need (0, 1, 2, 3).
Quoted 3 lines
Sorry I'm not following what you mean here. What is the reason to rename this field and change it to an array?
Having a padding explicitly tells there is a requirement of being aligned. Reserved sounds more like don't use this u16.
If someone add more field down the line say u8, then to make struct size aligned they will need to add another u8, u16, u32, and name those fields padding or reserved. IMO, having a u8 array named padding makes it easier to just change array length as per the need.
Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
include/linux/kho/abi/pci.h new file +17
-0+} __packed; + +/** +* struct pci_ser - PCI Subsystem Live Update State +* +* This struct tracks state about all devices that are being preserved across +* a Live Update for the next kernel. +* +* @max_nr_devices: The length of the devices[] flexible array. +* @nr_devices: The number of devices that were preserved. +* @devices: Flexible array of pci_dev_ser structs for each device. +*/ +struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed;Quoted 8 lines
include/linux/kho/abi/pci.h line 59
Quoted 4 lines
include/linux/kho/abi/pci.h new file +4
-0+ +/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );Nit: Maybe move this assert to be near to the definition of this struct, easier to find it when editing the struct vs finding it later during build.
Quoted 5 lines
The combination of these 2 asserts is what guarantees that every element of the devices[] array are naturally aligned, that's why I put them together here.
I can move it up though if you think it's better.
Okay, SGTM.
Re: [PATCH v4 01/11] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 24 lines · Vipin Sharma
Quoted 13 lines · David Matlack
Quoted 11 lines · Vipin Sharma
drivers/pci/liveupdate.c line 84
Quoted 6 lines · David Matlack
drivers/pci/liveupdate.c new file +6
-0+pr_debug ("Preserving struct pci_ser with room for %u devices\n" , + max_nr_devices); + + ser =kho_alloc_preserve (size); +if (IS_ERR (ser)) +return PTR_ERR (ser);Should there be a similar
pr_debug()in case of failure to denote that above "Preserving ..." message didn't finish, or, maybe just print onepr_debug()after the error check above?Quoted 4 lines
Hm... I guess there could always be more pr_debug()s but I don't want to instrument every error path. I could move it to the success path but I don't see how that makes it any better.
In current way, it is printing that it is preserving
pci_ser, but there is no indication did it succeed or not in logs. If we are printing the logs then may be complete picture will be to know what is the action and its result.
Quoted 6 lines
I think moving to success path or printing again based on the failure provides assurance of what happened. If this gets printed in happy path, then we will know it succeeded in preserving that struct on kho. Absence means it didn't.
We can also remove
pr_debug(), if this is of no value.
I think I'll just drop these. BPF can be used to trace this function and what it returns when debugging issues.
Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
include/linux/kho/abi/pci.h line 38
Quoted 13 lines
include/linux/kho/abi/pci.h new file +11
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @reserved: Reserved (to naturally align struct pci_dev_ser). +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 reserved;Should this be renamed to 'u8 __padding[2];' instead? This will allow to just change the array length based on the need (0, 1, 2, 3).
Quoted 6 lines
Quoted 3 lines
Sorry I'm not following what you mean here. What is the reason to rename this field and change it to an array?
Having a padding explicitly tells there is a requirement of being aligned. Reserved sounds more like don't use this u16.
It's documented above, but agree padding is a better name.
Quoted 4 lines
If someone add more field down the line say u8, then to make struct size aligned they will need to add another u8, u16, u32, and name those fields padding or reserved. IMO, having a u8 array named padding makes it easier to just change array length as per the need.
This field does get replaced in the next patch. But I see your point that if we need to pad by an amount other than u8, u16, or u32, then we would need an array.
PATCH v4 2/11 PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackAdd APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct pci_ser) and track the list of outgoing devices. pci_liveupdate_preserve() notifies the PCI core that a device must be preserved across Live Update. pci_liveupdate_unpreserve() reverses this (cancels the preservation of the device).
This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
--- drivers/pci/liveupdate.c | 101 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 7 +-- include/linux/pci.h | 26 ++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-)
drivers/pci/liveupdate.c +101 -0
@@ -43,6 +43,26 @@* * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` +* +* Device Tracking +* =============== +* +* Drivers must notify the PCI core when specific devices are preserved or +* unpreserved with the following APIs: +* +* * ``pci_liveupdate_preserve(pci_dev)`` +* * ``pci_liveupdate_unpreserve(pci_dev)`` +* +* This allows the PCI core to keep it's FLB data (struct pci_ser) up to date +* with the list of **outgoing** preserved devices for the next kernel. +* +* Restrictions +* ============ +* +* The PCI core enforces the following restrictions on which devices can be +* preserved. These may be relaxed in the future: +* +* * The device cannot be a Virtual Function (VF). */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -57,6 +77,8 @@#include <linux/pci.h> #include <linux/sort.h> +static DEFINE_MUTEX (pci_flb_outgoing_lock); +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_dev *dev =NULL ;
@@ -124,6 +146,85 @@ static struct liveupdate_flb pci_liveupdate_flb = { .compatible = PCI_LUO_FLB_COMPATIBLE, }; +int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_preserve); + +void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +struct pci_dev_ser *dev_ser; +struct pci_ser *ser =NULL ; +int ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); + +if (ret || !ser) { +pci_warn (dev,"Cannot unpreserve device without outgoing Live Update state\n" ); +return ; + + } + + dev_ser = dev->liveupdate_outgoing; +if (!dev_ser) { +pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); +return ; + } + +pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); + ser->nr_devices--; +memset (dev_ser,0 ,sizeof (*dev_ser)); + dev->liveupdate_outgoing =NULL ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {pr_debug ("Registering file handler \"%s\"\n" , fh->compatible);
include/linux/kho/abi/pci.h +4 -3
@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @reserved: Reserved (to naturally align struct pci_dev_ser). +* @refcount: Reference count used by the PCI core to keep track of whether it +* is done using a device's struct pci_dev_ser. */ struct pci_dev_ser {u32 domain;u16 bdf; -u16 reserved; +u16 refcount; } __packed;/**
include/linux/pci.h +26 -0
@@ -41,6 +41,7 @@#include <linux/msi_api.h> #include <uapi/linux/pci.h> #include <linux/liveupdate.h> +#include <linux/kho/abi/pci.h> #include <linux/pci_ids.h>
@@ -594,6 +595,9 @@ struct pci_dev {u8 tph_mode;/* TPH mode */ u8 tph_req_type;/* TPH requester type */ #endif +#ifdef CONFIG_PCI_LIVEUPDATE +struct pci_dev_ser *liveupdate_outgoing;/* State preserved for next kernel */ +#endif };static inline struct pci_dev *pci_physfn (struct pci_dev *dev)
@@ -2880,6 +2884,14 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);#ifdef CONFIG_PCI_LIVEUPDATE int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh);void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh); + +int pci_liveupdate_preserve (struct pci_dev *dev); +void pci_liveupdate_unpreserve (struct pci_dev *dev); + +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}#else static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {
@@ -2889,6 +2901,20 @@ static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fhstatic inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) { } + +static inline int pci_liveupdate_preserve (struct pci_dev *dev) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +} + +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return NULL ; +}#endif #endif /* LINUX_PCI_H */
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Hi David,
Quoted 77 lines · On Thu, 23 Apr 2026 21:23:06 +0000 David Matlack <[email protected]> wrote:
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct
pci_ser) and track the list of outgoing devices.pci_liveupdate_preserve()notifies the PCI core that a device must be preserved across Live Update.pci_liveupdate_unpreserve()reverses this (cancels the preservation of the device).This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 101 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 7 +-- include/linux/pci.h | 26 ++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-)drivers/pci/liveupdate.c +5
-0@@ -43,6 +43,26 @@* * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` +* +* Device Tracking +* =============== +* +* Drivers must notify the PCI core when specific devices are preserved or
+ * unpreserved with the following APIs:
+ *
+ * * ``pci_liveupdate_preserve(pci_dev)``
+ * * ``pci_liveupdate_unpreserve(pci_dev)``
+ *
+ * This allows the PCI core to keep it's FLB data (structpci_ser) up to date
+ * with the list of **outgoing** preserved devices for the next kernel.
+ *
+ * Restrictions
+ * ============
+ *
+ * The PCI core enforces the following restrictions on which devices can be
+ * preserved. These may be relaxed in the future:
+ *
+ * * The device cannot be a Virtual Function (VF).
*/#define
pr_fmt(fmt)"PCI: liveupdate: " fmtdrivers/pci/liveupdate.c +9
-0@@ -57,6 +77,8 @@#include <linux/pci.h> #include <linux/sort.h> +static DEFINE_MUTEX (pci_flb_outgoing_lock); +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_dev *dev =NULL ;@@ -124,6 +146,85 @@ static struct liveupdate_flb pci_liveupdate_flb = { .compatible =PCI_LUO_FLB_COMPATIBLE , }; +int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); +
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb · line 165
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+ ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ;
This can be left outside the mutex?
Quoted 160 lines
drivers/pci/liveupdate.c +10
-0+ +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result
drivers/pci/liveupdate.c +1
-0+* in a constant time search under expected conditions (devices
drivers/pci/liveupdate.c +3
-0+* are not getting unpreserved). +*/ + int index = (ser->nr_devices + i) %
ser->max_nr_devices;drivers/pci/liveupdate.c +6
-0+struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + + pci_info(dev, "Device will be preserved across nextLive Update\n");
drivers/pci/liveupdate.c +23
-0+ ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_preserve); + +void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +struct pci_dev_ser *dev_ser; +struct pci_ser *ser =NULL ; +int ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void**)&ser); +
drivers/pci/liveupdate.c +2
-0+if (ret || !ser) { + pci_warn(dev, "Cannot unpreserve device withoutoutgoing Live Update state\n");
drivers/pci/liveupdate.c +7
-0+return ; + + } + + dev_ser = dev->liveupdate_outgoing; +if (!dev_ser) { + pci_warn(dev, "Cannot unpreserve device that is notpreserved\n");
drivers/pci/liveupdate.c +4
-0+return ; + } + + pci_info(dev, "Device will no longer be preserved acrossnext Live Update\n");
drivers/pci/liveupdate.c +6
-0+ ser->nr_devices--; +memset (dev_ser,0 ,sizeof (*dev_ser)); + dev->liveupdate_outgoing =NULL ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) { pr_debug("Registering file handler \"%s\"\n",
fh->compatible); diff --gita/include/linux/kho/abi/pci.hb/include/linux/kho/abi/pci.hindex5c0e92588c00..5b4c8d9e462c100644include/linux/kho/abi/pci.h +0
-0@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */
include/linux/kho/abi/pci.h +2
-2-#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @reserved: Reserved (to naturally align struct pci_dev_ser). +* @refcount: Reference count used by the PCI core to keep track of whether it
+ * is done using a device's structpci_dev_ser.
*/
structpci_dev_ser{include/linux/kho/abi/pci.h +1
-1u32 domain;u16 bdf; -u16 reserved; +u16 refcount; } __packed;/** include/linux/pci.h +3
-0@@ -41,6 +41,7 @@#include <linux/msi_api.h> #include <uapi/linux/pci.h> #include <linux/liveupdate.h> +#include <linux/kho/abi/pci.h> #include <linux/pci_ids.h> @@ -594,6 +595,9 @@ struct pci_dev {u8 tph_mode;/* TPH mode */ u8 tph_req_type;/* TPH requester type */ #endif +#ifdef CONFIG_PCI_LIVEUPDATE +struct pci_dev_ser *liveupdate_outgoing;/* State preserved for next kernel */ +#endif
};static inline struct
pci_dev*pci_physfn(structpci_dev*dev)include/linux/pci.h +6
-0@@ -2880,6 +2884,14 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); #ifdef CONFIG_PCI_LIVEUPDATEint pci_liveupdate_register_flb (struct liveupdate_file_handler *fh);void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh); + +int pci_liveupdate_preserve(struct pci_dev *dev); +void pci_liveupdate_unpreserve (struct pci_dev *dev); + +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}#else static inline int pci_liveupdate_register_flb(struct
liveupdate_file_handler*fh) {include/linux/pci.h +0
-0@@ -2889,6 +2901,20 @@ static inline intpci_liveupdate_register_flb(struct
liveupdate_file_handler*fh static inline voidpci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh){ }include/linux/pci.h +11
-0+ +static inline int pci_liveupdate_preserve (struct pci_dev *dev) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +} + +static inline struct pci_dev_ser *pci_liveupdate_outgoing(struct
pci_dev*dev) +{include/linux/pci.h +2
-0+return NULL ; +}#endif #endif /* LINUX_PCI_H */
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 10 lines · Jacob Pan
Quoted 10 lines
drivers/pci/liveupdate.c +8
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void**)&ser);
+ if (ret)
Quoted 8 lines
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 164
Quoted 7 lines
drivers/pci/liveupdate.c +7
-0+return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ;This can be left outside the mutex?
Yes indeed. I will move it out in v5. Thanks!
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackQuoted 11 lines · David Matlack
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
+++
b/drivers/pci/liveupdate.cdrivers/pci/liveupdate.c +2
-0@@ -43,6 +43,26 @@* * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` +* +* Device Tracking
drivers/pci/liveupdate.c line 57
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+* =============== +* +* Drivers must notify the PCI core when specific devices are preserved or +* unpreserved with the following APIs: +* +* * ``pci_liveupdate_preserve(pci_dev)`` +* * ``pci_liveupdate_unpreserve(pci_dev)`` +* +* This allows the PCI core to keep it's FLB data (struct pci_ser) up to date +* with the list of **outgoing** preserved devices for the next kernel.
s/it's/its/
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackQuoted 86 lines · David Matlack
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct
pci_ser) and track the list of outgoing devices.pci_liveupdate_preserve()notifies the PCI core that a device must be preserved across Live Update.pci_liveupdate_unpreserve()reverses this (cancels the preservation of the device).This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
Signed-off-by David Matlack <[email protected]>---
drivers/pci/liveupdate.c | 101 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 7 +-- include/linux/pci.h | 26 ++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-)drivers/pci/liveupdate.c +43
-0@@ -43,6 +43,26 @@* * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` +* +* Device Tracking +* =============== +* +* Drivers must notify the PCI core when specific devices are preserved or +* unpreserved with the following APIs: +* +* * ``pci_liveupdate_preserve(pci_dev)`` +* * ``pci_liveupdate_unpreserve(pci_dev)`` +* +* This allows the PCI core to keep it's FLB data (struct pci_ser) up to date +* with the list of **outgoing** preserved devices for the next kernel. +* +* Restrictions +* ============ +* +* The PCI core enforces the following restrictions on which devices can be +* preserved. These may be relaxed in the future: +* +* * The device cannot be a Virtual Function (VF). */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt@@ -57,6 +77,8 @@#include <linux/pci.h> #include <linux/sort.h> +static DEFINE_MUTEX (pci_flb_outgoing_lock); +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_dev *dev =NULL ;@@ -124,6 +146,85 @@ static struct liveupdate_flb pci_liveupdate_flb = { .compatible = PCI_LUO_FLB_COMPATIBLE, }; +int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices)
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 179
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index];
nit: Maybe we can move this logic in a separate function as down the road when we expand this to add VFs and Hotpluggable devices, this might change significantly? It's good if it is self-contained.
Quoted 103 lines
drivers/pci/liveupdate.c +48
-0+ +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_preserve); + +void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +struct pci_dev_ser *dev_ser; +struct pci_ser *ser =NULL ; +int ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); + +if (ret || !ser) { +pci_warn (dev,"Cannot unpreserve device without outgoing Live Update state\n" ); +return ; + + } + + dev_ser = dev->liveupdate_outgoing; +if (!dev_ser) { +pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); +return ; + } + +pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); + ser->nr_devices--; +memset (dev_ser,0 ,sizeof (*dev_ser)); + dev->liveupdate_outgoing =NULL ; +} +EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {pr_debug ("Registering file handler \"%s\"\n" , fh->compatible);include/linux/kho/abi/pci.h +4
-3@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @reserved: Reserved (to naturally align struct pci_dev_ser). +* @refcount: Reference count used by the PCI core to keep track of whether it +* is done using a device's struct pci_dev_ser. */ struct pci_dev_ser {u32 domain;u16 bdf; -u16 reserved; +u16 refcount; } __packed;/** include/linux/pci.h +4
-0@@ -41,6 +41,7 @@#include <linux/msi_api.h> #include <uapi/linux/pci.h> #include <linux/liveupdate.h> +#include <linux/kho/abi/pci.h> #include <linux/pci_ids.h> @@ -594,6 +595,9 @@ struct pci_dev {u8 tph_mode;/* TPH mode */ u8 tph_req_type;/* TPH requester type */ #endif +#ifdef CONFIG_PCI_LIVEUPDATE +struct pci_dev_ser *liveupdate_outgoing;/* State preserved for next kernel */ +#endif };static inline struct pci_dev *pci_physfn (struct pci_dev *dev)@@ -2880,6 +2884,14 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);#ifdef CONFIG_PCI_LIVEUPDATE
include/linux/pci.h void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); · line 2894
Quoted 10 lines
include/linux/pci.h +8
-0int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh);void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh); + +int pci_liveupdate_preserve (struct pci_dev *dev); +void pci_liveupdate_unpreserve (struct pci_dev *dev); + +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}
Is this expected to be called under the outgoing lock?
Quoted 27 lines
include/linux/pci.h +14
-0#else static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {@@ -2889,6 +2901,20 @@ static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fhstatic inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) { } + +static inline int pci_liveupdate_preserve (struct pci_dev *dev) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +} + +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return NULL ; +}#endif #endif /* LINUX_PCI_H */ Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 33 lines · Samiullah Khawaja
Quoted 32 lines · David Matlack
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct
pci_ser) and track the list of outgoing devices.pci_liveupdate_preserve()notifies the PCI core that a device must be preserved across Live Update.pci_liveupdate_unpreserve()reverses this (cancels the preservation of the device).This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
Signed-off-by David Matlack <[email protected]>---
drivers/pci/liveupdate.c | 101 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 7 +-- include/linux/pci.h | 26 ++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-)include/linux/kho/abi/pci.h +1
-1@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"
Quoted 8 lines
include/linux/kho/abi/pci.h line 34
Quoted 8 lines
include/linux/kho/abi/pci.h +2
-1/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @reserved: Reserved (to naturally align struct pci_dev_ser). +* @refcount: Reference count used by the PCI core to keep track of whether it +* is done using a device's struct pci_dev_ser.
nit: I was wondering why is this named refcount and why it is needed. It seems you are using it to track the preservation dependency between parent devices and leaf. Maybe add a comment to clarify that.
Quoted 9 lines
include/linux/kho/abi/pci.h line 42
Quoted 9 lines
include/linux/kho/abi/pci.h +1
-1*/ struct pci_dev_ser {u32 domain;u16 bdf; -u16 reserved; +u16 refcount; } __packed;/**
Sami
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 34 lines · Samiullah Khawaja
Quoted 33 lines · Samiullah Khawaja
Quoted 32 lines · David Matlack
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct
pci_ser) and track the list of outgoing devices.pci_liveupdate_preserve()notifies the PCI core that a device must be preserved across Live Update.pci_liveupdate_unpreserve()reverses this (cancels the preservation of the device).This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
Signed-off-by David Matlack <[email protected]>---
drivers/pci/liveupdate.c | 101 ++++++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 7 +-- include/linux/pci.h | 26 ++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-)include/linux/kho/abi/pci.h +1
-1@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"
Quoted 12 lines
Quoted 8 lines
include/linux/kho/abi/pci.h line 34
Quoted 8 lines
include/linux/kho/abi/pci.h +2
-1/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @reserved: Reserved (to naturally align struct pci_dev_ser). +* @refcount: Reference count used by the PCI core to keep track of whether it +* is done using a device's struct pci_dev_ser. nit: I was wondering why is this named refcount and why it is needed. It seems you are using it to track the preservation dependency between parent devices and leaf. Maybe add a comment to clarify that.
Ack, I will clarify that more in the kerneldoc in v5, thanks.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to Samiullah KhawajaQuoted 14 lines · Samiullah Khawaja
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 179
Quoted 8 lines · David Matlack
drivers/pci/liveupdate.c +8
-0+for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index];nit: Maybe we can move this logic in a separate function as down the road when we expand this to add VFs and Hotpluggable devices, this might change significantly? It's good if it is self-contained.
Did you mean to leave this comment on pci_flb_preserve() where it decides how many devices to allocate room for?
Quoted 6 lines
include/linux/pci.h void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); · line 2894
Quoted 4 lines
include/linux/pci.h +4
-0+static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}Is this expected to be called under the outgoing lock?
For now this API is only used during shutdown, at which point userspace should have already been stopped so drivers should not be changing the preservation status of an outgoing device. So I don't think this needs to be under the outgoing lock, but it would be nice to have some more explicit synchronization.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 16 lines · David Matlack
Quoted 14 lines · Samiullah Khawaja
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 179
Quoted 8 lines · David Matlack
drivers/pci/liveupdate.c +8
-0+for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index];nit: Maybe we can move this logic in a separate function as down the road when we expand this to add VFs and Hotpluggable devices, this might change significantly? It's good if it is self-contained.
Quoted 2 lines
Did you mean to leave this comment on
pci_flb_preserve()where it decides how many devices to allocate room for?
I was talking about this one, as I think depending on the scheme we take this might change significantly. Just a nit, you can ignore it.
Quoted 8 lines
Quoted 7 lines
include/linux/pci.h void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); · line 2894
Quoted 5 lines
include/linux/pci.h +4
-0+static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}Is this expected to be called under the outgoing lock?
Quoted 5 lines
For now this API is only used during shutdown, at which point userspace should have already been stopped so drivers should not be changing the preservation status of an outgoing device. So I don't think this needs to be under the outgoing lock, but it would be nice to have some more explicit synchronization.
Ok that makes sense. I have similar cases in my series, but maybe we can add kdoc regarding these stating in which context this is expected to be used?
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 18 lines · Samiullah Khawaja
Quoted 16 lines · David Matlack
Quoted 14 lines · Samiullah Khawaja
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 179
Quoted 8 lines · David Matlack
drivers/pci/liveupdate.c +8
-0+for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index];nit: Maybe we can move this logic in a separate function as down the road when we expand this to add VFs and Hotpluggable devices, this might change significantly? It's good if it is self-contained.
Quoted 5 lines
Quoted 2 lines
Did you mean to leave this comment on
pci_flb_preserve()where it decides how many devices to allocate room for?I was talking about this one, as I think depending on the scheme we take this might change significantly. Just a nit, you can ignore it.
It would depend on if userspace is doing a lot of unpreserving as well... I'll see what I can do in v5.
Quoted 14 lines
Quoted 8 lines
Quoted 7 lines
include/linux/pci.h void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); · line 2894
Quoted 5 lines
include/linux/pci.h +4
-0+static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) +{ +return dev->liveupdate_outgoing; +}Is this expected to be called under the outgoing lock?
Quoted 5 lines
For now this API is only used during shutdown, at which point userspace should have already been stopped so drivers should not be changing the preservation status of an outgoing device. So I don't think this needs to be under the outgoing lock, but it would be nice to have some more explicit synchronization.
Quoted 3 lines
Ok that makes sense. I have similar cases in my series, but maybe we can add kdoc regarding these stating in which context this is expected to be used?
Yes will do. I'll add some documentation and also restrict it to avoid misuse (move to internal pci.h, return a bool instead of pointer, and use READ_ONCE()).
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackQuoted 37 lines · David Matlack
drivers/pci/liveupdate.c +37
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++;
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+ + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ;
Since it is executing under a mutex, and we already failed
'if (ser->nr_devices == ser->max_nr_devices) check above, will we ever reach here and return -ENOSPC?
include/linux/kho/abi/pci.h line 26
Quoted 10 lines
include/linux/kho/abi/pci.h +1
-1@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"
Just curious, why did we change the version here? It's not like just previous patch is working enough to perform a live update. As the config is experimental, can't we just keep it PCI-v1 for the whole series?
Quoted 1 line
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 45 lines · Vipin Sharma
Quoted 43 lines · David Matlack
drivers/pci/liveupdate.c +43
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser;
Quoted 8 lines
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+return 0 ; + } + +return -ENOSPC ;Since it is executing under a mutex, and we already failed
'if (ser->nr_devices==ser->max_nr_devices) check above, will we ever reach here and return-ENOSPC?
Yeah I wouldn't expect to ever reach here.
Quoted 8 lines
Quoted 8 lines
include/linux/kho/abi/pci.h +0
-0@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */
Quoted 4 lines
include/linux/kho/abi/pci.h line 26
Quoted 2 lines
include/linux/kho/abi/pci.h +1
-1-#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"Just curious, why did we change the version here?
Because a field in struct pci_dev_ser changed.
Quoted 3 lines
It's not like just
previous patch is working enough to perform a live update. As the config is experimental, can't we just keep it PCI-v1 for the whole series?
What is the benefit of keeping "pci-v1"?
I think it makes sense to follow the rule we set which is to update the compatibility string in any commit that changes the ABI.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 55 lines · David Matlack
Quoted 45 lines · Vipin Sharma
Quoted 43 lines · David Matlack
drivers/pci/liveupdate.c +43
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int i, ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser;Quoted 8 lines
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+return 0 ; + } + +return -ENOSPC ;Since it is executing under a mutex, and we already failed
'if (ser->nr_devices==ser->max_nr_devices) check above, will we ever reach here and return-ENOSPC?
Quoted 1 line
Yeah I wouldn't expect to ever reach here.
Will you be removing it or want to keep it just in case scenario?
Quoted 14 lines
Quoted 9 lines
Quoted 9 lines
include/linux/kho/abi/pci.h +0
-0@@ -23,19 +23,20 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ Quoted 4 lines
include/linux/kho/abi/pci.h line 26
Quoted 2 lines
include/linux/kho/abi/pci.h +1
-1-#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"Just curious, why did we change the version here?
Quoted 8 lines
Because a field in struct
pci_dev_serchanged.Quoted 3 lines
It's not like just
previous patch is working enough to perform a live update. As the config is experimental, can't we just keep it PCI-v1 for the whole series?What is the benefit of keeping "pci-v1"?
I don't see any benefit in keeping v1 or changing to v2 as well.
My reasoning is that before this series is merged, there is no real need for versioning here. This is first series which is introducing PCI liveupdate. It is not gonna be that someone has merged patch 1 only, run its kernel and then kexec to next kernel which has patch 2.
Quoted 2 lines
I think it makes sense to follow the rule we set which is to update the compatibility string in any commit that changes the ABI.
Okay, this is also fine.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 39 lines · Vipin Sharma
Quoted 38 lines · David Matlack
Quoted 36 lines · Vipin Sharma
Quoted 20 lines · David Matlack
drivers/pci/liveupdate.c +19
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++;drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+ + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ;Since it is executing under a mutex, and we already failed
'if (ser->nr_devices==ser->max_nr_devices) check above, will we ever reach here and return-ENOSPC?
Quoted 3 lines
Quoted 1 line
Yeah I wouldn't expect to ever reach here.
Will you be removing it or want to keep it just in case scenario?
I'm not sure how I would remove it. The code doesn't not compile without a return.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 40 lines · David Matlack
Quoted 39 lines · Vipin Sharma
Quoted 38 lines · David Matlack
Quoted 36 lines · Vipin Sharma
Quoted 20 lines · David Matlack
drivers/pci/liveupdate.c +19
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++;drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+ + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ;Since it is executing under a mutex, and we already failed
'if (ser->nr_devices==ser->max_nr_devices) check above, will we ever reach here and return-ENOSPC?
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Yeah I wouldn't expect to ever reach here.
Will you be removing it or want to keep it just in case scenario?
I'm not sure how I would remove it. The code doesn't not compile without a return.
Oh, I meant, inside loop a break and outside just return 0, that way it won't be a dead code.
Re: [PATCH v4 02/11] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 44 lines · Vipin Sharma
Quoted 42 lines · David Matlack
Quoted 41 lines · Vipin Sharma
Quoted 39 lines · David Matlack
Quoted 28 lines · Vipin Sharma
Quoted 26 lines · David Matlack
drivers/pci/liveupdate.c +25
-0+int pci_liveupdate_preserve (struct pci_dev *dev) +{ +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate_outgoing = dev_ser;Quoted 8 lines
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 195
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+return 0 ; + } + +return -ENOSPC ;Since it is executing under a mutex, and we already failed
'if (ser->nr_devices==ser->max_nr_devices) check above, will we ever reach here and return-ENOSPC?Yeah I wouldn't expect to ever reach here.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Will you be removing it or want to keep it just in case scenario?
I'm not sure how I would remove it. The code doesn't not compile without a return.
Oh, I meant, inside loop a break and outside just return 0, that way it won't be a dead code.
That would hide bugs if the refcounts in the array got messed up. How about:
/* This should never be reached. */
return WARN_ON_ONCE(-ENOSPC);
PATCH v4 3/11 PCI: liveupdate: Track incoming preserved PCI devices
In reply to David MatlackDuring PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add pci_liveupdate_setup_device() which is called during device setup to fetch the serialized state (struct pci_ser) from the Live Update Orchestrator. The first time this happens, pci_flb_retrieve() will run and convert the array of pci_dev_ser structs into an xarray so that it can be looked up efficiently.
If a device is found in the xarray, the PCI core stores a pointer to its state in dev->liveupdate_incoming and holds a reference to the incoming FLB until pci_liveupdate_finish() is called by the driver.
This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
--- drivers/pci/liveupdate.c | 189 ++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.h | 13 +++ drivers/pci/probe.c | 4 + include/linux/pci.h | 16 ++++ 4 files changed, 218 insertions(+), 4 deletions(-)
drivers/pci/liveupdate.c +185 -4
@@ -56,6 +56,20 @@* This allows the PCI core to keep it's FLB data (struct pci_ser) up to date * with the list of **outgoing** preserved devices for the next kernel. * +* After kexec, whenever a device is enumerated, the PCI core will check if it +* is an **incoming** preserved device (i.e. preserved by the previous kernel) +* by checking the incoming FLB data (struct pci_ser). +* +* Drivers must notify the PCI core when an **incoming** device is done +* participating in the incoming Live Update with the following API: +* +* * ``pci_liveupdate_finish(pci_dev)`` +* +* The PCI core does not enforce any ordering of ``pci_liveupdate_finish()`` and +* ``pci_liveupdate_preserve()``. i.e. A PCI device can be **outgoing** +* (preserved for next kernel) and **incoming** (preserved by previous kernel) +* at the same time. +* * Restrictions * ============ *
@@ -67,7 +81,6 @@#define pr_fmt (fmt) "PCI: liveupdate: " fmt -#include <linux/bsearch.h> #include <linux/io.h> #include <linux/kexec_handover.h> #include <linux/kho/abi/pci.h>
@@ -75,10 +88,24 @@#include <linux/mutex.h> #include <linux/mm.h> #include <linux/pci.h> -#include <linux/sort.h> + +#include "pci.h" static DEFINE_MUTEX (pci_flb_outgoing_lock); +struct pci_flb_incoming { +/* The pci_ser struct passed by the previous kernel. */ +struct pci_ser *ser; + +/* xarray used to quickly find a device in ser->devices[] */ +struct xarray xa; +}; + +static unsigned long pci_ser_xa_key (unsigned long domain,unsigned long bdf) +{ +return domain <<16 | bdf; +} +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_dev *dev =NULL ;
@@ -124,13 +151,44 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)static int pci_flb_retrieve (struct liveupdate_flb_op_args *args) { - args->obj =phys_to_virt (args->data); +struct pci_flb_incoming *incoming; +int i, ret; + + incoming =kmalloc (sizeof (*incoming),GFP_KERNEL ); +if (!incoming) +return -ENOMEM ; + + incoming->ser =phys_to_virt (args->data); + +xa_init (&incoming->xa); + +for (i =0 ; i < incoming->ser->max_nr_devices; i++) { +struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; +unsigned long key; + +if (!dev_ser->refcount) +continue ; + + key =pci_ser_xa_key (dev_ser->domain, dev_ser->bdf); + ret =xa_err (xa_store (&incoming->xa, key, dev_ser,GFP_KERNEL )); +if (ret) { +xa_destroy (&incoming->xa); +kfree (incoming); +return ret; + } + } + + args->obj = incoming;return 0 ; }static void pci_flb_finish (struct liveupdate_flb_op_args *args) { -kho_restore_free (args->obj); +struct pci_flb_incoming *incoming = args->obj; + +xa_destroy (&incoming->xa); +kho_restore_free (incoming->ser); +kfree (incoming); }static struct liveupdate_flb_ops pci_liveupdate_flb_ops = {
@@ -225,6 +283,129 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +static struct xarray *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming; +int ret; + + ret =liveupdate_flb_get_incoming (&pci_liveupdate_flb, (void **)&incoming); + +/* Live Update is not enabled. */ +if (ret == -EOPNOTSUPP ) +return NULL ; + +/* Live Update is enabled, but there is no incoming FLB data. */ +if (ret == -ENODATA ) +return NULL ; + +/* +* Live Update is enabled and there is incoming FLB data, but none of it +* matches pci_liveupdate_flb.compatible. +* +* This could mean that no PCI FLB data was passed by the previous +* kernel, but it could also mean the previous kernel used a different +* compatibility string (i.e. a different ABI). +*/ +if (ret == -ENOENT ) { +pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible); +return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved. +*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" ); +return NULL ; + } + +return &incoming->xa; +} + +static void pci_liveupdate_flb_put_incoming (void ) +{ +liveupdate_flb_put_incoming (&pci_liveupdate_flb); +} + +void pci_liveupdate_setup_device (struct pci_dev *dev) +{ +struct pci_dev_ser *dev_ser; +struct xarray *xa; +unsigned long key; + + xa =pci_liveupdate_flb_get_incoming (); +if (!xa) +return ; + + key =pci_ser_xa_key (pci_domain_nr (dev->bus),pci_dev_id (dev)); + dev_ser =xa_load (xa, key); + +/* This device was not preserved across Live Update */ +if (!dev_ser) { +pci_liveupdate_flb_put_incoming (); +return ; + } + +/* +* This device was preserved, but has already been probed and gone +* through pci_liveupdate_finish(). This can happen if PCI core probes +* the same device multiple times, e.g. due to hotplug. +*/ +if (!dev_ser->refcount) { +pci_liveupdate_flb_put_incoming (); +return ; + } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev_ser does not get freed while it is in use. +*/ + dev->liveupdate_incoming = dev_ser; +} + +void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +/* +* Drop the FLB reference acquired in pci_liveupdate_setup_device() if +* the device is being cleaned up before pci_liveupdate_finish(), e.g. +* due to allocation failure during setup. +* +* Do not drop dev->liveupdate_incoming->refcount since this device has +* not gone through pci_liveupdate_finish() and thus is still an +* incoming preserved device. +* +* Note: This cannot race with pci_liveupdate_finish() since it is only +* called in cleanup paths when there are no users of the pci_dev. +*/ +if (dev->liveupdate_incoming) +pci_liveupdate_flb_put_incoming (); +} + +void pci_liveupdate_finish (struct pci_dev *dev) +{ +if (!dev->liveupdate_incoming) { +pci_warn (dev,"Cannot finish preserving an unpreserved device\n" ); +return ; + } + +pci_info (dev,"Device is finished participating in Live Update\n" ); + +/* +* Drop the refcount so this device does not get treated as an incoming +* device again, e.g. in case pci_liveupdate_setup_device() gets called +* again becase the device is hot-plugged. +*/ + dev->liveupdate_incoming->refcount =0 ; + dev->liveupdate_incoming =NULL ; + +/* Drop this device's reference on the incoming FLB. */ +pci_liveupdate_flb_put_incoming (); +} +EXPORT_SYMBOL_GPL (pci_liveupdate_finish); +int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {pr_debug ("Registering file handler \"%s\"\n" , fh->compatible);
drivers/pci/pci.h +13 -0
@@ -1439,4 +1439,17 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde (PCI_CONF1_ADDRESS (bus, dev, func, reg) | \ PCI_CONF1_EXT_REG(reg)) +#ifdef CONFIG_PCI_LIVEUPDATE +void pci_liveupdate_setup_device (struct pci_dev *dev); +void pci_liveupdate_cleanup_device (struct pci_dev *dev); +#else +static inline void pci_liveupdate_setup_device (struct pci_dev *dev) +{ +} + +static inline void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +} +#endif +#endif /* DRIVERS_PCI_H */
drivers/pci/probe.c +4 -0
@@ -2069,6 +2069,8 @@ int pci_setup_device(struct pci_dev *dev)if (pci_early_dump)early_dump_pci_device (dev); +pci_liveupdate_setup_device (dev); +/* Need to have dev->class ready */ dev->cfg_size =pci_cfg_space_size (dev);
@@ -2192,6 +2194,7 @@ int pci_setup_device(struct pci_dev *dev)default :/* unknown header */ pci_err (dev,"unknown header type %02x, ignoring device\n" , dev->hdr_type); +pci_liveupdate_cleanup_device (dev);pci_release_of_node (dev);return -EIO ;
@@ -2490,6 +2493,7 @@ static void pci_release_dev(struct device *dev) pci_dev =to_pci_dev (dev);pci_release_capabilities (pci_dev); +pci_liveupdate_cleanup_device (pci_dev);pci_release_of_node (pci_dev);pcibios_release_device (pci_dev);pci_bus_put (pci_dev->bus);
include/linux/pci.h +16 -0
@@ -597,6 +597,7 @@ struct pci_dev {#endif #ifdef CONFIG_PCI_LIVEUPDATE struct pci_dev_ser *liveupdate_outgoing;/* State preserved for next kernel */ +struct pci_dev_ser *liveupdate_incoming;/* State preserved by previous kernel */ #endif };
@@ -2887,11 +2888,17 @@ void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh);int pci_liveupdate_preserve (struct pci_dev *dev);void pci_liveupdate_unpreserve (struct pci_dev *dev); +void pci_liveupdate_finish (struct pci_dev *dev);static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) {return dev->liveupdate_outgoing; } + +static inline struct pci_dev_ser *pci_liveupdate_incoming (struct pci_dev *dev) +{ +return dev->liveupdate_incoming; +}#else static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {
@@ -2911,10 +2918,19 @@ static inline void pci_liveupdate_unpreserve(struct pci_dev *dev) { } +static inline void pci_liveupdate_finish (struct pci_dev *dev) +{ +} +static inline struct pci_dev_ser *pci_liveupdate_outgoing (struct pci_dev *dev) {return NULL ; } + +static inline struct pci_dev_ser *pci_liveupdate_incoming (struct pci_dev *dev) +{ +return NULL ; +}#endif #endif /* LINUX_PCI_H */
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 03/11] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 10 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
+++
b/drivers/pci/liveupdate.cdrivers/pci/liveupdate.c +3
-0+void pci_liveupdate_finish (struct pci_dev *dev) +{ +if (!dev->liveupdate_incoming) {
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 399
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+pci_warn (dev,"Cannot finish preserving an unpreserved device\n" ); +return ; + } + +pci_info (dev,"Device is finished participating in Live Update\n" ); + +/* +* Drop the refcount so this device does not get treated as an incoming +* device again, e.g. in case pci_liveupdate_setup_device() gets called +* again becase the device is hot-plugged.
s/becase/because/
PATCH v4 4/11 PCI: liveupdate: Document driver binding responsibilities
In reply to David MatlackDocument how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
--- drivers/pci/liveupdate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/pci/liveupdate.c +16 -0
@@ -77,6 +77,22 @@* preserved. These may be relaxed in the future: * * * The device cannot be a Virtual Function (VF). +* +* Driver Binding +* ============== +* +* In the outgoing kernel, it is the driver's responsibility to ensure that it +* does not release a device between pci_liveupdate_preserve() and +* pci_liveupdate_unpreserve(). +* +* In the incoming kernel, it is the driver's responsibility to ensure that it +* does not release a preserved device between probe() and +* pci_liveupdate_finish(). +* +* It is the user's responsibility to ensure that incoming preserved devices are +* bound to the correct driver. i.e. The PCI core does not protect against a +* device getting preserved by driver A in the outgoing kernel and then getting +* bound to driver B in the incoming kernel. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
PATCH v4 5/11 PCI: liveupdate: Inherit bus numbers during Live Update
In reply to David MatlackInherit bus numbers from the previous kernel during a Live Update when one or more PCI devices are being preserved.
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep things simple, inherit the secondary and subordinate bus numbers on all bridges if any PCI devices were preserved (i.e. even bridges without any downstream endpoints that were preserved). This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is enumerated with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it. This is a safety measure to prevent topology conflicts.
Require that CONFIG_CARDBUS is not enabled to enable CONFIG_PCI_LIVEUPDATE since inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.
--- .../admin-guide/kernel-parameters.txt | 6 +++- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 28 +++++++++++++++++++ drivers/pci/probe.c | 21 +++++++++++--- include/linux/pci.h | 1 + 5 files changed, 52 insertions(+), 6 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +5 -1
@@ -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
drivers/pci/Kconfig +1 -1
@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support (EXPERIMENTAL)" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && !CARDBUS help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,
drivers/pci/liveupdate.c +28 -0
@@ -93,6 +93,19 @@* bound to the correct driver. i.e. The PCI core does not protect against a * device getting preserved by driver A in the outgoing kernel and then getting * bound to driver B in the incoming kernel. +* +* BDF Stability +* ============= +* +* The PCI core guarantees that incoming preserved devices can be identified by +* the same bus, device, and function numbers as prior to kexec. To accomplish +* this, the PCI core always inherits the secondary and subordinate bus numbers +* assigned to bridges during enumeration, rather than assigning new ones (the +* PCI core assumes that the previous kernel established a sane topology). +* +* If a misconfigured or unconfigured bridge is encountered during enumeration +* while there are incoming preserved devices, it's secondary and subordinate +* bus numbers will be cleared and devices below it will not be enumerated. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -354,6 +367,21 @@ void pci_liveupdate_setup_device(struct pci_dev *dev)if (!xa)return ; +/* +* During a Live Update, preserved devices are allowed to continue +* performing memory transactions. The kernel must not change the fabric +* topology, including bus numbers, since that would require disabling +* and flushing any memory transactions first. +* +* To keep things simple, inherit the secondary and subordinate bus +* numbers on _all_ bridges if _any_ PCI devices were preserved (i.e. +* even bridges without any downstream endpoints that were preserved). +* This avoids accidentally assigning a bridge a new window that +* overlaps with a preserved device that is downstream of a different +* bridge. +*/ + dev->liveupdate_inherit_buses = true; + key =pci_ser_xa_key (pci_domain_nr (dev->bus),pci_dev_id (dev)); dev_ser =xa_load (xa, key);
drivers/pci/probe.c +17 -4
@@ -1374,6 +1374,14 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)return true; } +static bool pci_should_assign_new_buses (struct pci_dev *dev) +{ +if (dev->liveupdate_inherit_buses) +return false; + +return pcibios_assign_all_busses (); +} +/* * pci_scan_bridge_extend() - Scan buses behind a bridge * @bus: Parent bus the bridge is on
@@ -1401,6 +1409,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_new_buses = pci_should_assign_new_buses(dev);struct pci_bus *child;u32 buses;u16 bctl;
@@ -1453,8 +1462,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_new_buses && !broken) {unsigned int cmax, buses;/*
@@ -1496,8 +1504,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_new_buses || broken)/* * Temporarily disable forwarding of the * configuration cycles on all bridges in
@@ -1511,6 +1518,12 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } +if (dev->liveupdate_inherit_buses) { +pci_err (dev,"Cannot reconfigure bridge during Live Update!\n" ); +pci_err (dev,"Downstream devices will not be enumerated!\n" ); + goto out; + } +/* Clear errors */ pci_write_config_word (dev,PCI_STATUS ,0xffff );
include/linux/pci.h +1 -0
@@ -511,6 +511,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ + unsigned int liveupdate_inherit_buses:1; /* Inherit bus numbers due to Live Update */pci_dev_flags_t dev_flags;atomic_t enable_cnt;/* pci_enable_device has been called */
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
Hi David,
Quoted 121 lines · On Thu, 23 Apr 2026 21:23:09 +0000 David Matlack <[email protected]> wrote:
Inherit bus numbers from the previous kernel during a Live Update when one or more PCI devices are being preserved.
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep things simple, inherit the secondary and subordinate bus numbers on all bridges if any PCI devices were preserved (i.e. even bridges without any downstream endpoints that were preserved). This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is enumerated with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>--- .../admin-guide/kernel-parameters.txt | 6 +++- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 28 +++++++++++++++++++ drivers/pci/probe.c | 21 +++++++++++--- include/linux/pci.h | 1 + 5 files changed, 52 insertions(+), 6 deletions(-)(quoted diff) +0
-0
b/Documentation/admin-guide/kernel-parameters.txtindexcf3807641d89..f412a4b77fb7100644 ---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.Documentation/admin-guide/kernel-parameters.txt +1
-1assign-busses [X86] Always assign all PCI bus numbers ourselves, overriding - whatever the firmware may have done. + whatever the firmware may have done.Ignored
(quoted diff) +1
-0+ during a Live Update, where thekernel must
(quoted diff) +1
-0+ inherit the PCI topology (includingbus numbers)
Documentation/admin-guide/kernel-parameters.txt +2
-0+ to avoid interrupting ongoing memory + transactions of preserved devices. usepirqmask [X86] Honor the possible IRQ maskstored 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 index08398cbe970c..6ef457ff9d08100644drivers/pci/Kconfig +1
-1@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support (EXPERIMENTAL)" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && !CARDBUS help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,drivers/pci/liveupdate.c +0
-0@@ -93,6 +93,19 @@* bound to the correct driver. i.e. The PCI core does not protect against a
* device getting preserved by driver A in the outgoing kernel and
then getting
* bound to driver B in the incoming kernel.
+ *
+ * BDF Stability
+ * =============
+ *
+ * The PCI core guarantees that incoming preserved devices can be identified by
+ * the same bus, device, and function numbers as prior to kexec. To accomplish
+ * this, the PCI core always inherits the secondary and subordinate bus numbers
+ * assigned to bridges during enumeration, rather than assigning new ones (the
+ * PCI core assumes that the previous kernel established a sane topology).
+ *
+ * If a misconfigured or unconfigured bridge is encountered during enumeration
+ * while there are incoming preserved devices, it's secondary and subordinate
+ * bus numbers will be cleared and devices below it will not be enumerated. */#define
pr_fmt(fmt)"PCI: liveupdate: " fmtdrivers/pci/liveupdate.c +2
-0@@ -354,6 +367,21 @@ void pci_liveupdate_setup_device(struct pci_dev *dev) if (!xa)return ; +/* +* During a Live Update, preserved devices are allowed to continue
drivers/pci/liveupdate.c +1
-0+* performing memory transactions. The kernel must not change the fabric
drivers/pci/liveupdate.c +1
-0+* topology, including bus numbers, since that would require disabling
drivers/pci/liveupdate.c +3
-0+* and flushing any memory transactions first. +* +* To keep things simple, inherit the secondary and subordinate bus
drivers/pci/liveupdate.c +1
-0+* numbers on _all_ bridges if _any_ PCI devices were preserved (i.e.
drivers/pci/liveupdate.c +1
-0+* even bridges without any downstream endpoints that were preserved).
drivers/pci/liveupdate.c +1
-0+* This avoids accidentally assigning a bridge a new window that
drivers/pci/liveupdate.c +1
-0+* overlaps with a preserved device that is downstream of a different
drivers/pci/liveupdate.c void pci_liveupdate_setup_device(struct pci_dev *dev) · line 384
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+* bridge. +*/ + dev->liveupdate_inherit_buses = true; +
This flag never gets cleared after the incoming kernel boot up, what if the user does a manual rescan via sysfs? i.e.
# echo 1 > /sys/bus/pci/rescan
pcibios_assign_all_busses() will never gets called for this device, and
may hit this
if (dev->liveupdate_inherit_buses) {
pci_err(dev, "Cannot reconfigure bridge during
Live Update!\n");So, maybe clear it in pci_liveupdate_finish()?
Quoted 80 lines
key = pci_ser_xa_key(pci_domain_nr(dev->bus),
pci_dev_id(dev));dev_ser=xa_load(xa, key);drivers/pci/probe.c +8
-0@@ -1374,6 +1374,14 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) return true; } +static bool pci_should_assign_new_buses (struct pci_dev *dev) +{ +if (dev->liveupdate_inherit_buses) +return false; + +return pcibios_assign_all_busses (); +} +/* * pci_scan_bridge_extend() - Scan buses behind a bridge * @bus: Parent bus the bridge is on @@ -1401,6 +1409,7 @@ static int pci_scan_bridge_extend(struct
pci_bus*bus, structpci_dev*dev, int max, unsigned intavailable_buses, int pass)
{drivers/pci/probe.c +1
-0+ const bool assign_new_buses =
pci_should_assign_new_buses(dev); structpci_bus*child;drivers/pci/probe.c +2
-4u32 buses;u16 bctl;@@ -1453,8 +1462,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_new_buses && !broken) {unsigned int cmax, buses;/* @@ -1496,8 +1504,7 @@ static int pci_scan_bridge_extend(structpci_bus *bus, struct pci_dev *dev, * do in the second pass. */ if (!pass) { -if (pcibios_assign_all_busses () || broken) - +if (assign_new_buses || broken)/* * Temporarily disable forwarding of the
* configuration cycles on all
bridges in @@ -1511,6 +1518,12 @@ static int pci_scan_bridge_extend(structpci_bus*bus, structpci_dev*dev, goto out; }drivers/pci/probe.c +2
-0+if (dev->liveupdate_inherit_buses) { + pci_err(dev, "Cannot reconfigure bridgeduring Live Update!\n");
drivers/pci/probe.c +1
-0+ pci_err(dev, "Downstream devices will not beenumerated!\n");
drivers/pci/probe.c +3
-0+ goto out; + } +/* Clear errors */ pci_write_config_word (dev,PCI_STATUS ,0xffff );include/linux/pci.h +0
-0@@ -511,6 +511,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BARdisable broken */ unsigned int rom_attr_enabled:1; /*
Display of ROM attribute enabled? */ unsigned int
non_mappable_bars:1; /* BARs can't be mapped to user-space */include/linux/pci.h +1
-0+ unsigned int liveupdate_inherit_buses:1; /* Inheritbus numbers due to Live Update */
pci_dev_flags_tdev_flags;
atomic_tenable_cnt; /*pci_enable_devicehas
been called */
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
Quoted 45 lines · Jacob Pan
Quoted 36 lines · On Thu, 23 Apr 2026 21:23:09 +0000 David Matlack <[email protected]> wrote:
To keep things simple, inherit the secondary and subordinate bus numbers on all bridges if any PCI devices were preserved (i.e. even bridges without any downstream endpoints that were preserved). This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is enumerated with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>(quoted diff) +2
-0+ /* + * During a Live Update, preserved devices are allowed tocontinue
(quoted diff) +1
-0+ * performing memory transactions. The kernel must notchange the fabric
(quoted diff) +1
-0+ * topology, including bus numbers, since that would requiredisabling
drivers/pci/liveupdate.c +3
-0+* and flushing any memory transactions first. +* +* To keep things simple, inherit the secondary and subordinate bus
(quoted diff) +1
-0+ * numbers on _all_ bridges if _any_ PCI devices werepreserved (i.e.
(quoted diff) +1
-0+ * even bridges without any downstream endpoints that werepreserved).
(quoted diff) +1
-0+ * This avoids accidentally assigning a bridge a new windowthat
(quoted diff) +1
-0+ * overlaps with a preserved device that is downstream of adifferent
drivers/pci/liveupdate.c void pci_liveupdate_setup_device(struct pci_dev *dev) · line 384
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+* bridge. +*/ + dev->liveupdate_inherit_buses = true; +This flag never gets cleared after the incoming kernel boot up, what if the user does a manual rescan via sysfs? i.e.
Quoted 8 lines
# echo 1 > /sys/bus/pci/rescan pcibios_assign_all_busses() will never gets called for this device, and may hit this if (dev->liveupdate_inherit_buses) { pci_err(dev, "Cannot reconfigure bridge during Live Update!\n");So, maybe clear it in
pci_liveupdate_finish()?
I think we can allo wa rescan to assign new bus numbers once all devices go through pci_liveupdate_finish() by clearing dev->liveupdate_inherit_buses on all devices in pci_flb_finish(). We would need to hold pci_rescan_remove_lock to avoid this racing with such a rescan.
Now that you bring up /sys/bus/pci/rescan... I think we also need to set dev->liveupdate_inherit_buses in the outgoing kernel, to avoid bus numbers changing on outgoing preserved devices. pci_flb_preserve() should take pci_rescan_remove_lock and set dev->liveupdate_inherit_buses on all devices, and pci_flb_unpreserve() should do the opposite.
If we did all then then /sys/bus/pci/rescan can work like normal as long as no devices are preserved (incoming or outgoing). If any devices are preserved then dev->liveupdate_inherit_buses gets set to prevent bus numbers from changing during a possible rescan.
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
Quoted 67 lines · David Matlack
Quoted 45 lines · Jacob Pan
Quoted 36 lines · On Thu, 23 Apr 2026 21:23:09 +0000 David Matlack <[email protected]> wrote:
To keep things simple, inherit the secondary and subordinate bus numbers on all bridges if any PCI devices were preserved (i.e. even bridges without any downstream endpoints that were preserved). This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is enumerated with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>(quoted diff) +2
-0+ /* + * During a Live Update, preserved devices are allowed tocontinue
(quoted diff) +1
-0+ * performing memory transactions. The kernel must notchange the fabric
(quoted diff) +1
-0+ * topology, including bus numbers, since that would requiredisabling
(quoted diff) +3
-0+ * and flushing any memory transactions first. + * + * To keep things simple, inherit the secondary andsubordinate bus
(quoted diff) +1
-0+ * numbers on _all_ bridges if _any_ PCI devices werepreserved (i.e.
(quoted diff) +1
-0+ * even bridges without any downstream endpoints that werepreserved).
(quoted diff) +1
-0+ * This avoids accidentally assigning a bridge a new windowthat
(quoted diff) +1
-0+ * overlaps with a preserved device that is downstream of adifferent
Review
Quoted 4 lines
(quoted diff) +4
-0+ * bridge. + */ + dev->liveupdate_inherit_buses = true; +This flag never gets cleared after the incoming kernel boot up, what if the user does a manual rescan via sysfs? i.e.
Quoted 8 lines
# echo 1 > /sys/bus/pci/rescan pcibios_assign_all_busses() will never gets called for this device, and may hit this if (dev->liveupdate_inherit_buses) { pci_err(dev, "Cannot reconfigure bridge during Live Update!\n");So, maybe clear it in
pci_liveupdate_finish()?I think we can allo wa rescan to assign new bus numbers once all devices go through
pci_liveupdate_finish()by clearingdev->liveupdate_inherit_buseson all devices inpci_flb_finish(). We would need to holdpci_rescan_remove_lockto avoid this racing with such a rescan.Now that you bring up
/sys/bus/pci/rescan... I think we also need to setdev->liveupdate_inherit_busesin the outgoing kernel, to avoid bus numbers changing on outgoing preserved devices.pci_flb_preserve()should takepci_rescan_remove_lockand setdev->liveupdate_inherit_buseson all devices, andpci_flb_unpreserve()should do the opposite.
Quoted 4 lines
If we did all then then
/sys/bus/pci/rescancan work like normal as long as no devices are preserved (incoming or outgoing). If any devices are preserved thendev->liveupdate_inherit_busesgets set to prevent bus numbers from changing during a possible rescan.
Something like this? This is a diff applied on top of this commit.
drivers/pci/liveupdate.c +45 -15
@@ -120,6 +120,20 @@#include "pci.h" +/* +* During a Live Update, preserved devices are allowed to continue performing +* memory transactions. The kernel must not change the fabric topology, +* including bus numbers, since that would require disabling and flushing any +* memory transactions first. +* +* To keep things simple, inherit the secondary and subordinate bus numbers on +* _all_ bridges if _any_ PCI devices are preserved (i.e. even bridges without +* any downstream endpoints that were preserved). This avoids accidentally +* assigning a bridge a new window that overlaps with a preserved device that is +* downstream of a different bridge. +*/ +static atomic_t inherit_buses; +struct pci_flb_outgoing {/* The pci_ser struct to be passed to the next kernel */ struct pci_ser *ser;
@@ -141,6 +155,29 @@ static unsigned long pci_ser_xa_key(unsigned long domain, unsigned long bdf)return domain <<16 | bdf; } +bool pci_liveupdate_inherit_buses (void ) +{ +return atomic_read (&inherit_buses); +} + +static void pci_set_liveupdate_inherit_buses (bool enable) +{ +/* Ensure updates to inherit_buses do not race with rescans */ +pci_lock_rescan_remove (); + +/* +* Increment/decrement instead of setting directly to true/false so that +* pci_liveupdate_inherit_buses() returns true if any device is outgoing +* preserved or incoming preserved. +*/ +if (enable) +atomic_inc (&inherit_buses); +else +atomic_dec (&inherit_buses); + +pci_unlock_rescan_remove (); +} +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_flb_outgoing *outgoing;
@@ -180,6 +217,8 @@ static int pci_flb_preserve(struct liveupdate_flb_op_args *args) args->obj = outgoing; args->data =virt_to_phys (outgoing->ser); + +pci_set_liveupdate_inherit_buses (true);return 0 ; }
@@ -187,6 +226,8 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) {struct pci_flb_outgoing *outgoing = args->obj; +pci_set_liveupdate_inherit_buses (false); +pr_debug ("Unpreserving struct pci_ser\n" );WARN_ON_ONCE (outgoing->ser->nr_devices);kho_unpreserve_free (outgoing->ser);
@@ -223,6 +264,8 @@ static int pci_flb_retrieve(struct liveupdate_flb_op_args *args) } args->obj = incoming; + +pci_set_liveupdate_inherit_buses (true);return 0 ; }
@@ -230,6 +273,8 @@ static void pci_flb_finish(struct liveupdate_flb_op_args *args) {struct pci_flb_incoming *incoming = args->obj; +pci_set_liveupdate_inherit_buses (false); +xa_destroy (&incoming->xa);kho_restore_free (incoming->ser);kfree (incoming);
@@ -385,21 +430,6 @@ void pci_liveupdate_setup_device(struct pci_dev *dev)if (!xa)return ; -/* -* During a Live Update, preserved devices are allowed to continue -* performing memory transactions. The kernel must not change the fabric -* topology, including bus numbers, since that would require disabling -* and flushing any memory transactions first. -* -* To keep things simple, inherit the secondary and subordinate bus -* numbers on _all_ bridges if _any_ PCI devices were preserved (i.e. -* even bridges without any downstream endpoints that were preserved). -* This avoids accidentally assigning a bridge a new window that -* overlaps with a preserved device that is downstream of a different -* bridge. -*/ - dev->liveupdate_inherit_buses = true; - key =pci_ser_xa_key (pci_domain_nr (dev->bus),pci_dev_id (dev)); dev_ser =xa_load (xa, key);
drivers/pci/pci.h +6 -0
@@ -1442,6 +1442,7 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde#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_inherit_buses (void );#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {
@@ -1450,6 +1451,11 @@ 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_inherit_buses (void ) +{ +return false; +}#endif #endif /* DRIVERS_PCI_H */
drivers/pci/probe.c +4 -4
@@ -1374,9 +1374,9 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)return true; } -static bool pci_should_assign_new_buses (struct pci_dev *dev) +static bool pci_should_assign_new_buses (void ) { -if (dev->liveupdate_inherit_buses) +if (pci_liveupdate_inherit_buses ())return false;return pcibios_assign_all_busses ();
@@ -1409,7 +1409,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_new_buses = pci_should_assign_new_buses(dev); + const bool assign_new_buses = pci_should_assign_new_buses();struct pci_bus *child;u32 buses;u16 bctl;
@@ -1518,7 +1518,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } -if (dev->liveupdate_inherit_buses) { +if (pci_liveupdate_inherit_buses ()) {pci_err (dev,"Cannot reconfigure bridge during Live Update!\n" );pci_err (dev,"Downstream devices will not be enumerated!\n" ); goto out;
include/linux/pci.h +0 -1
@@ -511,7 +511,6 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ - unsigned int liveupdate_inherit_buses:1; /* Inherit bus numbers due to Live Update */pci_dev_flags_t dev_flags;atomic_t enable_cnt;/* pci_enable_device has been called */
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
Hi David,
Quoted 71 lines · On Mon, 27 Apr 2026 21:16:12 +0000 David Matlack <[email protected]> wrote:
Quoted 70 lines · David Matlack
Quoted 47 lines · Jacob Pan
Quoted 38 lines · On Thu, 23 Apr 2026 21:23:09 +0000 David Matlack <[email protected]> wrote:
To keep things simple, inherit the secondary and subordinate bus numbers on all bridges if any PCI devices were preserved (i.e. even bridges without any downstream endpoints that were preserved). This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is enumerated with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>(quoted diff) +2
-0+ /* + * During a Live Update, preserved devices are allowedto continue
(quoted diff) +1
-0+ * performing memory transactions. The kernel must notchange the fabric
(quoted diff) +1
-0+ * topology, including bus numbers, since that wouldrequire disabling
(quoted diff) +3
-0+ * and flushing any memory transactions first. + * + * To keep things simple, inherit the secondary andsubordinate bus
(quoted diff) +1
-0+ * numbers on _all_ bridges if _any_ PCI devices werepreserved (i.e.
(quoted diff) +1
-0+ * even bridges without any downstream endpoints thatwere preserved).
(quoted diff) +1
-0+ * This avoids accidentally assigning a bridge a newwindow that
(quoted diff) +1
-0+ * overlaps with a preserved device that is downstreamof a different
drivers/pci/liveupdate.c line 136
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+* bridge. +*/ + dev->liveupdate_inherit_buses = true; +This flag never gets cleared after the incoming kernel boot up, what if the user does a manual rescan via sysfs? i.e.
Quoted 8 lines
# echo 1 > /sys/bus/pci/rescan pcibios_assign_all_busses() will never gets called for this device, and may hit this if (dev->liveupdate_inherit_buses) { pci_err(dev, "Cannot reconfigure bridge during Live Update!\n");So, maybe clear it in
pci_liveupdate_finish()?I think we can allo wa rescan to assign new bus numbers once all devices go through
pci_liveupdate_finish()by clearingdev->liveupdate_inherit_buseson all devices inpci_flb_finish(). We would need to holdpci_rescan_remove_lockto avoid this racing with such a rescan.Now that you bring up
/sys/bus/pci/rescan... I think we also need to setdev->liveupdate_inherit_busesin the outgoing kernel, to avoid bus numbers changing on outgoing preserved devices.pci_flb_preserve()should takepci_rescan_remove_lockand setdev->liveupdate_inherit_buseson all devices, andpci_flb_unpreserve()should do the opposite.
Quoted 6 lines
Quoted 4 lines
If we did all then then
/sys/bus/pci/rescancan work like normal as long as no devices are preserved (incoming or outgoing). If any devices are preserved thendev->liveupdate_inherit_busesgets set to prevent bus numbers from changing during a possible rescan.Something like this? This is a diff applied on top of this commit.
Below looks correct to me, but I have another question. How do you stablize PCI BARs? PCI BDF stability does not guarantee BARs don't get moved, right?
Quoted 204 lines
drivers/pci/liveupdate.c +2
-0@@ -120,6 +120,20 @@#include "pci.h" +/* +* During a Live Update, preserved devices are allowed to continue performing
+ * memory transactions. The kernel must not change the fabric topology,
+ * including bus numbers, since that would require disabling and flushing any
+ * memory transactions first.
+ *
+ * To keep things simple, inherit the secondary and subordinate bus numbers on
+ * _all_ bridges if _any_ PCI devices are preserved (i.e. even bridges without
+ * any downstream endpoints that were preserved). This avoids accidentally
+ * assigning a bridge a new window that overlaps with a preserved device that is
+ * downstream of a different bridge.
+ */drivers/pci/liveupdate.c +14
-0+static atomic_t inherit_buses; +struct pci_flb_outgoing {/* The pci_ser struct to be passed to the next kernel */ struct pci_ser *ser;@@ -141,6 +155,29 @@ static unsigned long pci_ser_xa_key(unsigned long domain, unsigned long bdf) return domain << 16 | bdf; } +bool pci_liveupdate_inherit_buses (void ) +{ +return atomic_read (&inherit_buses); +} + +static void pci_set_liveupdate_inherit_buses (bool enable) +{ +/* Ensure updates to inherit_buses do not race with rescans */ +pci_lock_rescan_remove (); + +/* +* Increment/decrement instead of setting directly to true/false so that
drivers/pci/liveupdate.c +1
-0+* pci_liveupdate_inherit_buses() returns true if any device is outgoing
drivers/pci/liveupdate.c +18
-2+* preserved or incoming preserved. +*/ +if (enable) +atomic_inc (&inherit_buses); +else +atomic_dec (&inherit_buses); + +pci_unlock_rescan_remove (); +} +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_flb_outgoing *outgoing;@@ -180,6 +217,8 @@ static int pci_flb_preserve(struct liveupdate_flb_op_args *args) args->obj = outgoing; args->data =virt_to_phys (outgoing->ser); + +pci_set_liveupdate_inherit_buses (true);return 0 ; }@@ -187,6 +226,8 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) {struct pci_flb_outgoing *outgoing = args->obj; +pci_set_liveupdate_inherit_buses (false); +pr_debug ("Unpreserving struct pci_ser\n" );WARN_ON_ONCE (outgoing->ser->nr_devices);kho_unpreserve_free (outgoing->ser);@@ -223,6 +264,8 @@ static int pci_flb_retrieve(struct liveupdate_flb_op_args *args) } args->obj = incoming; + +pci_set_liveupdate_inherit_buses (true);return 0 ; }@@ -230,6 +273,8 @@ static void pci_flb_finish(struct liveupdate_flb_op_args *args) {struct pci_flb_incoming *incoming = args->obj; +pci_set_liveupdate_inherit_buses (false); +xa_destroy (&incoming->xa);kho_restore_free (incoming->ser);kfree (incoming);@@ -385,21 +430,6 @@ void pci_liveupdate_setup_device(struct pci_dev *dev) if (!xa)return ; -/* -* During a Live Update, preserved devices are allowed to continue
drivers/pci/liveupdate.c +0
-1-* performing memory transactions. The kernel must not change the fabric
drivers/pci/liveupdate.c +0
-1-* topology, including bus numbers, since that would require disabling
drivers/pci/liveupdate.c +0
-3-* and flushing any memory transactions first. -* -* To keep things simple, inherit the secondary and subordinate bus
drivers/pci/liveupdate.c +0
-1-* numbers on _all_ bridges if _any_ PCI devices were preserved (i.e.
drivers/pci/liveupdate.c +0
-1-* even bridges without any downstream endpoints that were preserved).
drivers/pci/liveupdate.c +0
-1-* This avoids accidentally assigning a bridge a new window that
drivers/pci/liveupdate.c +0
-1-* overlaps with a preserved device that is downstream of a different
drivers/pci/liveupdate.c +0
-4-* bridge. -*/ - dev->liveupdate_inherit_buses = true; - key = pci_ser_xa_key(pci_domain_nr(dev->bus),
pci_dev_id(dev));dev_ser=xa_load(xa, key);drivers/pci/pci.h +0
-0@@ -1442,6 +1442,7 @@ static inline int pci_msix_write_tph_tag(struct
pci_dev*pdev, unsigned int inde #ifdefCONFIG_PCI_LIVEUPDATE
voidpci_liveupdate_setup_device(struct pci_dev *dev); voidpci_liveupdate_cleanup_device(struct pci_dev *dev);drivers/pci/pci.h +1
-0+bool pci_liveupdate_inherit_buses (void );#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {@@ -1450,6 +1451,11 @@ static inline void
pci_liveupdate_setup_device(struct pci_dev *dev)static inline voidpci_liveupdate_cleanup_device(struct pci_dev *dev){
}drivers/pci/pci.h +5
-0+ +static inline bool pci_liveupdate_inherit_buses (void ) +{ +return false; +}#endif #endif /* DRIVERS_PCI_H */ drivers/pci/probe.c +2
-2@@ -1374,9 +1374,9 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) return true; } -static bool pci_should_assign_new_buses (struct pci_dev *dev) +static bool pci_should_assign_new_buses (void ) { -if (dev->liveupdate_inherit_buses) +if (pci_liveupdate_inherit_buses ())return false;return pcibios_assign_all_busses ();@@ -1409,7 +1409,7 @@ static int pci_scan_bridge_extend(struct
pci_bus*bus, structpci_dev*dev, int max, unsigned intavailable_buses, int pass)
{drivers/pci/probe.c +0
-1- const bool assign_new_buses =
pci_should_assign_new_buses(dev);drivers/pci/probe.c +2
-1+const bool assign_new_buses =pci_should_assign_new_buses ();struct pci_bus *child;u32 buses;u16 bctl;@@ -1518,7 +1518,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } -if (dev->liveupdate_inherit_buses) { +if (pci_liveupdate_inherit_buses ()) { pci_err(dev, "Cannot reconfigure bridgeduring Live Update!\n");
pci_err(dev, "Downstream devices will not be enumerated!\n"); goto out;include/linux/pci.h +0
-0@@ -511,7 +511,6 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BARdisable broken */ unsigned int rom_attr_enabled:1; /*
Display of ROM attribute enabled? */ unsigned int
non_mappable_bars:1; /* BARs can't be mapped to user-space */include/linux/pci.h +0
-1- unsigned int liveupdate_inherit_buses:1; /* Inheritbus numbers due to Live Update */
pci_dev_flags_tdev_flags;
atomic_tenable_cnt; /*pci_enable_devicehas
been called */
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
Quoted 3 lines · Jacob Pan
Below looks correct to me, but I have another question. How do you stablize PCI BARs? PCI BDF stability does not guarantee BARs don't get moved, right?
That's right, this series does not guarantee that BARs do not get moved or sized. For P2P use-cases, we do need BARs to remain stable and avoid sizing during enumeration. We also need to ensure bridge windows are preserved.
My plan is to send another series to ready the PCI core for P2P use-cases, sometime after this one.
Re: [PATCH v4 05/11] PCI: liveupdate: Inherit bus numbers during Live Update
In reply to David MatlackQuoted 11 lines · David Matlack
Inherit bus numbers from the previous kernel during a Live Update when one or more PCI devices are being preserved.
+++
b/drivers/pci/liveupdate.cdrivers/pci/liveupdate.c +3
-0@@ -93,6 +93,19 @@* bound to the correct driver. i.e. The PCI core does not protect against a * device getting preserved by driver A in the outgoing kernel and then getting * bound to driver B in the incoming kernel. +* +* BDF Stability +* =============
drivers/pci/liveupdate.c line 108
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+* +* The PCI core guarantees that incoming preserved devices can be identified by +* the same bus, device, and function numbers as prior to kexec. To accomplish +* this, the PCI core always inherits the secondary and subordinate bus numbers +* assigned to bridges during enumeration, rather than assigning new ones (the +* PCI core assumes that the previous kernel established a sane topology). +* +* If a misconfigured or unconfigured bridge is encountered during enumeration +* while there are incoming preserved devices, it's secondary and subordinate +* bus numbers will be cleared and devices below it will not be enumerated.
s/it's/its/
PATCH v4 6/11 PCI: liveupdate: Auto-preserve upstream bridges across Live Update
In reply to David MatlackWhen a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update.
Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing.
To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update.
--- drivers/pci/liveupdate.c | 149 +++++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 38 deletions(-)
drivers/pci/liveupdate.c +111 -38
@@ -106,6 +106,18 @@* If a misconfigured or unconfigured bridge is encountered during enumeration * while there are incoming preserved devices, it's secondary and subordinate * bus numbers will be cleared and devices below it will not be enumerated. +* +* PCI-to-PCI Bridges +* ================== +* +* Any PCI-to-PCI bridges upstream of a preserved device are automatically +* preserved when the device is preserved. The PCI core keeps track of the +* number of downstream devices that are preserved under a bridge so that the +* bridge is only unpreserved once all downstream devices are unpreserved. +* +* 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. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -233,25 +245,14 @@ static struct liveupdate_flb pci_liveupdate_flb = { .compatible = PCI_LUO_FLB_COMPATIBLE, }; -int pci_liveupdate_preserve (struct pci_dev *dev) +static int pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) { -struct pci_ser *ser; -int i, ret; - -guard (mutex)(&pci_flb_outgoing_lock); - - ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); -if (ret) -return ret; +int i; -if (!ser) -return -ENOENT ; - -if (dev->is_virtfn) -return -EINVAL ; - -if (dev->liveupdate_outgoing) -return -EBUSY ; +if (dev->liveupdate_outgoing) { + dev->liveupdate_outgoing->refcount++; +return 0 ; + }if (ser->nr_devices == ser->max_nr_devices)return -ENOSPC ;
@@ -281,11 +282,82 @@ int pci_liveupdate_preserve(struct pci_dev *dev)return -ENOSPC ; } + +static void pci_liveupdate_unpreserve_path (struct pci_ser *ser,struct pci_dev *dev) +{ +struct pci_dev *upstream_bridge = dev->bus->self; +struct pci_dev_ser *dev_ser; + +if (upstream_bridge) +pci_liveupdate_unpreserve_path (ser, upstream_bridge); + + dev_ser = dev->liveupdate_outgoing; +if (!dev_ser) { +pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); +return ; + } + +if (--dev_ser->refcount ==0 ) { +pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); + ser->nr_devices--; +memset (dev_ser,0 ,sizeof (*dev_ser)); + dev->liveupdate_outgoing =NULL ; + } +} + +static int pci_liveupdate_preserve_path (struct pci_ser *ser,struct pci_dev *dev) +{ +struct pci_dev *upstream_bridge = dev->bus->self; +int ret =0 ; + +if (upstream_bridge) { + ret =pci_liveupdate_preserve_path (ser, upstream_bridge); +if (ret) +return ret; + }else if (!pci_is_root_bus (dev->bus)) { +pci_err (dev,"Failed to preserve up to root port\n" ); +return -EINVAL ; + } + + ret =pci_liveupdate_preserve_device (ser, dev); +if (ret) + goto err; + +return 0 ; + +err: +if (upstream_bridge) +pci_liveupdate_unpreserve_path (ser, upstream_bridge); + +return ret; +} + +int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser; +int ret; + +guard (mutex)(&pci_flb_outgoing_lock); + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ret; + +if (!ser) +return -ENOENT ; + +if (dev->is_virtfn) +return -EINVAL ; + +if (dev->liveupdate_outgoing) +return -EBUSY ; + +return pci_liveupdate_preserve_path (ser, dev); +}EXPORT_SYMBOL_GPL (pci_liveupdate_preserve);void pci_liveupdate_unpreserve (struct pci_dev *dev) { -struct pci_dev_ser *dev_ser;struct pci_ser *ser =NULL ;int ret;
@@ -296,19 +368,9 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev)if (ret || !ser) {pci_warn (dev,"Cannot unpreserve device without outgoing Live Update state\n" );return ; - - } - - dev_ser = dev->liveupdate_outgoing; -if (!dev_ser) { -pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); -return ; } -pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); - ser->nr_devices--; -memset (dev_ser,0 ,sizeof (*dev_ser)); - dev->liveupdate_outgoing =NULL ; +pci_liveupdate_unpreserve_path (ser, dev); }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve);
@@ -428,6 +490,25 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev)pci_liveupdate_flb_put_incoming (); } +static void pci_liveupdate_finish_path (struct pci_dev *dev) +{ +struct pci_dev *upstream_bridge = dev->bus->self; + +if (upstream_bridge) +pci_liveupdate_finish_path (upstream_bridge); + +/* +* Decrement the refcount so this device does not get treated as an +* incoming device again, e.g. in case pci_liveupdate_setup_device() +* gets called again becase the device is hot-plugged. +*/ +if (--dev->liveupdate_incoming->refcount) +return ; + +pci_info (dev,"Device is finished participating in Live Update\n" ); + dev->liveupdate_incoming =NULL ; +} +void pci_liveupdate_finish (struct pci_dev *dev) {if (!dev->liveupdate_incoming) {
@@ -435,15 +516,7 @@ void pci_liveupdate_finish(struct pci_dev *dev)return ; } -pci_info (dev,"Device is finished participating in Live Update\n" ); - -/* -* Drop the refcount so this device does not get treated as an incoming -* device again, e.g. in case pci_liveupdate_setup_device() gets called -* again becase the device is hot-plugged. -*/ - dev->liveupdate_incoming->refcount =0 ; - dev->liveupdate_incoming =NULL ; +pci_liveupdate_finish_path (dev);/* Drop this device's reference on the incoming FLB. */ pci_liveupdate_flb_put_incoming ();
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
PATCH v4 7/11 PCI: liveupdate: Inherit ACS flags in incoming preserved devices
In reply to David MatlackInherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
--- drivers/pci/liveupdate.c | 10 ++++++++++ drivers/pci/pci.c | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-)
drivers/pci/liveupdate.c +10 -0
@@ -118,6 +118,16 @@* 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. +* +* Handling Preserved Devices +* ========================== +* +* The PCI core treats preserved devices differently than non-preserved devices. +* This section enumerates those differences. +* +* * The PCI core inherits all ACS flags enabled on incoming preserved devices +* rather than assigning new ones. This ensures that TLPs are routed the same +* way after Live Update and ensures that IOMMU groups do not change. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
drivers/pci/pci.c +9 -1
@@ -1017,6 +1017,15 @@ void pci_enable_acs(struct pci_dev *dev)bool enable_acs = false;int pos; +/* +* ACS flags must be inherited from the previous kernel during a Live +* Update for preserved devices (which includes endpoints and any +* upstream bridges) to avoid changing routing while memory transactions +* are in flight. +*/ +if (pci_liveupdate_incoming (dev)) +return ; +/* If an iommu is present we start with kernel default caps */ if (pci_acs_enable) {if (pci_dev_specific_enable_acs (dev))
@@ -1041,7 +1050,6 @@ void pci_enable_acs(struct pci_dev *dev)PCI_ACS_RR |PCI_ACS_CR |PCI_ACS_EC , ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC));__pci_config_acs (dev, &caps, config_acs_param,0 ,0 ); -pci_write_config_word (dev, pos +PCI_ACS_CTRL , caps.ctrl); }
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 07/11] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 14 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Signed-off-by David Matlack <[email protected]>drivers/pci/pci.c +0
-0@@ -1017,6 +1017,15 @@ void pci_enable_acs(struct pci_dev *dev)bool enable_acs = false;
drivers/pci/pci.c void pci_enable_acs(struct pci_dev *dev) · line 1027
Quoted 10 lines
drivers/pci/pci.c +8
-0int pos; +/* +* ACS flags must be inherited from the previous kernel during a Live +* Update for preserved devices (which includes endpoints and any +* upstream bridges) to avoid changing routing while memory transactions +* are in flight. +*/ +if (pci_liveupdate_incoming (dev)) +return ;
Sashiko caught that pci_enable_acs() is also called from pci_restore_state() so this patch needs a fix to ensure that ACS flags do not change or get lost after a save+reset+restore.
PATCH v4 8/11 PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
In reply to David MatlackRestrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
--- drivers/iommu/iommu.c | 35 +++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.c | 6 ++++++ include/linux/iommu.h | 7 +++++++ 3 files changed, 48 insertions(+)
drivers/iommu/iommu.c +35 -0
@@ -1664,6 +1664,41 @@ struct iommu_group *pci_device_group(struct device *dev) }EXPORT_SYMBOL_GPL (pci_device_group); +bool pci_device_group_immutable_singleton (struct pci_dev *dev) +{ +struct iommu_group *group; +struct group_device *d; +struct pci_bus *bus; +int nr_devices =0 ; + + group =iommu_group_get (&dev->dev); +if (!group) +return false; + +mutex_lock (&group->mutex); + +for_each_group_device (group, d) + nr_devices++; + +mutex_unlock (&group->mutex); +iommu_group_put (group); + +if (nr_devices !=1 ) +return false; + +for (bus = dev->bus; !pci_is_root_bus (bus); bus = bus->parent) { +if (!bus->self) +continue ; + +if (!pci_acs_path_enabled (bus->self,NULL ,REQ_ACS_FLAGS )) +return false; + +break ; + } + +return true; +} +/* Get the IOMMU group for device on fsl-mc bus */ struct iommu_group *fsl_mc_device_group (struct device *dev) {
drivers/pci/liveupdate.c +6 -0
@@ -133,6 +133,7 @@#define pr_fmt (fmt) "PCI: liveupdate: " fmt#include <linux/io.h> +#include <linux/iommu.h> #include <linux/kexec_handover.h> #include <linux/kho/abi/pci.h> #include <linux/liveupdate.h>
@@ -359,6 +360,11 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (dev->is_virtfn)return -EINVAL ; +if (!pci_device_group_immutable_singleton (dev)) { +pci_warn (dev,"Device preservation limited to immutable singleton iommu groups\n" ); +return -EINVAL ; + } +if (dev->liveupdate_outgoing)return -EBUSY ;
include/linux/iommu.h +7 -0
@@ -1096,6 +1096,8 @@ extern struct iommu_group *generic_device_group(struct device *dev);struct iommu_group *fsl_mc_device_group (struct device *dev);extern struct iommu_group *generic_single_device_group (struct device *dev); +bool pci_device_group_immutable_singleton (struct pci_dev *dev); +/** * struct iommu_fwspec - per-device IOMMU instance data * @iommu_fwnode: firmware handle for this device's IOMMU
@@ -1528,6 +1530,11 @@ static inline int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)static inline void pci_dev_reset_iommu_done (struct pci_dev *pdev) { } + +static inline bool pci_device_group_immutable_singleton (struct pci_dev *dev) +{ +return false; +}#endif /* CONFIG_IOMMU_API */ #ifdef CONFIG_IRQ_MSI_IOMMU
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 15 lines · David Matlack
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
Quoted 5 lines
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Signed-off-by David Matlack <[email protected]>
Jason, do you think requiring singleton iommu groups is still necessary/useful now that this series preserves ACS flags on preserved devices and upstream bridges?
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 20 lines · David Matlack
Quoted 19 lines · David Matlack
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Quoted 5 lines
Quoted 1 line
Signed-off-by David Matlack <[email protected]>Jason, do you think requiring singleton iommu groups is still necessary/useful now that this series preserves ACS flags on preserved devices and upstream bridges?
I have forgotten why we introduced that? There are alot of funky things about iommu groups that might be important upon restoration..
Like if you preserve one group member but not the other what do you ?
Even if you have ACS flags there are cases where groups are still aliasing DMA..
Frankly, multi-device iommu groups don't even work fully last time we tried to use them in a VMM. So I think I would not expect them to ever intersect with live update. Blocking something tricky you can't test does seem like a reasonable thing.
Jason
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 22 lines · Jason Gunthorpe
Quoted 20 lines · David Matlack
Quoted 19 lines · David Matlack
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by David Matlack <[email protected]>Jason, do you think requiring singleton iommu groups is still necessary/useful now that this series preserves ACS flags on preserved devices and upstream bridges?
I have forgotten why we introduced that? There are alot of funky things about iommu groups that might be important upon restoration..
You had originally suggested it in this thread:
https://lore.kernel.org/kvm/[email protected]/
Quoted 1 line
Like if you preserve one group member but not the other what do you ?
Yeah I imagine there could be some tricky cases there...
I wonder if PCI core is the right layer to enforce this. Maybe this fits better into Sami's IOMMU core series since that is where all those tricky cases will be (I imagine?).
Quoted 2 lines
Even if you have ACS flags there are cases where groups are still aliasing DMA..
Hm, if a DMA alias can be created after boot time enumeration even with the REQ_ACS_FLAGS check, then pci_device_group_immutable_singleton() is not really immutable.
Quoted 4 lines
Frankly, multi-device iommu groups don't even work fully last time we tried to use them in a VMM. So I think I would not expect them to ever intersect with live update. Blocking something tricky you can't test does seem like a reasonable thing.
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 36 lines · David Matlack
Quoted 22 lines · Jason Gunthorpe
Quoted 20 lines · David Matlack
Quoted 19 lines · David Matlack
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by David Matlack <[email protected]>Jason, do you think requiring singleton iommu groups is still necessary/useful now that this series preserves ACS flags on preserved devices and upstream bridges?
I have forgotten why we introduced that? There are alot of funky things about iommu groups that might be important upon restoration..
You had originally suggested it in this thread:
Quoted 7 lines
Quoted 1 line
Like if you preserve one group member but not the other what do you ?
Yeah I imagine there could be some tricky cases there...
I wonder if PCI core is the right layer to enforce this. Maybe this fits better into Sami's IOMMU core series since that is where all those tricky cases will be (I imagine?).
+1
Also I think this should probably be checked by iommufd and invoked through vfio cdev. Basically when vfio cdev calls into iommufd to preserve IOMMU specific aspects of device (PASID table etc), iommufd can check this and return error.
Quoted 14 lines
Quoted 3 lines
Even if you have ACS flags there are cases where groups are still aliasing DMA..
Hm, if a DMA alias can be created after boot time enumeration even with the
REQ_ACS_FLAGScheck, thenpci_device_group_immutable_singleton()is not really immutable.Quoted 4 lines
Frankly, multi-device iommu groups don't even work fully last time we tried to use them in a VMM. So I think I would not expect them to ever intersect with live update. Blocking something tricky you can't test does seem like a reasonable thing.
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 45 lines · Samiullah Khawaja
Quoted 36 lines · David Matlack
Quoted 22 lines · Jason Gunthorpe
Quoted 20 lines · David Matlack
Quoted 19 lines · David Matlack
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by David Matlack <[email protected]>Jason, do you think requiring singleton iommu groups is still necessary/useful now that this series preserves ACS flags on preserved devices and upstream bridges?
I have forgotten why we introduced that? There are alot of funky things about iommu groups that might be important upon restoration..
You had originally suggested it in this thread:
Quoted 7 lines
Quoted 1 line
Like if you preserve one group member but not the other what do you ?
Yeah I imagine there could be some tricky cases there...
I wonder if PCI core is the right layer to enforce this. Maybe this fits better into Sami's IOMMU core series since that is where all those tricky cases will be (I imagine?).
Quoted 6 lines
+1
Also I think this should probably be checked by iommufd and invoked through vfio cdev. Basically when vfio cdev calls into iommufd to preserve IOMMU specific aspects of device (PASID table etc), iommufd can check this and return error.
Ok I will drop this patch from v5. The IOMMU core can check for it if it makes life simpler, but I can't think of anything in the PCI core that cares about this check.
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
In reply to David MatlackHi David,
Quoted 33 lines · On Thu, 23 Apr 2026 21:23:12 +0000 David Matlack <[email protected]> wrote:
Restrict support for preserving PCI devices across Live Update to devices in immutable singleton IOMMU groups. A device's group is considered immutable if all bridges upstream from the device up to the root port have the required ACS features enabled.
Since ACS flags are inherited across a Live Update for preserved devices and all the way up to the root port, the preserved device should be in a singleton IOMMU group after kexec in the new kernel.
This change should still permit all the current use-cases for PCI device preservation across Live Update, since it is intended to be used in Cloud enviroments which should have the required ACS features enabled for virtualization purposes.
If a device is part of a multi-device IOMMU group, preserving it will now fail with an error. This restriction may be lifted in the future if support for preserving multi-device groups is desired.
Signed-off-by David Matlack <[email protected]>--- drivers/iommu/iommu.c | 35 +++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.c | 6 ++++++ include/linux/iommu.h | 7 +++++++ 3 files changed, 48 insertions(+)drivers/iommu/iommu.c +0
-0@@ -1664,6 +1664,41 @@ struct iommu_group *pci_device_group(struct device *dev) }EXPORT_SYMBOL_GPL (pci_device_group);
drivers/iommu/iommu.c struct iommu_group *pci_device_group(struct · line 1676
Quoted 10 lines
drivers/iommu/iommu.c +10
-0+bool pci_device_group_immutable_singleton (struct pci_dev *dev) +{ +struct iommu_group *group; +struct group_device *d; +struct pci_bus *bus; +int nr_devices =0 ; + + group =iommu_group_get (&dev->dev); +if (!group) +return false;
This may not work for noiommu mode where we could have a null group. Maybe I can add special case later?
drivers/iommu/iommu.c struct iommu_group *pci_device_group(struct device *dev) · line 1684
Quoted 7 lines
drivers/iommu/iommu.c +7
-0+mutex_lock (&group->mutex); + +for_each_group_device (group, d) + nr_devices++; + +mutex_unlock (&group->mutex); +iommu_group_put (group);
nit:
scoped_guard(mutex, &group->mutex) {
for_each_group_device(group, d)
nr_devices++;}
Quoted 72 lines
drivers/iommu/iommu.c +17
-0+ +if (nr_devices !=1 ) +return false; + +for (bus = dev->bus; !pci_is_root_bus (bus); bus = bus->parent) { +if (!bus->self) +continue ; + +if (!pci_acs_path_enabled (bus->self,NULL ,REQ_ACS_FLAGS )) +return false; + +break ; + } + +return true; +} +/* Get the IOMMU group for device on fsl-mc bus */ struct iommu_group *fsl_mc_device_group (struct device *dev) {drivers/pci/liveupdate.c +6
-0@@ -133,6 +133,7 @@#define pr_fmt (fmt) "PCI: liveupdate: " fmt#include <linux/io.h> +#include <linux/iommu.h> #include <linux/kexec_handover.h> #include <linux/kho/abi/pci.h> #include <linux/liveupdate.h> @@ -359,6 +360,11 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (dev->is_virtfn)return -EINVAL ; +if (!pci_device_group_immutable_singleton (dev)) { + pci_warn(dev, "Device preservation limited to immutable singleton iommu groups\n"); + return -EINVAL; + } +if (dev->liveupdate_outgoing)return -EBUSY ;include/linux/iommu.h +2
-0@@ -1096,6 +1096,8 @@ extern struct iommu_group *generic_device_group(struct device *dev); struct iommu_group *fsl_mc_device_group (struct device *dev);extern struct iommu_group *generic_single_device_group (struct device *dev); +bool pci_device_group_immutable_singleton (struct pci_dev *dev); +/** * struct iommu_fwspec - per-device IOMMU instance data * @iommu_fwnode: firmware handle for this device's IOMMU @@ -1528,6 +1530,11 @@ static inline int
pci_dev_reset_iommu_prepare(struct pci_dev *pdev)static inline voidpci_dev_reset_iommu_done(struct pci_dev *pdev){
}include/linux/iommu.h +2
-0+ +static inline bool pci_device_group_immutable_singleton(struct
pci_dev*dev) +{include/linux/iommu.h +2
-0+ return false; +}#endif /* CONFIG_IOMMU_API */ #ifdef CONFIG_IRQ_MSI_IOMMU
Re: [PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups
Quoted 15 lines · Jacob Pan
drivers/iommu/iommu.c struct iommu_group *pci_device_group(struct device *dev) · line 1676
Quoted 10 lines · On Thu, 23 Apr 2026 21:23:12 +0000 David Matlack <[email protected]> wrote:
drivers/iommu/iommu.c +10
-0+bool pci_device_group_immutable_singleton (struct pci_dev *dev) +{ +struct iommu_group *group; +struct group_device *d; +struct pci_bus *bus; +int nr_devices =0 ; + + group =iommu_group_get (&dev->dev); +if (!group) +return false;This may not work for noiommu mode where we could have a null group. Maybe I can add special case later?
Yeah depending which series goes in first. But based on the other thread I am going to drop this patch from v5.
PATCH v4 9/11 PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
In reply to David MatlackInherit the ARI Forwarding Enable on preserved bridges and update pci_dev->ari_enabled accordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.
--- drivers/pci/liveupdate.c | 4 ++++ drivers/pci/pci.c | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-)
drivers/pci/liveupdate.c +4 -0
@@ -128,6 +128,10 @@* * The PCI core inherits all ACS flags enabled on incoming preserved devices * rather than assigning new ones. This ensures that TLPs are routed the same * way after Live Update and ensures that IOMMU groups do not change. +* +* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream +* preserved devices to ensure that all preserved devices on the bridge's +* secondary bus are addressable after the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
drivers/pci/pci.c +11 -1
@@ -3498,8 +3498,9 @@ void pci_configure_ari(struct pci_dev *dev) {u32 cap;struct pci_dev *bridge; +u16 val =0 ; -if (pcie_ari_disabled || !pci_is_pcie (dev) || dev->devfn) +if (!pci_is_pcie (dev) || dev->devfn)return ; bridge = dev->bus->self;
@@ -3510,6 +3511,15 @@ void pci_configure_ari(struct pci_dev *dev)if (!(cap &PCI_EXP_DEVCAP2_ARI ))return ; +if (pci_liveupdate_incoming (bridge)) { +pcie_capability_read_word (bridge,PCI_EXP_DEVCTL2 , &val); + bridge->ari_enabled = !!(val &PCI_EXP_DEVCTL2_ARI ); +return ; + } + +if (pcie_ari_disabled) +return ; +if (pci_find_ext_capability (dev,PCI_EXT_CAP_ID_ARI )) {pcie_capability_set_word (bridge,PCI_EXP_DEVCTL2 ,PCI_EXP_DEVCTL2_ARI );
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
PATCH v4 10/11 PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec
In reply to David MatlackDo not disable bus mastering on outgoing preserved devices during pci_device_shutdown() for kexec.
Preserved devices must be allowed to perform memory transactions during a Live Update to minimize downtime and ensure continuous operation. Clearing the bus mastering bit would prevent these devices from issuing any memory requests while the new kernel boots.
Because bridges upstream of preserved endpoint devices are also automatically preserved, this change also avoids clearing bus mastering on them. This is critical because clearing bus mastering on an upstream bridge prevents the bridge from forwarding memory requests upstream (i.e. it would prevent the endpoint device from accessing system RAM and doing peer-to-peer transactions with devices not downstream of the bridge).
--- drivers/pci/liveupdate.c | 4 ++++ drivers/pci/pci-driver.c | 31 ++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-)
drivers/pci/liveupdate.c +4 -0
@@ -132,6 +132,10 @@* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream * preserved devices to ensure that all preserved devices on the bridge's * secondary bus are addressable after the Live Update. +* +* * The PCI core does not disable bus mastering on outoing preserved devices +* during kexec. This allows preserved devices to issue memory transactions +* throughout the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
drivers/pci/pci-driver.c +22 -9
@@ -531,6 +531,27 @@ static void pci_device_remove(struct device *dev)pci_dev_put (pci_dev); } +/* +* Disable bus mastering on the device so that it does not perform memory +* transactions during kexec. +* +* Don't touch devices that are being preserved across kexec for Live +* Update or that are in D3cold or unknown states. +*/ +static void pci_clear_master_for_shutdown (struct pci_dev *pci_dev) +{ +if (!kexec_in_progress) +return ; + +if (pci_liveupdate_outgoing (pci_dev)) +return ; + +if (pci_dev->current_state > PCI_D3hot) +return ; + +pci_clear_master (pci_dev); +} +static void pci_device_shutdown (struct device *dev) {struct pci_dev *pci_dev =to_pci_dev (dev);
@@ -541,15 +562,7 @@ static void pci_device_shutdown(struct device *dev)if (drv && drv->shutdown) drv->shutdown (pci_dev); -/* -* If this is a kexec reboot, turn off Bus Master bit on the -* device to tell it to not continue to do DMA. Don't touch -* devices in D3cold or unknown states. -* If it is not a kexec reboot, firmware will hit the PCI -* devices with big hammer and stop their DMA any way. -*/ -if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot)) -pci_clear_master (pci_dev); +pci_clear_master_for_shutdown (pci_dev); }#ifdef CONFIG_PM_SLEEP
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog
Re: [PATCH v4 10/11] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec
drivers/pci/liveupdate.c line 137
Quoted 11 lines · David Matlack
Do not disable bus mastering on outgoing preserved devices during
pci_device_shutdown()for kexec.+++
b/drivers/pci/liveupdate.cdrivers/pci/liveupdate.c +3
-0@@ -132,6 +132,10 @@* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream * preserved devices to ensure that all preserved devices on the bridge's * secondary bus are addressable after the Live Update. +* +* * The PCI core does not disable bus mastering on outoing preserved devices +* during kexec. This allows preserved devices to issue memory transactions
s/outoing/outgoing/
PATCH v4 11/11 Documentation: PCI: Add documentation for Live Update
In reply to David MatlackAdd documentation files for the PCI subsystem's participation in Live Update.
These documentation files are generated from the kernel-doc comments in the PCI Live Update source code. They describe the File-Lifecycle Bound (FLB) API, the device tracking API, and the specific policies applied to preserved devices (such as bus number inheritance and bus mastering preservation).
--- Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 23 +++++++++++++++++++++++ Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 1 + 4 files changed, 26 insertions(+) create mode 100644 Documentation/PCI/liveupdate.rst
Documentation/PCI/index.rst +1 -0
@@ -20,3 +20,4 @@ PCI Bus Subsystem controller/index boot-interrupts tph + liveupdate
Documentation/PCI/liveupdate.rst new file +23 -0
@@ -0,0 +1,23 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +=========================== +PCI Support for Live Update +=========================== + +.. kernel-doc:: drivers/pci/liveupdate.c + :doc: PCI Live Update + +PCI Preservation ABI +==================== + +.. kernel-doc:: include/linux/kho/abi/pci.h + :doc: PCI File-Lifecycle Bound (FLB) Live Update ABI + +.. kernel-doc:: include/linux/kho/abi/pci.h + :internal: + +See Also +======== + + * :doc:`/core-api/liveupdate` + * :doc:`/core-api/kho/index`
Documentation/core-api/liveupdate.rst +1 -0
@@ -70,3 +70,4 @@ See Also - :doc:`Live Update uAPI </userspace-api/liveupdate>` - :doc:`/core-api/kho/index` +- :doc:`PCI </PCI/liveupdate>`
MAINTAINERS +1 -0
@@ -20564,6 +20564,7 @@ Q: https://patchwork.kernel.org/project/linux-pci/list/ B: https://bugzilla.kernel.org C: irc://irc.oftc.net/linux-pci T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: Documentation/PCI/liveupdate.rst F: drivers/pci/liveupdate.c F: include/linux/kho/abi/pci.h
Signature · 1 line
2.54.0.rc2.544.gc7ae2d5bb8-goog