* [PATCH 0/2] wifi: ath12k: Fix operation under virtio @ 2026-05-05 17:24 Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 1/2] wifi: ath12k: skip PCIe global reset on initial power-up Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs Nazar Mokrynskyi 0 siblings, 2 replies; 5+ messages in thread From: Nazar Mokrynskyi @ 2026-05-05 17:24 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, jeff.johnson, Nazar Mokrynskyi I've been struggling with ath12k and even ath11k for years: https://forum.openwrt.org/t/qcn9274-crashes-the-system-during-driver-load/239491?u=nazar-pc https://forum.openwrt.org/t/qcn9074-doesnt-initialize-on-x86-64/163288?u=nazar-pc With these patches it is finally possible to use QCN9274 under KVM with virtio. First patch avoids global reset, allowing module to power on properly. Similar patch should probably be added for ath11k too. Without this patch I was getting the following: ``` [ 6.856855] ath12k_pci 0000:01:00.0: BAR 0 [mem 0xfc600000-0xfc7fffff 64bit]: assigned [ 6.879292] ath12k_pci 0000:01:00.0: MSI vectors: 16 [ 6.883931] ath12k_pci 0000:01:00.0: Hardware name: qcn9274 hw2.0 [ 6.990901] ath12k_pci 0000:01:00.0: link down error during global reset [ 7.998602] ath12k_pci 0000:01:00.0: link failed to recover after global reset [ 8.011545] mhi mhi0: BHI offset: 0xffffffff is out of range: 0x200000 [ 8.013095] ath12k_pci 0000:01:00.0: failed to set mhi state: INIT(0) [ 8.014588] ath12k_pci 0000:01:00.0: failed to start mhi: -34 [ 8.016025] ath12k_pci 0000:01:00.0: failed to power up :-34 [ 8.050113] ath12k_pci 0000:01:00.0: failed to create soc 0 core: -34 [ 8.053079] ath12k_pci 0000:01:00.0: unable to create hw group [ 8.090241] ath12k_pci 0000:01:00.0: failed to init core: -34 [ 8.554526] ath12k_pci 0000:01:00.0: probe with driver ath12k_pci failed with error -34 ``` With the patch the process goes further: ``` [ 6.897009] ath12k_pci 0000:01:00.0: BAR 0 [mem 0xfc600000-0xfc7fffff 64bit]: assigned [ 6.906501] ath12k_pci 0000:01:00.0: MSI vectors: 16 [ 6.909033] ath12k_pci 0000:01:00.0: Hardware name: qcn9274 hw2.0 [ 6.959630] mhi mhi0: Requested to power ON [ 6.960899] mhi mhi0: Power on setup success [ 7.128588] mhi mhi0: Wait for device to enter SBL or Mission mode [ 7.659325] ath12k_pci 0000:01:00.0: qmi dma allocation failed (20971520 B type 1), will try later with small size [ 7.670187] ath12k_pci 0000:01:00.0: memory type 10 not supported [ 7.674957] kmodloader: done loading kernel modules from /etc/modules.d/* [ 7.683773] ath12k_pci 0000:01:00.0: chip_id 0x0 chip_family 0xb board_id 0x1019 soc_id 0x401a2200 [ 7.688137] ath12k_pci 0000:01:00.0: fw_version 0x160484db fw_build_timestamp 2025-12-09 20:09 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 [ 10.611560] ath12k_pci 0000:01:00.0: Invalid module id 2 [ 10.616467] ath12k_pci 0000:01:00.0: failed to parse tlv -22 [ 10.747508] debugfs: File 'simulate_fw_crash' in directory 'pci-0000:01:00.0' already present! [ 10.752188] debugfs: File 'device_dp_stats' in directory 'pci-0000:01:00.0' already present! [ 10.770705] ieee80211 phy0: copying sband (band 1) due to VHT EXT NSS BW flag [ 10.774844] debugfs: File 'ath12k' in directory 'phy0' already present! [ 13.968334] ath12k_pci 0000:01:00.0: failed to send WMI_PDEV_SET_PARAM cmd [ 13.971771] ath12k_pci 0000:01:00.0: failed to set ac override for ARP: -108 [ 13.975315] ath12k_pci 0000:01:00.0: fail to start mac operations in pdev idx 0 ret -108 [ 14.123699] ath12k_pci 0000:01:00.0: link down error during global reset [ 14.167537] mhi mhi0: BHI offset: 0xffffffff is out of range: 0x200000 [ 14.169031] ath12k_pci 0000:01:00.0: failed to set mhi state: INIT(0) [ 14.170504] ath12k_pci 0000:01:00.0: failed to start mhi: -34 ``` Second patch fixes an issue I had in OpenWRT, which may have been caused by firmware upgrade: ``` [ 10.611560] ath12k_pci 0000:01:00.0: Invalid module id 2 [ 10.616467] ath12k_pci 0000:01:00.0: failed to parse tlv -22 ``` My understanding is that it is fine to ignore unknown capability of the firmware, it should not be required if driver doesn't know about it anyway. I noticed a very similar code in ath11k, but wasn't sure if the change is needed there too, so skipped it. Though I have a strong suspicion the same firmware mismatch might happen there too. With both of those I can finally use QCN9274 under KVM virtual machine with virtio, at least with `pci=noaer` on the host. Without `pci=noaer` the module still boots and works properly, but any attempt to shut down or reboot inevitably crashes the host, which I reported to vfio maintainers, but I'd appreciate cooperation from ath12k maintainers too: https://lore.kernel.org/kvm/70de9b8f-b7c7-481b-8cb1-931e3b82eb0e@mokrynskyi.com/ Nazar Mokrynskyi (2): wifi: ath12k: skip PCIe global reset on initial power-up wifi: ath12k: skip unknown direct buffer ring module IDs drivers/net/wireless/ath/ath12k/pci.c | 3 ++- drivers/net/wireless/ath/ath12k/wmi.c | 12 ++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] wifi: ath12k: skip PCIe global reset on initial power-up 2026-05-05 17:24 [PATCH 0/2] wifi: ath12k: Fix operation under virtio Nazar Mokrynskyi @ 2026-05-05 17:24 ` Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs Nazar Mokrynskyi 1 sibling, 0 replies; 5+ messages in thread From: Nazar Mokrynskyi @ 2026-05-05 17:24 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, jeff.johnson, Nazar Mokrynskyi ath12k_pci_sw_reset() unconditionally calls ath12k_pci_soc_global_reset() regardless of whether the device is being powered up for the first time or recovering from a previous run. The global reset drops the PCIe link and relies on the host root complex to perform physical link retraining before the MHI BHI register can be accessed. When the device is passed through to a VM via VFIO, no physical link retraining occurs after the reset since QEMU's virtual PCIe bridge does not implement hardware LTSSM negotiation. As a result, all subsequent MMIO reads return 0xffffffff and MHI initialization fails with -EREMOTEIO. On initial power-up, vfio-pci has already performed a Function Level Reset before handing the device to the guest driver, placing it in a known clean state equivalent to what the global reset achieves. The global reset is therefore redundant on power-up and only necessary on the shutdown/recovery path where it tears down an already-running firmware. Skip ath12k_pci_soc_global_reset() when power_on is true to allow MHI initialization to succeed under VFIO passthrough without affecting bare metal behavior. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 Signed-off-by: Nazar Mokrynskyi <nazar@mokrynskyi.com> --- drivers/net/wireless/ath/ath12k/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 375277ca2..a3d7aeb72 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -303,7 +303,8 @@ static void ath12k_pci_sw_reset(struct ath12k_base *ab, bool power_on) ath12k_mhi_clear_vector(ab); ath12k_pci_clear_dbg_registers(ab); - ath12k_pci_soc_global_reset(ab); + if (!power_on) + ath12k_pci_soc_global_reset(ab); ath12k_mhi_set_mhictrl_reset(ab); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs 2026-05-05 17:24 [PATCH 0/2] wifi: ath12k: Fix operation under virtio Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 1/2] wifi: ath12k: skip PCIe global reset on initial power-up Nazar Mokrynskyi @ 2026-05-05 17:24 ` Nazar Mokrynskyi 2026-05-11 19:02 ` Jeff Johnson 1 sibling, 1 reply; 5+ messages in thread From: Nazar Mokrynskyi @ 2026-05-05 17:24 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, jeff.johnson, Nazar Mokrynskyi The firmware may advertise direct buffer ring capabilities for module IDs beyond what the driver currently knows about (WMI_DIRECT_BUF_MAX). This happens with newer firmware versions that support additional ring types not yet implemented in the driver. The current code treats an unknown module_id as a fatal error, returning -EINVAL and tearing down the entire driver initialization. This is incorrect: the driver only needs to set up rings for types it uses (SPECTRAL=0, CFR=1) and can safely ignore capability advertisements for unknown types. Change the unknown module_id handling to skip the entry with a debug message rather than failing, allowing initialization to proceed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 Signed-off-by: Nazar Mokrynskyi <nazar@mokrynskyi.com> --- drivers/net/wireless/ath/ath12k/wmi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 484fdd3b1..0e776a8d8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4814,10 +4814,10 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, dir_buff_caps = ab->db_caps; for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) { if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) { - ath12k_warn(ab, "Invalid module id %d\n", - le32_to_cpu(dma_caps[i].module_id)); - ret = -EINVAL; - goto free_dir_buff; + ath12k_dbg(ab, ATH12K_DBG_WMI, + "Skipping unknown direct buf ring module id %d\n", + le32_to_cpu(dma_caps[i].module_id)); + continue; } dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id); @@ -4829,10 +4829,6 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, } return 0; - -free_dir_buff: - ath12k_wmi_free_dbring_caps(ab); - return ret; } static void -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs 2026-05-05 17:24 ` [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs Nazar Mokrynskyi @ 2026-05-11 19:02 ` Jeff Johnson 2026-05-11 20:10 ` Nazar Mokrynskyi 0 siblings, 1 reply; 5+ messages in thread From: Jeff Johnson @ 2026-05-11 19:02 UTC (permalink / raw) To: Nazar Mokrynskyi, ath12k; +Cc: linux-wireless On 5/5/2026 10:24 AM, Nazar Mokrynskyi wrote: > The firmware may advertise direct buffer ring capabilities for module > IDs beyond what the driver currently knows about (WMI_DIRECT_BUF_MAX). > This happens with newer firmware versions that support additional ring > types not yet implemented in the driver. What "newer firmware version" are you using that has this issue? Can you share the "Skipping unknown direct buf ring module id" logs from your modified driver? > > The current code treats an unknown module_id as a fatal error, returning > -EINVAL and tearing down the entire driver initialization. This is > incorrect: the driver only needs to set up rings for types it uses > (SPECTRAL=0, CFR=1) and can safely ignore capability advertisements for > unknown types. > > Change the unknown module_id handling to skip the entry with a debug > message rather than failing, allowing initialization to proceed. > > Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 > > Signed-off-by: Nazar Mokrynskyi <nazar@mokrynskyi.com> > --- > drivers/net/wireless/ath/ath12k/wmi.c | 12 ++++-------- > 1 file changed, 4 insertions(+), 8 deletions(-) > > diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c > index 484fdd3b1..0e776a8d8 100644 > --- a/drivers/net/wireless/ath/ath12k/wmi.c > +++ b/drivers/net/wireless/ath/ath12k/wmi.c > @@ -4814,10 +4814,10 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, > dir_buff_caps = ab->db_caps; > for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) { > if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) { > - ath12k_warn(ab, "Invalid module id %d\n", > - le32_to_cpu(dma_caps[i].module_id)); > - ret = -EINVAL; > - goto free_dir_buff; > + ath12k_dbg(ab, ATH12K_DBG_WMI, > + "Skipping unknown direct buf ring module id %d\n", > + le32_to_cpu(dma_caps[i].module_id)); > + continue; by continuing you don't populate the dir_buff_caps[i] information below, leaving that record with zeroed data from the initial allocation. Does other code correctly handle that? would it be better to have a separate count of the number of dir_buff_caps records that are actually filled, and then update dma_caps_parse->n_dma_ring_caps to match once the parsing has completed? > } > > dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id); > @@ -4829,10 +4829,6 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, > } > > return 0; > - > -free_dir_buff: > - ath12k_wmi_free_dbring_caps(ab); > - return ret; > } > > static void ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs 2026-05-11 19:02 ` Jeff Johnson @ 2026-05-11 20:10 ` Nazar Mokrynskyi 0 siblings, 0 replies; 5+ messages in thread From: Nazar Mokrynskyi @ 2026-05-11 20:10 UTC (permalink / raw) To: Jeff Johnson, ath12k; +Cc: linux-wireless 11.05.26 22:02, Jeff Johnson: > On 5/5/2026 10:24 AM, Nazar Mokrynskyi wrote: >> The firmware may advertise direct buffer ring capabilities for module >> IDs beyond what the driver currently knows about (WMI_DIRECT_BUF_MAX). >> This happens with newer firmware versions that support additional ring >> types not yet implemented in the driver. > What "newer firmware version" are you using that has this issue? > > Can you share the "Skipping unknown direct buf ring module id" logs from your > modified driver? ID is the same as in the original warning: [ 10.611560] ath12k_pci 0000:01:00.0: Invalid module id 2 [ 10.616467] ath12k_pci 0000:01:00.0: failed to parse tlv -22 The firmware according to system logs (all this info is provided in [PATCH 0/2] email): [ 7.688137] ath12k_pci 0000:01:00.0: fw_version 0x160484db fw_build_timestamp 2025-12-09 20:09 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 This is running on OpenWRT 25.12, which uses 6.12.74 kernel with modules backported from 6.18.7 kernel: [ 0.000000] Linux version 6.12.74 (builder@buildhost) (x86_64-openwrt-linux-musl-gcc (OpenWrt GCC 14.3.0 r32802-f505120278) 14.3.0, GNU ld (GNU Binutils) 2.44) #0 SMP Wed Mar 25 20:09:53 2026 [ 6.997293] Loading modules backported from Linux version v6.18.7-0-g5dfbc5357 [ 6.999210] Backport generated by backports.git c8a37ce >> The current code treats an unknown module_id as a fatal error, returning >> -EINVAL and tearing down the entire driver initialization. This is >> incorrect: the driver only needs to set up rings for types it uses >> (SPECTRAL=0, CFR=1) and can safely ignore capability advertisements for >> unknown types. >> >> Change the unknown module_id handling to skip the entry with a debug >> message rather than failing, allowing initialization to proceed. >> >> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 >> >> Signed-off-by: Nazar Mokrynskyi <nazar@mokrynskyi.com> >> --- >> drivers/net/wireless/ath/ath12k/wmi.c | 12 ++++-------- >> 1 file changed, 4 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c >> index 484fdd3b1..0e776a8d8 100644 >> --- a/drivers/net/wireless/ath/ath12k/wmi.c >> +++ b/drivers/net/wireless/ath/ath12k/wmi.c >> @@ -4814,10 +4814,10 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, >> dir_buff_caps = ab->db_caps; >> for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) { >> if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) { >> - ath12k_warn(ab, "Invalid module id %d\n", >> - le32_to_cpu(dma_caps[i].module_id)); >> - ret = -EINVAL; >> - goto free_dir_buff; >> + ath12k_dbg(ab, ATH12K_DBG_WMI, >> + "Skipping unknown direct buf ring module id %d\n", >> + le32_to_cpu(dma_caps[i].module_id)); >> + continue; > by continuing you don't populate the dir_buff_caps[i] information below, > leaving that record with zeroed data from the initial allocation. Does other > code correctly handle that? > > would it be better to have a separate count of the number of dir_buff_caps > records that are actually filled, and then update > dma_caps_parse->n_dma_ring_caps to match once the parsing has completed? I'm very far from kernel development, let alone ath12k driver specifically. The patch is provided to better showcase the problems I had. If there is a better way to address it, I'd really appreciate if someone more knowledgeable could take over, I just hope this is helpful. With these changes QCN9274 runs an access point with over 3 weeks uptime as of right now. That is not necessary the proof of anything, but it does seem to work in practice so far. >> } >> >> dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id); >> @@ -4829,10 +4829,6 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, >> } >> >> return 0; >> - >> -free_dir_buff: >> - ath12k_wmi_free_dbring_caps(ab); >> - return ret; >> } >> >> static void ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-11 20:10 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-05 17:24 [PATCH 0/2] wifi: ath12k: Fix operation under virtio Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 1/2] wifi: ath12k: skip PCIe global reset on initial power-up Nazar Mokrynskyi 2026-05-05 17:24 ` [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs Nazar Mokrynskyi 2026-05-11 19:02 ` Jeff Johnson 2026-05-11 20:10 ` Nazar Mokrynskyi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox