Skip to content

Commit 4e43457

Browse files
Kang Yanggregkh
authored andcommitted
wifi: ath12k: update channel list in worker when wait flag is set
[ Upstream commit 437c7a2 ] With previous patch [1], ath12k_reg_update_chan_list() will be called during reg_process_self_managed_hint(). reg_process_self_managed_hint() will hold rtnl_lock all the time. But ath12k_reg_update_chan_list() may increase the occupation time of rtnl_lock, because when wait flag is set, wait_for_completion_timeout() will be called during 11d/hw scan. Should minimize the occupation time of rtnl_lock as much as possible to avoid interfering with rest of the system. So move the update channel list operation to a new worker, so that wait_for_completion_timeout() won't be called with the rtnl_lock held. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: f335295 ("wifi: ath12k: avoid deadlock during regulatory update in ath12k_regd_update()") #[1] Signed-off-by: Kang Yang <[email protected]> Reviewed-by: Aditya Kumar Singh <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jeff Johnson <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 716cab0 commit 4e43457

File tree

6 files changed

+78
-27
lines changed

6 files changed

+78
-27
lines changed

drivers/net/wireless/ath/ath12k/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,7 @@ void ath12k_core_halt(struct ath12k *ar)
14091409
ath12k_mac_peer_cleanup_all(ar);
14101410
cancel_delayed_work_sync(&ar->scan.timeout);
14111411
cancel_work_sync(&ar->regd_update_work);
1412+
cancel_work_sync(&ar->regd_channel_update_work);
14121413
cancel_work_sync(&ab->rfkill_work);
14131414
cancel_work_sync(&ab->update_11d_work);
14141415

drivers/net/wireless/ath/ath12k/core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ struct ath12k {
719719

720720
/* protects the radio specific data like debug stats, ppdu_stats_info stats,
721721
* vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info,
722-
* channel context data, survey info, test mode data.
722+
* channel context data, survey info, test mode data, regd_channel_update_queue.
723723
*/
724724
spinlock_t data_lock;
725725

@@ -778,6 +778,8 @@ struct ath12k {
778778
struct completion bss_survey_done;
779779

780780
struct work_struct regd_update_work;
781+
struct work_struct regd_channel_update_work;
782+
struct list_head regd_channel_update_queue;
781783

782784
struct wiphy_work wmi_mgmt_tx_work;
783785
struct sk_buff_head wmi_mgmt_tx_queue;

drivers/net/wireless/ath/ath12k/mac.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8289,6 +8289,7 @@ static void ath12k_mac_stop(struct ath12k *ar)
82898289
{
82908290
struct ath12k_hw *ah = ar->ah;
82918291
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
8292+
struct ath12k_wmi_scan_chan_list_arg *arg;
82928293
int ret;
82938294

82948295
lockdep_assert_held(&ah->hw_mutex);
@@ -8303,17 +8304,26 @@ static void ath12k_mac_stop(struct ath12k *ar)
83038304

83048305
cancel_delayed_work_sync(&ar->scan.timeout);
83058306
wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk);
8307+
cancel_work_sync(&ar->regd_channel_update_work);
83068308
cancel_work_sync(&ar->regd_update_work);
83078309
cancel_work_sync(&ar->ab->rfkill_work);
83088310
cancel_work_sync(&ar->ab->update_11d_work);
83098311
ar->state_11d = ATH12K_11D_IDLE;
83108312
complete(&ar->completed_11d_scan);
83118313

83128314
spin_lock_bh(&ar->data_lock);
8315+
83138316
list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
83148317
list_del(&ppdu_stats->list);
83158318
kfree(ppdu_stats);
83168319
}
8320+
8321+
while ((arg = list_first_entry_or_null(&ar->regd_channel_update_queue,
8322+
struct ath12k_wmi_scan_chan_list_arg,
8323+
list))) {
8324+
list_del(&arg->list);
8325+
kfree(arg);
8326+
}
83178327
spin_unlock_bh(&ar->data_lock);
83188328

83198329
rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL);
@@ -12207,6 +12217,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
1220712217
int i;
1220812218

1220912219
for_each_ar(ah, ar, i) {
12220+
cancel_work_sync(&ar->regd_channel_update_work);
1221012221
cancel_work_sync(&ar->regd_update_work);
1221112222
ath12k_debugfs_unregister(ar);
1221212223
ath12k_fw_stats_reset(ar);
@@ -12567,6 +12578,8 @@ static void ath12k_mac_setup(struct ath12k *ar)
1256712578

1256812579
INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
1256912580
wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work);
12581+
INIT_WORK(&ar->regd_channel_update_work, ath12k_regd_update_chan_list_work);
12582+
INIT_LIST_HEAD(&ar->regd_channel_update_queue);
1257012583
INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
1257112584

1257212585
wiphy_work_init(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work);

