Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: BSD-3-Clause-Clear
2/*
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5 */
6
7#include <linux/vmalloc.h>
8
9#include "debugfs_sta.h"
10#include "core.h"
11#include "peer.h"
12#include "debug.h"
13#include "dp_tx.h"
14#include "debugfs_htt_stats.h"
15
16void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
17 struct ath11k_per_peer_tx_stats *peer_stats,
18 u8 legacy_rate_idx)
19{
20 struct rate_info *txrate = &arsta->txrate;
21 struct ath11k_htt_tx_stats *tx_stats;
22 int gi, mcs, bw, nss;
23
24 if (!arsta->tx_stats)
25 return;
26
27 tx_stats = arsta->tx_stats;
28 gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
29 mcs = txrate->mcs;
30 bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
31 nss = txrate->nss - 1;
32
33#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
34
35 if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
36 STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
37 STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
38 STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
39 STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
40 STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
41 STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
42 } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
43 STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
44 STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
45 STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
46 STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
47 STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
48 STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
49 } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
50 STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
51 STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
52 STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
53 STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
54 STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
55 STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
56 } else {
57 mcs = legacy_rate_idx;
58
59 STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
60 STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
61 STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
62 STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
63 STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
64 STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
65 }
66
67 if (peer_stats->is_ampdu) {
68 tx_stats->ba_fails += peer_stats->ba_fails;
69
70 if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
71 STATS_OP_FMT(AMPDU).he[0][mcs] +=
72 peer_stats->succ_bytes + peer_stats->retry_bytes;
73 STATS_OP_FMT(AMPDU).he[1][mcs] +=
74 peer_stats->succ_pkts + peer_stats->retry_pkts;
75 } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
76 STATS_OP_FMT(AMPDU).ht[0][mcs] +=
77 peer_stats->succ_bytes + peer_stats->retry_bytes;
78 STATS_OP_FMT(AMPDU).ht[1][mcs] +=
79 peer_stats->succ_pkts + peer_stats->retry_pkts;
80 } else {
81 STATS_OP_FMT(AMPDU).vht[0][mcs] +=
82 peer_stats->succ_bytes + peer_stats->retry_bytes;
83 STATS_OP_FMT(AMPDU).vht[1][mcs] +=
84 peer_stats->succ_pkts + peer_stats->retry_pkts;
85 }
86 STATS_OP_FMT(AMPDU).bw[0][bw] +=
87 peer_stats->succ_bytes + peer_stats->retry_bytes;
88 STATS_OP_FMT(AMPDU).nss[0][nss] +=
89 peer_stats->succ_bytes + peer_stats->retry_bytes;
90 STATS_OP_FMT(AMPDU).gi[0][gi] +=
91 peer_stats->succ_bytes + peer_stats->retry_bytes;
92 STATS_OP_FMT(AMPDU).bw[1][bw] +=
93 peer_stats->succ_pkts + peer_stats->retry_pkts;
94 STATS_OP_FMT(AMPDU).nss[1][nss] +=
95 peer_stats->succ_pkts + peer_stats->retry_pkts;
96 STATS_OP_FMT(AMPDU).gi[1][gi] +=
97 peer_stats->succ_pkts + peer_stats->retry_pkts;
98 } else {
99 tx_stats->ack_fails += peer_stats->ba_fails;
100 }
101
102 STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
103 STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
104 STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
105
106 STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
107 STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
108 STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
109
110 STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
111 STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
112 STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
113
114 STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
115 STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
116 STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
117
118 STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
119 STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
120 STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
121
122 STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
123 STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
124 STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
125
126 tx_stats->tx_duration += peer_stats->duration;
127}
128
129void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
130 struct hal_tx_status *ts)
131{
132 ath11k_dp_tx_update_txcompl(ar, ts);
133}
134
135static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
136 char __user *user_buf,
137 size_t count, loff_t *ppos)
138{
139 struct ieee80211_sta *sta = file->private_data;
140 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
141 struct ath11k *ar = arsta->arvif->ar;
142 struct ath11k_htt_data_stats *stats;
143 static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
144 "retry", "ampdu"};
145 static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
146 int len = 0, i, j, k, retval = 0;
147 const int size = 2 * 4096;
148 char *buf;
149
150 if (!arsta->tx_stats)
151 return -ENOENT;
152
153 buf = kzalloc(size, GFP_KERNEL);
154 if (!buf)
155 return -ENOMEM;
156
157 mutex_lock(&ar->conf_mutex);
158
159 spin_lock_bh(&ar->data_lock);
160 for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
161 for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
162 stats = &arsta->tx_stats->stats[k];
163 len += scnprintf(buf + len, size - len, "%s_%s\n",
164 str_name[k],
165 str[j]);
166 len += scnprintf(buf + len, size - len,
167 " HE MCS %s\n",
168 str[j]);
169 for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
170 len += scnprintf(buf + len, size - len,
171 " %llu ",
172 stats->he[j][i]);
173 len += scnprintf(buf + len, size - len, "\n");
174 len += scnprintf(buf + len, size - len,
175 " VHT MCS %s\n",
176 str[j]);
177 for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
178 len += scnprintf(buf + len, size - len,
179 " %llu ",
180 stats->vht[j][i]);
181 len += scnprintf(buf + len, size - len, "\n");
182 len += scnprintf(buf + len, size - len, " HT MCS %s\n",
183 str[j]);
184 for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
185 len += scnprintf(buf + len, size - len,
186 " %llu ", stats->ht[j][i]);
187 len += scnprintf(buf + len, size - len, "\n");
188 len += scnprintf(buf + len, size - len,
189 " BW %s (20,40,80,160 MHz)\n", str[j]);
190 len += scnprintf(buf + len, size - len,
191 " %llu %llu %llu %llu\n",
192 stats->bw[j][0], stats->bw[j][1],
193 stats->bw[j][2], stats->bw[j][3]);
194 len += scnprintf(buf + len, size - len,
195 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
196 len += scnprintf(buf + len, size - len,
197 " %llu %llu %llu %llu\n",
198 stats->nss[j][0], stats->nss[j][1],
199 stats->nss[j][2], stats->nss[j][3]);
200 len += scnprintf(buf + len, size - len,
201 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
202 str[j]);
203 len += scnprintf(buf + len, size - len,
204 " %llu %llu %llu %llu\n",
205 stats->gi[j][0], stats->gi[j][1],
206 stats->gi[j][2], stats->gi[j][3]);
207 len += scnprintf(buf + len, size - len,
208 " legacy rate %s (1,2 ... Mbps)\n ",
209 str[j]);
210 for (i = 0; i < ATH11K_LEGACY_NUM; i++)
211 len += scnprintf(buf + len, size - len, "%llu ",
212 stats->legacy[j][i]);
213 len += scnprintf(buf + len, size - len, "\n");
214 }
215 }
216
217 len += scnprintf(buf + len, size - len,
218 "\nTX duration\n %llu usecs\n",
219 arsta->tx_stats->tx_duration);
220 len += scnprintf(buf + len, size - len,
221 "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
222 len += scnprintf(buf + len, size - len,
223 "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
224 spin_unlock_bh(&ar->data_lock);
225
226 if (len > size)
227 len = size;
228 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
229 kfree(buf);
230
231 mutex_unlock(&ar->conf_mutex);
232 return retval;
233}
234
235static const struct file_operations fops_tx_stats = {
236 .read = ath11k_dbg_sta_dump_tx_stats,
237 .open = simple_open,
238 .owner = THIS_MODULE,
239 .llseek = default_llseek,
240};
241
242#ifdef CONFIG_ATH11K_CFR
243static ssize_t ath11k_dbg_sta_write_cfr_capture(struct file *file,
244 const char __user *user_buf,
245 size_t count, loff_t *ppos)
246{
247 struct ieee80211_sta *sta = file->private_data;
248 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
249 struct ath11k *ar = arsta->arvif->ar;
250 struct ath11k_cfr *cfr = &ar->cfr;
251 struct wmi_peer_cfr_capture_conf_arg arg;
252 u32 cfr_capture_enable = 0, cfr_capture_bw = 0;
253 u32 cfr_capture_method = 0, cfr_capture_period = 0;
254 char buf[64] = {};
255 int ret;
256
257 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
258
259 guard(mutex)(&ar->conf_mutex);
260
261 if (ar->state != ATH11K_STATE_ON)
262 return -ENETDOWN;
263
264 if (!ar->cfr_enabled)
265 return -EINVAL;
266
267 ret = sscanf(buf, "%u %u %u %u", &cfr_capture_enable, &cfr_capture_bw,
268 &cfr_capture_period, &cfr_capture_method);
269
270 if (ret < 1 || (cfr_capture_enable && ret != 4))
271 return -EINVAL;
272
273 if (cfr_capture_enable == arsta->cfr_capture.cfr_enable &&
274 (cfr_capture_period &&
275 cfr_capture_period == arsta->cfr_capture.cfr_period) &&
276 cfr_capture_bw == arsta->cfr_capture.cfr_bw &&
277 cfr_capture_method == arsta->cfr_capture.cfr_method)
278 return count;
279
280 if (!cfr_capture_enable &&
281 cfr_capture_enable == arsta->cfr_capture.cfr_enable)
282 return count;
283
284 if (cfr_capture_enable > WMI_PEER_CFR_CAPTURE_ENABLE ||
285 cfr_capture_bw > WMI_PEER_CFR_CAPTURE_BW_80 ||
286 cfr_capture_method > ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE ||
287 cfr_capture_period > WMI_PEER_CFR_PERIODICITY_MAX)
288 return -EINVAL;
289
290 /* Target expects cfr period in multiple of 10 */
291 if (cfr_capture_period % 10) {
292 ath11k_err(ar->ab, "periodicity should be 10x\n");
293 return -EINVAL;
294 }
295
296 if (ar->cfr.cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS &&
297 !arsta->cfr_capture.cfr_enable) {
298 ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n",
299 ar->cfr.cfr_enabled_peer_cnt);
300 return -EINVAL;
301 }
302
303 if (!cfr_capture_enable) {
304 cfr_capture_bw = arsta->cfr_capture.cfr_bw;
305 cfr_capture_period = arsta->cfr_capture.cfr_period;
306 cfr_capture_method = arsta->cfr_capture.cfr_method;
307 }
308
309 arg.request = cfr_capture_enable;
310 arg.periodicity = cfr_capture_period;
311 arg.bw = cfr_capture_bw;
312 arg.method = cfr_capture_method;
313
314 ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id,
315 sta->addr, &arg);
316 if (ret) {
317 ath11k_warn(ar->ab,
318 "failed to send cfr capture info: vdev_id %u peer %pM: %d\n",
319 arsta->arvif->vdev_id, sta->addr, ret);
320 return ret;
321 }
322
323 spin_lock_bh(&ar->cfr.lock);
324
325 if (cfr_capture_enable &&
326 cfr_capture_enable != arsta->cfr_capture.cfr_enable)
327 cfr->cfr_enabled_peer_cnt++;
328 else if (!cfr_capture_enable)
329 cfr->cfr_enabled_peer_cnt--;
330
331 spin_unlock_bh(&ar->cfr.lock);
332
333 arsta->cfr_capture.cfr_enable = cfr_capture_enable;
334 arsta->cfr_capture.cfr_period = cfr_capture_period;
335 arsta->cfr_capture.cfr_bw = cfr_capture_bw;
336 arsta->cfr_capture.cfr_method = cfr_capture_method;
337
338 return count;
339}
340
341static ssize_t ath11k_dbg_sta_read_cfr_capture(struct file *file,
342 char __user *user_buf,
343 size_t count, loff_t *ppos)
344{
345 struct ieee80211_sta *sta = file->private_data;
346 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
347 struct ath11k *ar = arsta->arvif->ar;
348 char buf[512] = {};
349 int len = 0;
350
351 mutex_lock(&ar->conf_mutex);
352
353 len += scnprintf(buf + len, sizeof(buf) - len, "cfr_enabled = %d\n",
354 arsta->cfr_capture.cfr_enable);
355 len += scnprintf(buf + len, sizeof(buf) - len, "bandwidth = %d\n",
356 arsta->cfr_capture.cfr_bw);
357 len += scnprintf(buf + len, sizeof(buf) - len, "period = %d\n",
358 arsta->cfr_capture.cfr_period);
359 len += scnprintf(buf + len, sizeof(buf) - len, "cfr_method = %d\n",
360 arsta->cfr_capture.cfr_method);
361
362 mutex_unlock(&ar->conf_mutex);
363
364 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
365}
366
367static const struct file_operations fops_peer_cfr_capture = {
368 .write = ath11k_dbg_sta_write_cfr_capture,
369 .read = ath11k_dbg_sta_read_cfr_capture,
370 .open = simple_open,
371 .owner = THIS_MODULE,
372 .llseek = default_llseek,
373};
374#endif /* CONFIG_ATH11K_CFR */
375
376static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
377 char __user *user_buf,
378 size_t count, loff_t *ppos)
379{
380 struct ieee80211_sta *sta = file->private_data;
381 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
382 struct ath11k *ar = arsta->arvif->ar;
383 struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
384 int len = 0, i, retval = 0;
385 const int size = 4096;
386 char *buf;
387
388 if (!rx_stats)
389 return -ENOENT;
390
391 buf = kzalloc(size, GFP_KERNEL);
392 if (!buf)
393 return -ENOMEM;
394
395 mutex_lock(&ar->conf_mutex);
396 spin_lock_bh(&ar->ab->base_lock);
397
398 len += scnprintf(buf + len, size - len, "RX peer stats:\n");
399 len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
400 rx_stats->num_msdu);
401 len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
402 rx_stats->tcp_msdu_count);
403 len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
404 rx_stats->udp_msdu_count);
405 len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
406 rx_stats->ampdu_msdu_count);
407 len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
408 rx_stats->non_ampdu_msdu_count);
409 len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
410 rx_stats->stbc_count);
411 len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
412 rx_stats->beamformed_count);
413 len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
414 rx_stats->num_mpdu_fcs_ok);
415 len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
416 rx_stats->num_mpdu_fcs_err);
417 len += scnprintf(buf + len, size - len,
418 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
419 rx_stats->gi_count[0], rx_stats->gi_count[1],
420 rx_stats->gi_count[2], rx_stats->gi_count[3]);
421 len += scnprintf(buf + len, size - len,
422 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
423 rx_stats->bw_count[0], rx_stats->bw_count[1],
424 rx_stats->bw_count[2], rx_stats->bw_count[3]);
425 len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
426 rx_stats->coding_count[0], rx_stats->coding_count[1]);
427 len += scnprintf(buf + len, size - len,
428 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
429 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
430 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
431 rx_stats->pream_cnt[4]);
432 len += scnprintf(buf + len, size - len,
433 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
434 rx_stats->reception_type[0], rx_stats->reception_type[1],
435 rx_stats->reception_type[2], rx_stats->reception_type[3]);
436 len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
437 for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
438 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
439 len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
440 for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
441 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
442 len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
443 for (i = 0; i < HAL_RX_MAX_NSS; i++)
444 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
445 len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
446 rx_stats->rx_duration);
447 len += scnprintf(buf + len, size - len,
448 "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
449 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
450 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
451 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
452 rx_stats->ru_alloc_cnt[5]);
453
454 len += scnprintf(buf + len, size - len, "\n");
455
456 spin_unlock_bh(&ar->ab->base_lock);
457
458 if (len > size)
459 len = size;
460 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
461 kfree(buf);
462
463 mutex_unlock(&ar->conf_mutex);
464 return retval;
465}
466
467static const struct file_operations fops_rx_stats = {
468 .read = ath11k_dbg_sta_dump_rx_stats,
469 .open = simple_open,
470 .owner = THIS_MODULE,
471 .llseek = default_llseek,
472};
473
474static int
475ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
476{
477 struct ieee80211_sta *sta = inode->i_private;
478 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
479 struct ath11k *ar = arsta->arvif->ar;
480 struct debug_htt_stats_req *stats_req;
481 int type = ar->debug.htt_stats.type;
482 int ret;
483
484 if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO &&
485 type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) ||
486 type == ATH11K_DBG_HTT_EXT_STATS_RESET)
487 return -EPERM;
488
489 stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
490 if (!stats_req)
491 return -ENOMEM;
492
493 mutex_lock(&ar->conf_mutex);
494 ar->debug.htt_stats.stats_req = stats_req;
495 stats_req->type = type;
496 memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
497 ret = ath11k_debugfs_htt_stats_req(ar);
498 mutex_unlock(&ar->conf_mutex);
499 if (ret < 0)
500 goto out;
501
502 file->private_data = stats_req;
503 return 0;
504out:
505 vfree(stats_req);
506 ar->debug.htt_stats.stats_req = NULL;
507 return ret;
508}
509
510static int
511ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
512{
513 struct ieee80211_sta *sta = inode->i_private;
514 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
515 struct ath11k *ar = arsta->arvif->ar;
516
517 mutex_lock(&ar->conf_mutex);
518 vfree(file->private_data);
519 ar->debug.htt_stats.stats_req = NULL;
520 mutex_unlock(&ar->conf_mutex);
521
522 return 0;
523}
524
525static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
526 char __user *user_buf,
527 size_t count, loff_t *ppos)
528{
529 struct debug_htt_stats_req *stats_req = file->private_data;
530 char *buf;
531 u32 length = 0;
532
533 buf = stats_req->buf;
534 length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
535 return simple_read_from_buffer(user_buf, count, ppos, buf, length);
536}
537
538static const struct file_operations fops_htt_peer_stats = {
539 .open = ath11k_dbg_sta_open_htt_peer_stats,
540 .release = ath11k_dbg_sta_release_htt_peer_stats,
541 .read = ath11k_dbg_sta_read_htt_peer_stats,
542 .owner = THIS_MODULE,
543 .llseek = default_llseek,
544};
545
546static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
547 const char __user *buf,
548 size_t count, loff_t *ppos)
549{
550 struct ieee80211_sta *sta = file->private_data;
551 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
552 struct ath11k *ar = arsta->arvif->ar;
553 int ret, enable;
554
555 mutex_lock(&ar->conf_mutex);
556
557 if (ar->state != ATH11K_STATE_ON) {
558 ret = -ENETDOWN;
559 goto out;
560 }
561
562 ret = kstrtoint_from_user(buf, count, 0, &enable);
563 if (ret)
564 goto out;
565
566 ar->debug.pktlog_peer_valid = enable;
567 memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
568
569 /* Send peer based pktlog enable/disable */
570 ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
571 if (ret) {
572 ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
573 sta->addr, ret);
574 goto out;
575 }
576
577 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
578 enable);
579 ret = count;
580
581out:
582 mutex_unlock(&ar->conf_mutex);
583 return ret;
584}
585
586static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
587 char __user *ubuf,
588 size_t count, loff_t *ppos)
589{
590 struct ieee80211_sta *sta = file->private_data;
591 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
592 struct ath11k *ar = arsta->arvif->ar;
593 char buf[32] = {};
594 int len;
595
596 mutex_lock(&ar->conf_mutex);
597 len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
598 ar->debug.pktlog_peer_valid,
599 ar->debug.pktlog_peer_addr);
600 mutex_unlock(&ar->conf_mutex);
601
602 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
603}
604
605static const struct file_operations fops_peer_pktlog = {
606 .write = ath11k_dbg_sta_write_peer_pktlog,
607 .read = ath11k_dbg_sta_read_peer_pktlog,
608 .open = simple_open,
609 .owner = THIS_MODULE,
610 .llseek = default_llseek,
611};
612
613static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
614 const char __user *user_buf,
615 size_t count, loff_t *ppos)
616{
617 struct ieee80211_sta *sta = file->private_data;
618 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
619 struct ath11k *ar = arsta->arvif->ar;
620 u32 tid, initiator, reason;
621 int ret;
622 char buf[64] = {};
623
624 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
625 user_buf, count);
626 if (ret <= 0)
627 return ret;
628
629 ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
630 if (ret != 3)
631 return -EINVAL;
632
633 /* Valid TID values are 0 through 15 */
634 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
635 return -EINVAL;
636
637 mutex_lock(&ar->conf_mutex);
638 if (ar->state != ATH11K_STATE_ON ||
639 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
640 ret = count;
641 goto out;
642 }
643
644 ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
645 tid, initiator, reason);
646 if (ret) {
647 ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
648 arsta->arvif->vdev_id, sta->addr, tid, initiator,
649 reason);
650 }
651 ret = count;
652out:
653 mutex_unlock(&ar->conf_mutex);
654 return ret;
655}
656
657static const struct file_operations fops_delba = {
658 .write = ath11k_dbg_sta_write_delba,
659 .open = simple_open,
660 .owner = THIS_MODULE,
661 .llseek = default_llseek,
662};
663
664static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
665 const char __user *user_buf,
666 size_t count, loff_t *ppos)
667{
668 struct ieee80211_sta *sta = file->private_data;
669 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
670 struct ath11k *ar = arsta->arvif->ar;
671 u32 tid, status;
672 int ret;
673 char buf[64] = {};
674
675 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
676 user_buf, count);
677 if (ret <= 0)
678 return ret;
679
680 ret = sscanf(buf, "%u %u", &tid, &status);
681 if (ret != 2)
682 return -EINVAL;
683
684 /* Valid TID values are 0 through 15 */
685 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
686 return -EINVAL;
687
688 mutex_lock(&ar->conf_mutex);
689 if (ar->state != ATH11K_STATE_ON ||
690 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
691 ret = count;
692 goto out;
693 }
694
695 ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
696 tid, status);
697 if (ret) {
698 ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
699 arsta->arvif->vdev_id, sta->addr, tid, status);
700 }
701 ret = count;
702out:
703 mutex_unlock(&ar->conf_mutex);
704 return ret;
705}
706
707static const struct file_operations fops_addba_resp = {
708 .write = ath11k_dbg_sta_write_addba_resp,
709 .open = simple_open,
710 .owner = THIS_MODULE,
711 .llseek = default_llseek,
712};
713
714static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
715 const char __user *user_buf,
716 size_t count, loff_t *ppos)
717{
718 struct ieee80211_sta *sta = file->private_data;
719 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
720 struct ath11k *ar = arsta->arvif->ar;
721 u32 tid, buf_size;
722 int ret;
723 char buf[64] = {};
724
725 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
726 user_buf, count);
727 if (ret <= 0)
728 return ret;
729
730 ret = sscanf(buf, "%u %u", &tid, &buf_size);
731 if (ret != 2)
732 return -EINVAL;
733
734 /* Valid TID values are 0 through 15 */
735 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
736 return -EINVAL;
737
738 mutex_lock(&ar->conf_mutex);
739 if (ar->state != ATH11K_STATE_ON ||
740 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
741 ret = count;
742 goto out;
743 }
744
745 ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
746 tid, buf_size);
747 if (ret) {
748 ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
749 arsta->arvif->vdev_id, sta->addr, tid, buf_size);
750 }
751
752 ret = count;
753out:
754 mutex_unlock(&ar->conf_mutex);
755 return ret;
756}
757
758static const struct file_operations fops_addba = {
759 .write = ath11k_dbg_sta_write_addba,
760 .open = simple_open,
761 .owner = THIS_MODULE,
762 .llseek = default_llseek,
763};
764
765static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
766 char __user *user_buf,
767 size_t count, loff_t *ppos)
768{
769 struct ieee80211_sta *sta = file->private_data;
770 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
771 struct ath11k *ar = arsta->arvif->ar;
772 char buf[64];
773 int len = 0;
774
775 mutex_lock(&ar->conf_mutex);
776 len = scnprintf(buf, sizeof(buf) - len,
777 "aggregation mode: %s\n\n%s\n%s\n",
778 (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
779 "auto" : "manual", "auto = 0", "manual = 1");
780 mutex_unlock(&ar->conf_mutex);
781
782 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
783}
784
785static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
786 const char __user *user_buf,
787 size_t count, loff_t *ppos)
788{
789 struct ieee80211_sta *sta = file->private_data;
790 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
791 struct ath11k *ar = arsta->arvif->ar;
792 u32 aggr_mode;
793 int ret;
794
795 if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
796 return -EINVAL;
797
798 if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
799 return -EINVAL;
800
801 mutex_lock(&ar->conf_mutex);
802 if (ar->state != ATH11K_STATE_ON ||
803 aggr_mode == arsta->aggr_mode) {
804 ret = count;
805 goto out;
806 }
807
808 ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
809 if (ret) {
810 ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
811 ret);
812 goto out;
813 }
814
815 arsta->aggr_mode = aggr_mode;
816out:
817 mutex_unlock(&ar->conf_mutex);
818 return ret;
819}
820
821static const struct file_operations fops_aggr_mode = {
822 .read = ath11k_dbg_sta_read_aggr_mode,
823 .write = ath11k_dbg_sta_write_aggr_mode,
824 .open = simple_open,
825 .owner = THIS_MODULE,
826 .llseek = default_llseek,
827};
828
829static ssize_t
830ath11k_write_htt_peer_stats_reset(struct file *file,
831 const char __user *user_buf,
832 size_t count, loff_t *ppos)
833{
834 struct ieee80211_sta *sta = file->private_data;
835 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
836 struct ath11k *ar = arsta->arvif->ar;
837 struct htt_ext_stats_cfg_params cfg_params = {};
838 int ret;
839 u8 type;
840
841 ret = kstrtou8_from_user(user_buf, count, 0, &type);
842 if (ret)
843 return ret;
844
845 if (!type)
846 return ret;
847
848 mutex_lock(&ar->conf_mutex);
849 cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
850 cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
851 HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
852
853 cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
854
855 cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
856 cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
857 cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
858 cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
859
860 cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
861 cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
862
863 cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
864
865 ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
866 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
867 &cfg_params,
868 0ULL);
869 if (ret) {
870 ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
871 mutex_unlock(&ar->conf_mutex);
872 return ret;
873 }
874
875 mutex_unlock(&ar->conf_mutex);
876
877 ret = count;
878
879 return ret;
880}
881
882static const struct file_operations fops_htt_peer_stats_reset = {
883 .write = ath11k_write_htt_peer_stats_reset,
884 .open = simple_open,
885 .owner = THIS_MODULE,
886 .llseek = default_llseek,
887};
888
889static ssize_t ath11k_dbg_sta_read_peer_ps_state(struct file *file,
890 char __user *user_buf,
891 size_t count, loff_t *ppos)
892{
893 struct ieee80211_sta *sta = file->private_data;
894 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
895 struct ath11k *ar = arsta->arvif->ar;
896 char buf[20];
897 int len;
898
899 spin_lock_bh(&ar->data_lock);
900
901 len = scnprintf(buf, sizeof(buf), "%d\n", arsta->peer_ps_state);
902
903 spin_unlock_bh(&ar->data_lock);
904
905 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
906}
907
908static const struct file_operations fops_peer_ps_state = {
909 .open = simple_open,
910 .read = ath11k_dbg_sta_read_peer_ps_state,
911 .owner = THIS_MODULE,
912 .llseek = default_llseek,
913};
914
915static ssize_t ath11k_dbg_sta_read_current_ps_duration(struct file *file,
916 char __user *user_buf,
917 size_t count,
918 loff_t *ppos)
919{
920 struct ieee80211_sta *sta = file->private_data;
921 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
922 struct ath11k *ar = arsta->arvif->ar;
923 u64 time_since_station_in_power_save;
924 char buf[20];
925 int len;
926
927 spin_lock_bh(&ar->data_lock);
928
929 if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
930 arsta->peer_current_ps_valid)
931 time_since_station_in_power_save = jiffies_to_msecs(jiffies
932 - arsta->ps_start_jiffies);
933 else
934 time_since_station_in_power_save = 0;
935
936 len = scnprintf(buf, sizeof(buf), "%llu\n",
937 time_since_station_in_power_save);
938 spin_unlock_bh(&ar->data_lock);
939
940 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
941}
942
943static const struct file_operations fops_current_ps_duration = {
944 .open = simple_open,
945 .read = ath11k_dbg_sta_read_current_ps_duration,
946 .owner = THIS_MODULE,
947 .llseek = default_llseek,
948};
949
950static ssize_t ath11k_dbg_sta_read_total_ps_duration(struct file *file,
951 char __user *user_buf,
952 size_t count, loff_t *ppos)
953{
954 struct ieee80211_sta *sta = file->private_data;
955 struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
956 struct ath11k *ar = arsta->arvif->ar;
957 char buf[20];
958 u64 power_save_duration;
959 int len;
960
961 spin_lock_bh(&ar->data_lock);
962
963 if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
964 arsta->peer_current_ps_valid)
965 power_save_duration = jiffies_to_msecs(jiffies
966 - arsta->ps_start_jiffies)
967 + arsta->ps_total_duration;
968 else
969 power_save_duration = arsta->ps_total_duration;
970
971 len = scnprintf(buf, sizeof(buf), "%llu\n", power_save_duration);
972
973 spin_unlock_bh(&ar->data_lock);
974
975 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
976}
977
978static const struct file_operations fops_total_ps_duration = {
979 .open = simple_open,
980 .read = ath11k_dbg_sta_read_total_ps_duration,
981 .owner = THIS_MODULE,
982 .llseek = default_llseek,
983};
984
985void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
986 struct ieee80211_sta *sta, struct dentry *dir)
987{
988 struct ath11k *ar = hw->priv;
989
990 if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
991 debugfs_create_file("tx_stats", 0400, dir, sta,
992 &fops_tx_stats);
993 if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
994 debugfs_create_file("rx_stats", 0400, dir, sta,
995 &fops_rx_stats);
996
997 debugfs_create_file("htt_peer_stats", 0400, dir, sta,
998 &fops_htt_peer_stats);
999
1000 debugfs_create_file("peer_pktlog", 0644, dir, sta,
1001 &fops_peer_pktlog);
1002
1003 debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
1004 debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
1005 debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
1006 debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
1007
1008 if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
1009 ar->ab->wmi_ab.svc_map))
1010 debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
1011 &fops_htt_peer_stats_reset);
1012
1013#ifdef CONFIG_ATH11K_CFR
1014 if (test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT,
1015 ar->ab->wmi_ab.svc_map))
1016 debugfs_create_file("cfr_capture", 0600, dir, sta,
1017 &fops_peer_cfr_capture);
1018#endif/* CONFIG_ATH11K_CFR */
1019
1020 debugfs_create_file("peer_ps_state", 0400, dir, sta,
1021 &fops_peer_ps_state);
1022
1023 if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
1024 ar->ab->wmi_ab.svc_map)) {
1025 debugfs_create_file("current_ps_duration", 0440, dir, sta,
1026 &fops_current_ps_duration);
1027 debugfs_create_file("total_ps_duration", 0440, dir, sta,
1028 &fops_total_ps_duration);
1029 }
1030}