[PATCH ath-next 2/2] wifi: ath11k: initialise the CE descriptor waitqueue once per device

Julius Bairaktaris <[email protected]> Wed, 5 Aug 2026 21:21:29 +0200
Newsgroups org.kernel.vger.linux-wireless,org.infradead.lists.ath11k,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
ath11k_wmi_pdev_attach() runs init_waitqueue_head() on the pdev's
tx_ce_desc_wq. It is called from ath11k_wmi_attach() ->
ath11k_core_start(), which firmware crash recovery re-runs through
ath11k_core_qmi_firmware_ready(), so the head is reinitialised on every
recovery - including while a task is still queued on it.

Parts with hw_params.credit_flow clear - ipq8074, ipq6018, ipq5018,
wcn6750 - take the else branch of ath11k_wmi_cmd_send() and sleep there
in wait_event_timeout() for up to WMI_SEND_TIMEOUT_HZ. That is longer
than a recovery takes, so an ordinary WMI command issued from userspace
just before the crash is still on the queue when the head is cleared
under it, and finish_wait() then deletes the entry from a list head that
no longer refers to it:

  WARNING: CPU: 1 PID: 1861 at lib/list_debug.c:62 __list_del_entry_valid_or_report+0x110/0x154
  CPU: 0 UID: 101 Comm: hostapd
  Call trace:
   __list_del_entry_valid_or_report+0x110/0x154 (P)
   finish_wait+0xcc/0xd0
   ath11k_wmi_cmd_send+0x150/0x2f4 [ath11k]
   ath11k_wmi_vdev_set_param_cmd+0x64/0xd8 [ath11k]
   ath11k_mac_op_bss_info_changed+0xe8/0xf60 [ath11k]
   drv_link_info_changed+0x118/0x160 [mac80211]
   ieee80211_link_info_change_notify+0xe0/0x100 [mac80211]
   ieee80211_change_bss+0x1c8/0x250 [mac80211]
   nl80211_set_bss+0x1a0/0x330 [cfg80211]

Initialise it where its credit-flow sibling ab->wmi_ab.tx_credits_wq is
already initialised, in ath11k_core_alloc(), which runs once per device.
The array is fixed size, so all of it can be set up before any pdev is
attached, and nothing on the recovery path touches the head again.

Reproduced on a Xiaomi AX3600 (IPQ8074 hw2.0) with a userspace loop
pushing beacon updates while the firmware is asserted through the debugfs
simulate_fw_crash 'assert' trigger, on a stock ath11k with no out-of-tree
modules loaded: one warning per recovery, on all eleven recoveries
observed across two builds, and none at all over six recoveries with this
applied.

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.12-01460-QCAHKSWPL_SILICONZ-1

Fixes: f951380a6022 ("ath11k: Disabling credit flow for WMI path")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julius Bairaktaris <[email protected]>
---
 drivers/net/wireless/ath/ath11k/core.c | 5 +++++
 drivers/net/wireless/ath/ath11k/wmi.c  | 1 -
 2 files changed, 5 insertions(+), 1 deletion(-)

--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -2746,6 +2746,7 @@
 				      enum ath11k_bus bus)
 {
 	struct ath11k_base *ab;
+	int i;
 
 	ab = kzalloc(sizeof(*ab) + priv_size, GFP_KERNEL);
 	if (!ab)
@@ -2772,6 +2773,10 @@
 	INIT_LIST_HEAD(&ab->peers);
 	init_waitqueue_head(&ab->peer_mapping_wq);
 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
+
+	for (i = 0; i < ARRAY_SIZE(ab->wmi_ab.wmi); i++)
+		init_waitqueue_head(&ab->wmi_ab.wmi[i].tx_ce_desc_wq);
+
 	init_waitqueue_head(&ab->qmi.cold_boot_waitq);
 	INIT_WORK(&ab->restart_work, ath11k_core_restart);
 	INIT_WORK(&ab->update_11d_work, ath11k_update_11d);
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -9064,7 +9064,6 @@
 	ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid;
 	ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid;
 	ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len;
-	init_waitqueue_head(&ab->wmi_ab.wmi[pdev_idx].tx_ce_desc_wq);
 
 	return 0;
 }