Re: [PATCH v1 1/5] PCI: Don't suspend IOMMU when probing reset capability
From: Bjorn Helgaas
Date: Wed Nov 04 2026 - 19:23:36 EST
On Tue, Nov 03, 2026 at 10:33:42AM -0800, Nicolin Chen wrote:
> 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@xxxxxxxxxxxxxxx
> Reviewed-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
> Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
Acked-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
> ---
> 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 7c6f2aba81443..38b680e7c3d60 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5042,10 +5042,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);
> @@ -5054,7 +5056,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 7f1f47ea2ee41..3d3e95cb9f7dc 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -4406,14 +4406,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
>