drivers/net/wireless/ath/ath12k/reg.c

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -137,32 +137,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
137137
struct ath12k_wmi_channel_arg *ch;
138138
enum nl80211_band band;
139139
int num_channels = 0;
140-
int i, ret, left;
141-
142-
if (wait && ar->state_11d == ATH12K_11D_RUNNING) {
143-
left = wait_for_completion_timeout(&ar->completed_11d_scan,
144-
ATH12K_SCAN_TIMEOUT_HZ);
145-
if (!left) {
146-
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
147-
"failed to receive 11d scan complete: timed out\n");
148-
ar->state_11d = ATH12K_11D_IDLE;
149-
}
150-
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
151-
"reg 11d scan wait left time %d\n", left);
152-
}
153-
154-
if (wait &&
155-
(ar->scan.state == ATH12K_SCAN_STARTING ||
156-
ar->scan.state == ATH12K_SCAN_RUNNING)) {
157-
left = wait_for_completion_timeout(&ar->scan.completed,
158-
ATH12K_SCAN_TIMEOUT_HZ);
159-
if (!left)
160-
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
161-
"failed to receive hw scan complete: timed out\n");
162-
163-
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
164-
"reg hw scan wait left time %d\n", left);
165-
}
140+
int i, ret = 0;
166141

167142
if (ar->ah->state == ATH12K_HW_STATE_RESTARTING)
168143
return 0;
@@ -244,6 +219,16 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
244219
}
245220
}
246221

222+
if (wait) {
223+
spin_lock_bh(&ar->data_lock);
224+
list_add_tail(&arg->list, &ar->regd_channel_update_queue);
225+
spin_unlock_bh(&ar->data_lock);
226+
227+
queue_work(ar->ab->workqueue, &ar->regd_channel_update_work);
228+
229+
return 0;
230+
}
231+
247232
ret = ath12k_wmi_send_scan_chan_list_cmd(ar, arg);
248233
kfree(arg);
249234

@@ -764,6 +749,54 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
764749
return new_regd;
765750
}
766751

752+
void ath12k_regd_update_chan_list_work(struct work_struct *work)
753+
{
754+
struct ath12k *ar = container_of(work, struct ath12k,
755+
regd_channel_update_work);
756+
struct ath12k_wmi_scan_chan_list_arg *arg;
757+
struct list_head local_update_list;
758+
int left;
759+
760+
INIT_LIST_HEAD(&local_update_list);
761+
762+
spin_lock_bh(&ar->data_lock);
763+
list_splice_tail_init(&ar->regd_channel_update_queue, &local_update_list);
764+
spin_unlock_bh(&ar->data_lock);
765+
766+
while ((arg = list_first_entry_or_null(&local_update_list,
767+
struct ath12k_wmi_scan_chan_list_arg,
768+
list))) {
769+
if (ar->state_11d != ATH12K_11D_IDLE) {
770+
left = wait_for_completion_timeout(&ar->completed_11d_scan,
771+
ATH12K_SCAN_TIMEOUT_HZ);
772+
if (!left) {
773+
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
774+
"failed to receive 11d scan complete: timed out\n");
775+
ar->state_11d = ATH12K_11D_IDLE;
776+
}
777+
778+
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
779+
"reg 11d scan wait left time %d\n", left);
780+
}
781+
782+
if ((ar->scan.state == ATH12K_SCAN_STARTING ||
783+
ar->scan.state == ATH12K_SCAN_RUNNING)) {
784+
left = wait_for_completion_timeout(&ar->scan.completed,
785+
ATH12K_SCAN_TIMEOUT_HZ);
786+
if (!left)
787+
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
788+
"failed to receive hw scan complete: timed out\n");
789+
790+
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
791+
"reg hw scan wait left time %d\n", left);
792+
}
793+
794+
ath12k_wmi_send_scan_chan_list_cmd(ar, arg);
795+
list_del(&arg->list);
796+
kfree(arg);
797+
}
798+
}
799+
767800
void ath12k_regd_update_work(struct work_struct *work)
768801
{
769802
struct ath12k *ar = container_of(work, struct ath12k,

drivers/net/wireless/ath/ath12k/reg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
113113
struct ath12k_reg_info *reg_info,
114114
enum wmi_vdev_type vdev_type,
115115
enum ieee80211_ap_reg_power power_type);
116+
void ath12k_regd_update_chan_list_work(struct work_struct *work);
116117
enum wmi_reg_6g_ap_type
117118
ath12k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type);
118119
enum ath12k_reg_status ath12k_reg_validate_reg_info(struct ath12k_base *ab,

drivers/net/wireless/ath/ath12k/wmi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3948,6 +3948,7 @@ struct wmi_stop_scan_cmd {
39483948
} __packed;
39493949

39503950
struct ath12k_wmi_scan_chan_list_arg {
3951+
struct list_head list;
39513952
u32 pdev_id;
39523953
u16 nallchans;
39533954
struct ath12k_wmi_channel_arg channel[];

0 commit comments

Comments
 (0)