Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /* Copyright (C) 2020 MediaTek Inc. */
0003 
0004 #include <linux/relay.h>
0005 #include "mt7915.h"
0006 #include "eeprom.h"
0007 #include "mcu.h"
0008 #include "mac.h"
0009 
0010 #define FW_BIN_LOG_MAGIC    0x44e98caf
0011 
0012 /** global debugfs **/
0013 
0014 struct hw_queue_map {
0015     const char *name;
0016     u8 index;
0017     u8 pid;
0018     u8 qid;
0019 };
0020 
0021 static int
0022 mt7915_implicit_txbf_set(void *data, u64 val)
0023 {
0024     struct mt7915_dev *dev = data;
0025 
0026     if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
0027         return -EBUSY;
0028 
0029     dev->ibf = !!val;
0030 
0031     return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
0032 }
0033 
0034 static int
0035 mt7915_implicit_txbf_get(void *data, u64 *val)
0036 {
0037     struct mt7915_dev *dev = data;
0038 
0039     *val = dev->ibf;
0040 
0041     return 0;
0042 }
0043 
0044 DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
0045              mt7915_implicit_txbf_set, "%lld\n");
0046 
0047 /* test knob of system error recovery */
0048 static ssize_t
0049 mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
0050           size_t count, loff_t *ppos)
0051 {
0052     struct mt7915_phy *phy = file->private_data;
0053     struct mt7915_dev *dev = phy->dev;
0054     bool ext_phy = phy != &dev->phy;
0055     char buf[16];
0056     int ret = 0;
0057     u16 val;
0058 
0059     if (count >= sizeof(buf))
0060         return -EINVAL;
0061 
0062     if (copy_from_user(buf, user_buf, count))
0063         return -EFAULT;
0064 
0065     if (count && buf[count - 1] == '\n')
0066         buf[count - 1] = '\0';
0067     else
0068         buf[count] = '\0';
0069 
0070     if (kstrtou16(buf, 0, &val))
0071         return -EINVAL;
0072 
0073     switch (val) {
0074     case SER_QUERY:
0075         /* grab firmware SER stats */
0076         ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy);
0077         break;
0078     case SER_SET_RECOVER_L1:
0079     case SER_SET_RECOVER_L2:
0080     case SER_SET_RECOVER_L3_RX_ABORT:
0081     case SER_SET_RECOVER_L3_TX_ABORT:
0082     case SER_SET_RECOVER_L3_TX_DISABLE:
0083     case SER_SET_RECOVER_L3_BF:
0084         ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy);
0085         if (ret)
0086             return ret;
0087 
0088         ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy);
0089         break;
0090     default:
0091         break;
0092     }
0093 
0094     return ret ? ret : count;
0095 }
0096 
0097 static ssize_t
0098 mt7915_fw_ser_get(struct file *file, char __user *user_buf,
0099           size_t count, loff_t *ppos)
0100 {
0101     struct mt7915_phy *phy = file->private_data;
0102     struct mt7915_dev *dev = phy->dev;
0103     char *buff;
0104     int desc = 0;
0105     ssize_t ret;
0106     static const size_t bufsz = 400;
0107 
0108     buff = kmalloc(bufsz, GFP_KERNEL);
0109     if (!buff)
0110         return -ENOMEM;
0111 
0112     desc += scnprintf(buff + desc, bufsz - desc,
0113               "::E  R , SER_STATUS        = 0x%08x\n",
0114               mt76_rr(dev, MT_SWDEF_SER_STATS));
0115     desc += scnprintf(buff + desc, bufsz - desc,
0116               "::E  R , SER_PLE_ERR       = 0x%08x\n",
0117               mt76_rr(dev, MT_SWDEF_PLE_STATS));
0118     desc += scnprintf(buff + desc, bufsz - desc,
0119               "::E  R , SER_PLE_ERR_1     = 0x%08x\n",
0120               mt76_rr(dev, MT_SWDEF_PLE1_STATS));
0121     desc += scnprintf(buff + desc, bufsz - desc,
0122               "::E  R , SER_PLE_ERR_AMSDU = 0x%08x\n",
0123               mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
0124     desc += scnprintf(buff + desc, bufsz - desc,
0125               "::E  R , SER_PSE_ERR       = 0x%08x\n",
0126               mt76_rr(dev, MT_SWDEF_PSE_STATS));
0127     desc += scnprintf(buff + desc, bufsz - desc,
0128               "::E  R , SER_PSE_ERR_1     = 0x%08x\n",
0129               mt76_rr(dev, MT_SWDEF_PSE1_STATS));
0130     desc += scnprintf(buff + desc, bufsz - desc,
0131               "::E  R , SER_LMAC_WISR6_B0 = 0x%08x\n",
0132               mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
0133     desc += scnprintf(buff + desc, bufsz - desc,
0134               "::E  R , SER_LMAC_WISR6_B1 = 0x%08x\n",
0135               mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
0136     desc += scnprintf(buff + desc, bufsz - desc,
0137               "::E  R , SER_LMAC_WISR7_B0 = 0x%08x\n",
0138               mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
0139     desc += scnprintf(buff + desc, bufsz - desc,
0140               "::E  R , SER_LMAC_WISR7_B1 = 0x%08x\n",
0141               mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
0142 
0143     ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
0144     kfree(buff);
0145     return ret;
0146 }
0147 
0148 static const struct file_operations mt7915_fw_ser_ops = {
0149     .write = mt7915_fw_ser_set,
0150     .read = mt7915_fw_ser_get,
0151     .open = simple_open,
0152     .llseek = default_llseek,
0153 };
0154 
0155 static int
0156 mt7915_radar_trigger(void *data, u64 val)
0157 {
0158     struct mt7915_dev *dev = data;
0159 
0160     if (val > MT_RX_SEL2)
0161         return -EINVAL;
0162 
0163     return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE,
0164                        val, 0, 0);
0165 }
0166 
0167 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
0168              mt7915_radar_trigger, "%lld\n");
0169 
0170 static int
0171 mt7915_muru_debug_set(void *data, u64 val)
0172 {
0173     struct mt7915_dev *dev = data;
0174 
0175     dev->muru_debug = val;
0176     mt7915_mcu_muru_debug_set(dev, dev->muru_debug);
0177 
0178     return 0;
0179 }
0180 
0181 static int
0182 mt7915_muru_debug_get(void *data, u64 *val)
0183 {
0184     struct mt7915_dev *dev = data;
0185 
0186     *val = dev->muru_debug;
0187 
0188     return 0;
0189 }
0190 
0191 DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get,
0192              mt7915_muru_debug_set, "%lld\n");
0193 
0194 static int mt7915_muru_stats_show(struct seq_file *file, void *data)
0195 {
0196     struct mt7915_phy *phy = file->private;
0197     struct mt7915_dev *dev = phy->dev;
0198     struct mt7915_mcu_muru_stats mu_stats = {};
0199     static const char * const dl_non_he_type[] = {
0200         "CCK", "OFDM", "HT MIX", "HT GF",
0201         "VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
0202     };
0203     static const char * const dl_he_type[] = {
0204         "HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU",
0205         "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU",
0206         "HE >16RU"
0207     };
0208     static const char * const ul_he_type[] = {
0209         "HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU",
0210         "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU"
0211     };
0212     int ret, i;
0213     u64 total_ppdu_cnt, sub_total_cnt;
0214 
0215     if (!dev->muru_debug) {
0216         seq_puts(file, "Please enable muru_debug first.\n");
0217         return 0;
0218     }
0219 
0220     mutex_lock(&dev->mt76.mutex);
0221 
0222     ret = mt7915_mcu_muru_debug_get(phy, &mu_stats);
0223     if (ret)
0224         goto exit;
0225 
0226     /* Non-HE Downlink*/
0227     seq_puts(file, "[Non-HE]\nDownlink\nData Type:  ");
0228 
0229     for (i = 0; i < 5; i++)
0230         seq_printf(file, "%8s | ", dl_non_he_type[i]);
0231 
0232 #define __dl_u32(s)     le32_to_cpu(mu_stats.dl.s)
0233     seq_puts(file, "\nTotal Count:");
0234     seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",
0235            __dl_u32(cck_cnt),
0236            __dl_u32(ofdm_cnt),
0237            __dl_u32(htmix_cnt),
0238            __dl_u32(htgf_cnt),
0239            __dl_u32(vht_su_cnt));
0240 
0241     seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
0242 
0243     for (i = 5; i < 8; i++)
0244         seq_printf(file, "%8s | ", dl_non_he_type[i]);
0245 
0246     seq_puts(file, "\nTotal Count:");
0247     seq_printf(file, "%8u | %8u | %8u | ",
0248            __dl_u32(vht_2mu_cnt),
0249            __dl_u32(vht_3mu_cnt),
0250            __dl_u32(vht_4mu_cnt));
0251 
0252     sub_total_cnt = __dl_u32(vht_2mu_cnt) +
0253         __dl_u32(vht_3mu_cnt) +
0254         __dl_u32(vht_4mu_cnt);
0255 
0256     seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
0257            sub_total_cnt);
0258 
0259     total_ppdu_cnt = sub_total_cnt +
0260         __dl_u32(cck_cnt) +
0261         __dl_u32(ofdm_cnt) +
0262         __dl_u32(htmix_cnt) +
0263         __dl_u32(htgf_cnt) +
0264         __dl_u32(vht_su_cnt);
0265 
0266     seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
0267 
0268     /* HE Downlink */
0269     seq_puts(file, "\n\n[HE]\nDownlink\nData Type:  ");
0270 
0271     for (i = 0; i < 2; i++)
0272         seq_printf(file, "%8s | ", dl_he_type[i]);
0273 
0274     seq_puts(file, "\nTotal Count:");
0275     seq_printf(file, "%8u | %8u | ",
0276            __dl_u32(he_su_cnt),
0277            __dl_u32(he_ext_su_cnt));
0278 
0279     seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
0280 
0281     for (i = 2; i < 5; i++)
0282         seq_printf(file, "%8s | ", dl_he_type[i]);
0283 
0284     seq_puts(file, "\nTotal Count:");
0285     seq_printf(file, "%8u | %8u | %8u | ",
0286            __dl_u32(he_2mu_cnt),
0287            __dl_u32(he_3mu_cnt),
0288            __dl_u32(he_4mu_cnt));
0289 
0290     seq_puts(file, "\nDownlink OFDMA\nData Type:  ");
0291 
0292     for (i = 5; i < 11; i++)
0293         seq_printf(file, "%8s | ", dl_he_type[i]);
0294 
0295     seq_puts(file, "\nTotal Count:");
0296     seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",
0297            __dl_u32(he_2ru_cnt),
0298            __dl_u32(he_3ru_cnt),
0299            __dl_u32(he_4ru_cnt),
0300            __dl_u32(he_5to8ru_cnt),
0301            __dl_u32(he_9to16ru_cnt),
0302            __dl_u32(he_gtr16ru_cnt));
0303 
0304     sub_total_cnt = __dl_u32(he_2mu_cnt) +
0305         __dl_u32(he_3mu_cnt) +
0306         __dl_u32(he_4mu_cnt);
0307     total_ppdu_cnt = sub_total_cnt;
0308 
0309     seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",
0310            sub_total_cnt);
0311 
0312     sub_total_cnt = __dl_u32(he_2ru_cnt) +
0313         __dl_u32(he_3ru_cnt) +
0314         __dl_u32(he_4ru_cnt) +
0315         __dl_u32(he_5to8ru_cnt) +
0316         __dl_u32(he_9to16ru_cnt) +
0317         __dl_u32(he_gtr16ru_cnt);
0318     total_ppdu_cnt += sub_total_cnt;
0319 
0320     seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",
0321            sub_total_cnt);
0322 
0323     total_ppdu_cnt += __dl_u32(he_su_cnt) +
0324         __dl_u32(he_ext_su_cnt);
0325 
0326     seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
0327 #undef __dl_u32
0328 
0329     /* HE Uplink */
0330     seq_puts(file, "\n\nUplink");
0331     seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type:  ");
0332 
0333     for (i = 0; i < 3; i++)
0334         seq_printf(file, "%8s | ", ul_he_type[i]);
0335 
0336 #define __ul_u32(s)     le32_to_cpu(mu_stats.ul.s)
0337     seq_puts(file, "\nTotal Count:");
0338     seq_printf(file, "%8u | %8u | %8u | ",
0339            __ul_u32(hetrig_2mu_cnt),
0340            __ul_u32(hetrig_3mu_cnt),
0341            __ul_u32(hetrig_4mu_cnt));
0342 
0343     seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type:  ");
0344 
0345     for (i = 3; i < 10; i++)
0346         seq_printf(file, "%8s | ", ul_he_type[i]);
0347 
0348     seq_puts(file, "\nTotal Count:");
0349     seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u |  %7u | ",
0350            __ul_u32(hetrig_su_cnt),
0351            __ul_u32(hetrig_2ru_cnt),
0352            __ul_u32(hetrig_3ru_cnt),
0353            __ul_u32(hetrig_4ru_cnt),
0354            __ul_u32(hetrig_5to8ru_cnt),
0355            __ul_u32(hetrig_9to16ru_cnt),
0356            __ul_u32(hetrig_gtr16ru_cnt));
0357 
0358     sub_total_cnt = __ul_u32(hetrig_2mu_cnt) +
0359         __ul_u32(hetrig_3mu_cnt) +
0360         __ul_u32(hetrig_4mu_cnt);
0361     total_ppdu_cnt = sub_total_cnt;
0362 
0363     seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
0364            sub_total_cnt);
0365 
0366     sub_total_cnt = __ul_u32(hetrig_2ru_cnt) +
0367         __ul_u32(hetrig_3ru_cnt) +
0368         __ul_u32(hetrig_4ru_cnt) +
0369         __ul_u32(hetrig_5to8ru_cnt) +
0370         __ul_u32(hetrig_9to16ru_cnt) +
0371         __ul_u32(hetrig_gtr16ru_cnt);
0372     total_ppdu_cnt += sub_total_cnt;
0373 
0374     seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",
0375            sub_total_cnt);
0376 
0377     total_ppdu_cnt += __ul_u32(hetrig_su_cnt);
0378 
0379     seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
0380 #undef __ul_u32
0381 
0382 exit:
0383     mutex_unlock(&dev->mt76.mutex);
0384 
0385     return ret;
0386 }
0387 DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);
0388 
0389 static int
0390 mt7915_rdd_monitor(struct seq_file *s, void *data)
0391 {
0392     struct mt7915_dev *dev = dev_get_drvdata(s->private);
0393     struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;
0394     const char *bw;
0395     int ret = 0;
0396 
0397     mutex_lock(&dev->mt76.mutex);
0398 
0399     if (!cfg80211_chandef_valid(chandef)) {
0400         ret = -EINVAL;
0401         goto out;
0402     }
0403 
0404     if (!dev->rdd2_phy) {
0405         seq_puts(s, "not running\n");
0406         goto out;
0407     }
0408 
0409     switch (chandef->width) {
0410     case NL80211_CHAN_WIDTH_40:
0411         bw = "40";
0412         break;
0413     case NL80211_CHAN_WIDTH_80:
0414         bw = "80";
0415         break;
0416     case NL80211_CHAN_WIDTH_160:
0417         bw = "160";
0418         break;
0419     case NL80211_CHAN_WIDTH_80P80:
0420         bw = "80P80";
0421         break;
0422     default:
0423         bw = "20";
0424         break;
0425     }
0426 
0427     seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n",
0428            chandef->chan->hw_value, chandef->chan->center_freq,
0429            bw, chandef->center_freq1);
0430 out:
0431     mutex_unlock(&dev->mt76.mutex);
0432 
0433     return ret;
0434 }
0435 
0436 static int
0437 mt7915_fw_debug_wm_set(void *data, u64 val)
0438 {
0439     struct mt7915_dev *dev = data;
0440     enum {
0441         DEBUG_TXCMD = 62,
0442         DEBUG_CMD_RPT_TX,
0443         DEBUG_CMD_RPT_TRIG,
0444         DEBUG_SPL,
0445         DEBUG_RPT_RX,
0446     } debug;
0447     bool tx, rx, en;
0448     int ret;
0449 
0450     dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
0451 
0452     if (dev->fw.debug_bin)
0453         val = 16;
0454     else
0455         val = dev->fw.debug_wm;
0456 
0457     tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1));
0458     rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2));
0459     en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0));
0460 
0461     ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val);
0462     if (ret)
0463         goto out;
0464 
0465     for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
0466         if (debug == DEBUG_RPT_RX)
0467             val = en && rx;
0468         else
0469             val = en && tx;
0470 
0471         ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val);
0472         if (ret)
0473             goto out;
0474     }
0475 
0476     /* WM CPU info record control */
0477     mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
0478     mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw.debug_wm);
0479     mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
0480     mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
0481 
0482 out:
0483     if (ret)
0484         dev->fw.debug_wm = 0;
0485 
0486     return ret;
0487 }
0488 
0489 static int
0490 mt7915_fw_debug_wm_get(void *data, u64 *val)
0491 {
0492     struct mt7915_dev *dev = data;
0493 
0494     *val = dev->fw.debug_wm;
0495 
0496     return 0;
0497 }
0498 
0499 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,
0500              mt7915_fw_debug_wm_set, "%lld\n");
0501 
0502 static int
0503 mt7915_fw_debug_wa_set(void *data, u64 val)
0504 {
0505     struct mt7915_dev *dev = data;
0506     int ret;
0507 
0508     dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;
0509 
0510     ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa);
0511     if (ret)
0512         goto out;
0513 
0514     ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
0515                 MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0);
0516 out:
0517     if (ret)
0518         dev->fw.debug_wa = 0;
0519 
0520     return ret;
0521 }
0522 
0523 static int
0524 mt7915_fw_debug_wa_get(void *data, u64 *val)
0525 {
0526     struct mt7915_dev *dev = data;
0527 
0528     *val = dev->fw.debug_wa;
0529 
0530     return 0;
0531 }
0532 
0533 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
0534              mt7915_fw_debug_wa_set, "%lld\n");
0535 
0536 static struct dentry *
0537 create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
0538            struct rchan_buf *buf, int *is_global)
0539 {
0540     struct dentry *f;
0541 
0542     f = debugfs_create_file("fwlog_data", mode, parent, buf,
0543                 &relay_file_operations);
0544     if (IS_ERR(f))
0545         return NULL;
0546 
0547     *is_global = 1;
0548 
0549     return f;
0550 }
0551 
0552 static int
0553 remove_buf_file_cb(struct dentry *f)
0554 {
0555     debugfs_remove(f);
0556 
0557     return 0;
0558 }
0559 
0560 static int
0561 mt7915_fw_debug_bin_set(void *data, u64 val)
0562 {
0563     static struct rchan_callbacks relay_cb = {
0564         .create_buf_file = create_buf_file_cb,
0565         .remove_buf_file = remove_buf_file_cb,
0566     };
0567     struct mt7915_dev *dev = data;
0568 
0569     if (!dev->relay_fwlog)
0570         dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,
0571                         1500, 512, &relay_cb, NULL);
0572     if (!dev->relay_fwlog)
0573         return -ENOMEM;
0574 
0575     dev->fw.debug_bin = val;
0576 
0577     relay_reset(dev->relay_fwlog);
0578 
0579     return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm);
0580 }
0581 
0582 static int
0583 mt7915_fw_debug_bin_get(void *data, u64 *val)
0584 {
0585     struct mt7915_dev *dev = data;
0586 
0587     *val = dev->fw.debug_bin;
0588 
0589     return 0;
0590 }
0591 
0592 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,
0593              mt7915_fw_debug_bin_set, "%lld\n");
0594 
0595 static int
0596 mt7915_fw_util_wm_show(struct seq_file *file, void *data)
0597 {
0598     struct mt7915_dev *dev = file->private;
0599 
0600     seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC));
0601     seq_printf(file, "Exception state: 0x%x\n",
0602            is_mt7915(&dev->mt76) ?
0603            (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(15, 8)) :
0604            (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(7, 0)));
0605 
0606     if (dev->fw.debug_wm) {
0607         seq_printf(file, "Busy: %u%%  Peak busy: %u%%\n",
0608                mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),
0609                mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));
0610         seq_printf(file, "Idle count: %u  Peak idle count: %u\n",
0611                mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),
0612                mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));
0613     }
0614 
0615     return 0;
0616 }
0617 
0618 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);
0619 
0620 static int
0621 mt7915_fw_util_wa_show(struct seq_file *file, void *data)
0622 {
0623     struct mt7915_dev *dev = file->private;
0624 
0625     seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC));
0626 
0627     if (dev->fw.debug_wa)
0628         return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),
0629                      MCU_WA_PARAM_CPU_UTIL, 0, 0);
0630 
0631     return 0;
0632 }
0633 
0634 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);
0635 
0636 static void
0637 mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
0638                struct seq_file *file)
0639 {
0640     struct mt7915_dev *dev = phy->dev;
0641     bool ext_phy = phy != &dev->phy;
0642     int bound[15], range[4], i, n;
0643 
0644     /* Tx ampdu stat */
0645     for (i = 0; i < ARRAY_SIZE(range); i++)
0646         range[i] = mt76_rr(dev, MT_MIB_ARNG(phy->band_idx, i));
0647 
0648     for (i = 0; i < ARRAY_SIZE(bound); i++)
0649         bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
0650 
0651     seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, phy->band_idx);
0652 
0653     seq_printf(file, "Length: %8d | ", bound[0]);
0654     for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
0655         seq_printf(file, "%3d -%3d | ",
0656                bound[i] + 1, bound[i + 1]);
0657 
0658     seq_puts(file, "\nCount:  ");
0659     n = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
0660     for (i = 0; i < ARRAY_SIZE(bound); i++)
0661         seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]);
0662     seq_puts(file, "\n");
0663 
0664     seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
0665 }
0666 
0667 static void
0668 mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
0669 {
0670     static const char * const bw[] = {
0671         "BW20", "BW40", "BW80", "BW160"
0672     };
0673     struct mib_stats *mib = &phy->mib;
0674 
0675     /* Tx Beamformer monitor */
0676     seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
0677 
0678     seq_printf(s, "iBF: %d, eBF: %d\n",
0679            mib->tx_bf_ibf_ppdu_cnt,
0680            mib->tx_bf_ebf_ppdu_cnt);
0681 
0682     /* Tx Beamformer Rx feedback monitor */
0683     seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
0684 
0685     seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
0686            mib->tx_bf_rx_fb_all_cnt,
0687            mib->tx_bf_rx_fb_he_cnt,
0688            mib->tx_bf_rx_fb_vht_cnt,
0689            mib->tx_bf_rx_fb_ht_cnt);
0690 
0691     seq_printf(s, "%s, NC: %d, NR: %d\n",
0692            bw[mib->tx_bf_rx_fb_bw],
0693            mib->tx_bf_rx_fb_nc_cnt,
0694            mib->tx_bf_rx_fb_nr_cnt);
0695 
0696     /* Tx Beamformee Rx NDPA & Tx feedback report */
0697     seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",
0698            mib->tx_bf_fb_cpl_cnt);
0699     seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",
0700            mib->tx_bf_fb_trig_cnt);
0701 
0702     /* Tx SU & MU counters */
0703     seq_printf(s, "Tx multi-user Beamforming counts: %d\n",
0704            mib->tx_bf_cnt);
0705     seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
0706     seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",
0707            mib->tx_mu_acked_mpdu_cnt);
0708     seq_printf(s, "Tx single-user successful MPDU counts: %d\n",
0709            mib->tx_su_acked_mpdu_cnt);
0710 
0711     seq_puts(s, "\n");
0712 }
0713 
0714 static int
0715 mt7915_tx_stats_show(struct seq_file *file, void *data)
0716 {
0717     struct mt7915_phy *phy = file->private;
0718     struct mt7915_dev *dev = phy->dev;
0719     struct mib_stats *mib = &phy->mib;
0720     int i;
0721 
0722     mutex_lock(&dev->mt76.mutex);
0723 
0724     mt7915_ampdu_stat_read_phy(phy, file);
0725     mt7915_mac_update_stats(phy);
0726     mt7915_txbf_stat_read_phy(phy, file);
0727 
0728     /* Tx amsdu info */
0729     seq_puts(file, "Tx MSDU statistics:\n");
0730     for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
0731         seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
0732                i + 1, mib->tx_amsdu[i]);
0733         if (mib->tx_amsdu_cnt)
0734             seq_printf(file, "(%3d%%)\n",
0735                    mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
0736         else
0737             seq_puts(file, "\n");
0738     }
0739 
0740     mutex_unlock(&dev->mt76.mutex);
0741 
0742     return 0;
0743 }
0744 
0745 DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
0746 
0747 static void
0748 mt7915_hw_queue_read(struct seq_file *s, u32 size,
0749              const struct hw_queue_map *map)
0750 {
0751     struct mt7915_phy *phy = s->private;
0752     struct mt7915_dev *dev = phy->dev;
0753     u32 i, val;
0754 
0755     val = mt76_rr(dev, MT_FL_Q_EMPTY);
0756     for (i = 0; i < size; i++) {
0757         u32 ctrl, head, tail, queued;
0758 
0759         if (val & BIT(map[i].index))
0760             continue;
0761 
0762         ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24);
0763         mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
0764 
0765         head = mt76_get_field(dev, MT_FL_Q2_CTRL,
0766                       GENMASK(11, 0));
0767         tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
0768                       GENMASK(27, 16));
0769         queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
0770                     GENMASK(11, 0));
0771 
0772         seq_printf(s, "\t%s: ", map[i].name);
0773         seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
0774                queued, head, tail);
0775     }
0776 }
0777 
0778 static void
0779 mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
0780 {
0781     struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
0782     struct mt7915_dev *dev = msta->vif->phy->dev;
0783     struct seq_file *s = data;
0784     u8 ac;
0785 
0786     for (ac = 0; ac < 4; ac++) {
0787         u32 qlen, ctrl, val;
0788         u32 idx = msta->wcid.idx >> 5;
0789         u8 offs = msta->wcid.idx & GENMASK(4, 0);
0790 
0791         ctrl = BIT(31) | BIT(11) | (ac << 24);
0792         val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
0793 
0794         if (val & BIT(offs))
0795             continue;
0796 
0797         mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
0798         qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
0799                       GENMASK(11, 0));
0800         seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
0801                sta->addr, msta->wcid.idx,
0802                msta->vif->mt76.wmm_idx, ac, qlen);
0803     }
0804 }
0805 
0806 static int
0807 mt7915_hw_queues_show(struct seq_file *file, void *data)
0808 {
0809     struct mt7915_phy *phy = file->private;
0810     struct mt7915_dev *dev = phy->dev;
0811     static const struct hw_queue_map ple_queue_map[] = {
0812         { "CPU_Q0",  0,  1, MT_CTX0       },
0813         { "CPU_Q1",  1,  1, MT_CTX0 + 1       },
0814         { "CPU_Q2",  2,  1, MT_CTX0 + 2       },
0815         { "CPU_Q3",  3,  1, MT_CTX0 + 3       },
0816         { "ALTX_Q0", 8,  2, MT_LMAC_ALTX0     },
0817         { "BMC_Q0",  9,  2, MT_LMAC_BMC0      },
0818         { "BCN_Q0",  10, 2, MT_LMAC_BCN0      },
0819         { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0     },
0820         { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
0821         { "BMC_Q1",  13, 2, MT_LMAC_BMC0  + 4 },
0822         { "BCN_Q1",  14, 2, MT_LMAC_BCN0  + 4 },
0823         { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
0824     };
0825     static const struct hw_queue_map pse_queue_map[] = {
0826         { "CPU Q0",  0,  1, MT_CTX0       },
0827         { "CPU Q1",  1,  1, MT_CTX0 + 1       },
0828         { "CPU Q2",  2,  1, MT_CTX0 + 2       },
0829         { "CPU Q3",  3,  1, MT_CTX0 + 3       },
0830         { "HIF_Q0",  8,  0, MT_HIF0       },
0831         { "HIF_Q1",  9,  0, MT_HIF0 + 1       },
0832         { "HIF_Q2",  10, 0, MT_HIF0 + 2       },
0833         { "HIF_Q3",  11, 0, MT_HIF0 + 3       },
0834         { "HIF_Q4",  12, 0, MT_HIF0 + 4       },
0835         { "HIF_Q5",  13, 0, MT_HIF0 + 5       },
0836         { "LMAC_Q",  16, 2, 0             },
0837         { "MDP_TXQ", 17, 2, 1             },
0838         { "MDP_RXQ", 18, 2, 2             },
0839         { "SEC_TXQ", 19, 2, 3             },
0840         { "SEC_RXQ", 20, 2, 4             },
0841     };
0842     u32 val, head, tail;
0843 
0844     /* ple queue */
0845     val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
0846     head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
0847     tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
0848     seq_puts(file, "PLE page info:\n");
0849     seq_printf(file,
0850            "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
0851            val, head, tail);
0852 
0853     val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
0854     head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
0855     tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
0856     seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
0857            val, head, tail);
0858 
0859     seq_puts(file, "PLE non-empty queue info:\n");
0860     mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),
0861                  &ple_queue_map[0]);
0862 
0863     /* iterate per-sta ple queue */
0864     ieee80211_iterate_stations_atomic(phy->mt76->hw,
0865                       mt7915_sta_hw_queue_read, file);
0866     /* pse queue */
0867     seq_puts(file, "PSE non-empty queue info:\n");
0868     mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),
0869                  &pse_queue_map[0]);
0870 
0871     return 0;
0872 }
0873 
0874 DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
0875 
0876 static int
0877 mt7915_xmit_queues_show(struct seq_file *file, void *data)
0878 {
0879     struct mt7915_phy *phy = file->private;
0880     struct mt7915_dev *dev = phy->dev;
0881     struct {
0882         struct mt76_queue *q;
0883         char *queue;
0884     } queue_map[] = {
0885         { phy->mt76->q_tx[MT_TXQ_BE],    "   MAIN"  },
0886         { dev->mt76.q_mcu[MT_MCUQ_WM],   "  MCUWM"  },
0887         { dev->mt76.q_mcu[MT_MCUQ_WA],   "  MCUWA"  },
0888         { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
0889     };
0890     int i;
0891 
0892     seq_puts(file, "     queue | hw-queued |      head |      tail |\n");
0893     for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
0894         struct mt76_queue *q = queue_map[i].q;
0895 
0896         if (!q)
0897             continue;
0898 
0899         seq_printf(file, "   %s | %9d | %9d | %9d |\n",
0900                queue_map[i].queue, q->queued, q->head,
0901                q->tail);
0902     }
0903 
0904     return 0;
0905 }
0906 
0907 DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
0908 
0909 static int
0910 mt7915_rate_txpower_show(struct seq_file *file, void *data)
0911 {
0912     static const char * const sku_group_name[] = {
0913         "CCK", "OFDM", "HT20", "HT40",
0914         "VHT20", "VHT40", "VHT80", "VHT160",
0915         "RU26", "RU52", "RU106", "RU242/SU20",
0916         "RU484/SU40", "RU996/SU80", "RU2x996/SU160"
0917     };
0918     struct mt7915_phy *phy = file->private;
0919     s8 txpower[MT7915_SKU_RATE_NUM], *buf;
0920     int i;
0921 
0922     seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy);
0923     mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower));
0924     for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
0925         u8 mcs_num = mt7915_sku_group_len[i];
0926 
0927         if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160)
0928             mcs_num = 10;
0929 
0930         mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num);
0931         buf += mt7915_sku_group_len[i];
0932     }
0933 
0934     return 0;
0935 }
0936 
0937 DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower);
0938 
0939 static int
0940 mt7915_twt_stats(struct seq_file *s, void *data)
0941 {
0942     struct mt7915_dev *dev = dev_get_drvdata(s->private);
0943     struct mt7915_twt_flow *iter;
0944 
0945     rcu_read_lock();
0946 
0947     seq_puts(s, "     wcid |       id |    flags |      exp | mantissa");
0948     seq_puts(s, " | duration |            tsf |\n");
0949     list_for_each_entry_rcu(iter, &dev->twt_list, list)
0950         seq_printf(s,
0951             "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
0952             iter->wcid, iter->id,
0953             iter->sched ? 's' : 'u',
0954             iter->protection ? 'p' : '-',
0955             iter->trigger ? 't' : '-',
0956             iter->flowtype ? '-' : 'a',
0957             iter->exp, iter->mantissa,
0958             iter->duration, iter->tsf);
0959 
0960     rcu_read_unlock();
0961 
0962     return 0;
0963 }
0964 
0965 /* The index of RF registers use the generic regidx, combined with two parts:
0966  * WF selection [31:28] and offset [27:0].
0967  */
0968 static int
0969 mt7915_rf_regval_get(void *data, u64 *val)
0970 {
0971     struct mt7915_dev *dev = data;
0972     u32 regval;
0973     int ret;
0974 
0975     ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &regval, false);
0976     if (ret)
0977         return ret;
0978 
0979     *val = regval;
0980 
0981     return 0;
0982 }
0983 
0984 static int
0985 mt7915_rf_regval_set(void *data, u64 val)
0986 {
0987     struct mt7915_dev *dev = data;
0988     u32 val32 = val;
0989 
0990     return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true);
0991 }
0992 
0993 DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get,
0994              mt7915_rf_regval_set, "0x%08llx\n");
0995 
0996 int mt7915_init_debugfs(struct mt7915_phy *phy)
0997 {
0998     struct mt7915_dev *dev = phy->dev;
0999     bool ext_phy = phy != &dev->phy;
1000     struct dentry *dir;
1001 
1002     dir = mt76_register_debugfs_fops(phy->mt76, NULL);
1003     if (!dir)
1004         return -ENOMEM;
1005     debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);
1006     debugfs_create_file("muru_stats", 0400, dir, phy,
1007                 &mt7915_muru_stats_fops);
1008     debugfs_create_file("hw-queues", 0400, dir, phy,
1009                 &mt7915_hw_queues_fops);
1010     debugfs_create_file("xmit-queues", 0400, dir, phy,
1011                 &mt7915_xmit_queues_fops);
1012     debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
1013     debugfs_create_file("fw_ser", 0600, dir, phy, &mt7915_fw_ser_ops);
1014     debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
1015     debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
1016     debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
1017     debugfs_create_file("fw_util_wm", 0400, dir, dev,
1018                 &mt7915_fw_util_wm_fops);
1019     debugfs_create_file("fw_util_wa", 0400, dir, dev,
1020                 &mt7915_fw_util_wa_fops);
1021     debugfs_create_file("implicit_txbf", 0600, dir, dev,
1022                 &fops_implicit_txbf);
1023     debugfs_create_file("txpower_sku", 0400, dir, phy,
1024                 &mt7915_rate_txpower_fops);
1025     debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
1026                     mt7915_twt_stats);
1027     debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
1028 
1029     if (!dev->dbdc_support || phy->band_idx) {
1030         debugfs_create_u32("dfs_hw_pattern", 0400, dir,
1031                    &dev->hw_pattern);
1032         debugfs_create_file("radar_trigger", 0200, dir, dev,
1033                     &fops_radar_trigger);
1034         debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
1035                         mt7915_rdd_monitor);
1036     }
1037 
1038     if (!ext_phy)
1039         dev->debugfs_dir = dir;
1040 
1041     return 0;
1042 }
1043 
1044 static void
1045 mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,
1046              const void *data, int len)
1047 {
1048     static DEFINE_SPINLOCK(lock);
1049     unsigned long flags;
1050     void *dest;
1051 
1052     spin_lock_irqsave(&lock, flags);
1053     dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);
1054     if (dest) {
1055         *(u32 *)dest = hdrlen + len;
1056         dest += 4;
1057 
1058         if (hdrlen) {
1059             memcpy(dest, hdr, hdrlen);
1060             dest += hdrlen;
1061         }
1062 
1063         memcpy(dest, data, len);
1064         relay_flush(dev->relay_fwlog);
1065     }
1066     spin_unlock_irqrestore(&lock, flags);
1067 }
1068 
1069 void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)
1070 {
1071     struct {
1072         __le32 magic;
1073         __le32 timestamp;
1074         __le16 msg_type;
1075         __le16 len;
1076     } hdr = {
1077         .magic = cpu_to_le32(FW_BIN_LOG_MAGIC),
1078         .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
1079     };
1080 
1081     if (!dev->relay_fwlog)
1082         return;
1083 
1084     hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));
1085     hdr.len = *(__le16 *)data;
1086     mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len);
1087 }
1088 
1089 bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)
1090 {
1091     if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)
1092         return false;
1093 
1094     if (dev->relay_fwlog)
1095         mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len);
1096 
1097     return true;
1098 }
1099 
1100 #ifdef CONFIG_MAC80211_DEBUGFS
1101 /** per-station debugfs **/
1102 
1103 static ssize_t mt7915_sta_fixed_rate_set(struct file *file,
1104                      const char __user *user_buf,
1105                      size_t count, loff_t *ppos)
1106 {
1107     struct ieee80211_sta *sta = file->private_data;
1108     struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1109     struct mt7915_dev *dev = msta->vif->phy->dev;
1110     struct ieee80211_vif *vif;
1111     struct sta_phy phy = {};
1112     char buf[100];
1113     int ret;
1114     u32 field;
1115     u8 i, gi, he_ltf;
1116 
1117     if (count >= sizeof(buf))
1118         return -EINVAL;
1119 
1120     if (copy_from_user(buf, user_buf, count))
1121         return -EFAULT;
1122 
1123     if (count && buf[count - 1] == '\n')
1124         buf[count - 1] = '\0';
1125     else
1126         buf[count] = '\0';
1127 
1128     /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
1129      * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
1130      * nss - vht: 1~4, he: 1~4, others: ignore
1131      * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
1132      * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
1133      * ldpc - off: 0, on: 1
1134      * stbc - off: 0, on: 1
1135      * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
1136      */
1137     if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",
1138            &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,
1139            &phy.ldpc, &phy.stbc, &he_ltf) != 8) {
1140         dev_warn(dev->mt76.dev,
1141              "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");
1142         field = RATE_PARAM_AUTO;
1143         goto out;
1144     }
1145 
1146     phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);
1147     for (i = 0; i <= phy.bw; i++) {
1148         phy.sgi |= gi << (i << sta->deflink.he_cap.has_he);
1149         phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he);
1150     }
1151     field = RATE_PARAM_FIXED;
1152 
1153 out:
1154     vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
1155     ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
1156     if (ret)
1157         return -EFAULT;
1158 
1159     return count;
1160 }
1161 
1162 static const struct file_operations fops_fixed_rate = {
1163     .write = mt7915_sta_fixed_rate_set,
1164     .open = simple_open,
1165     .owner = THIS_MODULE,
1166     .llseek = default_llseek,
1167 };
1168 
1169 static int
1170 mt7915_queues_show(struct seq_file *s, void *data)
1171 {
1172     struct ieee80211_sta *sta = s->private;
1173 
1174     mt7915_sta_hw_queue_read(s, sta);
1175 
1176     return 0;
1177 }
1178 
1179 DEFINE_SHOW_ATTRIBUTE(mt7915_queues);
1180 
1181 void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1182                 struct ieee80211_sta *sta, struct dentry *dir)
1183 {
1184     debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
1185     debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
1186 }
1187 
1188 #endif