[PATCH v9 3/9] PCI: Avoid saving config space state in reset path
From: Farhan Ali
Date: Tue Feb 17 2026 - 13:26:00 EST
The current reset process saves the device's config space state before
reset and restores it afterward. However errors may occur unexpectedly and
it may then be impossible to save config space because the device may be
inaccessible (e.g. DPC) or config space may be corrupted. This results in
saving corrupted values that get written back to the device during state
restoration.
Since commit a2f1e22390ac ("PCI/ERR: Ensure error recoverability at all times"),
we now save the state of device at enumeration. On every restore we should
either use the enumeration saved state or driver's intentional saved state,
never a state saved at the unpredictable time of an error recovery reset.
Suggested-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Signed-off-by: Farhan Ali <alifm@xxxxxxxxxxxxx>
---
drivers/pci/pci.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 3090c727b76f..2242b97e7d46 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5012,7 +5012,7 @@ void pci_dev_unlock(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_dev_unlock);
-static void pci_dev_save_and_disable(struct pci_dev *dev)
+static void pci_dev_disable(struct pci_dev *dev)
{
const struct pci_error_handlers *err_handler =
dev->driver ? dev->driver->err_handler : NULL;
@@ -5029,13 +5029,11 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
pci_warn(dev, "resetting");
/*
- * Wake-up device prior to save. PM registers default to D0 after
- * reset and a simple register restore doesn't reliably return
- * to a non-D0 state anyway.
+ * PM registers default to D0 after reset and a simple register
+ * restore doesn't reliably return to a non-D0 state.
*/
pci_set_power_state(dev, PCI_D0);
- pci_save_state(dev);
/*
* Disable the device by clearing the Command register, except for
* INTx-disable which is set. This not only disables MMIO and I/O port
@@ -5199,7 +5197,7 @@ int pci_reset_function(struct pci_dev *dev)
pci_dev_lock(bridge);
pci_dev_lock(dev);
- pci_dev_save_and_disable(dev);
+ pci_dev_disable(dev);
rc = __pci_reset_function_locked(dev);
@@ -5241,7 +5239,7 @@ int pci_reset_function_locked(struct pci_dev *dev)
if (!pci_reset_supported(dev))
return -ENOTTY;
- pci_dev_save_and_disable(dev);
+ pci_dev_disable(dev);
rc = __pci_reset_function_locked(dev);
@@ -5267,7 +5265,7 @@ int pci_try_reset_function(struct pci_dev *dev)
if (!pci_dev_trylock(dev))
return -EAGAIN;
- pci_dev_save_and_disable(dev);
+ pci_dev_disable(dev);
rc = __pci_reset_function_locked(dev);
pci_dev_restore(dev);
pci_dev_unlock(dev);
@@ -5441,17 +5439,17 @@ static int pci_slot_trylock(struct pci_slot *slot)
}
/*
- * Save and disable devices from the top of the tree down while holding
+ * Disable devices from the top of the tree down while holding
* the @dev mutex lock for the entire tree.
*/
-static void pci_bus_save_and_disable_locked(struct pci_bus *bus)
+static void pci_bus_disable_locked(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
- pci_dev_save_and_disable(dev);
+ pci_dev_disable(dev);
if (dev->subordinate)
- pci_bus_save_and_disable_locked(dev->subordinate);
+ pci_bus_disable_locked(dev->subordinate);
}
}
@@ -5477,16 +5475,16 @@ static void pci_bus_restore_locked(struct pci_bus *bus)
* Save and disable devices from the top of the tree down while holding
* the @dev mutex lock for the entire tree.
*/
-static void pci_slot_save_and_disable_locked(struct pci_slot *slot)
+static void pci_slot_disable_locked(struct pci_slot *slot)
{
struct pci_dev *dev;
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
continue;
- pci_dev_save_and_disable(dev);
+ pci_dev_disable(dev);
if (dev->subordinate)
- pci_bus_save_and_disable_locked(dev->subordinate);
+ pci_bus_disable_locked(dev->subordinate);
}
}
@@ -5566,7 +5564,7 @@ static int __pci_reset_slot(struct pci_slot *slot)
return rc;
if (pci_slot_trylock(slot)) {
- pci_slot_save_and_disable_locked(slot);
+ pci_slot_disable_locked(slot);
might_sleep();
rc = pci_reset_hotplug_slot(slot->hotplug, PCI_RESET_DO_RESET);
pci_slot_restore_locked(slot);
@@ -5660,7 +5658,7 @@ int __pci_reset_bus(struct pci_bus *bus)
return rc;
if (pci_bus_trylock(bus)) {
- pci_bus_save_and_disable_locked(bus);
+ pci_bus_disable_locked(bus);
might_sleep();
rc = pci_bridge_secondary_bus_reset(bus->self);
pci_bus_restore_locked(bus);
--
2.43.0