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