* [PATCH v14 1/2] PCI: Add device-specific reset for Qualcomm SDX62/SDX65 modems
2026-09-17 7:16 [PATCH v14 0/2] PCI: Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
@ 2026-09-17 7:16 ` Jose Ignacio Tornos Martinez
2026-09-17 7:16 ` [PATCH v14 2/2] PCI: Add device-specific reset for Qualcomm WCN6855/WCN7850 WLAN Jose Ignacio Tornos Martinez
1 sibling, 0 replies; 3+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-09-17 7:16 UTC (permalink / raw)
To: bhelgaas, alex, mani
Cc: jjohnson, linux-pci, linux-wireless, ath11k, ath12k, mhi,
linux-kernel, Jose Ignacio Tornos Martinez
Qualcomm SDX62/SDX65 5G modems (17cb:0308) lack working reset methods for
VFIO passthrough scenarios. These devices have no FLR capability, advertise
NoSoftRst+ (blocking PM reset), and have broken bus reset (addressed by
quirk_no_bus_reset, merged for v7.2).
VFIO attempts to reset devices on every reassignment. Without a proper
reset capability, these devices never successfully initialize even on first
VM assignment.
Add a device-specific reset method using BAR-space hardware reset registers
that exist in these devices.
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
This is a true hardware reset mechanism (not power management or firmware
error recovery), providing proper device reset for VFIO scenarios.
Testing shows stable operation over 109 VM crash/reset cycles. Device-
specific reset is position #1 in the reset hierarchy, so these Qualcomm
devices will use hardware reset as their primary reset method.
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
v14: Address Bjorn Helgaas feedback:
- Split WLAN and modem resets into two separate patches
- No code changes from v13, only patch split and commit message
clarification (Mani's Reviewed-by retained)
v13: https://lore.kernel.org/all/20260915223634.GA878346@bhelgaas/
drivers/pci/quirks.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index de9bbccda21f..e72af7d2c775 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4230,6 +4230,45 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
return 0;
}
+#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 },
@@ -4245,6 +4284,7 @@ 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 */
{ 0 }
};
--
2.54.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v14 2/2] PCI: Add device-specific reset for Qualcomm WCN6855/WCN7850 WLAN
2026-09-17 7:16 [PATCH v14 0/2] PCI: Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
2026-09-17 7:16 ` [PATCH v14 1/2] PCI: Add device-specific reset for Qualcomm SDX62/SDX65 modems Jose Ignacio Tornos Martinez
@ 2026-09-17 7:16 ` Jose Ignacio Tornos Martinez
1 sibling, 0 replies; 3+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-09-17 7:16 UTC (permalink / raw)
To: bhelgaas, alex, mani
Cc: jjohnson, linux-pci, linux-wireless, ath11k, ath12k, mhi,
linux-kernel, Jose Ignacio Tornos Martinez
Qualcomm WCN6855 (17cb:1103) and WCN7850 (17cb:1107) WLAN devices lack
working reset methods for VFIO passthrough scenarios. These devices have no
FLR capability, advertise NoSoftRst+ (blocking PM reset), and have broken
bus reset (addressed by quirk_no_bus_reset, merged for v7.2).
VFIO attempts to reset devices on every reassignment. Without a working
reset method, the attempt fails. On clean VM shutdown, the guest driver
properly deinitializes the device via .shutdown/.remove callbacks, leaving
it in a usable state despite the failed reset. However, on unclean VM
termination (crash, force-off), the guest driver callbacks are not
triggered, the device remains in an undefined state (DMA active, interrupts
enabled, etc.), and without a working reset it cannot be reused.
Add a device-specific reset method 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
This is a true hardware reset mechanism (not power management or firmware
error recovery), providing proper device reset for VFIO scenarios.
Testing shows stable operation over 100+ VM crash/reset cycles, compared
to previous approaches that failed after ~30 cycles. Device-specific reset
is position #1 in the reset hierarchy, so these Qualcomm devices will use
hardware reset as their primary reset method.
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
v14: Address Bjorn Helgaas feedback:
- Split WLAN and modem resets into two separate patches
- Clarify commit message: VFIO resets on every reassignment, clean
shutdown leaves device in usable state via driver callbacks, but
unclean termination is where the lack of reset is critical
- No code changes from v13, only patch split and commit message
clarification (Mani's Reviewed-by retained)
v13: https://lore.kernel.org/all/20260915223634.GA878346@bhelgaas/
drivers/pci/quirks.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e72af7d2c775..e800dd517614 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>
@@ -4230,6 +4231,79 @@ 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)
@@ -4285,6 +4359,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ 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] 3+ messages in thread