* [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
@ 2026-07-21 8:13 Jose Ignacio Tornos Martinez
2026-07-22 12:21 ` Manivannan Sadhasivam
2026-09-15 22:36 ` Bjorn Helgaas
0 siblings, 2 replies; 7+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-07-21 8:13 UTC (permalink / raw)
To: bhelgaas, alex, mani
Cc: jjohnson, linux-pci, linux-wireless, ath11k, ath12k, mhi,
linux-kernel, Jose Ignacio Tornos Martinez
Some Qualcomm PCIe devices (WCN6855/WCN7850 WLAN cards, SDX62/SDX65 modems)
lack working reset methods for VFIO passthrough scenarios. These devices
have no FLR capability, advertise NoSoftRst+ (blocking PM reset), and have
broken bus reset.
The problem manifests in VFIO passthrough scenarios:
- WCN6855 (17cb:1103) and WCN7850 (17cb:1107) WLAN devices:
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.
- SDX62/SDX65 (17cb:0308) 5G modems: Never successfully initialize even
on first VM assignment without proper reset capability.
Add device-specific reset methods using BAR-space hardware reset registers
that exist in these devices:
- WCN6855/WCN7850 WLAN devices use SoC global reset via BAR0 (sequence from
ath11k/ath12k driver: ath11k_pci_soc_global_reset(), ath11k_pci_sw_reset(),
ath11k_mhi_set_mhictrl_reset()):
- Write/clear reset bit at offset 0x3008
- Wait for PCIe link recovery (up to 5 seconds)
- Clear MHI controller SYSERR status at offset 0x38
- SDX62/SDX65 modem devices use MHI SoC reset via BAR0 (sequence from MHI
driver: mhi_soc_reset(), mhi_pci_reset_prepare()):
- Write reset request to offset 0xb0
- Wait 2 seconds for reset completion
These are true hardware reset mechanisms (not power management or firmware
error recovery), providing proper device reset for VFIO scenarios.
Testing was performed on desktop platforms with M.2 WLAN and modem cards
using M.2-to-PCIe adapters, including extensive force-reset cycling to
verify stability.
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v13: Address Alex Williamson feedback:
- Validate initial ioread32() with PCI_POSSIBLE_ERROR() before
read-modify-write to avoid writing error response back to device
on platforms with APEI/GHES error escalation
- Replace time_before()/msleep() polling loop with read_poll_timeout()
for robustness against scheduling delays and code simplification
v12: https://lore.kernel.org/all/20260630065815.199693-1-jtornosm@redhat.com/
drivers/pci/quirks.c | 116 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 431c021d7414..bd1e0742052e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -22,6 +22,7 @@
#include <linux/isa-dma.h> /* isa_dma_bridge_buggy */
#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
@@ -4240,6 +4241,118 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
return 0;
}
+#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET 0x3008
+#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V BIT(0)
+#define QUALCOMM_WLAN_MHICTRL 0x38
+#define QUALCOMM_WLAN_MHICTRL_RESET_MASK 0x2
+
+/*
+ * Qualcomm WLAN device-specific reset using SoC global reset via BAR0
+ * registers.
+ */
+static int reset_qualcomm_wlan(struct pci_dev *pdev, bool probe)
+{
+ void __iomem *bar;
+ u32 val;
+ u16 cmd;
+ int ret;
+
+ if (probe)
+ return 0;
+
+ if (pdev->current_state != PCI_D0)
+ return -EINVAL;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
+
+ bar = pci_iomap(pdev, 0, 0);
+ if (!bar) {
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ return -ENODEV;
+ }
+
+ val = ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+ if (PCI_POSSIBLE_ERROR(val)) {
+ ret = -ENODEV;
+ goto out_restore;
+ }
+ val |= QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
+ iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+ ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+
+ msleep(10);
+
+ val &= ~QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
+ iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+ ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+
+ msleep(10);
+
+ ret = read_poll_timeout(ioread32, val,
+ !PCI_POSSIBLE_ERROR(val),
+ 20 * USEC_PER_MSEC,
+ 5 * USEC_PER_SEC, false,
+ bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
+ if (ret) {
+ pci_err(pdev, "PCIe link failed to recover after reset\n");
+ goto out_restore;
+ }
+
+ /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set
+ * and thus need to set MHICTRL_RESET to clear SYSERR.
+ */
+ iowrite32(QUALCOMM_WLAN_MHICTRL_RESET_MASK, bar + QUALCOMM_WLAN_MHICTRL);
+ ioread32(bar + QUALCOMM_WLAN_MHICTRL);
+
+ msleep(10);
+
+out_restore:
+ pci_iounmap(pdev, bar);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ return ret;
+}
+
+#define MHI_SOC_RESET_REQ_OFFSET 0xb0
+#define MHI_SOC_RESET_REQ BIT(0)
+
+/*
+ * Qualcomm modem device-specific reset using MHI SoC reset via BAR0
+ * register.
+ */
+static int reset_qualcomm_modem(struct pci_dev *pdev, bool probe)
+{
+ void __iomem *bar;
+ u16 cmd;
+
+ if (probe)
+ return 0;
+
+ if (pdev->current_state != PCI_D0)
+ return -EINVAL;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
+
+ bar = pci_iomap(pdev, 0, 0);
+ if (!bar) {
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ return -ENODEV;
+ }
+
+ iowrite32(MHI_SOC_RESET_REQ, bar + MHI_SOC_RESET_REQ_OFFSET);
+ ioread32(bar + MHI_SOC_RESET_REQ_OFFSET);
+
+ /* Be sure device reset has been executed */
+ msleep(2000);
+
+ pci_iounmap(pdev, bar);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ return 0;
+}
+
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
@@ -4255,6 +4368,9 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
reset_chelsio_generic_dev },
{ PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
reset_hinic_vf_dev },
+ { PCI_VENDOR_ID_QCOM, 0x0308, reset_qualcomm_modem }, /* SDX62/SDX65 modems */
+ { PCI_VENDOR_ID_QCOM, 0x1103, reset_qualcomm_wlan }, /* WCN6855 WLAN */
+ { PCI_VENDOR_ID_QCOM, 0x1107, reset_qualcomm_wlan }, /* WCN7850 WLAN */
{ 0 }
};
--
2.54.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
2026-07-21 8:13 [PATCH v13] PCI: Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
@ 2026-07-22 12:21 ` Manivannan Sadhasivam
2026-09-14 12:46 ` Jose Ignacio Tornos Martinez
2026-09-15 22:36 ` Bjorn Helgaas
1 sibling, 1 reply; 7+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-22 12:21 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez
Cc: bhelgaas, alex, jjohnson, linux-pci, linux-wireless, ath11k,
ath12k, mhi, linux-kernel
On Tue, Jul 21, 2026 at 10:13:01AM +0200, Jose Ignacio Tornos Martinez wrote:
> Some Qualcomm PCIe devices (WCN6855/WCN7850 WLAN cards, SDX62/SDX65 modems)
> lack working reset methods for VFIO passthrough scenarios. These devices
> have no FLR capability, advertise NoSoftRst+ (blocking PM reset), and have
> broken bus reset.
>
> The problem manifests in VFIO passthrough scenarios:
>
> - WCN6855 (17cb:1103) and WCN7850 (17cb:1107) WLAN devices:
> 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.
>
> - SDX62/SDX65 (17cb:0308) 5G modems: Never successfully initialize even
> on first VM assignment without proper reset capability.
>
> Add device-specific reset methods using BAR-space hardware reset registers
> that exist in these devices:
>
> - WCN6855/WCN7850 WLAN devices use SoC global reset via BAR0 (sequence from
> ath11k/ath12k driver: ath11k_pci_soc_global_reset(), ath11k_pci_sw_reset(),
> ath11k_mhi_set_mhictrl_reset()):
> - Write/clear reset bit at offset 0x3008
> - Wait for PCIe link recovery (up to 5 seconds)
> - Clear MHI controller SYSERR status at offset 0x38
>
> - SDX62/SDX65 modem devices use MHI SoC reset via BAR0 (sequence from MHI
> driver: mhi_soc_reset(), mhi_pci_reset_prepare()):
> - Write reset request to offset 0xb0
> - Wait 2 seconds for reset completion
>
> These are true hardware reset mechanisms (not power management or firmware
> error recovery), providing proper device reset for VFIO scenarios.
>
> Testing was performed on desktop platforms with M.2 WLAN and modem cards
> using M.2-to-PCIe adapters, including extensive force-reset cycling to
> verify stability.
>
> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
- Mani
> ---
> v13: Address Alex Williamson feedback:
> - Validate initial ioread32() with PCI_POSSIBLE_ERROR() before
> read-modify-write to avoid writing error response back to device
> on platforms with APEI/GHES error escalation
> - Replace time_before()/msleep() polling loop with read_poll_timeout()
> for robustness against scheduling delays and code simplification
> v12: https://lore.kernel.org/all/20260630065815.199693-1-jtornosm@redhat.com/
>
> drivers/pci/quirks.c | 116 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 116 insertions(+)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 431c021d7414..bd1e0742052e 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -22,6 +22,7 @@
> #include <linux/isa-dma.h> /* isa_dma_bridge_buggy */
> #include <linux/init.h>
> #include <linux/iommu.h>
> +#include <linux/iopoll.h>
> #include <linux/delay.h>
> #include <linux/acpi.h>
> #include <linux/dmi.h>
> @@ -4240,6 +4241,118 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
> return 0;
> }
>
> +#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET 0x3008
> +#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V BIT(0)
> +#define QUALCOMM_WLAN_MHICTRL 0x38
> +#define QUALCOMM_WLAN_MHICTRL_RESET_MASK 0x2
> +
> +/*
> + * Qualcomm WLAN device-specific reset using SoC global reset via BAR0
> + * registers.
> + */
> +static int reset_qualcomm_wlan(struct pci_dev *pdev, bool probe)
> +{
> + void __iomem *bar;
> + u32 val;
> + u16 cmd;
> + int ret;
> +
> + if (probe)
> + return 0;
> +
> + if (pdev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + pci_read_config_word(pdev, PCI_COMMAND, &cmd);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
> +
> + bar = pci_iomap(pdev, 0, 0);
> + if (!bar) {
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> + return -ENODEV;
> + }
> +
> + val = ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + if (PCI_POSSIBLE_ERROR(val)) {
> + ret = -ENODEV;
> + goto out_restore;
> + }
> + val |= QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + val &= ~QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + ret = read_poll_timeout(ioread32, val,
> + !PCI_POSSIBLE_ERROR(val),
> + 20 * USEC_PER_MSEC,
> + 5 * USEC_PER_SEC, false,
> + bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + if (ret) {
> + pci_err(pdev, "PCIe link failed to recover after reset\n");
> + goto out_restore;
> + }
> +
> + /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set
> + * and thus need to set MHICTRL_RESET to clear SYSERR.
> + */
> + iowrite32(QUALCOMM_WLAN_MHICTRL_RESET_MASK, bar + QUALCOMM_WLAN_MHICTRL);
> + ioread32(bar + QUALCOMM_WLAN_MHICTRL);
> +
> + msleep(10);
> +
> +out_restore:
> + pci_iounmap(pdev, bar);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> +
> + return ret;
> +}
> +
> +#define MHI_SOC_RESET_REQ_OFFSET 0xb0
> +#define MHI_SOC_RESET_REQ BIT(0)
> +
> +/*
> + * Qualcomm modem device-specific reset using MHI SoC reset via BAR0
> + * register.
> + */
> +static int reset_qualcomm_modem(struct pci_dev *pdev, bool probe)
> +{
> + void __iomem *bar;
> + u16 cmd;
> +
> + if (probe)
> + return 0;
> +
> + if (pdev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + pci_read_config_word(pdev, PCI_COMMAND, &cmd);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
> +
> + bar = pci_iomap(pdev, 0, 0);
> + if (!bar) {
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> + return -ENODEV;
> + }
> +
> + iowrite32(MHI_SOC_RESET_REQ, bar + MHI_SOC_RESET_REQ_OFFSET);
> + ioread32(bar + MHI_SOC_RESET_REQ_OFFSET);
> +
> + /* Be sure device reset has been executed */
> + msleep(2000);
> +
> + pci_iounmap(pdev, bar);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> +
> + return 0;
> +}
> +
> static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
> { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
> reset_intel_82599_sfp_virtfn },
> @@ -4255,6 +4368,9 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
> reset_chelsio_generic_dev },
> { PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
> reset_hinic_vf_dev },
> + { PCI_VENDOR_ID_QCOM, 0x0308, reset_qualcomm_modem }, /* SDX62/SDX65 modems */
> + { PCI_VENDOR_ID_QCOM, 0x1103, reset_qualcomm_wlan }, /* WCN6855 WLAN */
> + { PCI_VENDOR_ID_QCOM, 0x1107, reset_qualcomm_wlan }, /* WCN7850 WLAN */
> { 0 }
> };
>
> --
> 2.54.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
2026-07-22 12:21 ` Manivannan Sadhasivam
@ 2026-09-14 12:46 ` Jose Ignacio Tornos Martinez
0 siblings, 0 replies; 7+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-09-14 12:46 UTC (permalink / raw)
To: bhelgaas, mani
Cc: alex, ath11k, ath12k, jjohnson, jtornosm, linux-kernel,
linux-pci, linux-wireless, mhi
Hi Bjorn,
Friendly ping on this patch, now almost two months old.
It has Mani's Reviewed-by and has been tested over 100+ VM crash/reset
cycles.
The approach was developed following Alex's and Mani's guidance through
the series, using device-specific hardware reset registers.
Without this, Qualcomm WLAN and modem devices cannot be reused after unclean
VM termination in VFIO passthrough.
Could you help me to know if there is anything blocking this in order to
move forward?
Thanks
Jose Ignacio
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
2026-07-21 8:13 [PATCH v13] PCI: Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
2026-07-22 12:21 ` Manivannan Sadhasivam
@ 2026-09-15 22:36 ` Bjorn Helgaas
2026-09-17 6:59 ` Jose Ignacio Tornos Martinez
1 sibling, 1 reply; 7+ messages in thread
From: Bjorn Helgaas @ 2026-09-15 22:36 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez
Cc: bhelgaas, alex, mani, jjohnson, linux-pci, linux-wireless,
ath11k, ath12k, mhi, linux-kernel
On Tue, Jul 21, 2026 at 10:13:01AM +0200, Jose Ignacio Tornos Martinez wrote:
> Some Qualcomm PCIe devices (WCN6855/WCN7850 WLAN cards, SDX62/SDX65 modems)
> lack working reset methods for VFIO passthrough scenarios. These devices
> have no FLR capability, advertise NoSoftRst+ (blocking PM reset), and have
> broken bus reset.
>
> The problem manifests in VFIO passthrough scenarios:
>
> - WCN6855 (17cb:1103) and WCN7850 (17cb:1107) WLAN devices:
> 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.
Just to clarify the commit log, I asked earlier about why this says
"when the VM terminates *uncleanly*", since VFIO resets the device on
every reassignment regardless of whether the VM termination was clean
or unclean.
But I didn't understand the answer (here's the question/answer from
https://lore.kernel.org/all/20260612142638.1243895-1-jtornosm@redhat.com/t/#m853c96910f7c842dca597f5c0a0f2fcc90d98be1):
>>> I don't know enough about VFIO, but I sort of expected that VFIO
>>> would reset devices between reassignment regardless of how a VM
>>> terminates. I guess that's not true?
> VFIO does attempt reset on every reassignment. Without a working
> reset method, the attempt fails and the device remains in undefined
> state. With this quirk, D3hot successfully resets the device
> allowing reassignment.
I guess you are saying that some kind of reset *does* work fine in
normal, clean VM termination? If reset works fine for normal VM
termination but not for VM crash, do we have any idea why they are
different?
> - SDX62/SDX65 (17cb:0308) 5G modems: Never successfully initialize even
> on first VM assignment without proper reset capability.
>
> Add device-specific reset methods using BAR-space hardware reset registers
> that exist in these devices:
>
> - WCN6855/WCN7850 WLAN devices use SoC global reset via BAR0 (sequence from
> ath11k/ath12k driver: ath11k_pci_soc_global_reset(), ath11k_pci_sw_reset(),
> ath11k_mhi_set_mhictrl_reset()):
> - Write/clear reset bit at offset 0x3008
> - Wait for PCIe link recovery (up to 5 seconds)
> - Clear MHI controller SYSERR status at offset 0x38
>
> - SDX62/SDX65 modem devices use MHI SoC reset via BAR0 (sequence from MHI
> driver: mhi_soc_reset(), mhi_pci_reset_prepare()):
> - Write reset request to offset 0xb0
> - Wait 2 seconds for reset completion
Since these basically copy code from other drivers, is there an
opportunity to remove it from those drivers and use this instead?
I see that the maintainers for drivers/net/wireless/ath/ath11k/pci.c
and drivers/bus/mhi/host/main.c are already cc'd, so this is something
that could be done later (if it's possible); doesn't need to be done
before merging this patch.
This looks like two patches squashed together. If there's any other
reason to touch this patch, I would split them apart.
> These are true hardware reset mechanisms (not power management or firmware
> error recovery), providing proper device reset for VFIO scenarios.
>
> Testing was performed on desktop platforms with M.2 WLAN and modem cards
> using M.2-to-PCIe adapters, including extensive force-reset cycling to
> verify stability.
>
> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
> ---
> v13: Address Alex Williamson feedback:
> - Validate initial ioread32() with PCI_POSSIBLE_ERROR() before
> read-modify-write to avoid writing error response back to device
> on platforms with APEI/GHES error escalation
> - Replace time_before()/msleep() polling loop with read_poll_timeout()
> for robustness against scheduling delays and code simplification
> v12: https://lore.kernel.org/all/20260630065815.199693-1-jtornosm@redhat.com/
>
> drivers/pci/quirks.c | 116 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 116 insertions(+)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 431c021d7414..bd1e0742052e 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -22,6 +22,7 @@
> #include <linux/isa-dma.h> /* isa_dma_bridge_buggy */
> #include <linux/init.h>
> #include <linux/iommu.h>
> +#include <linux/iopoll.h>
> #include <linux/delay.h>
> #include <linux/acpi.h>
> #include <linux/dmi.h>
> @@ -4240,6 +4241,118 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
> return 0;
> }
>
> +#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET 0x3008
> +#define QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V BIT(0)
> +#define QUALCOMM_WLAN_MHICTRL 0x38
> +#define QUALCOMM_WLAN_MHICTRL_RESET_MASK 0x2
> +
> +/*
> + * Qualcomm WLAN device-specific reset using SoC global reset via BAR0
> + * registers.
> + */
> +static int reset_qualcomm_wlan(struct pci_dev *pdev, bool probe)
> +{
> + void __iomem *bar;
> + u32 val;
> + u16 cmd;
> + int ret;
> +
> + if (probe)
> + return 0;
> +
> + if (pdev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + pci_read_config_word(pdev, PCI_COMMAND, &cmd);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
> +
> + bar = pci_iomap(pdev, 0, 0);
> + if (!bar) {
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> + return -ENODEV;
> + }
> +
> + val = ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + if (PCI_POSSIBLE_ERROR(val)) {
> + ret = -ENODEV;
> + goto out_restore;
> + }
> + val |= QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + val &= ~QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + ret = read_poll_timeout(ioread32, val,
> + !PCI_POSSIBLE_ERROR(val),
> + 20 * USEC_PER_MSEC,
> + 5 * USEC_PER_SEC, false,
> + bar + QUALCOMM_WLAN_PCIE_SOC_GLOBAL_RESET);
> + if (ret) {
> + pci_err(pdev, "PCIe link failed to recover after reset\n");
> + goto out_restore;
> + }
> +
> + /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set
> + * and thus need to set MHICTRL_RESET to clear SYSERR.
> + */
> + iowrite32(QUALCOMM_WLAN_MHICTRL_RESET_MASK, bar + QUALCOMM_WLAN_MHICTRL);
> + ioread32(bar + QUALCOMM_WLAN_MHICTRL);
> +
> + msleep(10);
> +
> +out_restore:
> + pci_iounmap(pdev, bar);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> +
> + return ret;
> +}
> +
> +#define MHI_SOC_RESET_REQ_OFFSET 0xb0
> +#define MHI_SOC_RESET_REQ BIT(0)
> +
> +/*
> + * Qualcomm modem device-specific reset using MHI SoC reset via BAR0
> + * register.
> + */
> +static int reset_qualcomm_modem(struct pci_dev *pdev, bool probe)
> +{
> + void __iomem *bar;
> + u16 cmd;
> +
> + if (probe)
> + return 0;
> +
> + if (pdev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + pci_read_config_word(pdev, PCI_COMMAND, &cmd);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
> +
> + bar = pci_iomap(pdev, 0, 0);
> + if (!bar) {
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> + return -ENODEV;
> + }
> +
> + iowrite32(MHI_SOC_RESET_REQ, bar + MHI_SOC_RESET_REQ_OFFSET);
> + ioread32(bar + MHI_SOC_RESET_REQ_OFFSET);
> +
> + /* Be sure device reset has been executed */
> + msleep(2000);
> +
> + pci_iounmap(pdev, bar);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> +
> + return 0;
> +}
> +
> static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
> { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
> reset_intel_82599_sfp_virtfn },
> @@ -4255,6 +4368,9 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
> reset_chelsio_generic_dev },
> { PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
> reset_hinic_vf_dev },
> + { PCI_VENDOR_ID_QCOM, 0x0308, reset_qualcomm_modem }, /* SDX62/SDX65 modems */
> + { PCI_VENDOR_ID_QCOM, 0x1103, reset_qualcomm_wlan }, /* WCN6855 WLAN */
> + { PCI_VENDOR_ID_QCOM, 0x1107, reset_qualcomm_wlan }, /* WCN7850 WLAN */
> { 0 }
> };
>
> --
> 2.54.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
2026-09-15 22:36 ` Bjorn Helgaas
@ 2026-09-17 6:59 ` Jose Ignacio Tornos Martinez
0 siblings, 0 replies; 7+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-09-17 6:59 UTC (permalink / raw)
To: helgaas
Cc: alex, ath11k, ath12k, bhelgaas, jjohnson, jtornosm, linux-kernel,
linux-pci, linux-wireless, mani, mhi
Hi Bjorn,
Thanks for the review.
> I guess you are saying that some kind of reset *does* work
> fine in normal, clean VM termination? If reset works fine
> for normal VM termination but not for VM crash, do we have
> any idea why they are different?
It depends on the device:
- For the modems (SDX62/SDX65), without a proper reset
capability, these devices never successfully initialize
even on first VM assignment.
- For the WLAN devices (WCN6855/WCN7850), the reset fails
in both cases, but on clean VM shutdown the guest driver's
.shutdown/.remove callbacks properly deinitialize the device
(stop DMA, disable interrupts, etc.), so it ends up in a
known-good state even without a successful reset. On unclean
termination (crash, force-off), the guest driver callbacks
never run, the device stays in an undefined state, and
without a working reset it cannot be reused.
I will try to clarify this better in the commit messages for v14.
> Since these basically copy code from other drivers, is there
> an opportunity to remove it from those drivers and use this
> instead?
Yes, that could be a follow-up after this lands.
> This looks like two patches squashed together. If there's
> any other reason to touch this patch, I would split them
> apart.
Ok, I will split the WLAN and modem resets into separate
patches for v14.
Thanks
Best regards
Jose Ignacio
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
2026-07-22 11:28 ` Jose Ignacio Tornos Martinez
@ 2026-07-22 12:17 ` Manivannan Sadhasivam
0 siblings, 0 replies; 7+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-22 12:17 UTC (permalink / raw)
To: Jose Ignacio Tornos Martinez
Cc: bhelgaas, alex, sashiko-bot, sashiko-reviews, jjohnson,
linux-pci, linux-wireless, ath11k, ath12k, mhi, linux-kernel
On Wed, Jul 22, 2026 at 01:28:13PM +0200, Jose Ignacio Tornos Martinez wrote:
> > [Severity: High]
> > Will this sequence of ioread32 flush reads and
> > read_poll_timeout trigger Master Aborts on architectures
> > with strict error handling?
> >
> > The SoC global reset explicitly drops the device PCIe link.
> > Performing ioread32 flush reads immediately after asserting
> > the reset, and then actively polling the disconnected MMIO
> > space with read_poll_timeout while the link recovers, can
> > result in Unsupported Request errors.
> >
> > On strict platforms like ARM64 or x86 servers with APEI/GHES
> > Firmware First error handling, these can escalate to fatal
> > Uncorrectable Errors and cause a host kernel panic when a
> > guest VM exits.
> >
> > Should this avoid MMIO flush reads during these reset
> > sequences and instead use fixed delays to safely bridge the
> > link-down period?
>
> The SoC global reset at 0x3008 does not immediately drop the
> PCIe link. The flush reads execute while the device is still
> responsive - the actual reset takes effect during the
> subsequent msleep. The ath11k/ath12k drivers perform the same
> register accesses during this reset sequence, including on
> ARM64 Qualcomm platforms, without issues.
>
Yes, Qcom devices supporting SoC reset have a mechanism to keep the PCIe link
alive (in L0/L1) when the reset gets triggered in the device. So the register
access is available throughout the reset cycle.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v13] PCI: Add device-specific reset for Qualcomm devices
[not found] <20260721082933.7B5A41F000E9@smtp.kernel.org>
@ 2026-07-22 11:28 ` Jose Ignacio Tornos Martinez
2026-07-22 12:17 ` Manivannan Sadhasivam
0 siblings, 1 reply; 7+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-07-22 11:28 UTC (permalink / raw)
To: bhelgaas, alex, mani
Cc: jtornosm, sashiko-bot, sashiko-reviews, jjohnson, linux-pci,
linux-wireless, ath11k, ath12k, mhi, linux-kernel
> [Severity: High]
> Will this sequence of ioread32 flush reads and
> read_poll_timeout trigger Master Aborts on architectures
> with strict error handling?
>
> The SoC global reset explicitly drops the device PCIe link.
> Performing ioread32 flush reads immediately after asserting
> the reset, and then actively polling the disconnected MMIO
> space with read_poll_timeout while the link recovers, can
> result in Unsupported Request errors.
>
> On strict platforms like ARM64 or x86 servers with APEI/GHES
> Firmware First error handling, these can escalate to fatal
> Uncorrectable Errors and cause a host kernel panic when a
> guest VM exits.
>
> Should this avoid MMIO flush reads during these reset
> sequences and instead use fixed delays to safely bridge the
> link-down period?
The SoC global reset at 0x3008 does not immediately drop the
PCIe link. The flush reads execute while the device is still
responsive - the actual reset takes effect during the
subsequent msleep. The ath11k/ath12k drivers perform the same
register accesses during this reset sequence, including on
ARM64 Qualcomm platforms, without issues.
The read_poll_timeout polling for link recovery follows the
same pattern used elsewhere in the PCI subsystem for waiting
on device responses after reset.
Tested over 100+ VM crash/reset cycles on x86 with VFIO
passthrough without errors.
> [Severity: High]
> Could this immediate ioread32 flush read also trigger a
> fatal Master Abort if the link drops instantly after writing
> the MHI SoC reset request?
Same as above - the MHI SoC reset does not instantly drop the
PCIe link. The flush read completes before the reset takes
effect, and the 2-second delay covers the actual reset period.
This replicates the MHI driver behavior
(mhi_pci_reset_prepare()).
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-17 6:59 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-21 8:13 [PATCH v13] PCI: Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
2026-07-22 12:21 ` Manivannan Sadhasivam
2026-09-14 12:46 ` Jose Ignacio Tornos Martinez
2026-09-15 22:36 ` Bjorn Helgaas
2026-09-17 6:59 ` Jose Ignacio Tornos Martinez
[not found] <20260721082933.7B5A41F000E9@smtp.kernel.org>
2026-07-22 11:28 ` Jose Ignacio Tornos Martinez
2026-07-22 12:17 ` Manivannan Sadhasivam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®