1// SPDX-License-Identifier: ISC
2/* Copyright (C) 2020 MediaTek Inc. */
3
4#include <linux/relay.h>
5#include "mt7915.h"
6#include "eeprom.h"
7#include "mcu.h"
8#include "mac.h"
9
10#define FW_BIN_LOG_MAGIC 0x44e98caf
11
12/** global debugfs **/
13
14struct hw_queue_map {
15 const char *name;
16 u8 index;
17 u8 pid;
18 u8 qid;
19};
20
21static int
22mt7915_implicit_txbf_set(void *data, u64 val)
23{
24 struct mt7915_dev *dev = data;
25
26 /* The existing connected stations shall reconnect to apply
27 * new implicit txbf configuration.
28 */
29 dev->ibf = !!val;
30
31 return mt7915_mcu_set_txbf(dev, action: MT_BF_TYPE_UPDATE);
32}
33
34static int
35mt7915_implicit_txbf_get(void *data, u64 *val)
36{
37 struct mt7915_dev *dev = data;
38
39 *val = dev->ibf;
40
41 return 0;
42}
43
44DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
45 mt7915_implicit_txbf_set, "%lld\n");
46
47/* test knob of system error recovery */
48static ssize_t
49mt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
50 size_t count, loff_t *ppos)
51{
52 struct mt7915_phy *phy = file->private_data;
53 struct mt7915_dev *dev = phy->dev;
54 bool band = phy->mt76->band_idx;
55 char buf[16];
56 int ret = 0;
57 u16 val;
58
59 if (count >= sizeof(buf))
60 return -EINVAL;
61
62 if (copy_from_user(to: buf, from: user_buf, n: count))
63 return -EFAULT;
64
65 if (count && buf[count - 1] == '\n')
66 buf[count - 1] = '\0';
67 else
68 buf[count] = '\0';
69
70 if (kstrtou16(s: buf, base: 0, res: &val))
71 return -EINVAL;
72
73 switch (val) {
74 /*
75 * 0: grab firmware current SER state.
76 * 1: trigger & enable system error L1 recovery.
77 * 2: trigger & enable system error L2 recovery.
78 * 3: trigger & enable system error L3 rx abort.
79 * 4: trigger & enable system error L3 tx abort
80 * 5: trigger & enable system error L3 tx disable.
81 * 6: trigger & enable system error L3 bf recovery.
82 * 7: trigger & enable system error full recovery.
83 * 8: trigger firmware crash.
84 */
85 case SER_QUERY:
86 ret = mt7915_mcu_set_ser(dev, action: 0, set: 0, band);
87 break;
88 case SER_SET_RECOVER_L1:
89 case SER_SET_RECOVER_L2:
90 case SER_SET_RECOVER_L3_RX_ABORT:
91 case SER_SET_RECOVER_L3_TX_ABORT:
92 case SER_SET_RECOVER_L3_TX_DISABLE:
93 case SER_SET_RECOVER_L3_BF:
94 ret = mt7915_mcu_set_ser(dev, action: SER_ENABLE, BIT(val), band);
95 if (ret)
96 return ret;
97
98 ret = mt7915_mcu_set_ser(dev, action: SER_RECOVER, set: val, band);
99 break;
100
101 /* enable full chip reset */
102 case SER_SET_RECOVER_FULL:
103 mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
104 ret = mt7915_mcu_set_ser(dev, action: 1, set: 3, band);
105 if (ret)
106 return ret;
107
108 dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
109 mt7915_reset(dev);
110 break;
111
112 /* WARNING: trigger firmware crash */
113 case SER_SET_SYSTEM_ASSERT:
114 mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
115 mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
116 break;
117 default:
118 break;
119 }
120
121 return ret ? ret : count;
122}
123
124static ssize_t
125mt7915_sys_recovery_get(struct file *file, char __user *user_buf,
126 size_t count, loff_t *ppos)
127{
128 struct mt7915_phy *phy = file->private_data;
129 struct mt7915_dev *dev = phy->dev;
130 char *buff;
131 int desc = 0;
132 ssize_t ret;
133 static const size_t bufsz = 1024;
134
135 buff = kmalloc(bufsz, GFP_KERNEL);
136 if (!buff)
137 return -ENOMEM;
138
139 /* HELP */
140 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
141 fmt: "Please echo the correct value ...\n");
142 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
143 fmt: "0: grab firmware transient SER state\n");
144 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
145 fmt: "1: trigger system error L1 recovery\n");
146 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
147 fmt: "2: trigger system error L2 recovery\n");
148 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
149 fmt: "3: trigger system error L3 rx abort\n");
150 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
151 fmt: "4: trigger system error L3 tx abort\n");
152 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
153 fmt: "5: trigger system error L3 tx disable\n");
154 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
155 fmt: "6: trigger system error L3 bf recovery\n");
156 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
157 fmt: "7: trigger system error full recovery\n");
158 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
159 fmt: "8: trigger firmware crash\n");
160
161 /* SER statistics */
162 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
163 fmt: "\nlet's dump firmware SER statistics...\n");
164 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
165 fmt: "::E R , SER_STATUS = 0x%08x\n",
166 mt76_rr(dev, MT_SWDEF_SER_STATS));
167 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
168 fmt: "::E R , SER_PLE_ERR = 0x%08x\n",
169 mt76_rr(dev, MT_SWDEF_PLE_STATS));
170 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
171 fmt: "::E R , SER_PLE_ERR_1 = 0x%08x\n",
172 mt76_rr(dev, MT_SWDEF_PLE1_STATS));
173 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
174 fmt: "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n",
175 mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
176 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
177 fmt: "::E R , SER_PSE_ERR = 0x%08x\n",
178 mt76_rr(dev, MT_SWDEF_PSE_STATS));
179 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
180 fmt: "::E R , SER_PSE_ERR_1 = 0x%08x\n",
181 mt76_rr(dev, MT_SWDEF_PSE1_STATS));
182 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
183 fmt: "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n",
184 mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
185 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
186 fmt: "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n",
187 mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
188 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
189 fmt: "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n",
190 mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
191 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
192 fmt: "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n",
193 mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
194 desc += scnprintf(buf: buff + desc, size: bufsz - desc,
195 fmt: "\nSYS_RESET_COUNT: WM %d, WA %d\n",
196 dev->recovery.wm_reset_count,
197 dev->recovery.wa_reset_count);
198
199 ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buff, available: desc);
200 kfree(objp: buff);
201 return ret;
202}
203
204static const struct file_operations mt7915_sys_recovery_ops = {
205 .write = mt7915_sys_recovery_set,
206 .read = mt7915_sys_recovery_get,
207 .open = simple_open,
208 .llseek = default_llseek,
209};
210
211static int
212mt7915_radar_trigger(void *data, u64 val)
213{
214#define RADAR_MAIN_CHAIN 1
215#define RADAR_BACKGROUND 2
216 struct mt7915_phy *phy = data;
217 struct mt7915_dev *dev = phy->dev;
218 int rdd_idx;
219
220 if (!val || val > RADAR_BACKGROUND)
221 return -EINVAL;
222
223 if (val == RADAR_BACKGROUND && !dev->rdd2_phy) {
224 dev_err(dev->mt76.dev, "Background radar is not enabled\n");
225 return -EINVAL;
226 }
227
228 rdd_idx = mt7915_get_rdd_idx(phy, is_background: val == RADAR_BACKGROUND);
229 if (rdd_idx < 0) {
230 dev_err(dev->mt76.dev, "No RDD found\n");
231 return -EINVAL;
232 }
233
234 return mt76_connac_mcu_rdd_cmd(dev: &dev->mt76, cmd: RDD_RADAR_EMULATE,
235 index: rdd_idx, rx_sel: 0, val: 0);
236}
237
238DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
239 mt7915_radar_trigger, "%lld\n");
240
241static int
242mt7915_muru_debug_set(void *data, u64 val)
243{
244 struct mt7915_dev *dev = data;
245
246 dev->muru_debug = val;
247 mt7915_mcu_muru_debug_set(dev, enable: dev->muru_debug);
248
249 return 0;
250}
251
252static int
253mt7915_muru_debug_get(void *data, u64 *val)
254{
255 struct mt7915_dev *dev = data;
256
257 *val = dev->muru_debug;
258
259 return 0;
260}
261
262DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get,
263 mt7915_muru_debug_set, "%lld\n");
264
265static int mt7915_muru_stats_show(struct seq_file *file, void *data)
266{
267 struct mt7915_phy *phy = file->private;
268 struct mt7915_dev *dev = phy->dev;
269 static const char * const dl_non_he_type[] = {
270 "CCK", "OFDM", "HT MIX", "HT GF",
271 "VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
272 };
273 static const char * const dl_he_type[] = {
274 "HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU",
275 "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU",
276 "HE >16RU"
277 };
278 static const char * const ul_he_type[] = {
279 "HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU",
280 "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU"
281 };
282 int ret, i;
283 u64 total_ppdu_cnt, sub_total_cnt;
284
285 if (!dev->muru_debug) {
286 seq_puts(m: file, s: "Please enable muru_debug first.\n");
287 return 0;
288 }
289
290 mutex_lock(&dev->mt76.mutex);
291
292 ret = mt7915_mcu_muru_debug_get(phy);
293 if (ret)
294 goto exit;
295
296 /* Non-HE Downlink*/
297 seq_puts(m: file, s: "[Non-HE]\nDownlink\nData Type: ");
298
299 for (i = 0; i < 5; i++)
300 seq_printf(m: file, fmt: "%8s | ", dl_non_he_type[i]);
301
302 seq_puts(m: file, s: "\nTotal Count:");
303 seq_printf(m: file, fmt: "%8u | %8u | %8u | %8u | %8u | ",
304 phy->mib.dl_cck_cnt,
305 phy->mib.dl_ofdm_cnt,
306 phy->mib.dl_htmix_cnt,
307 phy->mib.dl_htgf_cnt,
308 phy->mib.dl_vht_su_cnt);
309
310 seq_puts(m: file, s: "\nDownlink MU-MIMO\nData Type: ");
311
312 for (i = 5; i < 8; i++)
313 seq_printf(m: file, fmt: "%8s | ", dl_non_he_type[i]);
314
315 seq_puts(m: file, s: "\nTotal Count:");
316 seq_printf(m: file, fmt: "%8u | %8u | %8u | ",
317 phy->mib.dl_vht_2mu_cnt,
318 phy->mib.dl_vht_3mu_cnt,
319 phy->mib.dl_vht_4mu_cnt);
320
321 sub_total_cnt = (u64)phy->mib.dl_vht_2mu_cnt +
322 phy->mib.dl_vht_3mu_cnt +
323 phy->mib.dl_vht_4mu_cnt;
324
325 seq_printf(m: file, fmt: "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
326 sub_total_cnt);
327
328 total_ppdu_cnt = sub_total_cnt +
329 phy->mib.dl_cck_cnt +
330 phy->mib.dl_ofdm_cnt +
331 phy->mib.dl_htmix_cnt +
332 phy->mib.dl_htgf_cnt +
333 phy->mib.dl_vht_su_cnt;
334
335 seq_printf(m: file, fmt: "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
336
337 /* HE Downlink */
338 seq_puts(m: file, s: "\n\n[HE]\nDownlink\nData Type: ");
339
340 for (i = 0; i < 2; i++)
341 seq_printf(m: file, fmt: "%8s | ", dl_he_type[i]);
342
343 seq_puts(m: file, s: "\nTotal Count:");
344 seq_printf(m: file, fmt: "%8u | %8u | ",
345 phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);
346
347 seq_puts(m: file, s: "\nDownlink MU-MIMO\nData Type: ");
348
349 for (i = 2; i < 5; i++)
350 seq_printf(m: file, fmt: "%8s | ", dl_he_type[i]);
351
352 seq_puts(m: file, s: "\nTotal Count:");
353 seq_printf(m: file, fmt: "%8u | %8u | %8u | ",
354 phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,
355 phy->mib.dl_he_4mu_cnt);
356
357 seq_puts(m: file, s: "\nDownlink OFDMA\nData Type: ");
358
359 for (i = 5; i < 11; i++)
360 seq_printf(m: file, fmt: "%8s | ", dl_he_type[i]);
361
362 seq_puts(m: file, s: "\nTotal Count:");
363 seq_printf(m: file, fmt: "%8u | %8u | %8u | %8u | %9u | %8u | ",
364 phy->mib.dl_he_2ru_cnt,
365 phy->mib.dl_he_3ru_cnt,
366 phy->mib.dl_he_4ru_cnt,
367 phy->mib.dl_he_5to8ru_cnt,
368 phy->mib.dl_he_9to16ru_cnt,
369 phy->mib.dl_he_gtr16ru_cnt);
370
371 sub_total_cnt = (u64)phy->mib.dl_he_2mu_cnt +
372 phy->mib.dl_he_3mu_cnt +
373 phy->mib.dl_he_4mu_cnt;
374 total_ppdu_cnt = sub_total_cnt;
375
376 seq_printf(m: file, fmt: "\nTotal HE MU-MIMO DL PPDU count: %lld",
377 sub_total_cnt);
378
379 sub_total_cnt = (u64)phy->mib.dl_he_2ru_cnt +
380 phy->mib.dl_he_3ru_cnt +
381 phy->mib.dl_he_4ru_cnt +
382 phy->mib.dl_he_5to8ru_cnt +
383 phy->mib.dl_he_9to16ru_cnt +
384 phy->mib.dl_he_gtr16ru_cnt;
385 total_ppdu_cnt += sub_total_cnt;
386
387 seq_printf(m: file, fmt: "\nTotal HE OFDMA DL PPDU count: %lld",
388 sub_total_cnt);
389
390 total_ppdu_cnt += (u64)phy->mib.dl_he_su_cnt +
391 phy->mib.dl_he_ext_su_cnt;
392
393 seq_printf(m: file, fmt: "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
394
395 /* HE Uplink */
396 seq_puts(m: file, s: "\n\nUplink");
397 seq_puts(m: file, s: "\nTrigger-based Uplink MU-MIMO\nData Type: ");
398
399 for (i = 0; i < 3; i++)
400 seq_printf(m: file, fmt: "%8s | ", ul_he_type[i]);
401
402 seq_puts(m: file, s: "\nTotal Count:");
403 seq_printf(m: file, fmt: "%8u | %8u | %8u | ",
404 phy->mib.ul_hetrig_2mu_cnt,
405 phy->mib.ul_hetrig_3mu_cnt,
406 phy->mib.ul_hetrig_4mu_cnt);
407
408 seq_puts(m: file, s: "\nTrigger-based Uplink OFDMA\nData Type: ");
409
410 for (i = 3; i < 10; i++)
411 seq_printf(m: file, fmt: "%8s | ", ul_he_type[i]);
412
413 seq_puts(m: file, s: "\nTotal Count:");
414 seq_printf(m: file, fmt: "%8u | %8u | %8u | %8u | %8u | %9u | %7u | ",
415 phy->mib.ul_hetrig_su_cnt,
416 phy->mib.ul_hetrig_2ru_cnt,
417 phy->mib.ul_hetrig_3ru_cnt,
418 phy->mib.ul_hetrig_4ru_cnt,
419 phy->mib.ul_hetrig_5to8ru_cnt,
420 phy->mib.ul_hetrig_9to16ru_cnt,
421 phy->mib.ul_hetrig_gtr16ru_cnt);
422
423 sub_total_cnt = (u64)phy->mib.ul_hetrig_2mu_cnt +
424 phy->mib.ul_hetrig_3mu_cnt +
425 phy->mib.ul_hetrig_4mu_cnt;
426 total_ppdu_cnt = sub_total_cnt;
427
428 seq_printf(m: file, fmt: "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
429 sub_total_cnt);
430
431 sub_total_cnt = (u64)phy->mib.ul_hetrig_2ru_cnt +
432 phy->mib.ul_hetrig_3ru_cnt +
433 phy->mib.ul_hetrig_4ru_cnt +
434 phy->mib.ul_hetrig_5to8ru_cnt +
435 phy->mib.ul_hetrig_9to16ru_cnt +
436 phy->mib.ul_hetrig_gtr16ru_cnt;
437 total_ppdu_cnt += sub_total_cnt;
438
439 seq_printf(m: file, fmt: "\nTotal HE OFDMA UL TB PPDU count: %lld",
440 sub_total_cnt);
441
442 total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;
443
444 seq_printf(m: file, fmt: "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
445
446exit:
447 mutex_unlock(lock: &dev->mt76.mutex);
448
449 return ret;
450}
451DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);
452
453static int
454mt7915_rdd_monitor(struct seq_file *s, void *data)
455{
456 struct mt7915_dev *dev = dev_get_drvdata(dev: s->private);
457 struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;
458 const char *bw;
459 int ret = 0;
460
461 mutex_lock(&dev->mt76.mutex);
462
463 if (!mt7915_eeprom_has_background_radar(dev)) {
464 seq_puts(m: s, s: "no background radar capability\n");
465 goto out;
466 }
467
468 if (!cfg80211_chandef_valid(chandef)) {
469 ret = -EINVAL;
470 goto out;
471 }
472
473 if (!dev->rdd2_phy) {
474 seq_puts(m: s, s: "not running\n");
475 goto out;
476 }
477
478 switch (chandef->width) {
479 case NL80211_CHAN_WIDTH_40:
480 bw = "40";
481 break;
482 case NL80211_CHAN_WIDTH_80:
483 bw = "80";
484 break;
485 case NL80211_CHAN_WIDTH_160:
486 bw = "160";
487 break;
488 case NL80211_CHAN_WIDTH_80P80:
489 bw = "80P80";
490 break;
491 default:
492 bw = "20";
493 break;
494 }
495
496 seq_printf(m: s, fmt: "channel %d (%d MHz) width %s MHz center1: %d MHz\n",
497 chandef->chan->hw_value, chandef->chan->center_freq,
498 bw, chandef->center_freq1);
499out:
500 mutex_unlock(lock: &dev->mt76.mutex);
501
502 return ret;
503}
504
505static int
506mt7915_fw_debug_wm_set(void *data, u64 val)
507{
508 struct mt7915_dev *dev = data;
509 enum {
510 DEBUG_TXCMD = 62,
511 DEBUG_CMD_RPT_TX,
512 DEBUG_CMD_RPT_TRIG,
513 DEBUG_SPL,
514 DEBUG_RPT_RX,
515 } debug;
516 bool tx, rx, en;
517 int ret;
518
519 dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
520
521 if (dev->fw.debug_bin)
522 val = 16;
523 else
524 val = dev->fw.debug_wm;
525
526 tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1));
527 rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2));
528 en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0));
529
530 ret = mt7915_mcu_fw_log_2_host(dev, type: MCU_FW_LOG_WM, ctrl: val);
531 if (ret)
532 goto out;
533
534 for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
535 if (debug == DEBUG_RPT_RX)
536 val = en && rx;
537 else
538 val = en && tx;
539
540 ret = mt7915_mcu_fw_dbg_ctrl(dev, module: debug, level: val);
541 if (ret)
542 goto out;
543 }
544
545 /* WM CPU info record control */
546 mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
547 mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) |
548 (dev->fw.debug_wm ? 0 : BIT(0)));
549 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
550 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
551
552out:
553 if (ret)
554 dev->fw.debug_wm = 0;
555
556 return ret;
557}
558
559static int
560mt7915_fw_debug_wm_get(void *data, u64 *val)
561{
562 struct mt7915_dev *dev = data;
563
564 *val = dev->fw.debug_wm;
565
566 return 0;
567}
568
569DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,
570 mt7915_fw_debug_wm_set, "%lld\n");
571
572static int
573mt7915_fw_debug_wa_set(void *data, u64 val)
574{
575 struct mt7915_dev *dev = data;
576 int ret;
577
578 dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;
579
580 ret = mt7915_mcu_fw_log_2_host(dev, type: MCU_FW_LOG_WA, ctrl: dev->fw.debug_wa);
581 if (ret)
582 goto out;
583
584 ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
585 a1: MCU_WA_PARAM_PDMA_RX, a2: !!dev->fw.debug_wa, a3: 0);
586out:
587 if (ret)
588 dev->fw.debug_wa = 0;
589
590 return ret;
591}
592
593static int
594mt7915_fw_debug_wa_get(void *data, u64 *val)
595{
596 struct mt7915_dev *dev = data;
597
598 *val = dev->fw.debug_wa;
599
600 return 0;
601}
602
603DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
604 mt7915_fw_debug_wa_set, "%lld\n");
605
606static struct dentry *
607create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
608 struct rchan_buf *buf, int *is_global)
609{
610 struct dentry *f;
611
612 f = debugfs_create_file("fwlog_data", mode, parent, buf,
613 &relay_file_operations);
614 if (IS_ERR(ptr: f))
615 return NULL;
616
617 *is_global = 1;
618
619 return f;
620}
621
622static int
623remove_buf_file_cb(struct dentry *f)
624{
625 debugfs_remove(dentry: f);
626
627 return 0;
628}
629
630static int
631mt7915_fw_debug_bin_set(void *data, u64 val)
632{
633 static struct rchan_callbacks relay_cb = {
634 .create_buf_file = create_buf_file_cb,
635 .remove_buf_file = remove_buf_file_cb,
636 };
637 struct mt7915_dev *dev = data;
638
639 if (!dev->relay_fwlog)
640 dev->relay_fwlog = relay_open(base_filename: "fwlog_data", parent: dev->debugfs_dir,
641 subbuf_size: 1500, n_subbufs: 512, cb: &relay_cb, NULL);
642 if (!dev->relay_fwlog)
643 return -ENOMEM;
644
645 dev->fw.debug_bin = val;
646
647 relay_reset(chan: dev->relay_fwlog);
648
649 return mt7915_fw_debug_wm_set(data: dev, val: dev->fw.debug_wm);
650}
651
652static int
653mt7915_fw_debug_bin_get(void *data, u64 *val)
654{
655 struct mt7915_dev *dev = data;
656
657 *val = dev->fw.debug_bin;
658
659 return 0;
660}
661
662DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,
663 mt7915_fw_debug_bin_set, "%lld\n");
664
665static int
666mt7915_fw_util_wm_show(struct seq_file *file, void *data)
667{
668 struct mt7915_dev *dev = file->private;
669
670 seq_printf(m: file, fmt: "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC));
671
672 if (dev->fw.debug_wm) {
673 seq_printf(m: file, fmt: "Busy: %u%% Peak busy: %u%%\n",
674 mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),
675 mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));
676 seq_printf(m: file, fmt: "Idle count: %u Peak idle count: %u\n",
677 mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),
678 mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));
679 }
680
681 return 0;
682}
683
684DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);
685
686static int
687mt7915_fw_util_wa_show(struct seq_file *file, void *data)
688{
689 struct mt7915_dev *dev = file->private;
690
691 seq_printf(m: file, fmt: "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC));
692
693 if (dev->fw.debug_wa)
694 return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),
695 a1: MCU_WA_PARAM_CPU_UTIL, a2: 0, a3: 0);
696
697 return 0;
698}
699
700DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);
701
702static void
703mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
704 struct seq_file *file)
705{
706 struct mt7915_dev *dev = phy->dev;
707 bool ext_phy = phy != &dev->phy;
708 int bound[15], range[4], i;
709 u8 band = phy->mt76->band_idx;
710
711 /* Tx ampdu stat */
712 for (i = 0; i < ARRAY_SIZE(range); i++)
713 range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i));
714
715 for (i = 0; i < ARRAY_SIZE(bound); i++)
716 bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
717
718 seq_printf(m: file, fmt: "\nPhy %d, Phy band %d\n", ext_phy, band);
719
720 seq_printf(m: file, fmt: "Length: %8d | ", bound[0]);
721 for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
722 seq_printf(m: file, fmt: "%3d -%3d | ",
723 bound[i] + 1, bound[i + 1]);
724
725 seq_puts(m: file, s: "\nCount: ");
726 for (i = 0; i < ARRAY_SIZE(bound); i++)
727 seq_printf(m: file, fmt: "%8d | ", phy->mt76->aggr_stats[i]);
728 seq_puts(m: file, s: "\n");
729
730 seq_printf(m: file, fmt: "BA miss count: %d\n", phy->mib.ba_miss_cnt);
731}
732
733static void
734mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
735{
736 struct mt76_mib_stats *mib = &phy->mib;
737 static const char * const bw[] = {
738 "BW20", "BW40", "BW80", "BW160"
739 };
740
741 /* Tx Beamformer monitor */
742 seq_puts(m: s, s: "\nTx Beamformer applied PPDU counts: ");
743
744 seq_printf(m: s, fmt: "iBF: %d, eBF: %d\n",
745 mib->tx_bf_ibf_ppdu_cnt,
746 mib->tx_bf_ebf_ppdu_cnt);
747
748 /* Tx Beamformer Rx feedback monitor */
749 seq_puts(m: s, s: "Tx Beamformer Rx feedback statistics: ");
750
751 seq_printf(m: s, fmt: "All: %d, HE: %d, VHT: %d, HT: %d, ",
752 mib->tx_bf_rx_fb_all_cnt,
753 mib->tx_bf_rx_fb_he_cnt,
754 mib->tx_bf_rx_fb_vht_cnt,
755 mib->tx_bf_rx_fb_ht_cnt);
756
757 seq_printf(m: s, fmt: "%s, NC: %d, NR: %d\n",
758 bw[mib->tx_bf_rx_fb_bw],
759 mib->tx_bf_rx_fb_nc_cnt,
760 mib->tx_bf_rx_fb_nr_cnt);
761
762 /* Tx Beamformee Rx NDPA & Tx feedback report */
763 seq_printf(m: s, fmt: "Tx Beamformee successful feedback frames: %d\n",
764 mib->tx_bf_fb_cpl_cnt);
765 seq_printf(m: s, fmt: "Tx Beamformee feedback triggered counts: %d\n",
766 mib->tx_bf_fb_trig_cnt);
767
768 /* Tx SU & MU counters */
769 seq_printf(m: s, fmt: "Tx multi-user Beamforming counts: %d\n",
770 mib->tx_bf_cnt);
771 seq_printf(m: s, fmt: "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
772 seq_printf(m: s, fmt: "Tx multi-user successful MPDU counts: %d\n",
773 mib->tx_mu_acked_mpdu_cnt);
774 seq_printf(m: s, fmt: "Tx single-user successful MPDU counts: %d\n",
775 mib->tx_su_acked_mpdu_cnt);
776
777 seq_puts(m: s, s: "\n");
778}
779
780static int
781mt7915_tx_stats_show(struct seq_file *file, void *data)
782{
783 struct mt7915_phy *phy = file->private;
784 struct mt7915_dev *dev = phy->dev;
785 struct mt76_mib_stats *mib = &phy->mib;
786 int i;
787
788 mutex_lock(&dev->mt76.mutex);
789
790 mt7915_ampdu_stat_read_phy(phy, file);
791 mt7915_mac_update_stats(phy);
792 mt7915_txbf_stat_read_phy(phy, s: file);
793
794 /* Tx amsdu info */
795 seq_puts(m: file, s: "Tx MSDU statistics:\n");
796 for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
797 seq_printf(m: file, fmt: "AMSDU pack count of %d MSDU in TXD: %8d ",
798 i + 1, mib->tx_amsdu[i]);
799 if (mib->tx_amsdu_cnt)
800 seq_printf(m: file, fmt: "(%3d%%)\n",
801 mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
802 else
803 seq_puts(m: file, s: "\n");
804 }
805
806 mutex_unlock(lock: &dev->mt76.mutex);
807
808 return 0;
809}
810
811DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
812
813static void
814mt7915_hw_queue_read(struct seq_file *s, u32 size,
815 const struct hw_queue_map *map)
816{
817 struct mt7915_phy *phy = s->private;
818 struct mt7915_dev *dev = phy->dev;
819 u32 i, val;
820
821 val = mt76_rr(dev, MT_FL_Q_EMPTY);
822 for (i = 0; i < size; i++) {
823 u32 ctrl, head, tail, queued;
824
825 if (val & BIT(map[i].index))
826 continue;
827
828 ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24);
829 mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
830
831 head = mt76_get_field(dev, MT_FL_Q2_CTRL,
832 GENMASK(11, 0));
833 tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
834 GENMASK(27, 16));
835 queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
836 GENMASK(11, 0));
837
838 seq_printf(m: s, fmt: "\t%s: ", map[i].name);
839 seq_printf(m: s, fmt: "queued:0x%03x head:0x%03x tail:0x%03x\n",
840 queued, head, tail);
841 }
842}
843
844static void
845mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
846{
847 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
848 struct mt7915_dev *dev = msta->vif->phy->dev;
849 struct seq_file *s = data;
850 u8 ac;
851
852 for (ac = 0; ac < 4; ac++) {
853 u32 qlen, ctrl, val;
854 u32 idx = msta->wcid.idx >> 5;
855 u8 offs = msta->wcid.idx & GENMASK(4, 0);
856
857 ctrl = BIT(31) | BIT(11) | (ac << 24);
858 val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
859
860 if (val & BIT(offs))
861 continue;
862
863 mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
864 qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
865 GENMASK(11, 0));
866 seq_printf(m: s, fmt: "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
867 sta->addr, msta->wcid.idx,
868 msta->vif->mt76.wmm_idx, ac, qlen);
869 }
870}
871
872static int
873mt7915_hw_queues_show(struct seq_file *file, void *data)
874{
875 struct mt7915_phy *phy = file->private;
876 struct mt7915_dev *dev = phy->dev;
877 static const struct hw_queue_map ple_queue_map[] = {
878 { "CPU_Q0", 0, 1, MT_CTX0 },
879 { "CPU_Q1", 1, 1, MT_CTX0 + 1 },
880 { "CPU_Q2", 2, 1, MT_CTX0 + 2 },
881 { "CPU_Q3", 3, 1, MT_CTX0 + 3 },
882 { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 },
883 { "BMC_Q0", 9, 2, MT_LMAC_BMC0 },
884 { "BCN_Q0", 10, 2, MT_LMAC_BCN0 },
885 { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 },
886 { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
887 { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 },
888 { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 },
889 { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
890 };
891 static const struct hw_queue_map pse_queue_map[] = {
892 { "CPU Q0", 0, 1, MT_CTX0 },
893 { "CPU Q1", 1, 1, MT_CTX0 + 1 },
894 { "CPU Q2", 2, 1, MT_CTX0 + 2 },
895 { "CPU Q3", 3, 1, MT_CTX0 + 3 },
896 { "HIF_Q0", 8, 0, MT_HIF0 },
897 { "HIF_Q1", 9, 0, MT_HIF0 + 1 },
898 { "HIF_Q2", 10, 0, MT_HIF0 + 2 },
899 { "HIF_Q3", 11, 0, MT_HIF0 + 3 },
900 { "HIF_Q4", 12, 0, MT_HIF0 + 4 },
901 { "HIF_Q5", 13, 0, MT_HIF0 + 5 },
902 { "LMAC_Q", 16, 2, 0 },
903 { "MDP_TXQ", 17, 2, 1 },
904 { "MDP_RXQ", 18, 2, 2 },
905 { "SEC_TXQ", 19, 2, 3 },
906 { "SEC_RXQ", 20, 2, 4 },
907 };
908 u32 val, head, tail;
909
910 /* ple queue */
911 val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
912 head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
913 tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
914 seq_puts(m: file, s: "PLE page info:\n");
915 seq_printf(m: file,
916 fmt: "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
917 val, head, tail);
918
919 val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
920 head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
921 tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
922 seq_printf(m: file, fmt: "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
923 val, head, tail);
924
925 seq_puts(m: file, s: "PLE non-empty queue info:\n");
926 mt7915_hw_queue_read(s: file, ARRAY_SIZE(ple_queue_map),
927 map: &ple_queue_map[0]);
928
929 /* iterate per-sta ple queue */
930 ieee80211_iterate_stations_atomic(hw: phy->mt76->hw,
931 iterator: mt7915_sta_hw_queue_read, data: file);
932 /* pse queue */
933 seq_puts(m: file, s: "PSE non-empty queue info:\n");
934 mt7915_hw_queue_read(s: file, ARRAY_SIZE(pse_queue_map),
935 map: &pse_queue_map[0]);
936
937 return 0;
938}
939
940DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
941
942static int
943mt7915_xmit_queues_show(struct seq_file *file, void *data)
944{
945 struct mt7915_phy *phy = file->private;
946 struct mt7915_dev *dev = phy->dev;
947 struct {
948 struct mt76_queue *q;
949 char *queue;
950 } queue_map[] = {
951 { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" },
952 { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" },
953 { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" },
954 { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
955 };
956 int i;
957
958 seq_puts(m: file, s: " queue | hw-queued | head | tail |\n");
959 for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
960 struct mt76_queue *q = queue_map[i].q;
961
962 if (!q)
963 continue;
964
965 seq_printf(m: file, fmt: " %s | %9d | %9d | %9d |\n",
966 queue_map[i].queue, q->queued, q->head,
967 q->tail);
968 }
969
970 return 0;
971}
972
973DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
974
975#define mt7915_txpower_puts(rate) \
976({ \
977 len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)"); \
978 for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++) \
979 len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]); \
980 len += scnprintf(buf + len, sz - len, "\n"); \
981})
982
983#define mt7915_txpower_sets(rate, pwr, flag) \
984({ \
985 offs += len; \
986 len = mt7915_sku_group_len[rate]; \
987 if (mode == flag) { \
988 for (i = 0; i < len; i++) \
989 req.txpower_sku[offs + i] = pwr; \
990 } \
991})
992
993static ssize_t
994mt7915_rate_txpower_get(struct file *file, char __user *user_buf,
995 size_t count, loff_t *ppos)
996{
997 struct mt7915_phy *phy = file->private_data;
998 struct mt7915_dev *dev = phy->dev;
999 s8 txpwr[MT7915_SKU_RATE_NUM];
1000 static const size_t sz = 2048;
1001 u8 band = phy->mt76->band_idx;
1002 int i, offs = 0, len = 0;
1003 ssize_t ret;
1004 char *buf;
1005 u32 reg;
1006
1007 buf = kzalloc(sz, GFP_KERNEL);
1008 if (!buf)
1009 return -ENOMEM;
1010
1011 ret = mt7915_mcu_get_txpower_sku(phy, txpower: txpwr, len: sizeof(txpwr));
1012 if (ret)
1013 goto out;
1014
1015 /* Txpower propagation path: TMAC -> TXV -> BBP */
1016 len += scnprintf(buf: buf + len, size: sz - len,
1017 fmt: "\nPhy%d Tx power table (channel %d)\n",
1018 phy != &dev->phy, phy->mt76->chandef.chan->hw_value);
1019 len += scnprintf(buf: buf + len, size: sz - len, fmt: "%-16s %6s %6s %6s %6s\n",
1020 " ", "1m", "2m", "5m", "11m");
1021 mt7915_txpower_puts(CCK);
1022
1023 len += scnprintf(buf: buf + len, size: sz - len,
1024 fmt: "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1025 " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
1026 "54m");
1027 mt7915_txpower_puts(OFDM);
1028
1029 len += scnprintf(buf: buf + len, size: sz - len,
1030 fmt: "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1031 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
1032 "mcs5", "mcs6", "mcs7");
1033 mt7915_txpower_puts(HT_BW20);
1034
1035 len += scnprintf(buf: buf + len, size: sz - len,
1036 fmt: "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1037 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
1038 "mcs6", "mcs7", "mcs32");
1039 mt7915_txpower_puts(HT_BW40);
1040
1041 len += scnprintf(buf: buf + len, size: sz - len,
1042 fmt: "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1043 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
1044 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
1045 mt7915_txpower_puts(VHT_BW20);
1046 mt7915_txpower_puts(VHT_BW40);
1047 mt7915_txpower_puts(VHT_BW80);
1048 mt7915_txpower_puts(VHT_BW160);
1049 mt7915_txpower_puts(HE_RU26);
1050 mt7915_txpower_puts(HE_RU52);
1051 mt7915_txpower_puts(HE_RU106);
1052 mt7915_txpower_puts(HE_RU242);
1053 mt7915_txpower_puts(HE_RU484);
1054 mt7915_txpower_puts(HE_RU996);
1055 mt7915_txpower_puts(HE_RU2x996);
1056
1057 reg = is_mt7915(dev: &dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) :
1058 MT_WF_PHY_TPC_CTRL_STAT_MT7916(band);
1059
1060 len += scnprintf(buf: buf + len, size: sz - len, fmt: "\nTx power (bbp) : %6ld\n",
1061 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER));
1062
1063 ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: len);
1064
1065out:
1066 kfree(objp: buf);
1067 return ret;
1068}
1069
1070static ssize_t
1071mt7915_rate_txpower_set(struct file *file, const char __user *user_buf,
1072 size_t count, loff_t *ppos)
1073{
1074 int i, ret, pwr, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0;
1075 struct mt7915_phy *phy = file->private_data;
1076 struct mt7915_dev *dev = phy->dev;
1077 struct mt76_phy *mphy = phy->mt76;
1078 struct mt7915_mcu_txpower_sku req = {
1079 .format_id = TX_POWER_LIMIT_TABLE,
1080 .band_idx = phy->mt76->band_idx,
1081 };
1082 char buf[100];
1083 enum mac80211_rx_encoding mode;
1084 u32 offs = 0, len = 0;
1085
1086 if (count >= sizeof(buf))
1087 return -EINVAL;
1088
1089 if (copy_from_user(to: buf, from: user_buf, n: count))
1090 return -EFAULT;
1091
1092 if (count && buf[count - 1] == '\n')
1093 buf[count - 1] = '\0';
1094 else
1095 buf[count] = '\0';
1096
1097 if (sscanf(buf, "%u %u %u %u %u",
1098 &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) {
1099 dev_warn(dev->mt76.dev,
1100 "per bandwidth power limit: Mode BW160 BW80 BW40 BW20");
1101 return -EINVAL;
1102 }
1103
1104 if (mode > RX_ENC_HE)
1105 return -EINVAL;
1106
1107 if (pwr160)
1108 pwr160 = mt76_get_power_bound(phy: mphy, txpower: pwr160);
1109 if (pwr80)
1110 pwr80 = mt76_get_power_bound(phy: mphy, txpower: pwr80);
1111 if (pwr40)
1112 pwr40 = mt76_get_power_bound(phy: mphy, txpower: pwr40);
1113 if (pwr20)
1114 pwr20 = mt76_get_power_bound(phy: mphy, txpower: pwr20);
1115
1116 if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0)
1117 return -EINVAL;
1118
1119 mutex_lock(&dev->mt76.mutex);
1120 ret = mt7915_mcu_get_txpower_sku(phy, txpower: req.txpower_sku,
1121 len: sizeof(req.txpower_sku));
1122 if (ret)
1123 goto out;
1124
1125 mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY);
1126 mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY);
1127 if (mode == RX_ENC_LEGACY)
1128 goto skip;
1129
1130 mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT);
1131 mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT);
1132 if (mode == RX_ENC_HT)
1133 goto skip;
1134
1135 mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT);
1136 mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT);
1137 mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT);
1138 mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT);
1139 if (mode == RX_ENC_VHT)
1140 goto skip;
1141
1142 mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1);
1143 mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1);
1144 mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1);
1145 mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE);
1146 mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE);
1147 mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE);
1148 mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE);
1149skip:
1150 ret = mt76_mcu_send_msg(dev: &dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
1151 data: &req, len: sizeof(req), wait_resp: true);
1152 if (ret)
1153 goto out;
1154
1155 pwr = max3(pwr80, pwr40, pwr20);
1156 mphy->txpower_cur = max3(mphy->txpower_cur, pwr160, pwr);
1157out:
1158 mutex_unlock(lock: &dev->mt76.mutex);
1159
1160 return ret ? ret : count;
1161}
1162
1163static const struct file_operations mt7915_rate_txpower_fops = {
1164 .write = mt7915_rate_txpower_set,
1165 .read = mt7915_rate_txpower_get,
1166 .open = simple_open,
1167 .owner = THIS_MODULE,
1168 .llseek = default_llseek,
1169};
1170
1171static int
1172mt7915_twt_stats(struct seq_file *s, void *data)
1173{
1174 struct mt7915_dev *dev = dev_get_drvdata(dev: s->private);
1175 struct mt7915_twt_flow *iter;
1176
1177 rcu_read_lock();
1178
1179 seq_puts(m: s, s: " wcid | id | flags | exp | mantissa");
1180 seq_puts(m: s, s: " | duration | tsf |\n");
1181 list_for_each_entry_rcu(iter, &dev->twt_list, list)
1182 seq_printf(m: s,
1183 fmt: "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
1184 iter->wcid, iter->id,
1185 iter->sched ? 's' : 'u',
1186 iter->protection ? 'p' : '-',
1187 iter->trigger ? 't' : '-',
1188 iter->flowtype ? '-' : 'a',
1189 iter->exp, iter->mantissa,
1190 iter->duration, iter->tsf);
1191
1192 rcu_read_unlock();
1193
1194 return 0;
1195}
1196
1197/* The index of RF registers use the generic regidx, combined with two parts:
1198 * WF selection [31:24] and offset [23:0].
1199 */
1200static int
1201mt7915_rf_regval_get(void *data, u64 *val)
1202{
1203 struct mt7915_dev *dev = data;
1204 u32 regval;
1205 int ret;
1206
1207 ret = mt7915_mcu_rf_regval(dev, regidx: dev->mt76.debugfs_reg, val: &regval, set: false);
1208 if (ret)
1209 return ret;
1210
1211 *val = regval;
1212
1213 return 0;
1214}
1215
1216static int
1217mt7915_rf_regval_set(void *data, u64 val)
1218{
1219 struct mt7915_dev *dev = data;
1220 u32 val32 = val;
1221
1222 return mt7915_mcu_rf_regval(dev, regidx: dev->mt76.debugfs_reg, val: &val32, set: true);
1223}
1224
1225DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get,
1226 mt7915_rf_regval_set, "0x%08llx\n");
1227
1228int mt7915_init_debugfs(struct mt7915_phy *phy)
1229{
1230 struct mt7915_dev *dev = phy->dev;
1231 bool ext_phy = phy != &dev->phy;
1232 struct dentry *dir;
1233
1234 dir = mt76_register_debugfs_fops(phy: phy->mt76, NULL);
1235 if (!dir)
1236 return -ENOMEM;
1237 debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);
1238 debugfs_create_file("muru_stats", 0400, dir, phy,
1239 &mt7915_muru_stats_fops);
1240 debugfs_create_file("hw-queues", 0400, dir, phy,
1241 &mt7915_hw_queues_fops);
1242 debugfs_create_file("xmit-queues", 0400, dir, phy,
1243 &mt7915_xmit_queues_fops);
1244 debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
1245 debugfs_create_file("sys_recovery", 0600, dir, phy,
1246 &mt7915_sys_recovery_ops);
1247 debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
1248 debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
1249 debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
1250 debugfs_create_file("fw_util_wm", 0400, dir, dev,
1251 &mt7915_fw_util_wm_fops);
1252 debugfs_create_file("fw_util_wa", 0400, dir, dev,
1253 &mt7915_fw_util_wa_fops);
1254 debugfs_create_file("implicit_txbf", 0600, dir, dev,
1255 &fops_implicit_txbf);
1256 debugfs_create_file("txpower_sku", 0400, dir, phy,
1257 &mt7915_rate_txpower_fops);
1258 debugfs_create_devm_seqfile(dev: dev->mt76.dev, name: "twt_stats", parent: dir,
1259 read_fn: mt7915_twt_stats);
1260 debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
1261
1262 if (!dev->dbdc_support || phy->mt76->band_idx) {
1263 debugfs_create_u32(name: "dfs_hw_pattern", mode: 0400, parent: dir,
1264 value: &dev->hw_pattern);
1265 debugfs_create_file("radar_trigger", 0200, dir, phy,
1266 &fops_radar_trigger);
1267 debugfs_create_devm_seqfile(dev: dev->mt76.dev, name: "rdd_monitor", parent: dir,
1268 read_fn: mt7915_rdd_monitor);
1269 }
1270
1271 if (!ext_phy)
1272 dev->debugfs_dir = dir;
1273
1274 return 0;
1275}
1276
1277static void
1278mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,
1279 const void *data, int len)
1280{
1281 static DEFINE_SPINLOCK(lock);
1282 unsigned long flags;
1283 void *dest;
1284
1285 spin_lock_irqsave(&lock, flags);
1286 dest = relay_reserve(chan: dev->relay_fwlog, length: hdrlen + len + 4);
1287 if (dest) {
1288 *(u32 *)dest = hdrlen + len;
1289 dest += 4;
1290
1291 if (hdrlen) {
1292 memcpy(dest, hdr, hdrlen);
1293 dest += hdrlen;
1294 }
1295
1296 memcpy(dest, data, len);
1297 relay_flush(chan: dev->relay_fwlog);
1298 }
1299 spin_unlock_irqrestore(lock: &lock, flags);
1300}
1301
1302void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)
1303{
1304 struct {
1305 __le32 magic;
1306 __le32 timestamp;
1307 __le16 msg_type;
1308 __le16 len;
1309 } hdr = {
1310 .magic = cpu_to_le32(FW_BIN_LOG_MAGIC),
1311 .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
1312 };
1313
1314 if (!dev->relay_fwlog)
1315 return;
1316
1317 hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));
1318 hdr.len = *(__le16 *)data;
1319 mt7915_debugfs_write_fwlog(dev, hdr: &hdr, hdrlen: sizeof(hdr), data, len);
1320}
1321
1322bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)
1323{
1324 if (get_unaligned_le32(p: data) != FW_BIN_LOG_MAGIC)
1325 return false;
1326
1327 if (dev->relay_fwlog)
1328 mt7915_debugfs_write_fwlog(dev, NULL, hdrlen: 0, data, len);
1329
1330 return true;
1331}
1332
1333#ifdef CONFIG_MAC80211_DEBUGFS
1334/** per-station debugfs **/
1335
1336static ssize_t mt7915_sta_fixed_rate_set(struct file *file,
1337 const char __user *user_buf,
1338 size_t count, loff_t *ppos)
1339{
1340 struct ieee80211_sta *sta = file->private_data;
1341 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1342 struct mt7915_dev *dev = msta->vif->phy->dev;
1343 struct ieee80211_vif *vif;
1344 struct sta_phy phy = {};
1345 char buf[100];
1346 int ret;
1347 u32 field;
1348 u8 i, gi, he_ltf;
1349
1350 if (count >= sizeof(buf))
1351 return -EINVAL;
1352
1353 if (copy_from_user(to: buf, from: user_buf, n: count))
1354 return -EFAULT;
1355
1356 if (count && buf[count - 1] == '\n')
1357 buf[count - 1] = '\0';
1358 else
1359 buf[count] = '\0';
1360
1361 /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
1362 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
1363 * nss - vht: 1~4, he: 1~4, others: ignore
1364 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
1365 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
1366 * ldpc - off: 0, on: 1
1367 * stbc - off: 0, on: 1
1368 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
1369 */
1370 if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",
1371 &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,
1372 &phy.ldpc, &phy.stbc, &he_ltf) != 8) {
1373 dev_warn(dev->mt76.dev,
1374 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");
1375 field = RATE_PARAM_AUTO;
1376 goto out;
1377 }
1378
1379 phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);
1380 for (i = 0; i <= phy.bw; i++) {
1381 phy.sgi |= gi << (i << sta->deflink.he_cap.has_he);
1382 phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he);
1383 }
1384 field = RATE_PARAM_FIXED;
1385
1386out:
1387 vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
1388 ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, data: &phy, field);
1389 if (ret)
1390 return -EFAULT;
1391
1392 return count;
1393}
1394
1395static const struct file_operations fops_fixed_rate = {
1396 .write = mt7915_sta_fixed_rate_set,
1397 .open = simple_open,
1398 .owner = THIS_MODULE,
1399 .llseek = default_llseek,
1400};
1401
1402static int
1403mt7915_queues_show(struct seq_file *s, void *data)
1404{
1405 struct ieee80211_sta *sta = s->private;
1406
1407 mt7915_sta_hw_queue_read(data: s, sta);
1408
1409 return 0;
1410}
1411
1412DEFINE_SHOW_ATTRIBUTE(mt7915_queues);
1413
1414void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1415 struct ieee80211_sta *sta, struct dentry *dir)
1416{
1417 debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
1418 debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
1419}
1420
1421#endif
1422

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c