* [PATCH v4 0/3] PCI: Add d3cold/soft reset methods for devices with limited reset capability
@ 2026-05-18 12:48 Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 1/3] PCI: Add d3cold as general reset method Jose Ignacio Tornos Martinez
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-18 12:48 UTC (permalink / raw)
To: bhelgaas, alex; +Cc: linux-pci, linux-kernel, Jose Ignacio Tornos Martinez
Some PCIe devices lack working reset methods for VFIO passthrough scenarios.
These devices typically have no FLR, advertise NoSoftRst+ (blocking PM reset),
and have broken or unavailable bus reset. When a VM crashes, VFIO cannot reset
the device for reuse without a working reset method.
This series addresses the problem by adding two new reset methods and a
device-specific quirk:
**Patch 1/3: d3cold reset method**
Adds D3cold as a general reset method with strict _PR3 requirement. Only
attempts true power cycling via platform control (ACPI _PR3), never falls
back to D3hot. This provides genuine power-off reset on platforms that
support it.
**Patch 2/3: soft reset method**
Adds "soft" reset as absolute last resort when all other methods fail.
Performs D3hot→D0 transition without checking NoSoftRst flag. Only becomes
available when both pci_pm_reset() and pci_d3cold_reset() return -ENOTTY.
Provides "better than nothing" reset for devices that would otherwise have
no reset capability. Users retain full policy control via reset_methods sysfs.
**Patch 3/3: Qualcomm quirk_no_bus_reset**
Disables broken bus reset for Qualcomm ath11k/ath12k WiFi and SDX62/SDX65
modems. Testing proves this is device-specific: MediaTek MT7925e works
correctly with bus reset using the same passive M.2-to-PCIe adapters where
Qualcomm devices fail, confirming PERST# is properly wired and the issue
is not deployment-specific.
mt7925e needs quirk_no_flr to work
(https://lore.kernel.org/all/20260511123936.36054-1-jtornosm@redhat.com/)
other cards using this adpaters are using flr method with no problem.
**Changes in v4:**
- Split v3's d3cold method (which fell back to D3hot) into two separate
methods based on maintainer feedback (Alex Williamson)
- d3cold now strictly requires _PR3, returns -ENOTTY otherwise
- New "soft" method handles D3hot transition as last resort
- Extracted pci_do_d3hot_transition() helper to avoid code duplication
between pci_pm_reset() and pci_soft_reset()
- Updated Qualcomm quirk commit message to reference new architecture
**Testing:**
All testing performed on 2023 desktops with M.2 WiFi cards via passive
M.2-to-PCIe adapters in standard PCIe expansion slots (00:1c.x ports).
Evidence for device-specific reset issues:
- Realtek RTL8922AE: 00:1c.1, reset_method="flr bus", FLR works correctly
(Proves FLR signaling works through passive adapters)
- MediaTek MT7925e: 00:1c.1, reset_method="bus", bus reset works correctly
(Has separate quirk_no_flr patch due to broken FLR, proves PERST# works)
- Qualcomm WCN785x: 00:1c.4, reset_method="bus", bus reset FAILS
(Same adapters, same slot type - proves device-specific SBR issue)
All three devices use identical passive M.2-to-PCIe adapters in standard
PCIe expansion slots. The fact that FLR works for Realtek and bus reset
works for MediaTek but both fail for their respective broken devices
confirms these are device-specific hardware issues, not deployment or
adapter issues.
D3hot transition testing (documented in detail):
- Command register cleared: 0x0002 → 0x0000 → 0x0506 after driver init
- BARs preserved: 0x84200004 maintained throughout
- Device successfully reusable for VFIO passthrough after VM crash
Reset hierarchy after this series:
1. device_specific
2. acpi
3. flr
4. af_flr
5. pm (unchanged - still checks NoSoftRst)
6. bus
7. cxl_bus
8. d3cold (NEW - strict _PR3 requirement)
9. soft (NEW - D3hot last resort)
Jose Ignacio Tornos Martinez (3):
PCI: Add d3cold as general reset method
PCI: Add soft reset method as last resort
PCI: Disable broken bus reset on Qualcomm devices
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/3] PCI: Add d3cold as general reset method
2026-05-18 12:48 [PATCH v4 0/3] PCI: Add d3cold/soft reset methods for devices with limited reset capability Jose Ignacio Tornos Martinez
@ 2026-05-18 12:48 ` Jose Ignacio Tornos Martinez
2026-05-18 13:27 ` sashiko-bot
2026-05-18 12:48 ` [PATCH v4 2/3] PCI: Add soft reset method as last resort Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 3/3] PCI: Disable broken bus reset on Qualcomm devices Jose Ignacio Tornos Martinez
2 siblings, 1 reply; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-18 12:48 UTC (permalink / raw)
To: bhelgaas, alex; +Cc: linux-pci, linux-kernel, Jose Ignacio Tornos Martinez
Add D3cold power cycle as a general PCI reset method for single-function
devices on platforms with ACPI _PR3 power resources. This provides true
power cycle reset capability when the platform can physically cut power
to the device.
The implementation strictly requires _PR3 to be present - the platform
must be able to control device power. This ensures d3cold only attempts
true power cycling, not falling back to D3hot transitions.
D3cold reset is placed at the end of the reset hierarchy since it requires
specific platform support and should be tried after standard methods.
Reset hierarchy with this change:
1. device_specific
2. acpi
3. flr
4. af_flr
5. pm (D3hot via config space, checks NoSoftRst)
6. bus (SBR)
7. cxl_bus
8. d3cold (NEW - true power cycle, requires _PR3)
This benefits:
- Platforms with _PR3 support
- Single-function devices needing true power cycle
- VFIO passthrough scenarios where FLR/PM unavailable
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v4: Strict _PR3 requirement - no D3hot fallback (Alex Williamson and Lukas
Wunner feedback)
v3: https://lore.kernel.org/all/20260513122349.268753-1-jtornosm@redhat.com/
drivers/pci/pci.c | 40 ++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 2 +-
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8f7cfcc00090..839903b59698 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4491,6 +4491,45 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
return ret;
}
+/**
+ * pci_d3cold_reset - Put device into D3cold and back to D0 for reset
+ * @dev: PCI device to reset
+ * @probe: if true, check if D3cold reset is supported; if false, perform reset
+ *
+ * Reset the device by transitioning through D3cold (actual power removal via
+ * platform power control) and back to D0. This requires ACPI _PR3 power
+ * resources to be present - the platform must be able to physically cut power
+ * to the device.
+ *
+ * Only available for single-function devices to avoid affecting other
+ * functions in multi-function devices.
+ *
+ * Returns 0 if device can be/was reset this way, -ENOTTY if not supported,
+ * or other negative error code on failure.
+ */
+static int pci_d3cold_reset(struct pci_dev *dev, bool probe)
+{
+ int ret;
+
+ if (dev->multifunction)
+ return -ENOTTY;
+
+ if (!pci_pr3_present(dev))
+ return -ENOTTY;
+
+ if (probe)
+ return 0;
+
+ if (dev->current_state != PCI_D0)
+ return -EINVAL;
+
+ ret = pci_set_power_state(dev, PCI_D3cold);
+ if (ret)
+ return ret;
+
+ return pci_set_power_state(dev, PCI_D0);
+}
+
/**
* pcie_wait_for_link_status - Wait for link status change
* @pdev: Device whose link to wait for.
@@ -5065,6 +5104,7 @@ const struct pci_reset_fn_method pci_reset_fn_methods[] = {
{ pci_pm_reset, .name = "pm" },
{ pci_reset_bus_function, .name = "bus" },
{ cxl_reset_bus_function, .name = "cxl_bus" },
+ { pci_d3cold_reset, .name = "d3cold" },
};
/**
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2c4454583c11..1ca7b880ead7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -51,7 +51,7 @@
PCI_STATUS_PARITY)
/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
-#define PCI_NUM_RESET_METHODS 8
+#define PCI_NUM_RESET_METHODS 9
#define PCI_RESET_PROBE true
#define PCI_RESET_DO_RESET false
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-18 12:48 [PATCH v4 0/3] PCI: Add d3cold/soft reset methods for devices with limited reset capability Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 1/3] PCI: Add d3cold as general reset method Jose Ignacio Tornos Martinez
@ 2026-05-18 12:48 ` Jose Ignacio Tornos Martinez
2026-05-18 13:48 ` sashiko-bot
2026-05-18 17:15 ` Alex Williamson
2026-05-18 12:48 ` [PATCH v4 3/3] PCI: Disable broken bus reset on Qualcomm devices Jose Ignacio Tornos Martinez
2 siblings, 2 replies; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-18 12:48 UTC (permalink / raw)
To: bhelgaas, alex; +Cc: linux-pci, linux-kernel, Jose Ignacio Tornos Martinez
Add a software-initiated "soft" reset method that attempts D3hot->D0
transition as an absolute last resort when all other reset methods
have failed.
Some devices incorrectly advertise NoSoftRst+ (blocking PM reset) but
the D3hot transition does provide sufficient reset for certain use cases,
particularly VFIO passthrough scenarios. This method provides a "better
than nothing" option when the device would otherwise have no reset
capability.
The method only becomes available when:
- pci_pm_reset() is unavailable (typically blocked by NoSoftRst+)
- pci_d3cold_reset() is unavailable (no platform _PR3 support)
- Device has PM capability (required for D3hot transition)
Extract the D3hot transition logic into a shared helper function
(pci_do_d3hot_transition) used by both pci_pm_reset and pci_soft_reset.
Reset hierarchy with this change:
1. device_specific
2. acpi
3. flr
4. af_flr
5. pm (proper method, checks NoSoftRst)
6. bus
7. cxl_bus
8. d3cold (requires _PR3)
9. soft (NEW - D3hot without NoSoftRst check, absolute last resort)
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v4: Implements D3hot transition as last resort when pm/d3cold unavailable
v3: https://lore.kernel.org/all/20260513122349.268753-1-jtornosm@redhat.com/
drivers/pci/pci.c | 98 ++++++++++++++++++++++++++++++++++-----------
include/linux/pci.h | 2 +-
2 files changed, 76 insertions(+), 24 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 839903b59698..8dad386bd65d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4437,6 +4437,43 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
return ret;
}
+/**
+ * pci_do_d3hot_transition - Perform D3hot->D0 power state transition
+ * @dev: Device to transition
+ *
+ * Common helper to perform D3hot->D0 transition for PM-based reset methods.
+ * Handles IOMMU preparation, state transition, and waiting for device ready.
+ */
+static int pci_do_d3hot_transition(struct pci_dev *dev)
+{
+ u16 csr;
+ int ret;
+
+ if (dev->current_state != PCI_D0)
+ return -EINVAL;
+
+ 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;
+ }
+
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
+ csr &= ~PCI_PM_CTRL_STATE_MASK;
+ csr |= PCI_D3hot;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
+ pci_dev_d3_sleep(dev);
+
+ csr &= ~PCI_PM_CTRL_STATE_MASK;
+ csr |= PCI_D0;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
+ pci_dev_d3_sleep(dev);
+
+ ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
+ pci_dev_reset_iommu_done(dev);
+ return ret;
+}
+
/**
* pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
* @dev: Device to reset.
@@ -4455,7 +4492,6 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
static int pci_pm_reset(struct pci_dev *dev, bool probe)
{
u16 csr;
- int ret;
if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
return -ENOTTY;
@@ -4467,28 +4503,7 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
if (probe)
return 0;
- if (dev->current_state != PCI_D0)
- return -EINVAL;
-
- 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;
- }
-
- csr &= ~PCI_PM_CTRL_STATE_MASK;
- csr |= PCI_D3hot;
- pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
- pci_dev_d3_sleep(dev);
-
- csr &= ~PCI_PM_CTRL_STATE_MASK;
- csr |= PCI_D0;
- pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
- pci_dev_d3_sleep(dev);
-
- ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
- pci_dev_reset_iommu_done(dev);
- return ret;
+ return pci_do_d3hot_transition(dev);
}
/**
@@ -4530,6 +4545,42 @@ static int pci_d3cold_reset(struct pci_dev *dev, bool probe)
return pci_set_power_state(dev, PCI_D0);
}
+/**
+ * pci_soft_reset - Software-initiated reset via D3hot as last resort
+ * @dev: PCI device to reset
+ * @probe: if true, check if soft reset is supported; if false, perform reset
+ *
+ * Attempt a software-initiated reset via D3hot->D0 transition as an absolute
+ * last resort when all other reset methods have failed. This method only
+ * becomes available if the device has PM capability, pci_pm_reset() is blocked
+ * (typically by NoSoftRst+), and pci_d3cold_reset() is not available.
+ *
+ * Some devices incorrectly advertise NoSoftRst+ but D3hot transition does
+ * provide sufficient reset for certain use cases (e.g., VFIO passthrough).
+ * This method provides a "better than nothing" option when the device would
+ * otherwise have no reset capability.
+ *
+ * Returns 0 if device can be/was reset this way, -ENOTTY if a better reset
+ * method is available (pm or d3cold) or device lacks PM capability, or other
+ * negative error code on failure.
+ */
+static int pci_soft_reset(struct pci_dev *dev, bool probe)
+{
+ if (pci_pm_reset(dev, true) == 0)
+ return -ENOTTY;
+
+ if (pci_d3cold_reset(dev, true) == 0)
+ return -ENOTTY;
+
+ if (!dev->pm_cap)
+ return -ENOTTY;
+
+ if (probe)
+ return 0;
+
+ return pci_do_d3hot_transition(dev);
+}
+
/**
* pcie_wait_for_link_status - Wait for link status change
* @pdev: Device whose link to wait for.
@@ -5105,6 +5156,7 @@ const struct pci_reset_fn_method pci_reset_fn_methods[] = {
{ pci_reset_bus_function, .name = "bus" },
{ cxl_reset_bus_function, .name = "cxl_bus" },
{ pci_d3cold_reset, .name = "d3cold" },
+ { pci_soft_reset, .name = "soft" },
};
/**
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1ca7b880ead7..bcd2987b868b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -51,7 +51,7 @@
PCI_STATUS_PARITY)
/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
-#define PCI_NUM_RESET_METHODS 9
+#define PCI_NUM_RESET_METHODS 10
#define PCI_RESET_PROBE true
#define PCI_RESET_DO_RESET false
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 3/3] PCI: Disable broken bus reset on Qualcomm devices
2026-05-18 12:48 [PATCH v4 0/3] PCI: Add d3cold/soft reset methods for devices with limited reset capability Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 1/3] PCI: Add d3cold as general reset method Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 2/3] PCI: Add soft reset method as last resort Jose Ignacio Tornos Martinez
@ 2026-05-18 12:48 ` Jose Ignacio Tornos Martinez
2 siblings, 0 replies; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-18 12:48 UTC (permalink / raw)
To: bhelgaas, alex; +Cc: linux-pci, linux-kernel, Jose Ignacio Tornos Martinez
Some Qualcomm PCIe devices do not properly support Secondary Bus Reset
(SBR). These devices have no FLR capability and advertise NoSoftRst+
(blocking PM reset), leaving bus reset as the only available method.
However, bus reset does not work reliably for these devices.
The problem manifests in VFIO passthrough scenarios with these affected
devices:
- ath11k WiFi (17cb:1103): Normal VM operation works fine, including
clean shutdown/reboot. However, when the VM terminates uncleanly
(crash, force-off), VFIO attempts to reset the device before it can
be assigned to another VM. Without a working reset method, the device
remains in an undefined state, preventing reuse.
- ath12k WiFi (17cb:1107): Same behavior as ath11k.
- SDX62/SDX65 5G modems (17cb:0308): Never successfully initialize even
on first VM assignment without proper reset capability.
Disable bus reset for these devices (following the pattern of other
Atheros/Qualcomm devices) so alternative reset methods (d3cold or soft)
are used instead, which provide working reset capability.
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v4: Quirk code unchanged from v3
v3: https://lore.kernel.org/all/20260513122349.268753-2-jtornosm@redhat.com/
drivers/pci/quirks.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 000000000000..111111111111 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3789,6 +3789,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x1103, quirk_no_bus_reset); /* ath11k */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x1107, quirk_no_bus_reset); /* ath12k */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x0308, quirk_no_bus_reset); /* SDX62/SDX65 */
/*
* Root port on some Cavium CN8xxx chips do not successfully complete a bus
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] PCI: Add d3cold as general reset method
2026-05-18 12:48 ` [PATCH v4 1/3] PCI: Add d3cold as general reset method Jose Ignacio Tornos Martinez
@ 2026-05-18 13:27 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-18 13:27 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] Missing IOMMU preparation and completion calls in the `pci_d3cold_reset` flow.
- [High] Missing wait for device readiness (CRS polling) after transitioning from D3cold back to D0.
- [High] Bypassing device quirks and user constraints (`dev->no_d3cold` and `dev->d3cold_allowed`) for D3cold transitions.
--
commit 6ccb7429bcb1b8c8a16f329c1b8caf009c316653
Author: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Subject: PCI: Add d3cold as general reset method
This commit adds a new PCI reset method using D3cold power cycling for
single-function devices. It utilizes ACPI _PR3 power resources to physically
cut power to the device.
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8f7cfcc000901..839903b596982 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
[ ... ]
> +static int pci_d3cold_reset(struct pci_dev *dev, bool probe)
> +{
> + int ret;
> +
> + if (dev->multifunction)
> + return -ENOTTY;
> +
> + if (!pci_pr3_present(dev))
> + return -ENOTTY;
> +
> + if (probe)
> + return 0;
Could this transition devices into D3cold even if they have the state
explicitly disabled via quirks or user constraints?
Should this check dev->no_d3cold and dev->d3cold_allowed before proceeding
with the transition?
> +
> + if (dev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + ret = pci_set_power_state(dev, PCI_D3cold);
Does this reset method need to pause IOMMU fault handling and wait for
pending DMA transactions before dropping physical power?
Other reset methods like pci_pm_reset() call pci_dev_reset_iommu_prepare()
before performing the hardware reset. Is similar synchronization required
here to prevent IOMMU faults?
> + if (ret)
> + return ret;
> +
> + return pci_set_power_state(dev, PCI_D0);
> +}
Does the device require time to reinitialize its link and internal state
after returning to PCI_D0?
The generic reset handler will immediately invoke pci_dev_restore() after
this returns. Should this function call pci_dev_wait() to check for
Configuration Request Retry Status (CRS) clearance, similar to how
pci_pm_reset() waits?
Also, if pci_dev_reset_iommu_prepare() is needed earlier in this function,
should pci_dev_reset_iommu_done() be called here before returning?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260518124836.460805-1-jtornosm@redhat.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-18 12:48 ` [PATCH v4 2/3] PCI: Add soft reset method as last resort Jose Ignacio Tornos Martinez
@ 2026-05-18 13:48 ` sashiko-bot
2026-05-18 17:15 ` Alex Williamson
1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-18 13:48 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] pci_soft_reset() falsely reports a successful reset for NoSoftRst+ devices, destroying hardware isolation guarantees for VFIO passthrough.
- [High] pci_soft_reset() bypasses the PCI_DEV_FLAGS_NO_PM_RESET quirk, forcing unprotected hardware power state transitions on vulnerable devices.
--
commit 9f864e1927975542a72967bb27f8a02e42ade61b
Author: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
PCI: Add soft reset method as last resort
This commit adds a software-initiated reset method that attempts a D3hot to D0
transition as a last resort when all other reset methods fail. It extracts the
transition logic into a shared helper function used by both the standard power
management reset and the new fallback soft reset.
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 839903b596982..970928d09fe19 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
[ ... ]
> @@ -4491,6 +4474,38 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
> return ret;
> }
>
> +/**
> + * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
[ ... ]
> +static int pci_pm_reset(struct pci_dev *dev, bool probe)
> +{
> + u16 csr;
> +
> + if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
> + return -ENOTTY;
[ ... ]
> @@ -4530,6 +4545,42 @@ static int pci_d3cold_reset(struct pci_dev *dev, bool probe)
> return pci_set_power_state(dev, PCI_D0);
> }
>
> +/**
> + * pci_soft_reset - Software-initiated reset via D3hot as last resort
[ ... ]
> +static int pci_soft_reset(struct pci_dev *dev, bool probe)
> +{
> + if (pci_pm_reset(dev, true) == 0)
> + return -ENOTTY;
> +
> + if (pci_d3cold_reset(dev, true) == 0)
> + return -ENOTTY;
> +
> + if (!dev->pm_cap)
> + return -ENOTTY;
> +
> + if (probe)
> + return 0;
> +
> + return pci_do_d3hot_transition(dev);
> +}
Does this sequence introduce a regression by bypassing the
PCI_DEV_FLAGS_NO_PM_RESET quirk?
When pci_pm_reset() is called with probe set to true, it returns -ENOTTY if
the device has the PCI_DEV_FLAGS_NO_PM_RESET flag set. Since -ENOTTY is not 0,
pci_soft_reset() will proceed and unconditionally execute
pci_do_d3hot_transition().
Could this force a power state transition on vulnerable devices that were
explicitly blacklisted from power management resets?
Additionally, does bypassing the NoSoftRst check globally introduce a
regression in device sanitization for compliant hardware?
The PCI specification defines the NoSoftRst bit to indicate that a device
retains its internal state during a D3hot to D0 transition. If a compliant
device correctly implements NoSoftRst set to 1, this fallback method will
falsely report a successful reset without actually scrubbing the device
context.
Since security boundaries like VFIO passthrough rely on pci_reset_function()
to guarantee complete device sanitization between VMs, can this global
fallback allow state contamination or data leaks?
Would it be safer to handle devices that incorrectly advertise NoSoftRst via
device-specific quirks instead of a global bypass?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260518124836.460805-1-jtornosm@redhat.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-18 12:48 ` [PATCH v4 2/3] PCI: Add soft reset method as last resort Jose Ignacio Tornos Martinez
2026-05-18 13:48 ` sashiko-bot
@ 2026-05-18 17:15 ` Alex Williamson
2026-05-19 5:35 ` Jose Ignacio Tornos Martinez
1 sibling, 1 reply; 10+ messages in thread
From: Alex Williamson @ 2026-05-18 17:15 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez; +Cc: bhelgaas, linux-pci, linux-kernel, alex
On Mon, 18 May 2026 14:48:34 +0200
Jose Ignacio Tornos Martinez <jtornosm@redhat.com> wrote:
> Add a software-initiated "soft" reset method that attempts D3hot->D0
> transition as an absolute last resort when all other reset methods
> have failed.
>
> Some devices incorrectly advertise NoSoftRst+ (blocking PM reset) but
> the D3hot transition does provide sufficient reset for certain use cases,
> particularly VFIO passthrough scenarios. This method provides a "better
> than nothing" option when the device would otherwise have no reset
> capability.
>
> The method only becomes available when:
> - pci_pm_reset() is unavailable (typically blocked by NoSoftRst+)
> - pci_d3cold_reset() is unavailable (no platform _PR3 support)
> - Device has PM capability (required for D3hot transition)
>
> Extract the D3hot transition logic into a shared helper function
> (pci_do_d3hot_transition) used by both pci_pm_reset and pci_soft_reset.
>
> Reset hierarchy with this change:
> 1. device_specific
> 2. acpi
> 3. flr
> 4. af_flr
> 5. pm (proper method, checks NoSoftRst)
> 6. bus
> 7. cxl_bus
> 8. d3cold (requires _PR3)
> 9. soft (NEW - D3hot without NoSoftRst check, absolute last resort)
>
> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
> ---
> v4: Implements D3hot transition as last resort when pm/d3cold unavailable
> v3: https://lore.kernel.org/all/20260513122349.268753-1-jtornosm@redhat.com/
>
> drivers/pci/pci.c | 98 ++++++++++++++++++++++++++++++++++-----------
> include/linux/pci.h | 2 +-
> 2 files changed, 76 insertions(+), 24 deletions(-)
NAK. This cannot happen as a general case, it will cause vfio-pci to
report reset capabilities for essentially all devices, whether
validated or not.
The suggestion was that for devices where this has proven "better than
nothing", we could think about a device specific version of this,
matching devices IDs, not a fall-through for any device.
Given the "partial reset" nature of this, even on the target device, I
still wonder though whether userspace cannot already handle this by
forcing the power state through sysfs prior to assigning. Thanks,
Alex
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 839903b59698..8dad386bd65d 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -4437,6 +4437,43 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
> return ret;
> }
>
> +/**
> + * pci_do_d3hot_transition - Perform D3hot->D0 power state transition
> + * @dev: Device to transition
> + *
> + * Common helper to perform D3hot->D0 transition for PM-based reset methods.
> + * Handles IOMMU preparation, state transition, and waiting for device ready.
> + */
> +static int pci_do_d3hot_transition(struct pci_dev *dev)
> +{
> + u16 csr;
> + int ret;
> +
> + if (dev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + 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;
> + }
> +
> + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
> + csr &= ~PCI_PM_CTRL_STATE_MASK;
> + csr |= PCI_D3hot;
> + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
> + pci_dev_d3_sleep(dev);
> +
> + csr &= ~PCI_PM_CTRL_STATE_MASK;
> + csr |= PCI_D0;
> + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
> + pci_dev_d3_sleep(dev);
> +
> + ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
> + pci_dev_reset_iommu_done(dev);
> + return ret;
> +}
> +
> /**
> * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
> * @dev: Device to reset.
> @@ -4455,7 +4492,6 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
> static int pci_pm_reset(struct pci_dev *dev, bool probe)
> {
> u16 csr;
> - int ret;
>
> if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
> return -ENOTTY;
> @@ -4467,28 +4503,7 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
> if (probe)
> return 0;
>
> - if (dev->current_state != PCI_D0)
> - return -EINVAL;
> -
> - 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;
> - }
> -
> - csr &= ~PCI_PM_CTRL_STATE_MASK;
> - csr |= PCI_D3hot;
> - pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
> - pci_dev_d3_sleep(dev);
> -
> - csr &= ~PCI_PM_CTRL_STATE_MASK;
> - csr |= PCI_D0;
> - pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
> - pci_dev_d3_sleep(dev);
> -
> - ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
> - pci_dev_reset_iommu_done(dev);
> - return ret;
> + return pci_do_d3hot_transition(dev);
> }
>
> /**
> @@ -4530,6 +4545,42 @@ static int pci_d3cold_reset(struct pci_dev *dev, bool probe)
> return pci_set_power_state(dev, PCI_D0);
> }
>
> +/**
> + * pci_soft_reset - Software-initiated reset via D3hot as last resort
> + * @dev: PCI device to reset
> + * @probe: if true, check if soft reset is supported; if false, perform reset
> + *
> + * Attempt a software-initiated reset via D3hot->D0 transition as an absolute
> + * last resort when all other reset methods have failed. This method only
> + * becomes available if the device has PM capability, pci_pm_reset() is blocked
> + * (typically by NoSoftRst+), and pci_d3cold_reset() is not available.
> + *
> + * Some devices incorrectly advertise NoSoftRst+ but D3hot transition does
> + * provide sufficient reset for certain use cases (e.g., VFIO passthrough).
> + * This method provides a "better than nothing" option when the device would
> + * otherwise have no reset capability.
> + *
> + * Returns 0 if device can be/was reset this way, -ENOTTY if a better reset
> + * method is available (pm or d3cold) or device lacks PM capability, or other
> + * negative error code on failure.
> + */
> +static int pci_soft_reset(struct pci_dev *dev, bool probe)
> +{
> + if (pci_pm_reset(dev, true) == 0)
> + return -ENOTTY;
> +
> + if (pci_d3cold_reset(dev, true) == 0)
> + return -ENOTTY;
> +
> + if (!dev->pm_cap)
> + return -ENOTTY;
> +
> + if (probe)
> + return 0;
> +
> + return pci_do_d3hot_transition(dev);
> +}
> +
> /**
> * pcie_wait_for_link_status - Wait for link status change
> * @pdev: Device whose link to wait for.
> @@ -5105,6 +5156,7 @@ const struct pci_reset_fn_method pci_reset_fn_methods[] = {
> { pci_reset_bus_function, .name = "bus" },
> { cxl_reset_bus_function, .name = "cxl_bus" },
> { pci_d3cold_reset, .name = "d3cold" },
> + { pci_soft_reset, .name = "soft" },
> };
>
> /**
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 1ca7b880ead7..bcd2987b868b 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -51,7 +51,7 @@
> PCI_STATUS_PARITY)
>
> /* Number of reset methods used in pci_reset_fn_methods array in pci.c */
> -#define PCI_NUM_RESET_METHODS 9
> +#define PCI_NUM_RESET_METHODS 10
>
> #define PCI_RESET_PROBE true
> #define PCI_RESET_DO_RESET false
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-18 17:15 ` Alex Williamson
@ 2026-05-19 5:35 ` Jose Ignacio Tornos Martinez
2026-05-20 16:13 ` Alex Williamson
0 siblings, 1 reply; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-19 5:35 UTC (permalink / raw)
To: alex; +Cc: bhelgaas, jtornosm, linux-kernel, linux-pci
Hello Alex,
Thank you for the feedback. I understand the concern about reporting reset
capabilities for all devices.
Regarding the sysfs power state approach: I tested this, but the challenge
is that VFIO needs automatic reset during VM crash/reassignment. When a VM
terminates uncleanly, VFIO calls the device reset path automatically before
reassignment - there's no opportunity for userspace to manipulate sysfs power
state in that flow.
For the device-specific approach you mentioned, what if I modify the "soft"
method to require an explicit quirk flag? Something like:
static int pci_soft_reset(struct pci_dev *dev, bool probe)
{
/* Only available if device explicitly quirked for soft reset */
if (!(dev->dev_flags & PCI_DEV_FLAGS_ALLOW_SOFT_RESET))
return -ENOTTY;
if (pci_pm_reset(dev, true) == 0)
return -ENOTTY;
if (pci_d3cold_reset(dev, true) == 0)
return -ENOTTY;
if (!dev->pm_cap)
return -ENOTTY;
if (probe)
return 0;
return pci_do_d3hot_transition(dev);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x1103, quirk_allow_soft_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x1107, quirk_allow_soft_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_QCOM, 0x0308, quirk_allow_soft_reset);
This way:
- Only proven device IDs get soft reset capability (no broad reset reporting)
- Device-specific version matching device IDs (as you suggested)
- Generic infrastructure but explicit opt-in per device
- Different from v2: new method with quirk, not modifying pm reset behavior
Would this approach be acceptable?
Thanks
Best regards
José Ignacio
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-19 5:35 ` Jose Ignacio Tornos Martinez
@ 2026-05-20 16:13 ` Alex Williamson
2026-05-21 6:32 ` Jose Ignacio Tornos Martinez
0 siblings, 1 reply; 10+ messages in thread
From: Alex Williamson @ 2026-05-20 16:13 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez; +Cc: bhelgaas, linux-kernel, linux-pci, alex
On Tue, 19 May 2026 07:35:50 +0200
Jose Ignacio Tornos Martinez <jtornosm@redhat.com> wrote:
> Hello Alex,
>
> Thank you for the feedback. I understand the concern about reporting reset
> capabilities for all devices.
>
> Regarding the sysfs power state approach: I tested this, but the challenge
> is that VFIO needs automatic reset during VM crash/reassignment. When a VM
> terminates uncleanly, VFIO calls the device reset path automatically before
> reassignment - there's no opportunity for userspace to manipulate sysfs power
> state in that flow.
>
> For the device-specific approach you mentioned, what if I modify the "soft"
> method to require an explicit quirk flag? Something like:
>
> static int pci_soft_reset(struct pci_dev *dev, bool probe)
> {
> /* Only available if device explicitly quirked for soft reset */
> if (!(dev->dev_flags & PCI_DEV_FLAGS_ALLOW_SOFT_RESET))
> return -ENOTTY;
>
...
>
> Would this approach be acceptable?
Device specific resets are made for this scenario. Look at
pci_dev_specific_reset() and pci_dev_reset_methods[]. The supporting
evidence that this performs a worthwhile reset is still a bit weak, but
heuristically it seems better than nothing, which is what we're left
with otherwise. Reset via D3hot for a device that does not expose
NoSoftRst- is not something we should enable or endorse for any common
use case. Thanks,
Alex
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] PCI: Add soft reset method as last resort
2026-05-20 16:13 ` Alex Williamson
@ 2026-05-21 6:32 ` Jose Ignacio Tornos Martinez
0 siblings, 0 replies; 10+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-05-21 6:32 UTC (permalink / raw)
To: alex; +Cc: bhelgaas, jtornosm, linux-kernel, linux-pci
Hello Alex,
Thank you for the guidance.
OK, using pci_dev_reset_methods[] makes sense.
I'll implement device_specific reset entries for the Qualcomm devices using
pci_set_power_state(dev, D3cold), which automatically falls back to D3hot
when the platform doesn't support D3cold. This handles both scenarios
(platforms with and without _PR3).
I'll keep the general d3cold reset method (patch 1/3) as well, since it
provides value for other devices that need strict _PR3-based power cycling
without D3hot fallback. The device_specific entries are the Qualcomm-specific
workaround, while d3cold remains general infrastructure.
I'll also keep quirk_no_bus_reset as a safety net to prevent the known-broken
bus reset from being attempted. This ensures that if users override reset
methods via sysfs, they can still use d3cold (when _PR3 is available) without
accidentally falling back to the broken bus reset.
Thanks
Best regards
José Ignacio
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-05-21 6:32 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-18 12:48 [PATCH v4 0/3] PCI: Add d3cold/soft reset methods for devices with limited reset capability Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 1/3] PCI: Add d3cold as general reset method Jose Ignacio Tornos Martinez
2026-05-18 13:27 ` sashiko-bot
2026-05-18 12:48 ` [PATCH v4 2/3] PCI: Add soft reset method as last resort Jose Ignacio Tornos Martinez
2026-05-18 13:48 ` sashiko-bot
2026-05-18 17:15 ` Alex Williamson
2026-05-19 5:35 ` Jose Ignacio Tornos Martinez
2026-05-20 16:13 ` Alex Williamson
2026-05-21 6:32 ` Jose Ignacio Tornos Martinez
2026-05-18 12:48 ` [PATCH v4 3/3] PCI: Disable broken bus reset on Qualcomm devices Jose Ignacio Tornos Martinez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox