# \[PATCH\] wifi: mac80211: drain TXQ wake tasklet before freeing hardware

- From: JB Tsai \<hidden\>
- Date: 2026-11-03 09:10:08 
- List: linux-wireless
- Page: https://ratatoskr.run/linux-wireless/2026/11/17850737
- Thread: https://ratatoskr.run/linux-wireless/2026/11/17850737/t.md

```text
From: Yin-Ming Li <redacted>

Driver queue wakeups schedule wake_txqs_tasklet asynchronously. Stopping
the driver work that issued a wakeup does not wait for this tasklet, and
ieee80211_unregister_hw() does not drain it.

Drain the tasklet in ieee80211_free_hw(), before destroying the local
mutex and releasing the hardware allocation. Drivers must stop their
asynchronous producers before calling ieee80211_free_hw(); this drain
waits for a tasklet those producers have already scheduled. Using the
final free boundary also covers deferred wakeups scheduled while the
driver finishes bus teardown after ieee80211_unregister_hw() returns.

Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Yin-Ming Li <redacted>
---
 net/mac80211/main.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index f996e15e3d9e35cacddedf482a34c40c587d3e52..086b9ca3485398b4ef2ff60c3f9387dd909a8008 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1755,6 +1755,9 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 	struct ieee80211_local *local = hw_to_local(hw);
 	enum nl80211_band band;
 
+	/* Driver callbacks have stopped; drain their deferred TXQ wakeups. */
+	tasklet_kill(&local->wake_txqs_tasklet);
+
 	mutex_destroy(&local->iflist_mtx);
 
 	idr_for_each(&local->ack_status_frames,
-- 
2.43.0
```
