[PATCH v4 01/24] PCI: Don't suspend IOMMU when probing reset capability
Nicolin Chen
nicolinc at nvidia.com
Mon May 18 20:38:44 PDT 2026
reset_method_store() in drivers/pci/pci-sysfs.c discovers supported reset
methods by calling reset_fn(pdev, PCI_RESET_PROBE, ...) without holding a
device_lock, since the probe path is expected to query the device's reset
capability without changing device state.
However, pci_reset_bus_function() and __pci_dev_specific_reset() violate
that contract after pci_dev_reset_iommu_prepare/done() were added, which
moves the device into a blocking domain and abruptly aborts any in-flight
DMA. Doing this for a probe -- a state-query call that does not even hold
device_lock -- can cause driver timeouts and data loss on a DMAing device.
The peer reset helpers all handle this correctly: they short-circuit on a
probe input before touching the IOMMU.
Skip pci_dev_reset_iommu_prepare()/_done() entirely when probe is set. The
inner reset routines already implement their own probe semantics, and they
perform the capability checks and return without changing device state.
Fixes: f5b16b802174 ("PCI: Suspend iommu function prior to resetting a device")
Cc: stable at vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
drivers/pci/pci.c | 13 ++++++++-----
drivers/pci/quirks.c | 13 ++++++++-----
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d34266651ad09..d0af8b5eca2ce 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4914,10 +4914,12 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
if (bridge && pcie_is_cxl(bridge) && cxl_sbr_masked(bridge))
return -ENOTTY;
- rc = pci_dev_reset_iommu_prepare(dev);
- if (rc) {
- pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", rc);
- return rc;
+ if (!probe) {
+ rc = pci_dev_reset_iommu_prepare(dev);
+ if (rc) {
+ pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", rc);
+ return rc;
+ }
}
rc = pci_dev_reset_slot_function(dev, probe);
@@ -4926,7 +4928,8 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
rc = pci_parent_bus_reset(dev, probe);
done:
- pci_dev_reset_iommu_done(dev);
+ if (!probe)
+ pci_dev_reset_iommu_done(dev);
return rc;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index caaed1a01dc02..a344abd745947 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4260,14 +4260,17 @@ static int __pci_dev_specific_reset(struct pci_dev *dev, bool probe,
{
int ret;
- ret = pci_dev_reset_iommu_prepare(dev);
- if (ret) {
- pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
- return ret;
+ if (!probe) {
+ ret = pci_dev_reset_iommu_prepare(dev);
+ if (ret) {
+ pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+ return ret;
+ }
}
ret = i->reset(dev, probe);
- pci_dev_reset_iommu_done(dev);
+ if (!probe)
+ pci_dev_reset_iommu_done(dev);
return ret;
}
--
2.43.0
More information about the linux-arm-kernel
mailing list