debugfs.c (30412B)
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 if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 27 return -EBUSY; 28 29 dev->ibf = !!val; 30 31 return mt7915_mcu_set_txbf(dev, 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_fw_ser_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 ext_phy = phy != &dev->phy; 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 else 68 buf[count] = '\0'; 69 70 if (kstrtou16(buf, 0, &val)) 71 return -EINVAL; 72 73 switch (val) { 74 case SER_QUERY: 75 /* grab firmware SER stats */ 76 ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy); 77 break; 78 case SER_SET_RECOVER_L1: 79 case SER_SET_RECOVER_L2: 80 case SER_SET_RECOVER_L3_RX_ABORT: 81 case SER_SET_RECOVER_L3_TX_ABORT: 82 case SER_SET_RECOVER_L3_TX_DISABLE: 83 case SER_SET_RECOVER_L3_BF: 84 ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy); 85 if (ret) 86 return ret; 87 88 ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy); 89 break; 90 default: 91 break; 92 } 93 94 return ret ? ret : count; 95} 96 97static ssize_t 98mt7915_fw_ser_get(struct file *file, char __user *user_buf, 99 size_t count, loff_t *ppos) 100{ 101 struct mt7915_phy *phy = file->private_data; 102 struct mt7915_dev *dev = phy->dev; 103 char *buff; 104 int desc = 0; 105 ssize_t ret; 106 static const size_t bufsz = 400; 107 108 buff = kmalloc(bufsz, GFP_KERNEL); 109 if (!buff) 110 return -ENOMEM; 111 112 desc += scnprintf(buff + desc, bufsz - desc, 113 "::E R , SER_STATUS = 0x%08x\n", 114 mt76_rr(dev, MT_SWDEF_SER_STATS)); 115 desc += scnprintf(buff + desc, bufsz - desc, 116 "::E R , SER_PLE_ERR = 0x%08x\n", 117 mt76_rr(dev, MT_SWDEF_PLE_STATS)); 118 desc += scnprintf(buff + desc, bufsz - desc, 119 "::E R , SER_PLE_ERR_1 = 0x%08x\n", 120 mt76_rr(dev, MT_SWDEF_PLE1_STATS)); 121 desc += scnprintf(buff + desc, bufsz - desc, 122 "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n", 123 mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS)); 124 desc += scnprintf(buff + desc, bufsz - desc, 125 "::E R , SER_PSE_ERR = 0x%08x\n", 126 mt76_rr(dev, MT_SWDEF_PSE_STATS)); 127 desc += scnprintf(buff + desc, bufsz - desc, 128 "::E R , SER_PSE_ERR_1 = 0x%08x\n", 129 mt76_rr(dev, MT_SWDEF_PSE1_STATS)); 130 desc += scnprintf(buff + desc, bufsz - desc, 131 "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n", 132 mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS)); 133 desc += scnprintf(buff + desc, bufsz - desc, 134 "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n", 135 mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS)); 136 desc += scnprintf(buff + desc, bufsz - desc, 137 "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n", 138 mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS)); 139 desc += scnprintf(buff + desc, bufsz - desc, 140 "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n", 141 mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS)); 142 143 ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); 144 kfree(buff); 145 return ret; 146} 147 148static const struct file_operations mt7915_fw_ser_ops = { 149 .write = mt7915_fw_ser_set, 150 .read = mt7915_fw_ser_get, 151 .open = simple_open, 152 .llseek = default_llseek, 153}; 154 155static int 156mt7915_radar_trigger(void *data, u64 val) 157{ 158 struct mt7915_dev *dev = data; 159 160 if (val > MT_RX_SEL2) 161 return -EINVAL; 162 163 return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE, 164 val, 0, 0); 165} 166 167DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, 168 mt7915_radar_trigger, "%lld\n"); 169 170static int 171mt7915_muru_debug_set(void *data, u64 val) 172{ 173 struct mt7915_dev *dev = data; 174 175 dev->muru_debug = val; 176 mt7915_mcu_muru_debug_set(dev, dev->muru_debug); 177 178 return 0; 179} 180 181static int 182mt7915_muru_debug_get(void *data, u64 *val) 183{ 184 struct mt7915_dev *dev = data; 185 186 *val = dev->muru_debug; 187 188 return 0; 189} 190 191DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get, 192 mt7915_muru_debug_set, "%lld\n"); 193 194static int mt7915_muru_stats_show(struct seq_file *file, void *data) 195{ 196 struct mt7915_phy *phy = file->private; 197 struct mt7915_dev *dev = phy->dev; 198 struct mt7915_mcu_muru_stats mu_stats = {}; 199 static const char * const dl_non_he_type[] = { 200 "CCK", "OFDM", "HT MIX", "HT GF", 201 "VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU" 202 }; 203 static const char * const dl_he_type[] = { 204 "HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU", 205 "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", 206 "HE >16RU" 207 }; 208 static const char * const ul_he_type[] = { 209 "HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU", 210 "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU" 211 }; 212 int ret, i; 213 u64 total_ppdu_cnt, sub_total_cnt; 214 215 if (!dev->muru_debug) { 216 seq_puts(file, "Please enable muru_debug first.\n"); 217 return 0; 218 } 219 220 mutex_lock(&dev->mt76.mutex); 221 222 ret = mt7915_mcu_muru_debug_get(phy, &mu_stats); 223 if (ret) 224 goto exit; 225 226 /* Non-HE Downlink*/ 227 seq_puts(file, "[Non-HE]\nDownlink\nData Type: "); 228 229 for (i = 0; i < 5; i++) 230 seq_printf(file, "%8s | ", dl_non_he_type[i]); 231 232#define __dl_u32(s) le32_to_cpu(mu_stats.dl.s) 233 seq_puts(file, "\nTotal Count:"); 234 seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ", 235 __dl_u32(cck_cnt), 236 __dl_u32(ofdm_cnt), 237 __dl_u32(htmix_cnt), 238 __dl_u32(htgf_cnt), 239 __dl_u32(vht_su_cnt)); 240 241 seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); 242 243 for (i = 5; i < 8; i++) 244 seq_printf(file, "%8s | ", dl_non_he_type[i]); 245 246 seq_puts(file, "\nTotal Count:"); 247 seq_printf(file, "%8u | %8u | %8u | ", 248 __dl_u32(vht_2mu_cnt), 249 __dl_u32(vht_3mu_cnt), 250 __dl_u32(vht_4mu_cnt)); 251 252 sub_total_cnt = __dl_u32(vht_2mu_cnt) + 253 __dl_u32(vht_3mu_cnt) + 254 __dl_u32(vht_4mu_cnt); 255 256 seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld", 257 sub_total_cnt); 258 259 total_ppdu_cnt = sub_total_cnt + 260 __dl_u32(cck_cnt) + 261 __dl_u32(ofdm_cnt) + 262 __dl_u32(htmix_cnt) + 263 __dl_u32(htgf_cnt) + 264 __dl_u32(vht_su_cnt); 265 266 seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt); 267 268 /* HE Downlink */ 269 seq_puts(file, "\n\n[HE]\nDownlink\nData Type: "); 270 271 for (i = 0; i < 2; i++) 272 seq_printf(file, "%8s | ", dl_he_type[i]); 273 274 seq_puts(file, "\nTotal Count:"); 275 seq_printf(file, "%8u | %8u | ", 276 __dl_u32(he_su_cnt), 277 __dl_u32(he_ext_su_cnt)); 278 279 seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); 280 281 for (i = 2; i < 5; i++) 282 seq_printf(file, "%8s | ", dl_he_type[i]); 283 284 seq_puts(file, "\nTotal Count:"); 285 seq_printf(file, "%8u | %8u | %8u | ", 286 __dl_u32(he_2mu_cnt), 287 __dl_u32(he_3mu_cnt), 288 __dl_u32(he_4mu_cnt)); 289 290 seq_puts(file, "\nDownlink OFDMA\nData Type: "); 291 292 for (i = 5; i < 11; i++) 293 seq_printf(file, "%8s | ", dl_he_type[i]); 294 295 seq_puts(file, "\nTotal Count:"); 296 seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ", 297 __dl_u32(he_2ru_cnt), 298 __dl_u32(he_3ru_cnt), 299 __dl_u32(he_4ru_cnt), 300 __dl_u32(he_5to8ru_cnt), 301 __dl_u32(he_9to16ru_cnt), 302 __dl_u32(he_gtr16ru_cnt)); 303 304 sub_total_cnt = __dl_u32(he_2mu_cnt) + 305 __dl_u32(he_3mu_cnt) + 306 __dl_u32(he_4mu_cnt); 307 total_ppdu_cnt = sub_total_cnt; 308 309 seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld", 310 sub_total_cnt); 311 312 sub_total_cnt = __dl_u32(he_2ru_cnt) + 313 __dl_u32(he_3ru_cnt) + 314 __dl_u32(he_4ru_cnt) + 315 __dl_u32(he_5to8ru_cnt) + 316 __dl_u32(he_9to16ru_cnt) + 317 __dl_u32(he_gtr16ru_cnt); 318 total_ppdu_cnt += sub_total_cnt; 319 320 seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld", 321 sub_total_cnt); 322 323 total_ppdu_cnt += __dl_u32(he_su_cnt) + 324 __dl_u32(he_ext_su_cnt); 325 326 seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt); 327#undef __dl_u32 328 329 /* HE Uplink */ 330 seq_puts(file, "\n\nUplink"); 331 seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type: "); 332 333 for (i = 0; i < 3; i++) 334 seq_printf(file, "%8s | ", ul_he_type[i]); 335 336#define __ul_u32(s) le32_to_cpu(mu_stats.ul.s) 337 seq_puts(file, "\nTotal Count:"); 338 seq_printf(file, "%8u | %8u | %8u | ", 339 __ul_u32(hetrig_2mu_cnt), 340 __ul_u32(hetrig_3mu_cnt), 341 __ul_u32(hetrig_4mu_cnt)); 342 343 seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type: "); 344 345 for (i = 3; i < 10; i++) 346 seq_printf(file, "%8s | ", ul_he_type[i]); 347 348 seq_puts(file, "\nTotal Count:"); 349 seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u | %7u | ", 350 __ul_u32(hetrig_su_cnt), 351 __ul_u32(hetrig_2ru_cnt), 352 __ul_u32(hetrig_3ru_cnt), 353 __ul_u32(hetrig_4ru_cnt), 354 __ul_u32(hetrig_5to8ru_cnt), 355 __ul_u32(hetrig_9to16ru_cnt), 356 __ul_u32(hetrig_gtr16ru_cnt)); 357 358 sub_total_cnt = __ul_u32(hetrig_2mu_cnt) + 359 __ul_u32(hetrig_3mu_cnt) + 360 __ul_u32(hetrig_4mu_cnt); 361 total_ppdu_cnt = sub_total_cnt; 362 363 seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld", 364 sub_total_cnt); 365 366 sub_total_cnt = __ul_u32(hetrig_2ru_cnt) + 367 __ul_u32(hetrig_3ru_cnt) + 368 __ul_u32(hetrig_4ru_cnt) + 369 __ul_u32(hetrig_5to8ru_cnt) + 370 __ul_u32(hetrig_9to16ru_cnt) + 371 __ul_u32(hetrig_gtr16ru_cnt); 372 total_ppdu_cnt += sub_total_cnt; 373 374 seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld", 375 sub_total_cnt); 376 377 total_ppdu_cnt += __ul_u32(hetrig_su_cnt); 378 379 seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt); 380#undef __ul_u32 381 382exit: 383 mutex_unlock(&dev->mt76.mutex); 384 385 return ret; 386} 387DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats); 388 389static int 390mt7915_rdd_monitor(struct seq_file *s, void *data) 391{ 392 struct mt7915_dev *dev = dev_get_drvdata(s->private); 393 struct cfg80211_chan_def *chandef = &dev->rdd2_chandef; 394 const char *bw; 395 int ret = 0; 396 397 mutex_lock(&dev->mt76.mutex); 398 399 if (!cfg80211_chandef_valid(chandef)) { 400 ret = -EINVAL; 401 goto out; 402 } 403 404 if (!dev->rdd2_phy) { 405 seq_puts(s, "not running\n"); 406 goto out; 407 } 408 409 switch (chandef->width) { 410 case NL80211_CHAN_WIDTH_40: 411 bw = "40"; 412 break; 413 case NL80211_CHAN_WIDTH_80: 414 bw = "80"; 415 break; 416 case NL80211_CHAN_WIDTH_160: 417 bw = "160"; 418 break; 419 case NL80211_CHAN_WIDTH_80P80: 420 bw = "80P80"; 421 break; 422 default: 423 bw = "20"; 424 break; 425 } 426 427 seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n", 428 chandef->chan->hw_value, chandef->chan->center_freq, 429 bw, chandef->center_freq1); 430out: 431 mutex_unlock(&dev->mt76.mutex); 432 433 return ret; 434} 435 436static int 437mt7915_fw_debug_wm_set(void *data, u64 val) 438{ 439 struct mt7915_dev *dev = data; 440 enum { 441 DEBUG_TXCMD = 62, 442 DEBUG_CMD_RPT_TX, 443 DEBUG_CMD_RPT_TRIG, 444 DEBUG_SPL, 445 DEBUG_RPT_RX, 446 } debug; 447 bool tx, rx, en; 448 int ret; 449 450 dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0; 451 452 if (dev->fw.debug_bin) 453 val = 16; 454 else 455 val = dev->fw.debug_wm; 456 457 tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1)); 458 rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2)); 459 en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0)); 460 461 ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val); 462 if (ret) 463 goto out; 464 465 for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) { 466 if (debug == DEBUG_RPT_RX) 467 val = en && rx; 468 else 469 val = en && tx; 470 471 ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val); 472 if (ret) 473 goto out; 474 } 475 476 /* WM CPU info record control */ 477 mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0)); 478 mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw.debug_wm); 479 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5)); 480 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5)); 481 482out: 483 if (ret) 484 dev->fw.debug_wm = 0; 485 486 return ret; 487} 488 489static int 490mt7915_fw_debug_wm_get(void *data, u64 *val) 491{ 492 struct mt7915_dev *dev = data; 493 494 *val = dev->fw.debug_wm; 495 496 return 0; 497} 498 499DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get, 500 mt7915_fw_debug_wm_set, "%lld\n"); 501 502static int 503mt7915_fw_debug_wa_set(void *data, u64 val) 504{ 505 struct mt7915_dev *dev = data; 506 int ret; 507 508 dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0; 509 510 ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa); 511 if (ret) 512 goto out; 513 514 ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), 515 MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0); 516out: 517 if (ret) 518 dev->fw.debug_wa = 0; 519 520 return ret; 521} 522 523static int 524mt7915_fw_debug_wa_get(void *data, u64 *val) 525{ 526 struct mt7915_dev *dev = data; 527 528 *val = dev->fw.debug_wa; 529 530 return 0; 531} 532 533DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get, 534 mt7915_fw_debug_wa_set, "%lld\n"); 535 536static struct dentry * 537create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode, 538 struct rchan_buf *buf, int *is_global) 539{ 540 struct dentry *f; 541 542 f = debugfs_create_file("fwlog_data", mode, parent, buf, 543 &relay_file_operations); 544 if (IS_ERR(f)) 545 return NULL; 546 547 *is_global = 1; 548 549 return f; 550} 551 552static int 553remove_buf_file_cb(struct dentry *f) 554{ 555 debugfs_remove(f); 556 557 return 0; 558} 559 560static int 561mt7915_fw_debug_bin_set(void *data, u64 val) 562{ 563 static struct rchan_callbacks relay_cb = { 564 .create_buf_file = create_buf_file_cb, 565 .remove_buf_file = remove_buf_file_cb, 566 }; 567 struct mt7915_dev *dev = data; 568 569 if (!dev->relay_fwlog) 570 dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir, 571 1500, 512, &relay_cb, NULL); 572 if (!dev->relay_fwlog) 573 return -ENOMEM; 574 575 dev->fw.debug_bin = val; 576 577 relay_reset(dev->relay_fwlog); 578 579 return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm); 580} 581 582static int 583mt7915_fw_debug_bin_get(void *data, u64 *val) 584{ 585 struct mt7915_dev *dev = data; 586 587 *val = dev->fw.debug_bin; 588 589 return 0; 590} 591 592DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get, 593 mt7915_fw_debug_bin_set, "%lld\n"); 594 595static int 596mt7915_fw_util_wm_show(struct seq_file *file, void *data) 597{ 598 struct mt7915_dev *dev = file->private; 599 600 seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC)); 601 seq_printf(file, "Exception state: 0x%x\n", 602 is_mt7915(&dev->mt76) ? 603 (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(15, 8)) : 604 (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(7, 0))); 605 606 if (dev->fw.debug_wm) { 607 seq_printf(file, "Busy: %u%% Peak busy: %u%%\n", 608 mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT), 609 mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT)); 610 seq_printf(file, "Idle count: %u Peak idle count: %u\n", 611 mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT), 612 mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT)); 613 } 614 615 return 0; 616} 617 618DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm); 619 620static int 621mt7915_fw_util_wa_show(struct seq_file *file, void *data) 622{ 623 struct mt7915_dev *dev = file->private; 624 625 seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC)); 626 627 if (dev->fw.debug_wa) 628 return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY), 629 MCU_WA_PARAM_CPU_UTIL, 0, 0); 630 631 return 0; 632} 633 634DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa); 635 636static void 637mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, 638 struct seq_file *file) 639{ 640 struct mt7915_dev *dev = phy->dev; 641 bool ext_phy = phy != &dev->phy; 642 int bound[15], range[4], i, n; 643 644 /* Tx ampdu stat */ 645 for (i = 0; i < ARRAY_SIZE(range); i++) 646 range[i] = mt76_rr(dev, MT_MIB_ARNG(phy->band_idx, i)); 647 648 for (i = 0; i < ARRAY_SIZE(bound); i++) 649 bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; 650 651 seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, phy->band_idx); 652 653 seq_printf(file, "Length: %8d | ", bound[0]); 654 for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 655 seq_printf(file, "%3d -%3d | ", 656 bound[i] + 1, bound[i + 1]); 657 658 seq_puts(file, "\nCount: "); 659 n = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; 660 for (i = 0; i < ARRAY_SIZE(bound); i++) 661 seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]); 662 seq_puts(file, "\n"); 663 664 seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); 665} 666 667static void 668mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) 669{ 670 static const char * const bw[] = { 671 "BW20", "BW40", "BW80", "BW160" 672 }; 673 struct mib_stats *mib = &phy->mib; 674 675 /* Tx Beamformer monitor */ 676 seq_puts(s, "\nTx Beamformer applied PPDU counts: "); 677 678 seq_printf(s, "iBF: %d, eBF: %d\n", 679 mib->tx_bf_ibf_ppdu_cnt, 680 mib->tx_bf_ebf_ppdu_cnt); 681 682 /* Tx Beamformer Rx feedback monitor */ 683 seq_puts(s, "Tx Beamformer Rx feedback statistics: "); 684 685 seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", 686 mib->tx_bf_rx_fb_all_cnt, 687 mib->tx_bf_rx_fb_he_cnt, 688 mib->tx_bf_rx_fb_vht_cnt, 689 mib->tx_bf_rx_fb_ht_cnt); 690 691 seq_printf(s, "%s, NC: %d, NR: %d\n", 692 bw[mib->tx_bf_rx_fb_bw], 693 mib->tx_bf_rx_fb_nc_cnt, 694 mib->tx_bf_rx_fb_nr_cnt); 695 696 /* Tx Beamformee Rx NDPA & Tx feedback report */ 697 seq_printf(s, "Tx Beamformee successful feedback frames: %d\n", 698 mib->tx_bf_fb_cpl_cnt); 699 seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n", 700 mib->tx_bf_fb_trig_cnt); 701 702 /* Tx SU & MU counters */ 703 seq_printf(s, "Tx multi-user Beamforming counts: %d\n", 704 mib->tx_bf_cnt); 705 seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt); 706 seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", 707 mib->tx_mu_acked_mpdu_cnt); 708 seq_printf(s, "Tx single-user successful MPDU counts: %d\n", 709 mib->tx_su_acked_mpdu_cnt); 710 711 seq_puts(s, "\n"); 712} 713 714static int 715mt7915_tx_stats_show(struct seq_file *file, void *data) 716{ 717 struct mt7915_phy *phy = file->private; 718 struct mt7915_dev *dev = phy->dev; 719 struct mib_stats *mib = &phy->mib; 720 int i; 721 722 mutex_lock(&dev->mt76.mutex); 723 724 mt7915_ampdu_stat_read_phy(phy, file); 725 mt7915_mac_update_stats(phy); 726 mt7915_txbf_stat_read_phy(phy, file); 727 728 /* Tx amsdu info */ 729 seq_puts(file, "Tx MSDU statistics:\n"); 730 for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 731 seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ", 732 i + 1, mib->tx_amsdu[i]); 733 if (mib->tx_amsdu_cnt) 734 seq_printf(file, "(%3d%%)\n", 735 mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt); 736 else 737 seq_puts(file, "\n"); 738 } 739 740 mutex_unlock(&dev->mt76.mutex); 741 742 return 0; 743} 744 745DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); 746 747static void 748mt7915_hw_queue_read(struct seq_file *s, u32 size, 749 const struct hw_queue_map *map) 750{ 751 struct mt7915_phy *phy = s->private; 752 struct mt7915_dev *dev = phy->dev; 753 u32 i, val; 754 755 val = mt76_rr(dev, MT_FL_Q_EMPTY); 756 for (i = 0; i < size; i++) { 757 u32 ctrl, head, tail, queued; 758 759 if (val & BIT(map[i].index)) 760 continue; 761 762 ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24); 763 mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); 764 765 head = mt76_get_field(dev, MT_FL_Q2_CTRL, 766 GENMASK(11, 0)); 767 tail = mt76_get_field(dev, MT_FL_Q2_CTRL, 768 GENMASK(27, 16)); 769 queued = mt76_get_field(dev, MT_FL_Q3_CTRL, 770 GENMASK(11, 0)); 771 772 seq_printf(s, "\t%s: ", map[i].name); 773 seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n", 774 queued, head, tail); 775 } 776} 777 778static void 779mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) 780{ 781 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 782 struct mt7915_dev *dev = msta->vif->phy->dev; 783 struct seq_file *s = data; 784 u8 ac; 785 786 for (ac = 0; ac < 4; ac++) { 787 u32 qlen, ctrl, val; 788 u32 idx = msta->wcid.idx >> 5; 789 u8 offs = msta->wcid.idx & GENMASK(4, 0); 790 791 ctrl = BIT(31) | BIT(11) | (ac << 24); 792 val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx)); 793 794 if (val & BIT(offs)) 795 continue; 796 797 mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx); 798 qlen = mt76_get_field(dev, MT_FL_Q3_CTRL, 799 GENMASK(11, 0)); 800 seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n", 801 sta->addr, msta->wcid.idx, 802 msta->vif->mt76.wmm_idx, ac, qlen); 803 } 804} 805 806static int 807mt7915_hw_queues_show(struct seq_file *file, void *data) 808{ 809 struct mt7915_phy *phy = file->private; 810 struct mt7915_dev *dev = phy->dev; 811 static const struct hw_queue_map ple_queue_map[] = { 812 { "CPU_Q0", 0, 1, MT_CTX0 }, 813 { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, 814 { "CPU_Q2", 2, 1, MT_CTX0 + 2 }, 815 { "CPU_Q3", 3, 1, MT_CTX0 + 3 }, 816 { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 }, 817 { "BMC_Q0", 9, 2, MT_LMAC_BMC0 }, 818 { "BCN_Q0", 10, 2, MT_LMAC_BCN0 }, 819 { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 }, 820 { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 }, 821 { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 }, 822 { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 }, 823 { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 }, 824 }; 825 static const struct hw_queue_map pse_queue_map[] = { 826 { "CPU Q0", 0, 1, MT_CTX0 }, 827 { "CPU Q1", 1, 1, MT_CTX0 + 1 }, 828 { "CPU Q2", 2, 1, MT_CTX0 + 2 }, 829 { "CPU Q3", 3, 1, MT_CTX0 + 3 }, 830 { "HIF_Q0", 8, 0, MT_HIF0 }, 831 { "HIF_Q1", 9, 0, MT_HIF0 + 1 }, 832 { "HIF_Q2", 10, 0, MT_HIF0 + 2 }, 833 { "HIF_Q3", 11, 0, MT_HIF0 + 3 }, 834 { "HIF_Q4", 12, 0, MT_HIF0 + 4 }, 835 { "HIF_Q5", 13, 0, MT_HIF0 + 5 }, 836 { "LMAC_Q", 16, 2, 0 }, 837 { "MDP_TXQ", 17, 2, 1 }, 838 { "MDP_RXQ", 18, 2, 2 }, 839 { "SEC_TXQ", 19, 2, 3 }, 840 { "SEC_RXQ", 20, 2, 4 }, 841 }; 842 u32 val, head, tail; 843 844 /* ple queue */ 845 val = mt76_rr(dev, MT_PLE_FREEPG_CNT); 846 head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0)); 847 tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16)); 848 seq_puts(file, "PLE page info:\n"); 849 seq_printf(file, 850 "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", 851 val, head, tail); 852 853 val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP); 854 head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0)); 855 tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16)); 856 seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", 857 val, head, tail); 858 859 seq_puts(file, "PLE non-empty queue info:\n"); 860 mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map), 861 &ple_queue_map[0]); 862 863 /* iterate per-sta ple queue */ 864 ieee80211_iterate_stations_atomic(phy->mt76->hw, 865 mt7915_sta_hw_queue_read, file); 866 /* pse queue */ 867 seq_puts(file, "PSE non-empty queue info:\n"); 868 mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map), 869 &pse_queue_map[0]); 870 871 return 0; 872} 873 874DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues); 875 876static int 877mt7915_xmit_queues_show(struct seq_file *file, void *data) 878{ 879 struct mt7915_phy *phy = file->private; 880 struct mt7915_dev *dev = phy->dev; 881 struct { 882 struct mt76_queue *q; 883 char *queue; 884 } queue_map[] = { 885 { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, 886 { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" }, 887 { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" }, 888 { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, 889 }; 890 int i; 891 892 seq_puts(file, " queue | hw-queued | head | tail |\n"); 893 for (i = 0; i < ARRAY_SIZE(queue_map); i++) { 894 struct mt76_queue *q = queue_map[i].q; 895 896 if (!q) 897 continue; 898 899 seq_printf(file, " %s | %9d | %9d | %9d |\n", 900 queue_map[i].queue, q->queued, q->head, 901 q->tail); 902 } 903 904 return 0; 905} 906 907DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); 908 909static int 910mt7915_rate_txpower_show(struct seq_file *file, void *data) 911{ 912 static const char * const sku_group_name[] = { 913 "CCK", "OFDM", "HT20", "HT40", 914 "VHT20", "VHT40", "VHT80", "VHT160", 915 "RU26", "RU52", "RU106", "RU242/SU20", 916 "RU484/SU40", "RU996/SU80", "RU2x996/SU160" 917 }; 918 struct mt7915_phy *phy = file->private; 919 s8 txpower[MT7915_SKU_RATE_NUM], *buf; 920 int i; 921 922 seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy); 923 mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); 924 for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { 925 u8 mcs_num = mt7915_sku_group_len[i]; 926 927 if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) 928 mcs_num = 10; 929 930 mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num); 931 buf += mt7915_sku_group_len[i]; 932 } 933 934 return 0; 935} 936 937DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower); 938 939static int 940mt7915_twt_stats(struct seq_file *s, void *data) 941{ 942 struct mt7915_dev *dev = dev_get_drvdata(s->private); 943 struct mt7915_twt_flow *iter; 944 945 rcu_read_lock(); 946 947 seq_puts(s, " wcid | id | flags | exp | mantissa"); 948 seq_puts(s, " | duration | tsf |\n"); 949 list_for_each_entry_rcu(iter, &dev->twt_list, list) 950 seq_printf(s, 951 "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n", 952 iter->wcid, iter->id, 953 iter->sched ? 's' : 'u', 954 iter->protection ? 'p' : '-', 955 iter->trigger ? 't' : '-', 956 iter->flowtype ? '-' : 'a', 957 iter->exp, iter->mantissa, 958 iter->duration, iter->tsf); 959 960 rcu_read_unlock(); 961 962 return 0; 963} 964 965/* The index of RF registers use the generic regidx, combined with two parts: 966 * WF selection [31:28] and offset [27:0]. 967 */ 968static int 969mt7915_rf_regval_get(void *data, u64 *val) 970{ 971 struct mt7915_dev *dev = data; 972 u32 regval; 973 int ret; 974 975 ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, ®val, false); 976 if (ret) 977 return ret; 978 979 *val = le32_to_cpu(regval); 980 981 return 0; 982} 983 984static int 985mt7915_rf_regval_set(void *data, u64 val) 986{ 987 struct mt7915_dev *dev = data; 988 989 return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, (u32 *)&val, true); 990} 991 992DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get, 993 mt7915_rf_regval_set, "0x%08llx\n"); 994 995int mt7915_init_debugfs(struct mt7915_phy *phy) 996{ 997 struct mt7915_dev *dev = phy->dev; 998 bool ext_phy = phy != &dev->phy; 999 struct dentry *dir; 1000 1001 dir = mt76_register_debugfs_fops(phy->mt76, NULL); 1002 if (!dir) 1003 return -ENOMEM; 1004 debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug); 1005 debugfs_create_file("muru_stats", 0400, dir, phy, 1006 &mt7915_muru_stats_fops); 1007 debugfs_create_file("hw-queues", 0400, dir, phy, 1008 &mt7915_hw_queues_fops); 1009 debugfs_create_file("xmit-queues", 0400, dir, phy, 1010 &mt7915_xmit_queues_fops); 1011 debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops); 1012 debugfs_create_file("fw_ser", 0600, dir, phy, &mt7915_fw_ser_ops); 1013 debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); 1014 debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); 1015 debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); 1016 debugfs_create_file("fw_util_wm", 0400, dir, dev, 1017 &mt7915_fw_util_wm_fops); 1018 debugfs_create_file("fw_util_wa", 0400, dir, dev, 1019 &mt7915_fw_util_wa_fops); 1020 debugfs_create_file("implicit_txbf", 0600, dir, dev, 1021 &fops_implicit_txbf); 1022 debugfs_create_file("txpower_sku", 0400, dir, phy, 1023 &mt7915_rate_txpower_fops); 1024 debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, 1025 mt7915_twt_stats); 1026 debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); 1027 1028 if (!dev->dbdc_support || phy->band_idx) { 1029 debugfs_create_u32("dfs_hw_pattern", 0400, dir, 1030 &dev->hw_pattern); 1031 debugfs_create_file("radar_trigger", 0200, dir, dev, 1032 &fops_radar_trigger); 1033 debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, 1034 mt7915_rdd_monitor); 1035 } 1036 1037 if (!ext_phy) 1038 dev->debugfs_dir = dir; 1039 1040 return 0; 1041} 1042 1043static void 1044mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen, 1045 const void *data, int len) 1046{ 1047 static DEFINE_SPINLOCK(lock); 1048 unsigned long flags; 1049 void *dest; 1050 1051 spin_lock_irqsave(&lock, flags); 1052 dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4); 1053 if (dest) { 1054 *(u32 *)dest = hdrlen + len; 1055 dest += 4; 1056 1057 if (hdrlen) { 1058 memcpy(dest, hdr, hdrlen); 1059 dest += hdrlen; 1060 } 1061 1062 memcpy(dest, data, len); 1063 relay_flush(dev->relay_fwlog); 1064 } 1065 spin_unlock_irqrestore(&lock, flags); 1066} 1067 1068void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len) 1069{ 1070 struct { 1071 __le32 magic; 1072 __le32 timestamp; 1073 __le16 msg_type; 1074 __le16 len; 1075 } hdr = { 1076 .magic = cpu_to_le32(FW_BIN_LOG_MAGIC), 1077 .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR), 1078 }; 1079 1080 if (!dev->relay_fwlog) 1081 return; 1082 1083 hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0))); 1084 hdr.len = *(__le16 *)data; 1085 mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len); 1086} 1087 1088bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len) 1089{ 1090 if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC) 1091 return false; 1092 1093 if (dev->relay_fwlog) 1094 mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len); 1095 1096 return true; 1097} 1098 1099#ifdef CONFIG_MAC80211_DEBUGFS 1100/** per-station debugfs **/ 1101 1102static ssize_t mt7915_sta_fixed_rate_set(struct file *file, 1103 const char __user *user_buf, 1104 size_t count, loff_t *ppos) 1105{ 1106 struct ieee80211_sta *sta = file->private_data; 1107 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 1108 struct mt7915_dev *dev = msta->vif->phy->dev; 1109 struct ieee80211_vif *vif; 1110 struct sta_phy phy = {}; 1111 char buf[100]; 1112 int ret; 1113 u32 field; 1114 u8 i, gi, he_ltf; 1115 1116 if (count >= sizeof(buf)) 1117 return -EINVAL; 1118 1119 if (copy_from_user(buf, user_buf, count)) 1120 return -EFAULT; 1121 1122 if (count && buf[count - 1] == '\n') 1123 buf[count - 1] = '\0'; 1124 else 1125 buf[count] = '\0'; 1126 1127 /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 1128 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3 1129 * nss - vht: 1~4, he: 1~4, others: ignore 1130 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2 1131 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2 1132 * ldpc - off: 0, on: 1 1133 * stbc - off: 0, on: 1 1134 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 1135 */ 1136 if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu", 1137 &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi, 1138 &phy.ldpc, &phy.stbc, &he_ltf) != 8) { 1139 dev_warn(dev->mt76.dev, 1140 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n"); 1141 field = RATE_PARAM_AUTO; 1142 goto out; 1143 } 1144 1145 phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0); 1146 for (i = 0; i <= phy.bw; i++) { 1147 phy.sgi |= gi << (i << sta->deflink.he_cap.has_he); 1148 phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he); 1149 } 1150 field = RATE_PARAM_FIXED; 1151 1152out: 1153 vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 1154 ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field); 1155 if (ret) 1156 return -EFAULT; 1157 1158 return count; 1159} 1160 1161static const struct file_operations fops_fixed_rate = { 1162 .write = mt7915_sta_fixed_rate_set, 1163 .open = simple_open, 1164 .owner = THIS_MODULE, 1165 .llseek = default_llseek, 1166}; 1167 1168static int 1169mt7915_queues_show(struct seq_file *s, void *data) 1170{ 1171 struct ieee80211_sta *sta = s->private; 1172 1173 mt7915_sta_hw_queue_read(s, sta); 1174 1175 return 0; 1176} 1177 1178DEFINE_SHOW_ATTRIBUTE(mt7915_queues); 1179 1180void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1181 struct ieee80211_sta *sta, struct dentry *dir) 1182{ 1183 debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); 1184 debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops); 1185} 1186 1187#endif