Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/athk/ath11k/debugfs.c
105419 views
1
// SPDX-License-Identifier: BSD-3-Clause-Clear
2
/*
3
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
4
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
5
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
6
*/
7
8
#include <linux/export.h>
9
#include <linux/vmalloc.h>
10
11
#include "debugfs.h"
12
13
#include "core.h"
14
#include "debug.h"
15
#include "wmi.h"
16
#include "hal_rx.h"
17
#include "dp_tx.h"
18
#include "debugfs_htt_stats.h"
19
#include "peer.h"
20
#include "hif.h"
21
22
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
23
"REO2SW1_RING",
24
"REO2SW2_RING",
25
"REO2SW3_RING",
26
"REO2SW4_RING",
27
"WBM2REO_LINK_RING",
28
"REO2TCL_RING",
29
"REO2FW_RING",
30
"RELEASE_RING",
31
"PPE_RELEASE_RING",
32
"TCL2TQM_RING",
33
"TQM_RELEASE_RING",
34
"REO_RELEASE_RING",
35
"WBM2SW0_RELEASE_RING",
36
"WBM2SW1_RELEASE_RING",
37
"WBM2SW2_RELEASE_RING",
38
"WBM2SW3_RELEASE_RING",
39
"REO_CMD_RING",
40
"REO_STATUS_RING",
41
};
42
43
static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
44
"FW2RXDMA_BUF_RING",
45
"FW2RXDMA_STATUS_RING",
46
"FW2RXDMA_LINK_RING",
47
"SW2RXDMA_BUF_RING",
48
"WBM2RXDMA_LINK_RING",
49
"RXDMA2FW_RING",
50
"RXDMA2SW_RING",
51
"RXDMA2RELEASE_RING",
52
"RXDMA2REO_RING",
53
"MONITOR_STATUS_RING",
54
"MONITOR_BUF_RING",
55
"MONITOR_DESC_RING",
56
"MONITOR_DEST_RING",
57
};
58
59
void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
60
enum wmi_direct_buffer_module id,
61
enum ath11k_dbg_dbr_event event,
62
struct hal_srng *srng)
63
{
64
struct ath11k_debug_dbr *dbr_debug;
65
struct ath11k_dbg_dbr_data *dbr_data;
66
struct ath11k_dbg_dbr_entry *entry;
67
68
if (id >= WMI_DIRECT_BUF_MAX || event >= ATH11K_DBG_DBR_EVENT_MAX)
69
return;
70
71
dbr_debug = ar->debug.dbr_debug[id];
72
if (!dbr_debug)
73
return;
74
75
if (!dbr_debug->dbr_debug_enabled)
76
return;
77
78
dbr_data = &dbr_debug->dbr_dbg_data;
79
80
spin_lock_bh(&dbr_data->lock);
81
82
if (dbr_data->entries) {
83
entry = &dbr_data->entries[dbr_data->dbr_debug_idx];
84
entry->hp = srng->u.src_ring.hp;
85
entry->tp = *srng->u.src_ring.tp_addr;
86
entry->timestamp = jiffies;
87
entry->event = event;
88
89
dbr_data->dbr_debug_idx++;
90
if (dbr_data->dbr_debug_idx ==
91
dbr_data->num_ring_debug_entries)
92
dbr_data->dbr_debug_idx = 0;
93
}
94
95
spin_unlock_bh(&dbr_data->lock);
96
}
97
98
void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats)
99
{
100
struct ath11k_base *ab = ar->ab;
101
bool is_end = true;
102
103
/* WMI_REQUEST_PDEV_STAT, WMI_REQUEST_RSSI_PER_CHAIN_STAT and
104
* WMI_REQUEST_VDEV_STAT requests have been already processed.
105
*/
106
if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
107
if (list_empty(&stats->bcn)) {
108
ath11k_warn(ab, "empty bcn stats");
109
return;
110
}
111
/* Mark end until we reached the count of all started VDEVs
112
* within the PDEV
113
*/
114
if (ar->num_started_vdevs)
115
is_end = ((++ar->fw_stats.num_bcn_recvd) ==
116
ar->num_started_vdevs);
117
118
list_splice_tail_init(&stats->bcn,
119
&ar->fw_stats.bcn);
120
121
if (is_end)
122
complete(&ar->fw_stats_done);
123
}
124
}
125
126
static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
127
{
128
struct ath11k *ar = inode->i_private;
129
struct ath11k_base *ab = ar->ab;
130
struct stats_request_params req_param;
131
void *buf = NULL;
132
int ret;
133
134
mutex_lock(&ar->conf_mutex);
135
136
if (ar->state != ATH11K_STATE_ON) {
137
ret = -ENETDOWN;
138
goto err_unlock;
139
}
140
141
buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
142
if (!buf) {
143
ret = -ENOMEM;
144
goto err_unlock;
145
}
146
147
req_param.pdev_id = ar->pdev->pdev_id;
148
req_param.vdev_id = 0;
149
req_param.stats_id = WMI_REQUEST_PDEV_STAT;
150
151
ret = ath11k_mac_fw_stats_request(ar, &req_param);
152
if (ret) {
153
ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
154
goto err_free;
155
}
156
157
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
158
159
file->private_data = buf;
160
161
mutex_unlock(&ar->conf_mutex);
162
return 0;
163
164
err_free:
165
vfree(buf);
166
167
err_unlock:
168
mutex_unlock(&ar->conf_mutex);
169
return ret;
170
}
171
172
static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
173
{
174
vfree(file->private_data);
175
176
return 0;
177
}
178
179
static ssize_t ath11k_read_pdev_stats(struct file *file,
180
char __user *user_buf,
181
size_t count, loff_t *ppos)
182
{
183
const char *buf = file->private_data;
184
size_t len = strlen(buf);
185
186
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
187
}
188
189
static const struct file_operations fops_pdev_stats = {
190
.open = ath11k_open_pdev_stats,
191
.release = ath11k_release_pdev_stats,
192
.read = ath11k_read_pdev_stats,
193
.owner = THIS_MODULE,
194
.llseek = default_llseek,
195
};
196
197
static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
198
{
199
struct ath11k *ar = inode->i_private;
200
struct stats_request_params req_param;
201
void *buf = NULL;
202
int ret;
203
204
mutex_lock(&ar->conf_mutex);
205
206
if (ar->state != ATH11K_STATE_ON) {
207
ret = -ENETDOWN;
208
goto err_unlock;
209
}
210
211
buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
212
if (!buf) {
213
ret = -ENOMEM;
214
goto err_unlock;
215
}
216
217
req_param.pdev_id = ar->pdev->pdev_id;
218
/* VDEV stats is always sent for all active VDEVs from FW */
219
req_param.vdev_id = 0;
220
req_param.stats_id = WMI_REQUEST_VDEV_STAT;
221
222
ret = ath11k_mac_fw_stats_request(ar, &req_param);
223
if (ret) {
224
ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
225
goto err_free;
226
}
227
228
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
229
230
file->private_data = buf;
231
232
mutex_unlock(&ar->conf_mutex);
233
return 0;
234
235
err_free:
236
vfree(buf);
237
238
err_unlock:
239
mutex_unlock(&ar->conf_mutex);
240
return ret;
241
}
242
243
static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
244
{
245
vfree(file->private_data);
246
247
return 0;
248
}
249
250
static ssize_t ath11k_read_vdev_stats(struct file *file,
251
char __user *user_buf,
252
size_t count, loff_t *ppos)
253
{
254
const char *buf = file->private_data;
255
size_t len = strlen(buf);
256
257
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
258
}
259
260
static const struct file_operations fops_vdev_stats = {
261
.open = ath11k_open_vdev_stats,
262
.release = ath11k_release_vdev_stats,
263
.read = ath11k_read_vdev_stats,
264
.owner = THIS_MODULE,
265
.llseek = default_llseek,
266
};
267
268
static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
269
{
270
struct ath11k *ar = inode->i_private;
271
struct ath11k_vif *arvif;
272
struct stats_request_params req_param;
273
void *buf = NULL;
274
int ret;
275
276
mutex_lock(&ar->conf_mutex);
277
278
if (ar->state != ATH11K_STATE_ON) {
279
ret = -ENETDOWN;
280
goto err_unlock;
281
}
282
283
buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
284
if (!buf) {
285
ret = -ENOMEM;
286
goto err_unlock;
287
}
288
289
req_param.stats_id = WMI_REQUEST_BCN_STAT;
290
req_param.pdev_id = ar->pdev->pdev_id;
291
292
/* loop all active VDEVs for bcn stats */
293
list_for_each_entry(arvif, &ar->arvifs, list) {
294
if (!arvif->is_up)
295
continue;
296
297
req_param.vdev_id = arvif->vdev_id;
298
ret = ath11k_mac_fw_stats_request(ar, &req_param);
299
if (ret) {
300
ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
301
goto err_free;
302
}
303
}
304
305
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
306
307
/* since beacon stats request is looped for all active VDEVs, saved fw
308
* stats is not freed for each request until done for all active VDEVs
309
*/
310
spin_lock_bh(&ar->data_lock);
311
ath11k_fw_stats_bcn_free(&ar->fw_stats.bcn);
312
spin_unlock_bh(&ar->data_lock);
313
314
file->private_data = buf;
315
316
mutex_unlock(&ar->conf_mutex);
317
return 0;
318
319
err_free:
320
vfree(buf);
321
322
err_unlock:
323
mutex_unlock(&ar->conf_mutex);
324
return ret;
325
}
326
327
static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
328
{
329
vfree(file->private_data);
330
331
return 0;
332
}
333
334
static ssize_t ath11k_read_bcn_stats(struct file *file,
335
char __user *user_buf,
336
size_t count, loff_t *ppos)
337
{
338
const char *buf = file->private_data;
339
size_t len = strlen(buf);
340
341
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
342
}
343
344
static const struct file_operations fops_bcn_stats = {
345
.open = ath11k_open_bcn_stats,
346
.release = ath11k_release_bcn_stats,
347
.read = ath11k_read_bcn_stats,
348
.owner = THIS_MODULE,
349
.llseek = default_llseek,
350
};
351
352
static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
353
char __user *user_buf,
354
size_t count, loff_t *ppos)
355
{
356
const char buf[] =
357
"To simulate firmware crash write one of the keywords to this file:\n"
358
"`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
359
"`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
360
361
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
362
}
363
364
/* Simulate firmware crash:
365
* 'soft': Call wmi command causing firmware hang. This firmware hang is
366
* recoverable by warm firmware reset.
367
* 'hard': Force firmware crash by setting any vdev parameter for not allowed
368
* vdev id. This is hard firmware crash because it is recoverable only by cold
369
* firmware reset.
370
*/
371
static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
372
const char __user *user_buf,
373
size_t count, loff_t *ppos)
374
{
375
struct ath11k_base *ab = file->private_data;
376
struct ath11k_pdev *pdev;
377
struct ath11k *ar = ab->pdevs[0].ar;
378
char buf[32] = {};
379
ssize_t rc;
380
int i, ret, radioup = 0;
381
382
for (i = 0; i < ab->num_radios; i++) {
383
pdev = &ab->pdevs[i];
384
ar = pdev->ar;
385
if (ar && ar->state == ATH11K_STATE_ON) {
386
radioup = 1;
387
break;
388
}
389
}
390
/* filter partial writes and invalid commands */
391
if (*ppos != 0 || count >= sizeof(buf) || count == 0)
392
return -EINVAL;
393
394
rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
395
if (rc < 0)
396
return rc;
397
398
/* drop the possible '\n' from the end */
399
if (buf[*ppos - 1] == '\n')
400
buf[*ppos - 1] = '\0';
401
402
if (radioup == 0) {
403
ret = -ENETDOWN;
404
goto exit;
405
}
406
407
if (!strcmp(buf, "assert")) {
408
ath11k_info(ab, "simulating firmware assert crash\n");
409
ret = ath11k_wmi_force_fw_hang_cmd(ar,
410
ATH11K_WMI_FW_HANG_ASSERT_TYPE,
411
ATH11K_WMI_FW_HANG_DELAY);
412
} else if (!strcmp(buf, "hw-restart")) {
413
ath11k_info(ab, "user requested hw restart\n");
414
queue_work(ab->workqueue_aux, &ab->reset_work);
415
ret = 0;
416
} else {
417
ret = -EINVAL;
418
goto exit;
419
}
420
421
if (ret) {
422
ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
423
goto exit;
424
}
425
426
ret = count;
427
428
exit:
429
return ret;
430
}
431
432
static const struct file_operations fops_simulate_fw_crash = {
433
.read = ath11k_read_simulate_fw_crash,
434
.write = ath11k_write_simulate_fw_crash,
435
.open = simple_open,
436
.owner = THIS_MODULE,
437
.llseek = default_llseek,
438
};
439
440
static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
441
const char __user *ubuf,
442
size_t count, loff_t *ppos)
443
{
444
struct ath11k *ar = file->private_data;
445
u32 filter;
446
int ret;
447
448
if (kstrtouint_from_user(ubuf, count, 0, &filter))
449
return -EINVAL;
450
451
mutex_lock(&ar->conf_mutex);
452
453
if (ar->state != ATH11K_STATE_ON) {
454
ret = -ENETDOWN;
455
goto out;
456
}
457
458
if (filter == ar->debug.extd_tx_stats) {
459
ret = count;
460
goto out;
461
}
462
463
ar->debug.extd_tx_stats = filter;
464
ret = count;
465
466
out:
467
mutex_unlock(&ar->conf_mutex);
468
return ret;
469
}
470
471
static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
472
char __user *ubuf,
473
size_t count, loff_t *ppos)
474
475
{
476
char buf[32] = {};
477
struct ath11k *ar = file->private_data;
478
int len = 0;
479
480
mutex_lock(&ar->conf_mutex);
481
len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
482
ar->debug.extd_tx_stats);
483
mutex_unlock(&ar->conf_mutex);
484
485
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
486
}
487
488
static const struct file_operations fops_extd_tx_stats = {
489
.read = ath11k_read_enable_extd_tx_stats,
490
.write = ath11k_write_enable_extd_tx_stats,
491
.open = simple_open
492
};
493
494
static ssize_t ath11k_write_extd_rx_stats(struct file *file,
495
const char __user *ubuf,
496
size_t count, loff_t *ppos)
497
{
498
struct ath11k *ar = file->private_data;
499
struct ath11k_base *ab = ar->ab;
500
struct htt_rx_ring_tlv_filter tlv_filter = {};
501
u32 enable, rx_filter = 0, ring_id;
502
int i;
503
int ret;
504
505
if (kstrtouint_from_user(ubuf, count, 0, &enable))
506
return -EINVAL;
507
508
mutex_lock(&ar->conf_mutex);
509
510
if (ar->state != ATH11K_STATE_ON) {
511
ret = -ENETDOWN;
512
goto exit;
513
}
514
515
if (enable > 1) {
516
ret = -EINVAL;
517
goto exit;
518
}
519
520
if (enable == ar->debug.extd_rx_stats) {
521
ret = count;
522
goto exit;
523
}
524
525
if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {
526
ar->debug.extd_rx_stats = enable;
527
ret = count;
528
goto exit;
529
}
530
531
if (enable) {
532
rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
533
rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
534
rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
535
rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
536
rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
537
rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
538
539
tlv_filter.rx_filter = rx_filter;
540
tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
541
tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
542
tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
543
tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
544
HTT_RX_FP_DATA_FILTER_FLASG3;
545
} else {
546
tlv_filter = ath11k_mac_mon_status_filter_default;
547
}
548
549
ar->debug.rx_filter = tlv_filter.rx_filter;
550
551
for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {
552
ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
553
ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
554
HAL_RXDMA_MONITOR_STATUS,
555
DP_RX_BUFFER_SIZE, &tlv_filter);
556
557
if (ret) {
558
ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
559
goto exit;
560
}
561
}
562
563
ar->debug.extd_rx_stats = enable;
564
ret = count;
565
exit:
566
mutex_unlock(&ar->conf_mutex);
567
return ret;
568
}
569
570
static ssize_t ath11k_read_extd_rx_stats(struct file *file,
571
char __user *ubuf,
572
size_t count, loff_t *ppos)
573
{
574
struct ath11k *ar = file->private_data;
575
char buf[32];
576
int len = 0;
577
578
mutex_lock(&ar->conf_mutex);
579
len = scnprintf(buf, sizeof(buf) - len, "%d\n",
580
ar->debug.extd_rx_stats);
581
mutex_unlock(&ar->conf_mutex);
582
583
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
584
}
585
586
static const struct file_operations fops_extd_rx_stats = {
587
.read = ath11k_read_extd_rx_stats,
588
.write = ath11k_write_extd_rx_stats,
589
.open = simple_open,
590
};
591
592
static int ath11k_fill_bp_stats(struct ath11k_base *ab,
593
struct ath11k_bp_stats *bp_stats,
594
char *buf, int len, int size)
595
{
596
lockdep_assert_held(&ab->base_lock);
597
598
len += scnprintf(buf + len, size - len, "count: %u\n",
599
bp_stats->count);
600
len += scnprintf(buf + len, size - len, "hp: %u\n",
601
bp_stats->hp);
602
len += scnprintf(buf + len, size - len, "tp: %u\n",
603
bp_stats->tp);
604
len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
605
jiffies_to_msecs(jiffies - bp_stats->jiffies));
606
return len;
607
}
608
609
static ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
610
char *buf, int size)
611
{
612
struct ath11k_bp_stats *bp_stats;
613
bool stats_rxd = false;
614
u8 i, pdev_idx;
615
int len = 0;
616
617
len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
618
len += scnprintf(buf + len, size - len, "==================\n");
619
620
spin_lock_bh(&ab->base_lock);
621
for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
622
bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
623
624
if (!bp_stats->count)
625
continue;
626
627
len += scnprintf(buf + len, size - len, "Ring: %s\n",
628
htt_bp_umac_ring[i]);
629
len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
630
stats_rxd = true;
631
}
632
633
for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
634
for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
635
bp_stats =
636
&ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
637
638
if (!bp_stats->count)
639
continue;
640
641
len += scnprintf(buf + len, size - len, "Ring: %s\n",
642
htt_bp_lmac_ring[i]);
643
len += scnprintf(buf + len, size - len, "pdev: %d\n",
644
pdev_idx);
645
len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
646
stats_rxd = true;
647
}
648
}
649
spin_unlock_bh(&ab->base_lock);
650
651
if (!stats_rxd)
652
len += scnprintf(buf + len, size - len,
653
"No Ring Backpressure stats received\n\n");
654
655
return len;
656
}
657
658
static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file,
659
char __user *user_buf,
660
size_t count, loff_t *ppos)
661
{
662
struct ath11k_base *ab = file->private_data;
663
struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
664
int len = 0, i, retval;
665
const int size = 4096;
666
static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
667
"Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
668
"Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
669
"AMSDU parse", "SA timeout", "DA timeout",
670
"Flow timeout", "Flush req"};
671
static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
672
"Desc addr zero", "Desc inval", "AMPDU in non BA",
673
"Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
674
"Frame OOR", "BAR OOR", "No BA session",
675
"Frame SN equal SSN", "PN check fail", "2k err",
676
"PN err", "Desc blocked"};
677
678
char *buf;
679
680
buf = kzalloc(size, GFP_KERNEL);
681
if (!buf)
682
return -ENOMEM;
683
684
len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
685
len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
686
soc_stats->err_ring_pkts);
687
len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
688
soc_stats->invalid_rbm);
689
len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
690
for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
691
len += scnprintf(buf + len, size - len, "%s: %u\n",
692
rxdma_err[i], soc_stats->rxdma_error[i]);
693
694
len += scnprintf(buf + len, size - len, "\nREO errors:\n");
695
for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
696
len += scnprintf(buf + len, size - len, "%s: %u\n",
697
reo_err[i], soc_stats->reo_error[i]);
698
699
len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
700
len += scnprintf(buf + len, size - len,
701
"ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
702
soc_stats->hal_reo_error[0],
703
soc_stats->hal_reo_error[1],
704
soc_stats->hal_reo_error[2],
705
soc_stats->hal_reo_error[3]);
706
707
len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
708
len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
709
710
for (i = 0; i < ab->hw_params.max_tx_ring; i++)
711
len += scnprintf(buf + len, size - len, "ring%d: %u\n",
712
i, soc_stats->tx_err.desc_na[i]);
713
714
len += scnprintf(buf + len, size - len,
715
"\nMisc Transmit Failures: %d\n",
716
atomic_read(&soc_stats->tx_err.misc_fail));
717
718
len += ath11k_debugfs_dump_soc_ring_bp_stats(ab, buf + len, size - len);
719
720
if (len > size)
721
len = size;
722
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
723
kfree(buf);
724
725
return retval;
726
}
727
728
static const struct file_operations fops_soc_dp_stats = {
729
.read = ath11k_debugfs_dump_soc_dp_stats,
730
.open = simple_open,
731
.owner = THIS_MODULE,
732
.llseek = default_llseek,
733
};
734
735
static ssize_t ath11k_write_fw_dbglog(struct file *file,
736
const char __user *user_buf,
737
size_t count, loff_t *ppos)
738
{
739
struct ath11k *ar = file->private_data;
740
char buf[128] = {};
741
struct ath11k_fw_dbglog dbglog;
742
unsigned int param, mod_id_index, is_end;
743
u64 value;
744
int ret, num;
745
746
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
747
user_buf, count);
748
if (ret <= 0)
749
return ret;
750
751
num = sscanf(buf, "%u %llx %u %u", &param, &value, &mod_id_index, &is_end);
752
753
if (num < 2)
754
return -EINVAL;
755
756
mutex_lock(&ar->conf_mutex);
757
if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP ||
758
param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) {
759
if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) {
760
ret = -EINVAL;
761
goto out;
762
}
763
ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value);
764
if (!is_end) {
765
ret = count;
766
goto out;
767
}
768
} else {
769
if (num != 2) {
770
ret = -EINVAL;
771
goto out;
772
}
773
}
774
775
dbglog.param = param;
776
dbglog.value = lower_32_bits(value);
777
ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog);
778
if (ret) {
779
ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n",
780
ret);
781
goto out;
782
}
783
784
ret = count;
785
786
out:
787
mutex_unlock(&ar->conf_mutex);
788
return ret;
789
}
790
791
static const struct file_operations fops_fw_dbglog = {
792
.write = ath11k_write_fw_dbglog,
793
.open = simple_open,
794
.owner = THIS_MODULE,
795
.llseek = default_llseek,
796
};
797
798
static int ath11k_open_sram_dump(struct inode *inode, struct file *file)
799
{
800
struct ath11k_base *ab = inode->i_private;
801
u8 *buf;
802
u32 start, end;
803
int ret;
804
805
start = ab->hw_params.sram_dump.start;
806
end = ab->hw_params.sram_dump.end;
807
808
buf = vmalloc(end - start + 1);
809
if (!buf)
810
return -ENOMEM;
811
812
ret = ath11k_hif_read(ab, buf, start, end);
813
if (ret) {
814
ath11k_warn(ab, "failed to dump sram: %d\n", ret);
815
vfree(buf);
816
return ret;
817
}
818
819
file->private_data = buf;
820
return 0;
821
}
822
823
static ssize_t ath11k_read_sram_dump(struct file *file,
824
char __user *user_buf,
825
size_t count, loff_t *ppos)
826
{
827
struct ath11k_base *ab = file->f_inode->i_private;
828
const char *buf = file->private_data;
829
int len;
830
u32 start, end;
831
832
start = ab->hw_params.sram_dump.start;
833
end = ab->hw_params.sram_dump.end;
834
len = end - start + 1;
835
836
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
837
}
838
839
static int ath11k_release_sram_dump(struct inode *inode, struct file *file)
840
{
841
vfree(file->private_data);
842
file->private_data = NULL;
843
844
return 0;
845
}
846
847
static const struct file_operations fops_sram_dump = {
848
.open = ath11k_open_sram_dump,
849
.read = ath11k_read_sram_dump,
850
.release = ath11k_release_sram_dump,
851
.owner = THIS_MODULE,
852
.llseek = default_llseek,
853
};
854
855
int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
856
{
857
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
858
return 0;
859
860
debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
861
&fops_simulate_fw_crash);
862
863
debugfs_create_file("soc_dp_stats", 0400, ab->debugfs_soc, ab,
864
&fops_soc_dp_stats);
865
866
if (ab->hw_params.sram_dump.start != 0)
867
debugfs_create_file("sram", 0400, ab->debugfs_soc, ab,
868
&fops_sram_dump);
869
870
return 0;
871
}
872
873
void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
874
{
875
debugfs_remove_recursive(ab->debugfs_soc);
876
ab->debugfs_soc = NULL;
877
}
878
879
int ath11k_debugfs_soc_create(struct ath11k_base *ab)
880
{
881
struct dentry *root;
882
bool dput_needed;
883
char name[64];
884
int ret;
885
886
root = debugfs_lookup("ath11k", NULL);
887
if (!root) {
888
root = debugfs_create_dir("ath11k", NULL);
889
if (IS_ERR_OR_NULL(root))
890
return PTR_ERR(root);
891
892
dput_needed = false;
893
} else {
894
/* a dentry from lookup() needs dput() after we don't use it */
895
dput_needed = true;
896
}
897
898
scnprintf(name, sizeof(name), "%s-%s", ath11k_bus_str(ab->hif.bus),
899
dev_name(ab->dev));
900
901
ab->debugfs_soc = debugfs_create_dir(name, root);
902
if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
903
ret = PTR_ERR(ab->debugfs_soc);
904
goto out;
905
}
906
907
ret = 0;
908
909
out:
910
if (dput_needed)
911
dput(root);
912
913
return ret;
914
}
915
916
void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
917
{
918
debugfs_remove_recursive(ab->debugfs_soc);
919
ab->debugfs_soc = NULL;
920
921
/* We are not removing ath11k directory on purpose, even if it
922
* would be empty. This simplifies the directory handling and it's
923
* a minor cosmetic issue to leave an empty ath11k directory to
924
* debugfs.
925
*/
926
}
927
EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
928
929
void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
930
{
931
struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
932
ar->debug.debugfs_pdev);
933
934
ar->fw_stats.debugfs_fwstats = fwstats_dir;
935
936
/* all stats debugfs files created are under "fw_stats" directory
937
* created per PDEV
938
*/
939
debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
940
&fops_pdev_stats);
941
debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
942
&fops_vdev_stats);
943
debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
944
&fops_bcn_stats);
945
}
946
947
static ssize_t ath11k_write_pktlog_filter(struct file *file,
948
const char __user *ubuf,
949
size_t count, loff_t *ppos)
950
{
951
struct ath11k *ar = file->private_data;
952
struct ath11k_base *ab = ar->ab;
953
struct htt_rx_ring_tlv_filter tlv_filter = {};
954
u32 rx_filter = 0, ring_id, filter, mode;
955
u8 buf[128] = {};
956
int i, ret, rx_buf_sz = 0;
957
ssize_t rc;
958
959
mutex_lock(&ar->conf_mutex);
960
if (ar->state != ATH11K_STATE_ON) {
961
ret = -ENETDOWN;
962
goto out;
963
}
964
965
rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
966
if (rc < 0) {
967
ret = rc;
968
goto out;
969
}
970
buf[rc] = '\0';
971
972
ret = sscanf(buf, "0x%x %u", &filter, &mode);
973
if (ret != 2) {
974
ret = -EINVAL;
975
goto out;
976
}
977
978
if (filter) {
979
ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
980
if (ret) {
981
ath11k_warn(ar->ab,
982
"failed to enable pktlog filter %x: %d\n",
983
ar->debug.pktlog_filter, ret);
984
goto out;
985
}
986
} else {
987
ret = ath11k_wmi_pdev_pktlog_disable(ar);
988
if (ret) {
989
ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
990
goto out;
991
}
992
}
993
994
/* Clear rx filter set for monitor mode and rx status */
995
for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {
996
ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
997
ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
998
HAL_RXDMA_MONITOR_STATUS,
999
rx_buf_sz, &tlv_filter);
1000
if (ret) {
1001
ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
1002
goto out;
1003
}
1004
}
1005
#define HTT_RX_FILTER_TLV_LITE_MODE \
1006
(HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
1007
HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
1008
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
1009
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
1010
HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
1011
HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
1012
1013
if (mode == ATH11K_PKTLOG_MODE_FULL) {
1014
rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
1015
HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
1016
HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
1017
HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
1018
HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
1019
HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
1020
rx_buf_sz = DP_RX_BUFFER_SIZE;
1021
} else if (mode == ATH11K_PKTLOG_MODE_LITE) {
1022
ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1023
HTT_PPDU_STATS_TAG_PKTLOG);
1024
if (ret) {
1025
ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
1026
goto out;
1027
}
1028
1029
rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
1030
rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;
1031
} else {
1032
rx_buf_sz = DP_RX_BUFFER_SIZE;
1033
tlv_filter = ath11k_mac_mon_status_filter_default;
1034
rx_filter = tlv_filter.rx_filter;
1035
1036
ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1037
HTT_PPDU_STATS_TAG_DEFAULT);
1038
if (ret) {
1039
ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
1040
ret);
1041
goto out;
1042
}
1043
}
1044
1045
tlv_filter.rx_filter = rx_filter;
1046
if (rx_filter) {
1047
tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
1048
tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
1049
tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
1050
tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
1051
HTT_RX_FP_DATA_FILTER_FLASG3;
1052
}
1053
1054
for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {
1055
ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
1056
ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
1057
ar->dp.mac_id + i,
1058
HAL_RXDMA_MONITOR_STATUS,
1059
rx_buf_sz, &tlv_filter);
1060
1061
if (ret) {
1062
ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");
1063
goto out;
1064
}
1065
}
1066
1067
ath11k_info(ab, "pktlog mode %s\n",
1068
((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
1069
1070
ar->debug.pktlog_filter = filter;
1071
ar->debug.pktlog_mode = mode;
1072
ret = count;
1073
1074
out:
1075
mutex_unlock(&ar->conf_mutex);
1076
return ret;
1077
}
1078
1079
static ssize_t ath11k_read_pktlog_filter(struct file *file,
1080
char __user *ubuf,
1081
size_t count, loff_t *ppos)
1082
1083
{
1084
char buf[32] = {};
1085
struct ath11k *ar = file->private_data;
1086
int len = 0;
1087
1088
mutex_lock(&ar->conf_mutex);
1089
len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
1090
ar->debug.pktlog_filter,
1091
ar->debug.pktlog_mode);
1092
mutex_unlock(&ar->conf_mutex);
1093
1094
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1095
}
1096
1097
static const struct file_operations fops_pktlog_filter = {
1098
.read = ath11k_read_pktlog_filter,
1099
.write = ath11k_write_pktlog_filter,
1100
.open = simple_open
1101
};
1102
1103
static ssize_t ath11k_write_simulate_radar(struct file *file,
1104
const char __user *user_buf,
1105
size_t count, loff_t *ppos)
1106
{
1107
struct ath11k *ar = file->private_data;
1108
int ret;
1109
1110
ret = ath11k_wmi_simulate_radar(ar);
1111
if (ret)
1112
return ret;
1113
1114
return count;
1115
}
1116
1117
static const struct file_operations fops_simulate_radar = {
1118
.write = ath11k_write_simulate_radar,
1119
.open = simple_open
1120
};
1121
1122
static ssize_t ath11k_debug_dump_dbr_entries(struct file *file,
1123
char __user *user_buf,
1124
size_t count, loff_t *ppos)
1125
{
1126
struct ath11k_dbg_dbr_data *dbr_dbg_data = file->private_data;
1127
static const char * const event_id_to_string[] = {"empty", "Rx", "Replenish"};
1128
int size = ATH11K_DEBUG_DBR_ENTRIES_MAX * 100;
1129
char *buf;
1130
int i, ret;
1131
int len = 0;
1132
1133
buf = kzalloc(size, GFP_KERNEL);
1134
if (!buf)
1135
return -ENOMEM;
1136
1137
len += scnprintf(buf + len, size - len,
1138
"-----------------------------------------\n");
1139
len += scnprintf(buf + len, size - len,
1140
"| idx | hp | tp | timestamp | event |\n");
1141
len += scnprintf(buf + len, size - len,
1142
"-----------------------------------------\n");
1143
1144
spin_lock_bh(&dbr_dbg_data->lock);
1145
1146
for (i = 0; i < dbr_dbg_data->num_ring_debug_entries; i++) {
1147
len += scnprintf(buf + len, size - len,
1148
"|%4u|%8u|%8u|%11llu|%8s|\n", i,
1149
dbr_dbg_data->entries[i].hp,
1150
dbr_dbg_data->entries[i].tp,
1151
dbr_dbg_data->entries[i].timestamp,
1152
event_id_to_string[dbr_dbg_data->entries[i].event]);
1153
}
1154
1155
spin_unlock_bh(&dbr_dbg_data->lock);
1156
1157
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1158
kfree(buf);
1159
1160
return ret;
1161
}
1162
1163
static const struct file_operations fops_debug_dump_dbr_entries = {
1164
.read = ath11k_debug_dump_dbr_entries,
1165
.open = simple_open,
1166
.owner = THIS_MODULE,
1167
.llseek = default_llseek,
1168
};
1169
1170
static void ath11k_debugfs_dbr_dbg_destroy(struct ath11k *ar, int dbr_id)
1171
{
1172
struct ath11k_debug_dbr *dbr_debug;
1173
struct ath11k_dbg_dbr_data *dbr_dbg_data;
1174
1175
if (!ar->debug.dbr_debug[dbr_id])
1176
return;
1177
1178
dbr_debug = ar->debug.dbr_debug[dbr_id];
1179
dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1180
1181
debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1182
kfree(dbr_dbg_data->entries);
1183
kfree(dbr_debug);
1184
ar->debug.dbr_debug[dbr_id] = NULL;
1185
}
1186
1187
static int ath11k_debugfs_dbr_dbg_init(struct ath11k *ar, int dbr_id)
1188
{
1189
struct ath11k_debug_dbr *dbr_debug;
1190
struct ath11k_dbg_dbr_data *dbr_dbg_data;
1191
static const char * const dbr_id_to_str[] = {"spectral", "CFR"};
1192
1193
if (ar->debug.dbr_debug[dbr_id])
1194
return 0;
1195
1196
ar->debug.dbr_debug[dbr_id] = kzalloc(sizeof(*dbr_debug),
1197
GFP_KERNEL);
1198
1199
if (!ar->debug.dbr_debug[dbr_id])
1200
return -ENOMEM;
1201
1202
dbr_debug = ar->debug.dbr_debug[dbr_id];
1203
dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1204
1205
if (dbr_debug->dbr_debugfs)
1206
return 0;
1207
1208
dbr_debug->dbr_debugfs = debugfs_create_dir(dbr_id_to_str[dbr_id],
1209
ar->debug.debugfs_pdev);
1210
if (IS_ERR_OR_NULL(dbr_debug->dbr_debugfs)) {
1211
if (IS_ERR(dbr_debug->dbr_debugfs))
1212
return PTR_ERR(dbr_debug->dbr_debugfs);
1213
return -ENOMEM;
1214
}
1215
1216
dbr_debug->dbr_debug_enabled = true;
1217
dbr_dbg_data->num_ring_debug_entries = ATH11K_DEBUG_DBR_ENTRIES_MAX;
1218
dbr_dbg_data->dbr_debug_idx = 0;
1219
dbr_dbg_data->entries = kcalloc(ATH11K_DEBUG_DBR_ENTRIES_MAX,
1220
sizeof(struct ath11k_dbg_dbr_entry),
1221
GFP_KERNEL);
1222
if (!dbr_dbg_data->entries)
1223
return -ENOMEM;
1224
1225
spin_lock_init(&dbr_dbg_data->lock);
1226
1227
debugfs_create_file("dump_dbr_debug", 0444, dbr_debug->dbr_debugfs,
1228
dbr_dbg_data, &fops_debug_dump_dbr_entries);
1229
1230
return 0;
1231
}
1232
1233
static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file,
1234
const char __user *ubuf,
1235
size_t count, loff_t *ppos)
1236
{
1237
struct ath11k *ar = file->private_data;
1238
char buf[32] = {};
1239
u32 dbr_id, enable;
1240
int ret;
1241
1242
mutex_lock(&ar->conf_mutex);
1243
1244
if (ar->state != ATH11K_STATE_ON) {
1245
ret = -ENETDOWN;
1246
goto out;
1247
}
1248
1249
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1250
if (ret < 0)
1251
goto out;
1252
1253
buf[ret] = '\0';
1254
ret = sscanf(buf, "%u %u", &dbr_id, &enable);
1255
if (ret != 2 || dbr_id > 1 || enable > 1) {
1256
ret = -EINVAL;
1257
ath11k_warn(ar->ab, "usage: echo <dbr_id> <val> dbr_id:0-Spectral 1-CFR val:0-disable 1-enable\n");
1258
goto out;
1259
}
1260
1261
if (enable) {
1262
ret = ath11k_debugfs_dbr_dbg_init(ar, dbr_id);
1263
if (ret) {
1264
ath11k_warn(ar->ab, "db ring module debugfs init failed: %d\n",
1265
ret);
1266
goto out;
1267
}
1268
} else {
1269
ath11k_debugfs_dbr_dbg_destroy(ar, dbr_id);
1270
}
1271
1272
ret = count;
1273
out:
1274
mutex_unlock(&ar->conf_mutex);
1275
return ret;
1276
}
1277
1278
static const struct file_operations fops_dbr_debug = {
1279
.write = ath11k_debugfs_write_enable_dbr_dbg,
1280
.open = simple_open,
1281
.owner = THIS_MODULE,
1282
.llseek = default_llseek,
1283
};
1284
1285
static ssize_t ath11k_write_ps_timekeeper_enable(struct file *file,
1286
const char __user *user_buf,
1287
size_t count, loff_t *ppos)
1288
{
1289
struct ath11k *ar = file->private_data;
1290
ssize_t ret;
1291
u8 ps_timekeeper_enable;
1292
1293
if (kstrtou8_from_user(user_buf, count, 0, &ps_timekeeper_enable))
1294
return -EINVAL;
1295
1296
mutex_lock(&ar->conf_mutex);
1297
1298
if (ar->state != ATH11K_STATE_ON) {
1299
ret = -ENETDOWN;
1300
goto exit;
1301
}
1302
1303
if (!ar->ps_state_enable) {
1304
ret = -EINVAL;
1305
goto exit;
1306
}
1307
1308
ar->ps_timekeeper_enable = !!ps_timekeeper_enable;
1309
ret = count;
1310
exit:
1311
mutex_unlock(&ar->conf_mutex);
1312
1313
return ret;
1314
}
1315
1316
static ssize_t ath11k_read_ps_timekeeper_enable(struct file *file,
1317
char __user *user_buf,
1318
size_t count, loff_t *ppos)
1319
{
1320
struct ath11k *ar = file->private_data;
1321
char buf[32];
1322
int len;
1323
1324
mutex_lock(&ar->conf_mutex);
1325
len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_timekeeper_enable);
1326
mutex_unlock(&ar->conf_mutex);
1327
1328
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1329
}
1330
1331
static const struct file_operations fops_ps_timekeeper_enable = {
1332
.read = ath11k_read_ps_timekeeper_enable,
1333
.write = ath11k_write_ps_timekeeper_enable,
1334
.open = simple_open,
1335
.owner = THIS_MODULE,
1336
.llseek = default_llseek,
1337
};
1338
1339
static void ath11k_reset_peer_ps_duration(void *data,
1340
struct ieee80211_sta *sta)
1341
{
1342
struct ath11k *ar = data;
1343
struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
1344
1345
spin_lock_bh(&ar->data_lock);
1346
arsta->ps_total_duration = 0;
1347
spin_unlock_bh(&ar->data_lock);
1348
}
1349
1350
static ssize_t ath11k_write_reset_ps_duration(struct file *file,
1351
const char __user *user_buf,
1352
size_t count, loff_t *ppos)
1353
{
1354
struct ath11k *ar = file->private_data;
1355
int ret;
1356
u8 reset_ps_duration;
1357
1358
if (kstrtou8_from_user(user_buf, count, 0, &reset_ps_duration))
1359
return -EINVAL;
1360
1361
mutex_lock(&ar->conf_mutex);
1362
1363
if (ar->state != ATH11K_STATE_ON) {
1364
ret = -ENETDOWN;
1365
goto exit;
1366
}
1367
1368
if (!ar->ps_state_enable) {
1369
ret = -EINVAL;
1370
goto exit;
1371
}
1372
1373
ieee80211_iterate_stations_atomic(ar->hw,
1374
ath11k_reset_peer_ps_duration,
1375
ar);
1376
1377
ret = count;
1378
exit:
1379
mutex_unlock(&ar->conf_mutex);
1380
return ret;
1381
}
1382
1383
static const struct file_operations fops_reset_ps_duration = {
1384
.write = ath11k_write_reset_ps_duration,
1385
.open = simple_open,
1386
.owner = THIS_MODULE,
1387
.llseek = default_llseek,
1388
};
1389
1390
static void ath11k_peer_ps_state_disable(void *data,
1391
struct ieee80211_sta *sta)
1392
{
1393
struct ath11k *ar = data;
1394
struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
1395
1396
spin_lock_bh(&ar->data_lock);
1397
arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
1398
arsta->ps_start_time = 0;
1399
arsta->ps_total_duration = 0;
1400
spin_unlock_bh(&ar->data_lock);
1401
}
1402
1403
static ssize_t ath11k_write_ps_state_enable(struct file *file,
1404
const char __user *user_buf,
1405
size_t count, loff_t *ppos)
1406
{
1407
struct ath11k *ar = file->private_data;
1408
struct ath11k_pdev *pdev = ar->pdev;
1409
int ret;
1410
u32 param;
1411
u8 ps_state_enable;
1412
1413
if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
1414
return -EINVAL;
1415
1416
mutex_lock(&ar->conf_mutex);
1417
1418
ps_state_enable = !!ps_state_enable;
1419
1420
if (ar->ps_state_enable == ps_state_enable) {
1421
ret = count;
1422
goto exit;
1423
}
1424
1425
param = WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE;
1426
ret = ath11k_wmi_pdev_set_param(ar, param, ps_state_enable, pdev->pdev_id);
1427
if (ret) {
1428
ath11k_warn(ar->ab, "failed to enable ps_state_enable: %d\n",
1429
ret);
1430
goto exit;
1431
}
1432
ar->ps_state_enable = ps_state_enable;
1433
1434
if (!ar->ps_state_enable) {
1435
ar->ps_timekeeper_enable = false;
1436
ieee80211_iterate_stations_atomic(ar->hw,
1437
ath11k_peer_ps_state_disable,
1438
ar);
1439
}
1440
1441
ret = count;
1442
1443
exit:
1444
mutex_unlock(&ar->conf_mutex);
1445
1446
return ret;
1447
}
1448
1449
static ssize_t ath11k_read_ps_state_enable(struct file *file,
1450
char __user *user_buf,
1451
size_t count, loff_t *ppos)
1452
{
1453
struct ath11k *ar = file->private_data;
1454
char buf[32];
1455
int len;
1456
1457
mutex_lock(&ar->conf_mutex);
1458
len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_state_enable);
1459
mutex_unlock(&ar->conf_mutex);
1460
1461
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1462
}
1463
1464
static const struct file_operations fops_ps_state_enable = {
1465
.read = ath11k_read_ps_state_enable,
1466
.write = ath11k_write_ps_state_enable,
1467
.open = simple_open,
1468
.owner = THIS_MODULE,
1469
.llseek = default_llseek,
1470
};
1471
1472
int ath11k_debugfs_register(struct ath11k *ar)
1473
{
1474
struct ath11k_base *ab = ar->ab;
1475
char pdev_name[10];
1476
char buf[100] = {};
1477
1478
snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx);
1479
1480
ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1481
if (IS_ERR(ar->debug.debugfs_pdev))
1482
return PTR_ERR(ar->debug.debugfs_pdev);
1483
1484
/* Create a symlink under ieee80211/phy* */
1485
snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
1486
debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
1487
1488
ath11k_debugfs_htt_stats_init(ar);
1489
1490
ath11k_debugfs_fw_stats_init(ar);
1491
1492
debugfs_create_file("ext_tx_stats", 0644,
1493
ar->debug.debugfs_pdev, ar,
1494
&fops_extd_tx_stats);
1495
debugfs_create_file("ext_rx_stats", 0644,
1496
ar->debug.debugfs_pdev, ar,
1497
&fops_extd_rx_stats);
1498
debugfs_create_file("pktlog_filter", 0644,
1499
ar->debug.debugfs_pdev, ar,
1500
&fops_pktlog_filter);
1501
debugfs_create_file("fw_dbglog_config", 0600,
1502
ar->debug.debugfs_pdev, ar,
1503
&fops_fw_dbglog);
1504
1505
if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
1506
debugfs_create_file("dfs_simulate_radar", 0200,
1507
ar->debug.debugfs_pdev, ar,
1508
&fops_simulate_radar);
1509
debugfs_create_bool("dfs_block_radar_events", 0200,
1510
ar->debug.debugfs_pdev,
1511
&ar->dfs_block_radar_events);
1512
}
1513
1514
if (ab->hw_params.dbr_debug_support)
1515
debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev,
1516
ar, &fops_dbr_debug);
1517
1518
debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,
1519
&fops_ps_state_enable);
1520
1521
if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
1522
ar->ab->wmi_ab.svc_map)) {
1523
debugfs_create_file("ps_timekeeper_enable", 0600,
1524
ar->debug.debugfs_pdev, ar,
1525
&fops_ps_timekeeper_enable);
1526
1527
debugfs_create_file("reset_ps_duration", 0200,
1528
ar->debug.debugfs_pdev, ar,
1529
&fops_reset_ps_duration);
1530
}
1531
1532
return 0;
1533
}
1534
1535
void ath11k_debugfs_unregister(struct ath11k *ar)
1536
{
1537
struct ath11k_debug_dbr *dbr_debug;
1538
struct ath11k_dbg_dbr_data *dbr_dbg_data;
1539
int i;
1540
1541
for (i = 0; i < WMI_DIRECT_BUF_MAX; i++) {
1542
dbr_debug = ar->debug.dbr_debug[i];
1543
if (!dbr_debug)
1544
continue;
1545
1546
dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1547
kfree(dbr_dbg_data->entries);
1548
debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1549
kfree(dbr_debug);
1550
ar->debug.dbr_debug[i] = NULL;
1551
}
1552
}
1553
1554
static ssize_t ath11k_write_twt_add_dialog(struct file *file,
1555
const char __user *ubuf,
1556
size_t count, loff_t *ppos)
1557
{
1558
struct ath11k_vif *arvif = file->private_data;
1559
struct wmi_twt_add_dialog_params params = {};
1560
struct wmi_twt_enable_params twt_params = {};
1561
struct ath11k *ar = arvif->ar;
1562
u8 buf[128] = {};
1563
int ret;
1564
1565
if (ar->twt_enabled == 0) {
1566
ath11k_err(ar->ab, "twt support is not enabled\n");
1567
return -EOPNOTSUPP;
1568
}
1569
1570
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1571
if (ret < 0)
1572
return ret;
1573
1574
buf[ret] = '\0';
1575
ret = sscanf(buf,
1576
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu",
1577
&params.peer_macaddr[0],
1578
&params.peer_macaddr[1],
1579
&params.peer_macaddr[2],
1580
&params.peer_macaddr[3],
1581
&params.peer_macaddr[4],
1582
&params.peer_macaddr[5],
1583
&params.dialog_id,
1584
&params.wake_intvl_us,
1585
&params.wake_intvl_mantis,
1586
&params.wake_dura_us,
1587
&params.sp_offset_us,
1588
&params.twt_cmd,
1589
&params.flag_bcast,
1590
&params.flag_trigger,
1591
&params.flag_flow_type,
1592
&params.flag_protection);
1593
if (ret != 16)
1594
return -EINVAL;
1595
1596
/* In the case of station vif, TWT is entirely handled by
1597
* the firmware based on the input parameters in the TWT enable
1598
* WMI command that is sent to the target during assoc.
1599
* For manually testing the TWT feature, we need to first disable
1600
* TWT and send enable command again with TWT input parameter
1601
* sta_cong_timer_ms set to 0.
1602
*/
1603
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
1604
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
1605
1606
ath11k_wmi_fill_default_twt_params(&twt_params);
1607
twt_params.sta_cong_timer_ms = 0;
1608
1609
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
1610
}
1611
1612
params.vdev_id = arvif->vdev_id;
1613
1614
ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, &params);
1615
if (ret)
1616
goto err_twt_add_dialog;
1617
1618
return count;
1619
1620
err_twt_add_dialog:
1621
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
1622
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
1623
ath11k_wmi_fill_default_twt_params(&twt_params);
1624
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
1625
}
1626
1627
return ret;
1628
}
1629
1630
static ssize_t ath11k_write_twt_del_dialog(struct file *file,
1631
const char __user *ubuf,
1632
size_t count, loff_t *ppos)
1633
{
1634
struct ath11k_vif *arvif = file->private_data;
1635
struct wmi_twt_del_dialog_params params = {};
1636
struct wmi_twt_enable_params twt_params = {};
1637
struct ath11k *ar = arvif->ar;
1638
u8 buf[64] = {};
1639
int ret;
1640
1641
if (ar->twt_enabled == 0) {
1642
ath11k_err(ar->ab, "twt support is not enabled\n");
1643
return -EOPNOTSUPP;
1644
}
1645
1646
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1647
if (ret < 0)
1648
return ret;
1649
1650
buf[ret] = '\0';
1651
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1652
&params.peer_macaddr[0],
1653
&params.peer_macaddr[1],
1654
&params.peer_macaddr[2],
1655
&params.peer_macaddr[3],
1656
&params.peer_macaddr[4],
1657
&params.peer_macaddr[5],
1658
&params.dialog_id);
1659
if (ret != 7)
1660
return -EINVAL;
1661
1662
params.vdev_id = arvif->vdev_id;
1663
1664
ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, &params);
1665
if (ret)
1666
return ret;
1667
1668
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
1669
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
1670
ath11k_wmi_fill_default_twt_params(&twt_params);
1671
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
1672
}
1673
1674
return count;
1675
}
1676
1677
static ssize_t ath11k_write_twt_pause_dialog(struct file *file,
1678
const char __user *ubuf,
1679
size_t count, loff_t *ppos)
1680
{
1681
struct ath11k_vif *arvif = file->private_data;
1682
struct wmi_twt_pause_dialog_params params = {};
1683
u8 buf[64] = {};
1684
int ret;
1685
1686
if (arvif->ar->twt_enabled == 0) {
1687
ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1688
return -EOPNOTSUPP;
1689
}
1690
1691
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1692
if (ret < 0)
1693
return ret;
1694
1695
buf[ret] = '\0';
1696
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1697
&params.peer_macaddr[0],
1698
&params.peer_macaddr[1],
1699
&params.peer_macaddr[2],
1700
&params.peer_macaddr[3],
1701
&params.peer_macaddr[4],
1702
&params.peer_macaddr[5],
1703
&params.dialog_id);
1704
if (ret != 7)
1705
return -EINVAL;
1706
1707
params.vdev_id = arvif->vdev_id;
1708
1709
ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, &params);
1710
if (ret)
1711
return ret;
1712
1713
return count;
1714
}
1715
1716
static ssize_t ath11k_write_twt_resume_dialog(struct file *file,
1717
const char __user *ubuf,
1718
size_t count, loff_t *ppos)
1719
{
1720
struct ath11k_vif *arvif = file->private_data;
1721
struct wmi_twt_resume_dialog_params params = {};
1722
u8 buf[64] = {};
1723
int ret;
1724
1725
if (arvif->ar->twt_enabled == 0) {
1726
ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1727
return -EOPNOTSUPP;
1728
}
1729
1730
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1731
if (ret < 0)
1732
return ret;
1733
1734
buf[ret] = '\0';
1735
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u",
1736
&params.peer_macaddr[0],
1737
&params.peer_macaddr[1],
1738
&params.peer_macaddr[2],
1739
&params.peer_macaddr[3],
1740
&params.peer_macaddr[4],
1741
&params.peer_macaddr[5],
1742
&params.dialog_id,
1743
&params.sp_offset_us,
1744
&params.next_twt_size);
1745
if (ret != 9)
1746
return -EINVAL;
1747
1748
params.vdev_id = arvif->vdev_id;
1749
1750
ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, &params);
1751
if (ret)
1752
return ret;
1753
1754
return count;
1755
}
1756
1757
static const struct file_operations ath11k_fops_twt_add_dialog = {
1758
.write = ath11k_write_twt_add_dialog,
1759
.open = simple_open
1760
};
1761
1762
static const struct file_operations ath11k_fops_twt_del_dialog = {
1763
.write = ath11k_write_twt_del_dialog,
1764
.open = simple_open
1765
};
1766
1767
static const struct file_operations ath11k_fops_twt_pause_dialog = {
1768
.write = ath11k_write_twt_pause_dialog,
1769
.open = simple_open
1770
};
1771
1772
static const struct file_operations ath11k_fops_twt_resume_dialog = {
1773
.write = ath11k_write_twt_resume_dialog,
1774
.open = simple_open
1775
};
1776
1777
void ath11k_debugfs_op_vif_add(struct ieee80211_hw *hw,
1778
struct ieee80211_vif *vif)
1779
{
1780
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
1781
struct ath11k_base *ab = arvif->ar->ab;
1782
struct dentry *debugfs_twt;
1783
1784
if (arvif->vif->type != NL80211_IFTYPE_AP &&
1785
!(arvif->vif->type == NL80211_IFTYPE_STATION &&
1786
test_bit(WMI_TLV_SERVICE_STA_TWT, ab->wmi_ab.svc_map)))
1787
return;
1788
1789
debugfs_twt = debugfs_create_dir("twt",
1790
arvif->vif->debugfs_dir);
1791
debugfs_create_file("add_dialog", 0200, debugfs_twt,
1792
arvif, &ath11k_fops_twt_add_dialog);
1793
1794
debugfs_create_file("del_dialog", 0200, debugfs_twt,
1795
arvif, &ath11k_fops_twt_del_dialog);
1796
1797
debugfs_create_file("pause_dialog", 0200, debugfs_twt,
1798
arvif, &ath11k_fops_twt_pause_dialog);
1799
1800
debugfs_create_file("resume_dialog", 0200, debugfs_twt,
1801
arvif, &ath11k_fops_twt_resume_dialog);
1802
}
1803
1804
1805