From: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
To: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>,
bhelgaas@google.com, alex@shazbot.org, mani@kernel.org
Cc: jjohnson@kernel.org, linux-pci@vger.kernel.org,
linux-wireless@vger.kernel.org, ath11k@lists.infradead.org,
ath12k@lists.infradead.org, mhi@lists.linux.dev,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v10] Add device-specific reset for Qualcomm devices
Date: Wed, 24 Jun 2026 15:47:12 +0800 [thread overview]
Message-ID: <4cdfb71b-2ef8-4985-8294-c4a29e37faa3@oss.qualcomm.com> (raw)
In-Reply-To: <20260623183115.1585273-1-jtornosm@redhat.com>
On 6/24/2026 2:31 AM, Jose Ignacio Tornos Martinez wrote:
> Some Qualcomm PCIe devices (WCN6855/WCN7850 WiFi 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) WiFi 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 WiFi 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 WiFi 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>
> ---
> v10:
> - Complete redesign based on maintainer feedback (Manivannan Sadhasivam,
> Alex Williamson): use actual hardware reset registers from
> device drivers instead of D3hot power cycling
> v9: https://lore.kernel.org/all/20260612142638.1243895-1-jtornosm@redhat.com/
>
> drivers/pci/quirks.c | 118 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 118 insertions(+)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 431c021d7414..8ad3f214e520 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -4240,6 +4240,121 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
> return 0;
> }
>
> +#define QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET 0x3008
> +#define QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET_V BIT(0)
> +#define QUALCOMM_WIFI_MHISTATUS 0x48
> +#define QUALCOMM_WIFI_MHICTRL 0x38
> +#define QUALCOMM_WIFI_MHICTRL_RESET_MASK 0x2
> +
> +/*
> + * Qualcomm WiFi device-specific reset using SoC global reset via BAR0
> + * registers.
> + */
> +static int reset_qualcomm_wifi(struct pci_dev *pdev, bool probe)
> +{
> + bool link_recovered = false;
> + unsigned long timeout;
> + void __iomem *bar;
> + u32 val;
> + 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;
> + }
> +
> + val = ioread32(bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET is beyond the first 4K bar area hence requires MHI
wakeup before accessing, see [1]. the wakeup callback for WCN6855 is
ath11k_pci_bus_wake_up() which calls mhi_device_get_sync(). Not sure how this can be done
here. Maybe Mani can provide some hints?
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ath/ath11k/pcic.c#n216
> + val |= QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + val &= ~QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET_V;
> + iowrite32(val, bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
> + ioread32(bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
> +
> + msleep(10);
> +
> + timeout = jiffies + msecs_to_jiffies(5000);
> + while (time_before(jiffies, timeout)) {
> + val = ioread32(bar + QUALCOMM_WIFI_PCIE_SOC_GLOBAL_RESET);
> + if (val != 0xffffffff) {
> + link_recovered = true;
> + break;
> + }
> + msleep(20);
> + }
> +
> + if (!link_recovered) {
> + 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_WIFI_MHICTRL_RESET_MASK, bar + QUALCOMM_WIFI_MHICTRL);
> + ioread32(bar + QUALCOMM_WIFI_MHICTRL);
> +
> + msleep(10);
> +
> +out_restore:
> + pci_iounmap(pdev, bar);
> + pci_write_config_word(pdev, PCI_COMMAND, cmd);
> +
> + return link_recovered ? 0 : -ETIMEDOUT;
> +}
> +
> +#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 +4370,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, 0x1103, reset_qualcomm_wifi }, /* WCN6855 WiFi */
> + { PCI_VENDOR_ID_QCOM, 0x1107, reset_qualcomm_wifi }, /* WCN7850 WiFi */
> + { PCI_VENDOR_ID_QCOM, 0x0308, reset_qualcomm_modem }, /* SDX62/SDX65 modems */
> { 0 }
> };
>
next prev parent reply other threads:[~2026-06-24 7:47 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 18:31 [PATCH v10] Add device-specific reset for Qualcomm devices Jose Ignacio Tornos Martinez
2026-06-24 7:47 ` Baochen Qiang [this message]
2026-06-25 10:35 ` Jose Ignacio Tornos Martinez
2026-06-25 13:03 ` Manivannan Sadhasivam
2026-06-29 9:44 ` Baochen Qiang
2026-06-25 13:46 ` Manivannan Sadhasivam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4cdfb71b-2ef8-4985-8294-c4a29e37faa3@oss.qualcomm.com \
--to=baochen.qiang@oss.qualcomm.com \
--cc=alex@shazbot.org \
--cc=ath11k@lists.infradead.org \
--cc=ath12k@lists.infradead.org \
--cc=bhelgaas@google.com \
--cc=jjohnson@kernel.org \
--cc=jtornosm@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=mani@kernel.org \
--cc=mhi@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox