1 // SPDX-License-Identifier: ISC 2 /* Copyright (C) 2020 MediaTek Inc. */ 3 4 #include "mt7915.h" 5 #include "eeprom.h" 6 #include "mcu.h" 7 8 /** global debugfs **/ 9 10 struct hw_queue_map { 11 const char *name; 12 u8 index; 13 u8 pid; 14 u8 qid; 15 }; 16 17 static int 18 mt7915_implicit_txbf_set(void *data, u64 val) 19 { 20 struct mt7915_dev *dev = data; 21 22 if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 23 return -EBUSY; 24 25 dev->ibf = !!val; 26 27 return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); 28 } 29 30 static int 31 mt7915_implicit_txbf_get(void *data, u64 *val) 32 { 33 struct mt7915_dev *dev = data; 34 35 *val = dev->ibf; 36 37 return 0; 38 } 39 40 DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get, 41 mt7915_implicit_txbf_set, "%lld\n"); 42 43 /* test knob of system layer 1/2 error recovery */ 44 static int mt7915_ser_trigger_set(void *data, u64 val) 45 { 46 enum { 47 SER_SET_RECOVER_L1 = 1, 48 SER_SET_RECOVER_L2, 49 SER_ENABLE = 2, 50 SER_RECOVER 51 }; 52 struct mt7915_dev *dev = data; 53 int ret = 0; 54 55 switch (val) { 56 case SER_SET_RECOVER_L1: 57 case SER_SET_RECOVER_L2: 58 ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0); 59 if (ret) 60 return ret; 61 62 return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0); 63 default: 64 break; 65 } 66 67 return ret; 68 } 69 70 DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL, 71 mt7915_ser_trigger_set, "%lld\n"); 72 73 static int 74 mt7915_radar_trigger(void *data, u64 val) 75 { 76 struct mt7915_dev *dev = data; 77 78 return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0); 79 } 80 81 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, 82 mt7915_radar_trigger, "%lld\n"); 83 84 static int 85 mt7915_fw_debug_wm_set(void *data, u64 val) 86 { 87 struct mt7915_dev *dev = data; 88 enum { 89 DEBUG_TXCMD = 62, 90 DEBUG_CMD_RPT_TX, 91 DEBUG_CMD_RPT_TRIG, 92 DEBUG_SPL, 93 DEBUG_RPT_RX, 94 } debug; 95 int ret; 96 97 dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0; 98 99 ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, dev->fw_debug_wm); 100 if (ret) 101 return ret; 102 103 for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) { 104 ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, !!dev->fw_debug_wm); 105 if (ret) 106 return ret; 107 } 108 109 /* WM CPU info record control */ 110 mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0)); 111 mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw_debug_wm); 112 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5)); 113 mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5)); 114 115 return 0; 116 } 117 118 static int 119 mt7915_fw_debug_wm_get(void *data, u64 *val) 120 { 121 struct mt7915_dev *dev = data; 122 123 *val = dev->fw_debug_wm; 124 125 return 0; 126 } 127 128 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get, 129 mt7915_fw_debug_wm_set, "%lld\n"); 130 131 static int 132 mt7915_fw_debug_wa_set(void *data, u64 val) 133 { 134 struct mt7915_dev *dev = data; 135 int ret; 136 137 dev->fw_debug_wa = val ? MCU_FW_LOG_TO_HOST : 0; 138 139 ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw_debug_wa); 140 if (ret) 141 return ret; 142 143 return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_PDMA_RX, 144 !!dev->fw_debug_wa, 0); 145 } 146 147 static int 148 mt7915_fw_debug_wa_get(void *data, u64 *val) 149 { 150 struct mt7915_dev *dev = data; 151 152 *val = dev->fw_debug_wa; 153 154 return 0; 155 } 156 157 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get, 158 mt7915_fw_debug_wa_set, "%lld\n"); 159 160 static int 161 mt7915_fw_util_wm_show(struct seq_file *file, void *data) 162 { 163 struct mt7915_dev *dev = file->private; 164 165 if (dev->fw_debug_wm) { 166 seq_printf(file, "Busy: %u%% Peak busy: %u%%\n", 167 mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT), 168 mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT)); 169 seq_printf(file, "Idle count: %u Peak idle count: %u\n", 170 mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT), 171 mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT)); 172 } 173 174 return 0; 175 } 176 177 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm); 178 179 static int 180 mt7915_fw_util_wa_show(struct seq_file *file, void *data) 181 { 182 struct mt7915_dev *dev = file->private; 183 184 if (dev->fw_debug_wa) 185 return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY), 186 MCU_WA_PARAM_CPU_UTIL, 0, 0); 187 188 return 0; 189 } 190 191 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa); 192 193 static void 194 mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, 195 struct seq_file *file) 196 { 197 struct mt7915_dev *dev = phy->dev; 198 bool ext_phy = phy != &dev->phy; 199 int bound[15], range[4], i, n; 200 201 /* Tx ampdu stat */ 202 for (i = 0; i < ARRAY_SIZE(range); i++) 203 range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i)); 204 205 for (i = 0; i < ARRAY_SIZE(bound); i++) 206 bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; 207 208 seq_printf(file, "\nPhy %d\n", ext_phy); 209 210 seq_printf(file, "Length: %8d | ", bound[0]); 211 for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 212 seq_printf(file, "%3d -%3d | ", 213 bound[i] + 1, bound[i + 1]); 214 215 seq_puts(file, "\nCount: "); 216 n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; 217 for (i = 0; i < ARRAY_SIZE(bound); i++) 218 seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]); 219 seq_puts(file, "\n"); 220 221 seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); 222 } 223 224 static void 225 mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) 226 { 227 static const char * const bw[] = { 228 "BW20", "BW40", "BW80", "BW160" 229 }; 230 struct mib_stats *mib = &phy->mib; 231 232 /* Tx Beamformer monitor */ 233 seq_puts(s, "\nTx Beamformer applied PPDU counts: "); 234 235 seq_printf(s, "iBF: %d, eBF: %d\n", 236 mib->tx_bf_ibf_ppdu_cnt, 237 mib->tx_bf_ebf_ppdu_cnt); 238 239 /* Tx Beamformer Rx feedback monitor */ 240 seq_puts(s, "Tx Beamformer Rx feedback statistics: "); 241 242 seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", 243 mib->tx_bf_rx_fb_all_cnt, 244 mib->tx_bf_rx_fb_he_cnt, 245 mib->tx_bf_rx_fb_vht_cnt, 246 mib->tx_bf_rx_fb_ht_cnt); 247 248 seq_printf(s, "%s, NC: %d, NR: %d\n", 249 bw[mib->tx_bf_rx_fb_bw], 250 mib->tx_bf_rx_fb_nc_cnt, 251 mib->tx_bf_rx_fb_nr_cnt); 252 253 /* Tx Beamformee Rx NDPA & Tx feedback report */ 254 seq_printf(s, "Tx Beamformee successful feedback frames: %d\n", 255 mib->tx_bf_fb_cpl_cnt); 256 seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n", 257 mib->tx_bf_fb_trig_cnt); 258 259 /* Tx SU & MU counters */ 260 seq_printf(s, "Tx multi-user Beamforming counts: %d\n", 261 mib->tx_bf_cnt); 262 seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt); 263 seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", 264 mib->tx_mu_acked_mpdu_cnt); 265 seq_printf(s, "Tx single-user successful MPDU counts: %d\n", 266 mib->tx_su_acked_mpdu_cnt); 267 268 seq_puts(s, "\n"); 269 } 270 271 static int 272 mt7915_tx_stats_show(struct seq_file *file, void *data) 273 { 274 struct mt7915_phy *phy = file->private; 275 struct mt7915_dev *dev = phy->dev; 276 struct mib_stats *mib = &phy->mib; 277 int i; 278 279 mutex_lock(&dev->mt76.mutex); 280 281 mt7915_ampdu_stat_read_phy(phy, file); 282 mt7915_mac_update_stats(phy); 283 mt7915_txbf_stat_read_phy(phy, file); 284 285 /* Tx amsdu info */ 286 seq_puts(file, "Tx MSDU statistics:\n"); 287 for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 288 seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ", 289 i + 1, mib->tx_amsdu[i]); 290 if (mib->tx_amsdu_cnt) 291 seq_printf(file, "(%3d%%)\n", 292 mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt); 293 else 294 seq_puts(file, "\n"); 295 } 296 297 mutex_unlock(&dev->mt76.mutex); 298 299 return 0; 300 } 301 302 DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); 303 304 static void 305 mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size, 306 const struct hw_queue_map *map) 307 { 308 struct mt7915_phy *phy = s->private; 309 struct mt7915_dev *dev = phy->dev; 310 u32 i, val; 311 312 val = mt76_rr(dev, base + MT_FL_Q_EMPTY); 313 for (i = 0; i < size; i++) { 314 u32 ctrl, head, tail, queued; 315 316 if (val & BIT(map[i].index)) 317 continue; 318 319 ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24); 320 mt76_wr(dev, base + MT_FL_Q0_CTRL, ctrl); 321 322 head = mt76_get_field(dev, base + MT_FL_Q2_CTRL, 323 GENMASK(11, 0)); 324 tail = mt76_get_field(dev, base + MT_FL_Q2_CTRL, 325 GENMASK(27, 16)); 326 queued = mt76_get_field(dev, base + MT_FL_Q3_CTRL, 327 GENMASK(11, 0)); 328 329 seq_printf(s, "\t%s: ", map[i].name); 330 seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n", 331 queued, head, tail); 332 } 333 } 334 335 static void 336 mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) 337 { 338 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 339 struct mt7915_dev *dev = msta->vif->phy->dev; 340 struct seq_file *s = data; 341 u8 ac; 342 343 for (ac = 0; ac < 4; ac++) { 344 u32 qlen, ctrl, val; 345 u32 idx = msta->wcid.idx >> 5; 346 u8 offs = msta->wcid.idx & GENMASK(4, 0); 347 348 ctrl = BIT(31) | BIT(11) | (ac << 24); 349 val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx)); 350 351 if (val & BIT(offs)) 352 continue; 353 354 mt76_wr(dev, MT_PLE_BASE + MT_FL_Q0_CTRL, ctrl | msta->wcid.idx); 355 qlen = mt76_get_field(dev, MT_PLE_BASE + MT_FL_Q3_CTRL, 356 GENMASK(11, 0)); 357 seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n", 358 sta->addr, msta->wcid.idx, msta->vif->wmm_idx, 359 ac, qlen); 360 } 361 } 362 363 static int 364 mt7915_hw_queues_show(struct seq_file *file, void *data) 365 { 366 struct mt7915_phy *phy = file->private; 367 struct mt7915_dev *dev = phy->dev; 368 static const struct hw_queue_map ple_queue_map[] = { 369 { "CPU_Q0", 0, 1, MT_CTX0 }, 370 { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, 371 { "CPU_Q2", 2, 1, MT_CTX0 + 2 }, 372 { "CPU_Q3", 3, 1, MT_CTX0 + 3 }, 373 { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 }, 374 { "BMC_Q0", 9, 2, MT_LMAC_BMC0 }, 375 { "BCN_Q0", 10, 2, MT_LMAC_BCN0 }, 376 { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 }, 377 { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 }, 378 { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 }, 379 { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 }, 380 { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 }, 381 }; 382 static const struct hw_queue_map pse_queue_map[] = { 383 { "CPU Q0", 0, 1, MT_CTX0 }, 384 { "CPU Q1", 1, 1, MT_CTX0 + 1 }, 385 { "CPU Q2", 2, 1, MT_CTX0 + 2 }, 386 { "CPU Q3", 3, 1, MT_CTX0 + 3 }, 387 { "HIF_Q0", 8, 0, MT_HIF0 }, 388 { "HIF_Q1", 9, 0, MT_HIF0 + 1 }, 389 { "HIF_Q2", 10, 0, MT_HIF0 + 2 }, 390 { "HIF_Q3", 11, 0, MT_HIF0 + 3 }, 391 { "HIF_Q4", 12, 0, MT_HIF0 + 4 }, 392 { "HIF_Q5", 13, 0, MT_HIF0 + 5 }, 393 { "LMAC_Q", 16, 2, 0 }, 394 { "MDP_TXQ", 17, 2, 1 }, 395 { "MDP_RXQ", 18, 2, 2 }, 396 { "SEC_TXQ", 19, 2, 3 }, 397 { "SEC_RXQ", 20, 2, 4 }, 398 }; 399 u32 val, head, tail; 400 401 /* ple queue */ 402 val = mt76_rr(dev, MT_PLE_FREEPG_CNT); 403 head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0)); 404 tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16)); 405 seq_puts(file, "PLE page info:\n"); 406 seq_printf(file, 407 "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", 408 val, head, tail); 409 410 val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP); 411 head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0)); 412 tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16)); 413 seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", 414 val, head, tail); 415 416 seq_puts(file, "PLE non-empty queue info:\n"); 417 mt7915_hw_queue_read(file, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map), 418 &ple_queue_map[0]); 419 420 /* iterate per-sta ple queue */ 421 ieee80211_iterate_stations_atomic(phy->mt76->hw, 422 mt7915_sta_hw_queue_read, file); 423 /* pse queue */ 424 seq_puts(file, "PSE non-empty queue info:\n"); 425 mt7915_hw_queue_read(file, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map), 426 &pse_queue_map[0]); 427 428 return 0; 429 } 430 431 DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues); 432 433 static int 434 mt7915_xmit_queues_show(struct seq_file *file, void *data) 435 { 436 struct mt7915_phy *phy = file->private; 437 struct mt7915_dev *dev = phy->dev; 438 struct { 439 struct mt76_queue *q; 440 char *queue; 441 } queue_map[] = { 442 { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, 443 { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" }, 444 { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" }, 445 { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, 446 }; 447 int i; 448 449 seq_puts(file, " queue | hw-queued | head | tail |\n"); 450 for (i = 0; i < ARRAY_SIZE(queue_map); i++) { 451 struct mt76_queue *q = queue_map[i].q; 452 453 if (!q) 454 continue; 455 456 seq_printf(file, " %s | %9d | %9d | %9d |\n", 457 queue_map[i].queue, q->queued, q->head, 458 q->tail); 459 } 460 461 return 0; 462 } 463 464 DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); 465 466 static int 467 mt7915_rate_txpower_show(struct seq_file *file, void *data) 468 { 469 static const char * const sku_group_name[] = { 470 "CCK", "OFDM", "HT20", "HT40", 471 "VHT20", "VHT40", "VHT80", "VHT160", 472 "RU26", "RU52", "RU106", "RU242/SU20", 473 "RU484/SU40", "RU996/SU80", "RU2x996/SU160" 474 }; 475 struct mt7915_phy *phy = file->private; 476 s8 txpower[MT7915_SKU_RATE_NUM], *buf; 477 int i; 478 479 seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy); 480 mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); 481 for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { 482 u8 mcs_num = mt7915_sku_group_len[i]; 483 484 if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) 485 mcs_num = 10; 486 487 mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num); 488 buf += mt7915_sku_group_len[i]; 489 } 490 491 return 0; 492 } 493 494 DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower); 495 496 static int 497 mt7915_twt_stats(struct seq_file *s, void *data) 498 { 499 struct mt7915_dev *dev = dev_get_drvdata(s->private); 500 struct mt7915_twt_flow *iter; 501 502 rcu_read_lock(); 503 504 seq_puts(s, " wcid | id | flags | exp | mantissa"); 505 seq_puts(s, " | duration | tsf |\n"); 506 list_for_each_entry_rcu(iter, &dev->twt_list, list) 507 seq_printf(s, 508 "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n", 509 iter->wcid, iter->id, 510 iter->sched ? 's' : 'u', 511 iter->protection ? 'p' : '-', 512 iter->trigger ? 't' : '-', 513 iter->flowtype ? '-' : 'a', 514 iter->exp, iter->mantissa, 515 iter->duration, iter->tsf); 516 517 rcu_read_unlock(); 518 519 return 0; 520 } 521 522 int mt7915_init_debugfs(struct mt7915_phy *phy) 523 { 524 struct mt7915_dev *dev = phy->dev; 525 bool ext_phy = phy != &dev->phy; 526 struct dentry *dir; 527 528 dir = mt76_register_debugfs_fops(phy->mt76, NULL); 529 if (!dir) 530 return -ENOMEM; 531 532 debugfs_create_file("hw-queues", 0400, dir, phy, 533 &mt7915_hw_queues_fops); 534 debugfs_create_file("xmit-queues", 0400, dir, phy, 535 &mt7915_xmit_queues_fops); 536 debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops); 537 debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); 538 debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); 539 debugfs_create_file("fw_util_wm", 0400, dir, dev, 540 &mt7915_fw_util_wm_fops); 541 debugfs_create_file("fw_util_wa", 0400, dir, dev, 542 &mt7915_fw_util_wa_fops); 543 debugfs_create_file("implicit_txbf", 0600, dir, dev, 544 &fops_implicit_txbf); 545 debugfs_create_file("txpower_sku", 0400, dir, phy, 546 &mt7915_rate_txpower_fops); 547 debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, 548 mt7915_twt_stats); 549 debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); 550 if (!dev->dbdc_support || ext_phy) { 551 debugfs_create_u32("dfs_hw_pattern", 0400, dir, 552 &dev->hw_pattern); 553 debugfs_create_file("radar_trigger", 0200, dir, dev, 554 &fops_radar_trigger); 555 } 556 557 return 0; 558 } 559 560 #ifdef CONFIG_MAC80211_DEBUGFS 561 /** per-station debugfs **/ 562 563 static ssize_t mt7915_sta_fixed_rate_set(struct file *file, 564 const char __user *user_buf, 565 size_t count, loff_t *ppos) 566 { 567 struct ieee80211_sta *sta = file->private_data; 568 struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 569 struct mt7915_dev *dev = msta->vif->phy->dev; 570 struct ieee80211_vif *vif; 571 struct sta_phy phy = {}; 572 char buf[100]; 573 int ret; 574 u32 field; 575 u8 i, gi, he_ltf; 576 577 if (count >= sizeof(buf)) 578 return -EINVAL; 579 580 if (copy_from_user(buf, user_buf, count)) 581 return -EFAULT; 582 583 if (count && buf[count - 1] == '\n') 584 buf[count - 1] = '\0'; 585 else 586 buf[count] = '\0'; 587 588 /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 589 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3 590 * nss - vht: 1~4, he: 1~4, others: ignore 591 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2 592 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2 593 * ldpc - off: 0, on: 1 594 * stbc - off: 0, on: 1 595 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 596 */ 597 if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu", 598 &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi, 599 &phy.ldpc, &phy.stbc, &he_ltf) != 8) { 600 dev_warn(dev->mt76.dev, 601 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n"); 602 field = RATE_PARAM_AUTO; 603 goto out; 604 } 605 606 phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0); 607 for (i = 0; i <= phy.bw; i++) { 608 phy.sgi |= gi << (i << sta->he_cap.has_he); 609 phy.he_ltf |= he_ltf << (i << sta->he_cap.has_he); 610 } 611 field = RATE_PARAM_FIXED; 612 613 out: 614 vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 615 ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field); 616 if (ret) 617 return -EFAULT; 618 619 return count; 620 } 621 622 static const struct file_operations fops_fixed_rate = { 623 .write = mt7915_sta_fixed_rate_set, 624 .open = simple_open, 625 .owner = THIS_MODULE, 626 .llseek = default_llseek, 627 }; 628 629 static int 630 mt7915_queues_show(struct seq_file *s, void *data) 631 { 632 struct ieee80211_sta *sta = s->private; 633 634 mt7915_sta_hw_queue_read(s, sta); 635 636 return 0; 637 } 638 639 DEFINE_SHOW_ATTRIBUTE(mt7915_queues); 640 641 void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 642 struct ieee80211_sta *sta, struct dentry *dir) 643 { 644 debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); 645 debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops); 646 } 647 648 #endif 649