Loading...
1// SPDX-License-Identifier: BSD-3-Clause-Clear
2/*
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
5 */
6
7#include <linux/vmalloc.h>
8#include "core.h"
9#include "debug.h"
10
11void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
12{
13 struct va_format vaf = {
14 .fmt = fmt,
15 };
16 va_list args;
17
18 va_start(args, fmt);
19 vaf.va = &args;
20 dev_info(ab->dev, "%pV", &vaf);
21 trace_ath11k_log_info(ab, &vaf);
22 va_end(args);
23}
24EXPORT_SYMBOL(ath11k_info);
25
26void ath11k_err(struct ath11k_base *ab, const char *fmt, ...)
27{
28 struct va_format vaf = {
29 .fmt = fmt,
30 };
31 va_list args;
32
33 va_start(args, fmt);
34 vaf.va = &args;
35 dev_err(ab->dev, "%pV", &vaf);
36 trace_ath11k_log_err(ab, &vaf);
37 va_end(args);
38}
39EXPORT_SYMBOL(ath11k_err);
40
41void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...)
42{
43 struct va_format vaf = {
44 .fmt = fmt,
45 };
46 va_list args;
47
48 va_start(args, fmt);
49 vaf.va = &args;
50 dev_warn_ratelimited(ab->dev, "%pV", &vaf);
51 trace_ath11k_log_warn(ab, &vaf);
52 va_end(args);
53}
54EXPORT_SYMBOL(ath11k_warn);
55
56#ifdef CONFIG_ATH11K_DEBUG
57
58void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask,
59 const char *fmt, ...)
60{
61 struct va_format vaf;
62 va_list args;
63
64 va_start(args, fmt);
65
66 vaf.fmt = fmt;
67 vaf.va = &args;
68
69 if (ath11k_debug_mask & mask)
70 dev_printk(KERN_DEBUG, ab->dev, "%s %pV", ath11k_dbg_str(mask), &vaf);
71
72 trace_ath11k_log_dbg(ab, mask, &vaf);
73
74 va_end(args);
75}
76EXPORT_SYMBOL(__ath11k_dbg);
77
78void ath11k_dbg_dump(struct ath11k_base *ab,
79 enum ath11k_debug_mask mask,
80 const char *msg, const char *prefix,
81 const void *buf, size_t len)
82{
83 char linebuf[256];
84 size_t linebuflen;
85 const void *ptr;
86
87 if (ath11k_debug_mask & mask) {
88 if (msg)
89 __ath11k_dbg(ab, mask, "%s\n", msg);
90
91 for (ptr = buf; (ptr - buf) < len; ptr += 16) {
92 linebuflen = 0;
93 linebuflen += scnprintf(linebuf + linebuflen,
94 sizeof(linebuf) - linebuflen,
95 "%s%08x: ",
96 (prefix ? prefix : ""),
97 (unsigned int)(ptr - buf));
98 hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
99 linebuf + linebuflen,
100 sizeof(linebuf) - linebuflen, true);
101 dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf);
102 }
103 }
104
105 /* tracing code doesn't like null strings */
106 trace_ath11k_log_dbg_dump(ab, msg ? msg : "", prefix ? prefix : "",
107 buf, len);
108}
109EXPORT_SYMBOL(ath11k_dbg_dump);
110
111#endif /* CONFIG_ATH11K_DEBUG */
1// SPDX-License-Identifier: BSD-3-Clause-Clear
2/*
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/vmalloc.h>
7#include "core.h"
8#include "debug.h"
9#include "wmi.h"
10#include "hal_rx.h"
11#include "dp_tx.h"
12#include "debug_htt_stats.h"
13#include "peer.h"
14
15static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
16 "REO2SW1_RING",
17 "REO2SW2_RING",
18 "REO2SW3_RING",
19 "REO2SW4_RING",
20 "WBM2REO_LINK_RING",
21 "REO2TCL_RING",
22 "REO2FW_RING",
23 "RELEASE_RING",
24 "PPE_RELEASE_RING",
25 "TCL2TQM_RING",
26 "TQM_RELEASE_RING",
27 "REO_RELEASE_RING",
28 "WBM2SW0_RELEASE_RING",
29 "WBM2SW1_RELEASE_RING",
30 "WBM2SW2_RELEASE_RING",
31 "WBM2SW3_RELEASE_RING",
32 "REO_CMD_RING",
33 "REO_STATUS_RING",
34};
35
36static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
37 "FW2RXDMA_BUF_RING",
38 "FW2RXDMA_STATUS_RING",
39 "FW2RXDMA_LINK_RING",
40 "SW2RXDMA_BUF_RING",
41 "WBM2RXDMA_LINK_RING",
42 "RXDMA2FW_RING",
43 "RXDMA2SW_RING",
44 "RXDMA2RELEASE_RING",
45 "RXDMA2REO_RING",
46 "MONITOR_STATUS_RING",
47 "MONITOR_BUF_RING",
48 "MONITOR_DESC_RING",
49 "MONITOR_DEST_RING",
50};
51
52void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
53{
54 struct va_format vaf = {
55 .fmt = fmt,
56 };
57 va_list args;
58
59 va_start(args, fmt);
60 vaf.va = &args;
61 dev_info(ab->dev, "%pV", &vaf);
62 /* TODO: Trace the log */
63 va_end(args);
64}
65
66void ath11k_err(struct ath11k_base *ab, const char *fmt, ...)
67{
68 struct va_format vaf = {
69 .fmt = fmt,
70 };
71 va_list args;
72
73 va_start(args, fmt);
74 vaf.va = &args;
75 dev_err(ab->dev, "%pV", &vaf);
76 /* TODO: Trace the log */
77 va_end(args);
78}
79
80void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...)
81{
82 struct va_format vaf = {
83 .fmt = fmt,
84 };
85 va_list args;
86
87 va_start(args, fmt);
88 vaf.va = &args;
89 dev_warn_ratelimited(ab->dev, "%pV", &vaf);
90 /* TODO: Trace the log */
91 va_end(args);
92}
93
94#ifdef CONFIG_ATH11K_DEBUG
95void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask,
96 const char *fmt, ...)
97{
98 struct va_format vaf;
99 va_list args;
100
101 va_start(args, fmt);
102
103 vaf.fmt = fmt;
104 vaf.va = &args;
105
106 if (ath11k_debug_mask & mask)
107 dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf);
108
109 /* TODO: trace log */
110
111 va_end(args);
112}
113
114void ath11k_dbg_dump(struct ath11k_base *ab,
115 enum ath11k_debug_mask mask,
116 const char *msg, const char *prefix,
117 const void *buf, size_t len)
118{
119 char linebuf[256];
120 size_t linebuflen;
121 const void *ptr;
122
123 if (ath11k_debug_mask & mask) {
124 if (msg)
125 __ath11k_dbg(ab, mask, "%s\n", msg);
126
127 for (ptr = buf; (ptr - buf) < len; ptr += 16) {
128 linebuflen = 0;
129 linebuflen += scnprintf(linebuf + linebuflen,
130 sizeof(linebuf) - linebuflen,
131 "%s%08x: ",
132 (prefix ? prefix : ""),
133 (unsigned int)(ptr - buf));
134 hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
135 linebuf + linebuflen,
136 sizeof(linebuf) - linebuflen, true);
137 dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf);
138 }
139 }
140}
141
142#endif
143
144#ifdef CONFIG_ATH11K_DEBUGFS
145static void ath11k_fw_stats_pdevs_free(struct list_head *head)
146{
147 struct ath11k_fw_stats_pdev *i, *tmp;
148
149 list_for_each_entry_safe(i, tmp, head, list) {
150 list_del(&i->list);
151 kfree(i);
152 }
153}
154
155static void ath11k_fw_stats_vdevs_free(struct list_head *head)
156{
157 struct ath11k_fw_stats_vdev *i, *tmp;
158
159 list_for_each_entry_safe(i, tmp, head, list) {
160 list_del(&i->list);
161 kfree(i);
162 }
163}
164
165static void ath11k_fw_stats_bcn_free(struct list_head *head)
166{
167 struct ath11k_fw_stats_bcn *i, *tmp;
168
169 list_for_each_entry_safe(i, tmp, head, list) {
170 list_del(&i->list);
171 kfree(i);
172 }
173}
174
175static void ath11k_debug_fw_stats_reset(struct ath11k *ar)
176{
177 spin_lock_bh(&ar->data_lock);
178 ar->debug.fw_stats_done = false;
179 ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
180 ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
181 spin_unlock_bh(&ar->data_lock);
182}
183
184void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
185{
186 struct ath11k_fw_stats stats = {};
187 struct ath11k *ar;
188 struct ath11k_pdev *pdev;
189 bool is_end;
190 static unsigned int num_vdev, num_bcn;
191 size_t total_vdevs_started = 0;
192 int i, ret;
193
194 INIT_LIST_HEAD(&stats.pdevs);
195 INIT_LIST_HEAD(&stats.vdevs);
196 INIT_LIST_HEAD(&stats.bcn);
197
198 ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
199 if (ret) {
200 ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
201 goto free;
202 }
203
204 rcu_read_lock();
205 ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
206 if (!ar) {
207 rcu_read_unlock();
208 ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
209 stats.pdev_id, ret);
210 goto free;
211 }
212
213 spin_lock_bh(&ar->data_lock);
214
215 if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
216 list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
217 ar->debug.fw_stats_done = true;
218 goto complete;
219 }
220
221 if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
222 if (list_empty(&stats.vdevs)) {
223 ath11k_warn(ab, "empty vdev stats");
224 goto complete;
225 }
226 /* FW sends all the active VDEV stats irrespective of PDEV,
227 * hence limit until the count of all VDEVs started
228 */
229 for (i = 0; i < ab->num_radios; i++) {
230 pdev = rcu_dereference(ab->pdevs_active[i]);
231 if (pdev && pdev->ar)
232 total_vdevs_started += ar->num_started_vdevs;
233 }
234
235 is_end = ((++num_vdev) == total_vdevs_started);
236
237 list_splice_tail_init(&stats.vdevs,
238 &ar->debug.fw_stats.vdevs);
239
240 if (is_end) {
241 ar->debug.fw_stats_done = true;
242 num_vdev = 0;
243 }
244 goto complete;
245 }
246
247 if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
248 if (list_empty(&stats.bcn)) {
249 ath11k_warn(ab, "empty bcn stats");
250 goto complete;
251 }
252 /* Mark end until we reached the count of all started VDEVs
253 * within the PDEV
254 */
255 is_end = ((++num_bcn) == ar->num_started_vdevs);
256
257 list_splice_tail_init(&stats.bcn,
258 &ar->debug.fw_stats.bcn);
259
260 if (is_end) {
261 ar->debug.fw_stats_done = true;
262 num_bcn = 0;
263 }
264 }
265complete:
266 complete(&ar->debug.fw_stats_complete);
267 rcu_read_unlock();
268 spin_unlock_bh(&ar->data_lock);
269
270free:
271 ath11k_fw_stats_pdevs_free(&stats.pdevs);
272 ath11k_fw_stats_vdevs_free(&stats.vdevs);
273 ath11k_fw_stats_bcn_free(&stats.bcn);
274}
275
276static int ath11k_debug_fw_stats_request(struct ath11k *ar,
277 struct stats_request_params *req_param)
278{
279 struct ath11k_base *ab = ar->ab;
280 unsigned long timeout, time_left;
281 int ret;
282
283 lockdep_assert_held(&ar->conf_mutex);
284
285 /* FW stats can get split when exceeding the stats data buffer limit.
286 * In that case, since there is no end marking for the back-to-back
287 * received 'update stats' event, we keep a 3 seconds timeout in case,
288 * fw_stats_done is not marked yet
289 */
290 timeout = jiffies + msecs_to_jiffies(3 * HZ);
291
292 ath11k_debug_fw_stats_reset(ar);
293
294 reinit_completion(&ar->debug.fw_stats_complete);
295
296 ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
297
298 if (ret) {
299 ath11k_warn(ab, "could not request fw stats (%d)\n",
300 ret);
301 return ret;
302 }
303
304 time_left =
305 wait_for_completion_timeout(&ar->debug.fw_stats_complete,
306 1 * HZ);
307 if (!time_left)
308 return -ETIMEDOUT;
309
310 for (;;) {
311 if (time_after(jiffies, timeout))
312 break;
313
314 spin_lock_bh(&ar->data_lock);
315 if (ar->debug.fw_stats_done) {
316 spin_unlock_bh(&ar->data_lock);
317 break;
318 }
319 spin_unlock_bh(&ar->data_lock);
320 }
321 return 0;
322}
323
324static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
325{
326 struct ath11k *ar = inode->i_private;
327 struct ath11k_base *ab = ar->ab;
328 struct stats_request_params req_param;
329 void *buf = NULL;
330 int ret;
331
332 mutex_lock(&ar->conf_mutex);
333
334 if (ar->state != ATH11K_STATE_ON) {
335 ret = -ENETDOWN;
336 goto err_unlock;
337 }
338
339 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
340 if (!buf) {
341 ret = -ENOMEM;
342 goto err_unlock;
343 }
344
345 req_param.pdev_id = ar->pdev->pdev_id;
346 req_param.vdev_id = 0;
347 req_param.stats_id = WMI_REQUEST_PDEV_STAT;
348
349 ret = ath11k_debug_fw_stats_request(ar, &req_param);
350 if (ret) {
351 ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
352 goto err_free;
353 }
354
355 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
356 buf);
357
358 file->private_data = buf;
359
360 mutex_unlock(&ar->conf_mutex);
361 return 0;
362
363err_free:
364 vfree(buf);
365
366err_unlock:
367 mutex_unlock(&ar->conf_mutex);
368 return ret;
369}
370
371static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
372{
373 vfree(file->private_data);
374
375 return 0;
376}
377
378static ssize_t ath11k_read_pdev_stats(struct file *file,
379 char __user *user_buf,
380 size_t count, loff_t *ppos)
381{
382 const char *buf = file->private_data;
383 size_t len = strlen(buf);
384
385 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
386}
387
388static const struct file_operations fops_pdev_stats = {
389 .open = ath11k_open_pdev_stats,
390 .release = ath11k_release_pdev_stats,
391 .read = ath11k_read_pdev_stats,
392 .owner = THIS_MODULE,
393 .llseek = default_llseek,
394};
395
396static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
397{
398 struct ath11k *ar = inode->i_private;
399 struct stats_request_params req_param;
400 void *buf = NULL;
401 int ret;
402
403 mutex_lock(&ar->conf_mutex);
404
405 if (ar->state != ATH11K_STATE_ON) {
406 ret = -ENETDOWN;
407 goto err_unlock;
408 }
409
410 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
411 if (!buf) {
412 ret = -ENOMEM;
413 goto err_unlock;
414 }
415
416 req_param.pdev_id = ar->pdev->pdev_id;
417 /* VDEV stats is always sent for all active VDEVs from FW */
418 req_param.vdev_id = 0;
419 req_param.stats_id = WMI_REQUEST_VDEV_STAT;
420
421 ret = ath11k_debug_fw_stats_request(ar, &req_param);
422 if (ret) {
423 ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
424 goto err_free;
425 }
426
427 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
428 buf);
429
430 file->private_data = buf;
431
432 mutex_unlock(&ar->conf_mutex);
433 return 0;
434
435err_free:
436 vfree(buf);
437
438err_unlock:
439 mutex_unlock(&ar->conf_mutex);
440 return ret;
441}
442
443static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
444{
445 vfree(file->private_data);
446
447 return 0;
448}
449
450static ssize_t ath11k_read_vdev_stats(struct file *file,
451 char __user *user_buf,
452 size_t count, loff_t *ppos)
453{
454 const char *buf = file->private_data;
455 size_t len = strlen(buf);
456
457 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
458}
459
460static const struct file_operations fops_vdev_stats = {
461 .open = ath11k_open_vdev_stats,
462 .release = ath11k_release_vdev_stats,
463 .read = ath11k_read_vdev_stats,
464 .owner = THIS_MODULE,
465 .llseek = default_llseek,
466};
467
468static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
469{
470 struct ath11k *ar = inode->i_private;
471 struct ath11k_vif *arvif;
472 struct stats_request_params req_param;
473 void *buf = NULL;
474 int ret;
475
476 mutex_lock(&ar->conf_mutex);
477
478 if (ar->state != ATH11K_STATE_ON) {
479 ret = -ENETDOWN;
480 goto err_unlock;
481 }
482
483 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
484 if (!buf) {
485 ret = -ENOMEM;
486 goto err_unlock;
487 }
488
489 req_param.stats_id = WMI_REQUEST_BCN_STAT;
490 req_param.pdev_id = ar->pdev->pdev_id;
491
492 /* loop all active VDEVs for bcn stats */
493 list_for_each_entry(arvif, &ar->arvifs, list) {
494 if (!arvif->is_up)
495 continue;
496
497 req_param.vdev_id = arvif->vdev_id;
498 ret = ath11k_debug_fw_stats_request(ar, &req_param);
499 if (ret) {
500 ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
501 goto err_free;
502 }
503 }
504
505 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
506 buf);
507
508 /* since beacon stats request is looped for all active VDEVs, saved fw
509 * stats is not freed for each request until done for all active VDEVs
510 */
511 spin_lock_bh(&ar->data_lock);
512 ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
513 spin_unlock_bh(&ar->data_lock);
514
515 file->private_data = buf;
516
517 mutex_unlock(&ar->conf_mutex);
518 return 0;
519
520err_free:
521 vfree(buf);
522
523err_unlock:
524 mutex_unlock(&ar->conf_mutex);
525 return ret;
526}
527
528static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
529{
530 vfree(file->private_data);
531
532 return 0;
533}
534
535static ssize_t ath11k_read_bcn_stats(struct file *file,
536 char __user *user_buf,
537 size_t count, loff_t *ppos)
538{
539 const char *buf = file->private_data;
540 size_t len = strlen(buf);
541
542 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
543}
544
545static const struct file_operations fops_bcn_stats = {
546 .open = ath11k_open_bcn_stats,
547 .release = ath11k_release_bcn_stats,
548 .read = ath11k_read_bcn_stats,
549 .owner = THIS_MODULE,
550 .llseek = default_llseek,
551};
552
553static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
554 char __user *user_buf,
555 size_t count, loff_t *ppos)
556{
557 const char buf[] =
558 "To simulate firmware crash write one of the keywords to this file:\n"
559 "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
560 "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
561
562 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
563}
564
565/* Simulate firmware crash:
566 * 'soft': Call wmi command causing firmware hang. This firmware hang is
567 * recoverable by warm firmware reset.
568 * 'hard': Force firmware crash by setting any vdev parameter for not allowed
569 * vdev id. This is hard firmware crash because it is recoverable only by cold
570 * firmware reset.
571 */
572static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
573 const char __user *user_buf,
574 size_t count, loff_t *ppos)
575{
576 struct ath11k_base *ab = file->private_data;
577 struct ath11k_pdev *pdev;
578 struct ath11k *ar = ab->pdevs[0].ar;
579 char buf[32] = {0};
580 ssize_t rc;
581 int i, ret, radioup = 0;
582
583 for (i = 0; i < ab->num_radios; i++) {
584 pdev = &ab->pdevs[i];
585 ar = pdev->ar;
586 if (ar && ar->state == ATH11K_STATE_ON) {
587 radioup = 1;
588 break;
589 }
590 }
591 /* filter partial writes and invalid commands */
592 if (*ppos != 0 || count >= sizeof(buf) || count == 0)
593 return -EINVAL;
594
595 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
596 if (rc < 0)
597 return rc;
598
599 /* drop the possible '\n' from the end */
600 if (buf[*ppos - 1] == '\n')
601 buf[*ppos - 1] = '\0';
602
603 if (radioup == 0) {
604 ret = -ENETDOWN;
605 goto exit;
606 }
607
608 if (!strcmp(buf, "assert")) {
609 ath11k_info(ab, "simulating firmware assert crash\n");
610 ret = ath11k_wmi_force_fw_hang_cmd(ar,
611 ATH11K_WMI_FW_HANG_ASSERT_TYPE,
612 ATH11K_WMI_FW_HANG_DELAY);
613 } else {
614 ret = -EINVAL;
615 goto exit;
616 }
617
618 if (ret) {
619 ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
620 goto exit;
621 }
622
623 ret = count;
624
625exit:
626 return ret;
627}
628
629static const struct file_operations fops_simulate_fw_crash = {
630 .read = ath11k_read_simulate_fw_crash,
631 .write = ath11k_write_simulate_fw_crash,
632 .open = simple_open,
633 .owner = THIS_MODULE,
634 .llseek = default_llseek,
635};
636
637static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
638 const char __user *ubuf,
639 size_t count, loff_t *ppos)
640{
641 struct ath11k *ar = file->private_data;
642 u32 filter;
643 int ret;
644
645 if (kstrtouint_from_user(ubuf, count, 0, &filter))
646 return -EINVAL;
647
648 mutex_lock(&ar->conf_mutex);
649
650 if (ar->state != ATH11K_STATE_ON) {
651 ret = -ENETDOWN;
652 goto out;
653 }
654
655 if (filter == ar->debug.extd_tx_stats) {
656 ret = count;
657 goto out;
658 }
659
660 ar->debug.extd_tx_stats = filter;
661 ret = count;
662
663out:
664 mutex_unlock(&ar->conf_mutex);
665 return ret;
666}
667
668static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
669 char __user *ubuf,
670 size_t count, loff_t *ppos)
671
672{
673 char buf[32] = {0};
674 struct ath11k *ar = file->private_data;
675 int len = 0;
676
677 mutex_lock(&ar->conf_mutex);
678 len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
679 ar->debug.extd_tx_stats);
680 mutex_unlock(&ar->conf_mutex);
681
682 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
683}
684
685static const struct file_operations fops_extd_tx_stats = {
686 .read = ath11k_read_enable_extd_tx_stats,
687 .write = ath11k_write_enable_extd_tx_stats,
688 .open = simple_open
689};
690
691static ssize_t ath11k_write_extd_rx_stats(struct file *file,
692 const char __user *ubuf,
693 size_t count, loff_t *ppos)
694{
695 struct ath11k *ar = file->private_data;
696 struct htt_rx_ring_tlv_filter tlv_filter = {0};
697 u32 enable, rx_filter = 0, ring_id;
698 int ret;
699
700 if (kstrtouint_from_user(ubuf, count, 0, &enable))
701 return -EINVAL;
702
703 mutex_lock(&ar->conf_mutex);
704
705 if (ar->state != ATH11K_STATE_ON) {
706 ret = -ENETDOWN;
707 goto exit;
708 }
709
710 if (enable > 1) {
711 ret = -EINVAL;
712 goto exit;
713 }
714
715 if (enable == ar->debug.extd_rx_stats) {
716 ret = count;
717 goto exit;
718 }
719
720 if (enable) {
721 rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
722 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
723 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
724 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
725 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
726 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
727
728 tlv_filter.rx_filter = rx_filter;
729 tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
730 tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
731 tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
732 tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
733 HTT_RX_FP_DATA_FILTER_FLASG3;
734 } else {
735 tlv_filter = ath11k_mac_mon_status_filter_default;
736 }
737
738 ar->debug.rx_filter = tlv_filter.rx_filter;
739
740 ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
741 ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
742 HAL_RXDMA_MONITOR_STATUS,
743 DP_RX_BUFFER_SIZE, &tlv_filter);
744
745 if (ret) {
746 ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
747 goto exit;
748 }
749
750 ar->debug.extd_rx_stats = enable;
751 ret = count;
752exit:
753 mutex_unlock(&ar->conf_mutex);
754 return ret;
755}
756
757static ssize_t ath11k_read_extd_rx_stats(struct file *file,
758 char __user *ubuf,
759 size_t count, loff_t *ppos)
760{
761 struct ath11k *ar = file->private_data;
762 char buf[32];
763 int len = 0;
764
765 mutex_lock(&ar->conf_mutex);
766 len = scnprintf(buf, sizeof(buf) - len, "%d\n",
767 ar->debug.extd_rx_stats);
768 mutex_unlock(&ar->conf_mutex);
769
770 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
771}
772
773static const struct file_operations fops_extd_rx_stats = {
774 .read = ath11k_read_extd_rx_stats,
775 .write = ath11k_write_extd_rx_stats,
776 .open = simple_open,
777};
778
779static int ath11k_fill_bp_stats(struct ath11k_base *ab,
780 struct ath11k_bp_stats *bp_stats,
781 char *buf, int len, int size)
782{
783 lockdep_assert_held(&ab->base_lock);
784
785 len += scnprintf(buf + len, size - len, "count: %u\n",
786 bp_stats->count);
787 len += scnprintf(buf + len, size - len, "hp: %u\n",
788 bp_stats->hp);
789 len += scnprintf(buf + len, size - len, "tp: %u\n",
790 bp_stats->tp);
791 len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
792 jiffies_to_msecs(jiffies - bp_stats->jiffies));
793 return len;
794}
795
796static ssize_t ath11k_debug_dump_soc_ring_bp_stats(struct ath11k_base *ab,
797 char *buf, int size)
798{
799 struct ath11k_bp_stats *bp_stats;
800 bool stats_rxd = false;
801 u8 i, pdev_idx;
802 int len = 0;
803
804 len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
805 len += scnprintf(buf + len, size - len, "==================\n");
806
807 spin_lock_bh(&ab->base_lock);
808 for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
809 bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
810
811 if (!bp_stats->count)
812 continue;
813
814 len += scnprintf(buf + len, size - len, "Ring: %s\n",
815 htt_bp_umac_ring[i]);
816 len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
817 stats_rxd = true;
818 }
819
820 for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
821 for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
822 bp_stats =
823 &ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
824
825 if (!bp_stats->count)
826 continue;
827
828 len += scnprintf(buf + len, size - len, "Ring: %s\n",
829 htt_bp_lmac_ring[i]);
830 len += scnprintf(buf + len, size - len, "pdev: %d\n",
831 pdev_idx);
832 len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
833 stats_rxd = true;
834 }
835 }
836 spin_unlock_bh(&ab->base_lock);
837
838 if (!stats_rxd)
839 len += scnprintf(buf + len, size - len,
840 "No Ring Backpressure stats received\n\n");
841
842 return len;
843}
844
845static ssize_t ath11k_debug_dump_soc_dp_stats(struct file *file,
846 char __user *user_buf,
847 size_t count, loff_t *ppos)
848{
849 struct ath11k_base *ab = file->private_data;
850 struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
851 int len = 0, i, retval;
852 const int size = 4096;
853 static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
854 "Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
855 "Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
856 "AMSDU parse", "SA timeout", "DA timeout",
857 "Flow timeout", "Flush req"};
858 static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
859 "Desc addr zero", "Desc inval", "AMPDU in non BA",
860 "Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
861 "Frame OOR", "BAR OOR", "No BA session",
862 "Frame SN equal SSN", "PN check fail", "2k err",
863 "PN err", "Desc blocked"};
864
865 char *buf;
866
867 buf = kzalloc(size, GFP_KERNEL);
868 if (!buf)
869 return -ENOMEM;
870
871 len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
872 len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
873 soc_stats->err_ring_pkts);
874 len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
875 soc_stats->invalid_rbm);
876 len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
877 for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
878 len += scnprintf(buf + len, size - len, "%s: %u\n",
879 rxdma_err[i], soc_stats->rxdma_error[i]);
880
881 len += scnprintf(buf + len, size - len, "\nREO errors:\n");
882 for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
883 len += scnprintf(buf + len, size - len, "%s: %u\n",
884 reo_err[i], soc_stats->reo_error[i]);
885
886 len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
887 len += scnprintf(buf + len, size - len,
888 "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
889 soc_stats->hal_reo_error[0],
890 soc_stats->hal_reo_error[1],
891 soc_stats->hal_reo_error[2],
892 soc_stats->hal_reo_error[3]);
893
894 len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
895 len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
896
897 for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
898 len += scnprintf(buf + len, size - len, "ring%d: %u\n",
899 i, soc_stats->tx_err.desc_na[i]);
900
901 len += scnprintf(buf + len, size - len,
902 "\nMisc Transmit Failures: %d\n",
903 atomic_read(&soc_stats->tx_err.misc_fail));
904
905 len += ath11k_debug_dump_soc_ring_bp_stats(ab, buf + len, size - len);
906
907 if (len > size)
908 len = size;
909 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
910 kfree(buf);
911
912 return retval;
913}
914
915static const struct file_operations fops_soc_dp_stats = {
916 .read = ath11k_debug_dump_soc_dp_stats,
917 .open = simple_open,
918 .owner = THIS_MODULE,
919 .llseek = default_llseek,
920};
921
922int ath11k_debug_pdev_create(struct ath11k_base *ab)
923{
924 if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
925 return 0;
926
927 ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
928
929 if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
930 if (IS_ERR(ab->debugfs_soc))
931 return PTR_ERR(ab->debugfs_soc);
932 return -ENOMEM;
933 }
934
935 debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
936 &fops_simulate_fw_crash);
937
938 debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
939 &fops_soc_dp_stats);
940
941 return 0;
942}
943
944void ath11k_debug_pdev_destroy(struct ath11k_base *ab)
945{
946 debugfs_remove_recursive(ab->debugfs_ath11k);
947 ab->debugfs_ath11k = NULL;
948}
949
950int ath11k_debug_soc_create(struct ath11k_base *ab)
951{
952 ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
953
954 if (IS_ERR_OR_NULL(ab->debugfs_ath11k)) {
955 if (IS_ERR(ab->debugfs_ath11k))
956 return PTR_ERR(ab->debugfs_ath11k);
957 return -ENOMEM;
958 }
959
960 return 0;
961}
962
963void ath11k_debug_soc_destroy(struct ath11k_base *ab)
964{
965 debugfs_remove_recursive(ab->debugfs_soc);
966 ab->debugfs_soc = NULL;
967}
968
969void ath11k_debug_fw_stats_init(struct ath11k *ar)
970{
971 struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
972 ar->debug.debugfs_pdev);
973
974 ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
975
976 /* all stats debugfs files created are under "fw_stats" directory
977 * created per PDEV
978 */
979 debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
980 &fops_pdev_stats);
981 debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
982 &fops_vdev_stats);
983 debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
984 &fops_bcn_stats);
985
986 INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
987 INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
988 INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
989
990 init_completion(&ar->debug.fw_stats_complete);
991}
992
993static ssize_t ath11k_write_pktlog_filter(struct file *file,
994 const char __user *ubuf,
995 size_t count, loff_t *ppos)
996{
997 struct ath11k *ar = file->private_data;
998 struct htt_rx_ring_tlv_filter tlv_filter = {0};
999 u32 rx_filter = 0, ring_id, filter, mode;
1000 u8 buf[128] = {0};
1001 int ret;
1002 ssize_t rc;
1003
1004 mutex_lock(&ar->conf_mutex);
1005 if (ar->state != ATH11K_STATE_ON) {
1006 ret = -ENETDOWN;
1007 goto out;
1008 }
1009
1010 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1011 if (rc < 0) {
1012 ret = rc;
1013 goto out;
1014 }
1015 buf[rc] = '\0';
1016
1017 ret = sscanf(buf, "0x%x %u", &filter, &mode);
1018 if (ret != 2) {
1019 ret = -EINVAL;
1020 goto out;
1021 }
1022
1023 if (filter) {
1024 ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
1025 if (ret) {
1026 ath11k_warn(ar->ab,
1027 "failed to enable pktlog filter %x: %d\n",
1028 ar->debug.pktlog_filter, ret);
1029 goto out;
1030 }
1031 } else {
1032 ret = ath11k_wmi_pdev_pktlog_disable(ar);
1033 if (ret) {
1034 ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
1035 goto out;
1036 }
1037 }
1038
1039#define HTT_RX_FILTER_TLV_LITE_MODE \
1040 (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
1041 HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
1042 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
1043 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
1044 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
1045 HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
1046
1047 if (mode == ATH11K_PKTLOG_MODE_FULL) {
1048 rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
1049 HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
1050 HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
1051 HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
1052 HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
1053 HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
1054 } else if (mode == ATH11K_PKTLOG_MODE_LITE) {
1055 ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1056 HTT_PPDU_STATS_TAG_PKTLOG);
1057 if (ret) {
1058 ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
1059 goto out;
1060 }
1061
1062 rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
1063 } else {
1064 ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1065 HTT_PPDU_STATS_TAG_DEFAULT);
1066 if (ret) {
1067 ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
1068 ret);
1069 goto out;
1070 }
1071 }
1072
1073 tlv_filter.rx_filter = rx_filter;
1074 if (rx_filter) {
1075 tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
1076 tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
1077 tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
1078 tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
1079 HTT_RX_FP_DATA_FILTER_FLASG3;
1080 }
1081
1082 ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
1083 ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
1084 HAL_RXDMA_MONITOR_STATUS,
1085 DP_RX_BUFFER_SIZE, &tlv_filter);
1086 if (ret) {
1087 ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
1088 goto out;
1089 }
1090
1091 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n",
1092 filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
1093
1094 ar->debug.pktlog_filter = filter;
1095 ar->debug.pktlog_mode = mode;
1096 ret = count;
1097
1098out:
1099 mutex_unlock(&ar->conf_mutex);
1100 return ret;
1101}
1102
1103static ssize_t ath11k_read_pktlog_filter(struct file *file,
1104 char __user *ubuf,
1105 size_t count, loff_t *ppos)
1106
1107{
1108 char buf[32] = {0};
1109 struct ath11k *ar = file->private_data;
1110 int len = 0;
1111
1112 mutex_lock(&ar->conf_mutex);
1113 len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
1114 ar->debug.pktlog_filter,
1115 ar->debug.pktlog_mode);
1116 mutex_unlock(&ar->conf_mutex);
1117
1118 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1119}
1120
1121static const struct file_operations fops_pktlog_filter = {
1122 .read = ath11k_read_pktlog_filter,
1123 .write = ath11k_write_pktlog_filter,
1124 .open = simple_open
1125};
1126
1127static ssize_t ath11k_write_simulate_radar(struct file *file,
1128 const char __user *user_buf,
1129 size_t count, loff_t *ppos)
1130{
1131 struct ath11k *ar = file->private_data;
1132 int ret;
1133
1134 ret = ath11k_wmi_simulate_radar(ar);
1135 if (ret)
1136 return ret;
1137
1138 return count;
1139}
1140
1141static const struct file_operations fops_simulate_radar = {
1142 .write = ath11k_write_simulate_radar,
1143 .open = simple_open
1144};
1145
1146int ath11k_debug_register(struct ath11k *ar)
1147{
1148 struct ath11k_base *ab = ar->ab;
1149 char pdev_name[5];
1150 char buf[100] = {0};
1151
1152 snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
1153
1154 ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1155
1156 if (IS_ERR_OR_NULL(ar->debug.debugfs_pdev)) {
1157 if (IS_ERR(ar->debug.debugfs_pdev))
1158 return PTR_ERR(ar->debug.debugfs_pdev);
1159
1160 return -ENOMEM;
1161 }
1162
1163 /* Create a symlink under ieee80211/phy* */
1164 snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
1165 debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
1166
1167 ath11k_debug_htt_stats_init(ar);
1168
1169 ath11k_debug_fw_stats_init(ar);
1170
1171 debugfs_create_file("ext_tx_stats", 0644,
1172 ar->debug.debugfs_pdev, ar,
1173 &fops_extd_tx_stats);
1174 debugfs_create_file("ext_rx_stats", 0644,
1175 ar->debug.debugfs_pdev, ar,
1176 &fops_extd_rx_stats);
1177 debugfs_create_file("pktlog_filter", 0644,
1178 ar->debug.debugfs_pdev, ar,
1179 &fops_pktlog_filter);
1180
1181 if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
1182 debugfs_create_file("dfs_simulate_radar", 0200,
1183 ar->debug.debugfs_pdev, ar,
1184 &fops_simulate_radar);
1185 debugfs_create_bool("dfs_block_radar_events", 0200,
1186 ar->debug.debugfs_pdev,
1187 &ar->dfs_block_radar_events);
1188 }
1189
1190 return 0;
1191}
1192
1193void ath11k_debug_unregister(struct ath11k *ar)
1194{
1195}
1196#endif /* CONFIG_ATH11K_DEBUGFS */