Skip to content

Commit 9f6e82d

Browse files
Baochen Qiangjeff-t-johnson
authored andcommitted
wifi: ath11k: avoid burning CPU in ath11k_debugfs_fw_stats_request()
We get report [1] that CPU is running a hot loop in ath11k_debugfs_fw_stats_request(): 94.60% 0.00% i3status [kernel.kallsyms] [k] do_syscall_64 | --94.60%--do_syscall_64 | --94.55%--__sys_sendmsg ___sys_sendmsg ____sys_sendmsg netlink_sendmsg netlink_unicast genl_rcv netlink_rcv_skb genl_rcv_msg | --94.55%--genl_family_rcv_msg_dumpit __netlink_dump_start netlink_dump genl_dumpit nl80211_dump_station | --94.55%--ieee80211_dump_station sta_set_sinfo | --94.55%--ath11k_mac_op_sta_statistics ath11k_debugfs_get_fw_stats | --94.55%--ath11k_debugfs_fw_stats_request | |--41.73%--_raw_spin_lock_bh | |--22.74%--__local_bh_enable_ip | |--9.22%--_raw_spin_unlock_bh | --6.66%--srso_alias_safe_ret This is because, if for whatever reason ar->fw_stats_done is not set by ath11k_update_stats_event(), ath11k_debugfs_fw_stats_request() won't yield CPU before an up to 3s timeout. Change to completion mechanism to avoid CPU burning. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.37 Fixes: d5c6515 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Reported-by: Yury Vostrikov <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ # [1] Signed-off-by: Baochen Qiang <[email protected]> Reviewed-by: Vasanthakumar Thiagarajan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jeff Johnson <[email protected]>
1 parent 5939636 commit 9f6e82d

File tree

5 files changed

+18
-27
lines changed

5 files changed

+18
-27
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ void ath11k_fw_stats_init(struct ath11k *ar)
990990
INIT_LIST_HEAD(&ar->fw_stats.bcn);
991991

992992
init_completion(&ar->fw_stats_complete);
993+
init_completion(&ar->fw_stats_done);
993994
}
994995

995996
void ath11k_fw_stats_free(struct ath11k_fw_stats *stats)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ struct ath11k {
784784
u8 alpha2[REG_ALPHA2_LEN + 1];
785785
struct ath11k_fw_stats fw_stats;
786786
struct completion fw_stats_complete;
787-
bool fw_stats_done;
787+
struct completion fw_stats_done;
788788

789789
/* protected by conf_mutex */
790790
bool ps_state_enable;

drivers/net/wireless/ath/ath11k/debugfs.c

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: BSD-3-Clause-Clear
22
/*
33
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
4-
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4+
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
55
*/
66

77
#include <linux/vmalloc.h>
@@ -96,7 +96,6 @@ void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
9696
static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
9797
{
9898
spin_lock_bh(&ar->data_lock);
99-
ar->fw_stats_done = false;
10099
ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
101100
ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
102101
spin_unlock_bh(&ar->data_lock);
@@ -114,7 +113,7 @@ void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *
114113
/* WMI_REQUEST_PDEV_STAT request has been already processed */
115114

116115
if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
117-
ar->fw_stats_done = true;
116+
complete(&ar->fw_stats_done);
118117
return;
119118
}
120119

@@ -138,7 +137,7 @@ void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *
138137
&ar->fw_stats.vdevs);
139138

140139
if (is_end) {
141-
ar->fw_stats_done = true;
140+
complete(&ar->fw_stats_done);
142141
num_vdev = 0;
143142
}
144143
return;
@@ -158,7 +157,7 @@ void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *
158157
&ar->fw_stats.bcn);
159158

160159
if (is_end) {
161-
ar->fw_stats_done = true;
160+
complete(&ar->fw_stats_done);
162161
num_bcn = 0;
163162
}
164163
}
@@ -168,21 +167,15 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
168167
struct stats_request_params *req_param)
169168
{
170169
struct ath11k_base *ab = ar->ab;
171-
unsigned long timeout, time_left;
170+
unsigned long time_left;
172171
int ret;
173172

174173
lockdep_assert_held(&ar->conf_mutex);
175174

176-
/* FW stats can get split when exceeding the stats data buffer limit.
177-
* In that case, since there is no end marking for the back-to-back
178-
* received 'update stats' event, we keep a 3 seconds timeout in case,
179-
* fw_stats_done is not marked yet
180-
*/
181-
timeout = jiffies + secs_to_jiffies(3);
182-
183175
ath11k_debugfs_fw_stats_reset(ar);
184176

185177
reinit_completion(&ar->fw_stats_complete);
178+
reinit_completion(&ar->fw_stats_done);
186179

187180
ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
188181

@@ -193,21 +186,18 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
193186
}
194187

195188
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
196-
197189
if (!time_left)
198190
return -ETIMEDOUT;
199191

200-
for (;;) {
201-
if (time_after(jiffies, timeout))
202-
break;
192+
/* FW stats can get split when exceeding the stats data buffer limit.
193+
* In that case, since there is no end marking for the back-to-back
194+
* received 'update stats' event, we keep a 3 seconds timeout in case,
195+
* fw_stats_done is not marked yet
196+
*/
197+
time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
198+
if (!time_left)
199+
return -ETIMEDOUT;
203200

204-
spin_lock_bh(&ar->data_lock);
205-
if (ar->fw_stats_done) {
206-
spin_unlock_bh(&ar->data_lock);
207-
break;
208-
}
209-
spin_unlock_bh(&ar->data_lock);
210-
}
211201
return 0;
212202
}
213203

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9390,11 +9390,11 @@ static int ath11k_fw_stats_request(struct ath11k *ar,
93909390
lockdep_assert_held(&ar->conf_mutex);
93919391

93929392
spin_lock_bh(&ar->data_lock);
9393-
ar->fw_stats_done = false;
93949393
ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
93959394
spin_unlock_bh(&ar->data_lock);
93969395

93979396
reinit_completion(&ar->fw_stats_complete);
9397+
reinit_completion(&ar->fw_stats_done);
93989398

93999399
ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
94009400
if (ret) {

drivers/net/wireless/ath/ath11k/wmi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8189,7 +8189,7 @@ static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *sk
81898189
*/
81908190
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
81918191
list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
8192-
ar->fw_stats_done = true;
8192+
complete(&ar->fw_stats_done);
81938193
goto complete;
81948194
}
81958195

0 commit comments

Comments
 (0)