[PATCH v4 10/11] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec

David Matlack
2026-04-23T21:23:39Z

Do 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).

Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/pci/liveupdate.c | 4 ++++
drivers/pci/pci-driver.c | 31 ++++++++++++++++++++++---------
2 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index 25c86cd4c173..2a4a139623a6 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -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
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d10ece0889f0..05584bc76332 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -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