summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWen Gong <quic_wgong@quicinc.com>2023-07-18 05:47:24 +0300
committerKalle Valo <quic_kvalo@quicinc.com>2023-08-03 12:19:44 +0300
commit8198950ccb7d311f8b4389441d8dcb597f926340 (patch)
treec421323a66966082f6a3b1197b06c53826bc17b6 /drivers
parent9632ea57be659887ab0d28a2a1d7b901dfddd263 (diff)
downloadlinux-8198950ccb7d311f8b4389441d8dcb597f926340.tar.xz
wifi: ath12k: avoid deadlock by change ieee80211_queue_work for regd_update_work
Deadlock is easily happened while shutdown wlan interface such as run "ifconfig wlan0 down". The reason is because when ar->regd_update_work is ran, it will call wiphy_lock(ar->hw->wiphy) in function ath12k_regd_update() which is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). Another thread from "ifconfig wlan0 down" will also accuqire the lock by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), this will wait the workqueue of ieee80211_local finished. Then deadlock will happen easily if the two thread run meanwhile. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> Link: https://lore.kernel.org/r/20230718024724.29120-1-quic_wgong@quicinc.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index fab4d33c8984..9ed33e2d6da0 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5473,7 +5473,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ar = ab->pdevs[pdev_idx].ar;
kfree(ab->new_regd[pdev_idx]);
ab->new_regd[pdev_idx] = regd;
- ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+ queue_work(ab->workqueue, &ar->regd_update_work);
} else {
/* Multiple events for the same *ar is not expected. But we
* can still clear any previously stored default_regd if we