blob: c04e36f935f05da5221cdfee5fcb45113b2973a3 [file] [log] [blame]
From 3330075935bef71cea064ce4bf0d4453fdc2301a Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Tue, 3 Jan 2023 09:42:07 +0800
Subject: [PATCH 035/223] mtk: mt76: mt7996: support BF/MIMO debug commands
This commit includes the following commands:
1. starec_bf_read
2. txbf_snd_info: start/stop sounding and set sounding period
3. fbkRptInfo
4. fix muru rate
fix the wrong wlan_idx for user3
Align the format of mcu event mt7996_mcu_bf_starec_read with
firmware definition.
Fw gerrit change:
https://gerrit.mediatek.inc/c/neptune/firmware/bora/wifi/core/+/8218143
Change-Id: Id6cbaf16e4e6f63238a495ac9f45744e1dd38e9b
Change-Id: I7ece7399370f2bd22d2564029025baeda27057a5
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt7996/mcu.c | 5 +
mt7996/mcu.h | 4 +
mt7996/mt7996.h | 5 +
mt7996/mtk_debugfs.c | 9 +
mt7996/mtk_mcu.c | 624 +++++++++++++++++++++++++++++++++++++++++++
mt7996/mtk_mcu.h | 342 ++++++++++++++++++++++++
6 files changed, 989 insertions(+)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index 2a647b7b..baf71b0a 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -754,6 +754,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_TESTMODE_CTRL:
mt7996_tm_rf_test_event(dev, skb);
break;
+#endif
+#if defined CONFIG_NL80211_TESTMODE || defined CONFIG_MTK_DEBUG
+ case MCU_UNI_EVENT_BF:
+ mt7996_mcu_rx_bf_event(dev, skb);
+ break;
#endif
default:
break;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
index 3e9364de..8a718513 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -770,8 +770,12 @@ enum {
enum {
BF_SOUNDING_ON = 1,
+ BF_PFMU_TAG_READ = 5,
+ BF_STA_REC_READ = 11,
BF_HW_EN_UPDATE = 17,
BF_MOD_EN_CTRL = 20,
+ BF_FBRPT_DBG_INFO_READ = 23,
+ BF_TXSND_INFO = 24,
};
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index 22d44542..8d986dee 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -847,6 +847,11 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev);
+int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx);
+void mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb);
+int mt7996_mcu_set_muru_fixed_rate_enable(struct mt7996_dev *dev, u8 action, int val);
+int mt7996_mcu_set_muru_fixed_rate_parameter(struct mt7996_dev *dev, u8 action, void *para);
+int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para);
#endif
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
index 13ea6274..51449df4 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
@@ -2996,6 +2996,15 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("sr_stats", 0400, dir, phy, &mt7996_sr_stats_fops);
debugfs_create_file("sr_scene_cond", 0400, dir, phy, &mt7996_sr_scene_cond_fops);
+ debugfs_create_file("muru_fixed_rate_enable", 0600, dir, dev,
+ &fops_muru_fixed_rate_enable);
+ debugfs_create_file("muru_fixed_group_rate", 0600, dir, dev,
+ &fops_muru_fixed_group_rate);
+ debugfs_create_file("bf_txsnd_info", 0600, dir, phy, &fops_bf_txsnd_info);
+ debugfs_create_file("bf_starec_read", 0600, dir, phy, &fops_starec_bf_read);
+ debugfs_create_file("bf_fbk_rpt", 0600, dir, phy, &fops_bf_fbk_rpt);
+ debugfs_create_file("pfmu_tag_read", 0600, dir, phy, &fops_bf_pfmu_tag_read);
+
return 0;
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
index ea4e5bf2..6b2cdad6 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
@@ -280,4 +280,628 @@ int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev)
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(CHIP_CONFIG), &req,
sizeof(req), true);
}
+
+static struct tlv *
+__mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len)
+{
+ struct tlv *ptlv, tlv = {
+ .tag = cpu_to_le16(tag),
+ .len = cpu_to_le16(len),
+ };
+
+ ptlv = skb_put(skb, len);
+ memcpy(ptlv, &tlv, sizeof(tlv));
+
+ return ptlv;
+}
+
+int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx)
+{
+ struct mt7996_dev *dev = phy->dev;
+#define MT7996_MTK_BF_MAX_SIZE sizeof(struct bf_starec_read)
+ struct uni_header hdr;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ int len = sizeof(hdr) + MT7996_MTK_BF_MAX_SIZE;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &hdr, sizeof(hdr));
+
+ switch (action) {
+ case BF_PFMU_TAG_READ: {
+ struct bf_pfmu_tag *req;
+
+ tlv = __mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req));
+ req = (struct bf_pfmu_tag *)tlv;
+#define BFER 1
+ req->pfmu_id = idx;
+ req->bfer = BFER;
+ req->band_idx = phy->mt76->band_idx;
+ break;
+ }
+ case BF_STA_REC_READ: {
+ struct bf_starec_read *req;
+
+ tlv = __mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req));
+ req = (struct bf_starec_read *)tlv;
+ req->wlan_idx = idx;
+ break;
+ }
+ case BF_FBRPT_DBG_INFO_READ: {
+ struct bf_fbk_rpt_info *req;
+
+ if (idx != 0) {
+ dev_info(dev->mt76.dev, "Invalid input");
+ return 0;
+ }
+
+ tlv = __mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req));
+ req = (struct bf_fbk_rpt_info *)tlv;
+ req->action = idx;
+ req->band_idx = phy->mt76->band_idx;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, MCU_WM_UNI_CMD(BF), false);
+}
+
+int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para)
+{
+ char *buf = (char *)para;
+ __le16 input[5] = {0};
+ u8 recv_arg = 0;
+ struct bf_txsnd_info *req;
+ struct uni_header hdr;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ int len = sizeof(hdr) + MT7996_MTK_BF_MAX_SIZE;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ skb = mt76_mcu_msg_alloc(&phy->dev->mt76, NULL, len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &hdr, sizeof(hdr));
+
+ recv_arg = sscanf(buf, "%hx:%hx:%hx:%hx:%hx", &input[0], &input[1], &input[2],
+ &input[3], &input[4]);
+
+ if (!recv_arg)
+ return -EINVAL;
+
+ tlv = __mt7996_mcu_add_uni_tlv(skb, BF_TXSND_INFO, sizeof(*req));
+ req = (struct bf_txsnd_info *)tlv;
+ req->action = input[0];
+
+ switch (req->action) {
+ case BF_SND_READ_INFO: {
+ req->read_clr = input[1];
+ break;
+ }
+ case BF_SND_CFG_OPT: {
+ req->vht_opt = input[1];
+ req->he_opt = input[2];
+ req->glo_opt = input[3];
+ break;
+ }
+ case BF_SND_CFG_INTV: {
+ req->wlan_idx = input[1];
+ req->snd_intv = input[2];
+ break;
+ }
+ case BF_SND_STA_STOP: {
+ req->wlan_idx = input[1];
+ req->snd_stop = input[2];
+ break;
+ }
+ case BF_SND_CFG_MAX_STA: {
+ req->max_snd_stas = input[1];
+ break;
+ }
+ case BF_SND_CFG_BFRP: {
+ req->man = input[1];
+ req->tx_time = input[2];
+ req->mcs = input[3];
+ req->ldpc = input[4];
+ break;
+ }
+ case BF_SND_CFG_INF: {
+ req->inf = input[1];
+ break;
+ }
+ case BF_SND_CFG_TXOP_SND: {
+ req->man = input[1];
+ req->ac_queue = input[2];
+ req->sxn_protect = input[3];
+ req->direct_fbk = input[4];
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, MCU_WM_UNI_CMD(BF), false);
+}
+
+void
+mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+#define HE_MODE 3
+ struct mt7996_mcu_bf_basic_event *event;
+
+ event = (struct mt7996_mcu_bf_basic_event *)skb->data;
+
+ dev_info(dev->mt76.dev, " bf_event tag = %d\n", event->tag);
+
+ switch (event->tag) {
+ case UNI_EVENT_BF_PFMU_TAG: {
+
+ struct mt7996_pfmu_tag_event *tag;
+ u32 *raw_t1, *raw_t2;
+
+ tag = (struct mt7996_pfmu_tag_event *) skb->data;
+
+ raw_t1 = (u32 *)&tag->t1;
+ raw_t2 = (u32 *)&tag->t2;
+
+ dev_info(dev->mt76.dev, "=================== TXBf Profile Tag1 Info ==================\n");
+ dev_info(dev->mt76.dev,
+ "DW0 = 0x%08x, DW1 = 0x%08x, DW2 = 0x%08x\n",
+ raw_t1[0], raw_t1[1], raw_t1[2]);
+ dev_info(dev->mt76.dev,
+ "DW4 = 0x%08x, DW5 = 0x%08x, DW6 = 0x%08x\n\n",
+ raw_t1[3], raw_t1[4], raw_t1[5]);
+ dev_info(dev->mt76.dev, "PFMU ID = %d Invalid status = %d\n",
+ tag->t1.pfmu_idx, tag->t1.invalid_prof);
+ dev_info(dev->mt76.dev, "iBf/eBf = %d\n\n", tag->t1.ebf);
+ dev_info(dev->mt76.dev, "DBW = %d\n", tag->t1.data_bw);
+ dev_info(dev->mt76.dev, "SU/MU = %d\n", tag->t1.is_mu);
+ dev_info(dev->mt76.dev,
+ "nrow = %d, ncol = %d, ng = %d, LM = %d, CodeBook = %d MobCalEn = %d\n",
+ tag->t1.nr, tag->t1.nc, tag->t1.ngroup, tag->t1.lm, tag->t1.codebook,
+ tag->t1.mob_cal_en);
+
+ if (tag->t1.lm <= HE_MODE) {
+ dev_info(dev->mt76.dev, "RU start = %d, RU end = %d\n",
+ tag->t1.field.ru_start_id, tag->t1.field.ru_end_id);
+ } else {
+ dev_info(dev->mt76.dev, "PartialBW = %d\n",
+ tag->t1.bw_info.partial_bw_info);
+ }
+
+ dev_info(dev->mt76.dev, "Mem Col1 = %d, Mem Row1 = %d, Mem Col2 = %d, Mem Row2 = %d\n",
+ tag->t1.col_id1, tag->t1.row_id1, tag->t1.col_id2, tag->t1.row_id2);
+ dev_info(dev->mt76.dev, "Mem Col3 = %d, Mem Row3 = %d, Mem Col4 = %d, Mem Row4 = %d\n\n",
+ tag->t1.col_id3, tag->t1.row_id3, tag->t1.col_id4, tag->t1.row_id4);
+ dev_info(dev->mt76.dev,
+ "STS0_SNR = 0x%02x, STS1_SNR = 0x%02x, STS2_SNR = 0x%02x, STS3_SNR = 0x%02x\n",
+ tag->t1.snr_sts0, tag->t1.snr_sts1, tag->t1.snr_sts2, tag->t1.snr_sts3);
+ dev_info(dev->mt76.dev,
+ "STS4_SNR = 0x%02x, STS5_SNR = 0x%02x, STS6_SNR = 0x%02x, STS7_SNR = 0x%02x\n",
+ tag->t1.snr_sts4, tag->t1.snr_sts5, tag->t1.snr_sts6, tag->t1.snr_sts7);
+ dev_info(dev->mt76.dev, "=============================================================\n");
+
+ dev_info(dev->mt76.dev, "=================== TXBf Profile Tag2 Info ==================\n");
+ dev_info(dev->mt76.dev,
+ "DW0 = 0x%08x, DW1 = 0x%08x, DW2 = 0x%08x\n",
+ raw_t2[0], raw_t2[1], raw_t2[2]);
+ dev_info(dev->mt76.dev,
+ "DW3 = 0x%08x, DW4 = 0x%08x, DW5 = 0x%08x\n\n",
+ raw_t2[3], raw_t2[4], raw_t2[5]);
+ dev_info(dev->mt76.dev, "Smart antenna ID = 0x%x, SE index = %d\n",
+ tag->t2.smart_ant, tag->t2.se_idx);
+ dev_info(dev->mt76.dev, "Timeout = 0x%x\n", tag->t2.ibf_timeout);
+ dev_info(dev->mt76.dev, "Desired BW = %d, Desired Ncol = %d, Desired Nrow = %d\n",
+ tag->t2.ibf_data_bw, tag->t2.ibf_nc, tag->t2.ibf_nr);
+ dev_info(dev->mt76.dev, "Desired RU Allocation = %d\n", tag->t2.ibf_ru);
+ dev_info(dev->mt76.dev, "Mobility DeltaT = %d, Mobility LQ = %d\n",
+ tag->t2.mob_delta_t, tag->t2.mob_lq_result);
+ dev_info(dev->mt76.dev, "=============================================================\n");
+ break;
+ }
+ case UNI_EVENT_BF_STAREC: {
+
+ struct mt7996_mcu_bf_starec_read *r;
+
+ r = (struct mt7996_mcu_bf_starec_read *)skb->data;
+ dev_info(dev->mt76.dev, "=================== BF StaRec ===================\n"
+ "rStaRecBf.u2PfmuId = %d\n"
+ "rStaRecBf.fgSU_MU = %d\n"
+ "rStaRecBf.u1TxBfCap = %d\n"
+ "rStaRecBf.ucSoundingPhy = %d\n"
+ "rStaRecBf.ucNdpaRate = %d\n"
+ "rStaRecBf.ucNdpRate = %d\n"
+ "rStaRecBf.ucReptPollRate= %d\n"
+ "rStaRecBf.ucTxMode = %d\n"
+ "rStaRecBf.ucNc = %d\n"
+ "rStaRecBf.ucNr = %d\n"
+ "rStaRecBf.ucCBW = %d\n"
+ "rStaRecBf.ucMemRequire20M = %d\n"
+ "rStaRecBf.ucMemRow0 = %d\n"
+ "rStaRecBf.ucMemCol0 = %d\n"
+ "rStaRecBf.ucMemRow1 = %d\n"
+ "rStaRecBf.ucMemCol1 = %d\n"
+ "rStaRecBf.ucMemRow2 = %d\n"
+ "rStaRecBf.ucMemCol2 = %d\n"
+ "rStaRecBf.ucMemRow3 = %d\n"
+ "rStaRecBf.ucMemCol3 = %d\n",
+ r->pfmu_id,
+ r->is_su_mu,
+ r->txbf_cap,
+ r->sounding_phy,
+ r->ndpa_rate,
+ r->ndp_rate,
+ r->rpt_poll_rate,
+ r->tx_mode,
+ r->nc,
+ r->nr,
+ r->bw,
+ r->mem_require_20m,
+ r->mem_row0,
+ r->mem_col0,
+ r->mem_row1,
+ r->mem_col1,
+ r->mem_row2,
+ r->mem_col2,
+ r->mem_row3,
+ r->mem_col3);
+
+ dev_info(dev->mt76.dev, "rStaRecBf.u2SmartAnt = 0x%x\n"
+ "rStaRecBf.ucSEIdx = %d\n"
+ "rStaRecBf.uciBfTimeOut = 0x%x\n"
+ "rStaRecBf.uciBfDBW = %d\n"
+ "rStaRecBf.uciBfNcol = %d\n"
+ "rStaRecBf.uciBfNrow = %d\n"
+ "rStaRecBf.nr_bw160 = %d\n"
+ "rStaRecBf.nc_bw160 = %d\n"
+ "rStaRecBf.ru_start_idx = %d\n"
+ "rStaRecBf.ru_end_idx = %d\n"
+ "rStaRecBf.trigger_su = %d\n"
+ "rStaRecBf.trigger_mu = %d\n"
+ "rStaRecBf.ng16_su = %d\n"
+ "rStaRecBf.ng16_mu = %d\n"
+ "rStaRecBf.codebook42_su = %d\n"
+ "rStaRecBf.codebook75_mu = %d\n"
+ "rStaRecBf.he_ltf = %d\n"
+ "======================================\n",
+ r->smart_ant,
+ r->se_idx,
+ r->bf_timeout,
+ r->bf_dbw,
+ r->bf_ncol,
+ r->bf_nrow,
+ r->nr_lt_bw80,
+ r->nc_lt_bw80,
+ r->ru_start_idx,
+ r->ru_end_idx,
+ r->trigger_su,
+ r->trigger_mu,
+ r->ng16_su,
+ r->ng16_mu,
+ r->codebook42_su,
+ r->codebook75_mu,
+ r->he_ltf);
+ break;
+ }
+ case UNI_EVENT_BF_FBK_INFO: {
+ struct mt7996_mcu_txbf_fbk_info *info;
+ __le32 total, i;
+
+ info = (struct mt7996_mcu_txbf_fbk_info *)skb->data;
+
+ total = info->u4PFMUWRDoneCnt + info->u4PFMUWRFailCnt;
+ total += info->u4PFMUWRTimeoutFreeCnt + info->u4FbRptPktDropCnt;
+
+ dev_info(dev->mt76.dev, "\n");
+ dev_info(dev->mt76.dev, "\x1b[32m =================================\x1b[m\n");
+ dev_info(dev->mt76.dev, "\x1b[32m PFMUWRDoneCnt = %u\x1b[m\n",
+ info->u4PFMUWRDoneCnt);
+ dev_info(dev->mt76.dev, "\x1b[32m PFMUWRFailCnt = %u\x1b[m\n",
+ info->u4PFMUWRFailCnt);
+ dev_info(dev->mt76.dev, "\x1b[32m PFMUWRTimeOutCnt = %u\x1b[m\n",
+ info->u4PFMUWRTimeOutCnt);
+ dev_info(dev->mt76.dev, "\x1b[32m PFMUWRTimeoutFreeCnt = %u\x1b[m\n",
+ info->u4PFMUWRTimeoutFreeCnt);
+ dev_info(dev->mt76.dev, "\x1b[32m FbRptPktDropCnt = %u\x1b[m\n",
+ info->u4FbRptPktDropCnt);
+ dev_info(dev->mt76.dev, "\x1b[32m TotalFbRptPkt = %u\x1b[m\n", total);
+ dev_info(dev->mt76.dev, "\x1b[32m PollPFMUIntrStatTimeOut = %u(micro-sec)\x1b[m\n",
+ info->u4PollPFMUIntrStatTimeOut);
+ dev_info(dev->mt76.dev, "\x1b[32m FbRptDeQInterval = %u(milli-sec)\x1b[m\n",
+ info->u4DeQInterval);
+ dev_info(dev->mt76.dev, "\x1b[32m PktCntInFbRptTimeOutQ = %u\x1b[m\n",
+ info->u4RptPktTimeOutListNum);
+ dev_info(dev->mt76.dev, "\x1b[32m PktCntInFbRptQ = %u\x1b[m\n",
+ info->u4RptPktListNum);
+
+ // [ToDo] Check if it is valid entry
+ for (i = 0; ((i < 5) && (i < CFG_BF_STA_REC_NUM)); i++) {
+
+ // [ToDo] AID needs to be refined
+ dev_info(dev->mt76.dev,"\x1b[32m AID%u RxFbRptCnt = %u\x1b[m\n"
+ , i, info->au4RxPerStaFbRptCnt[i]);
+ }
+
+ break;
+ }
+ case UNI_EVENT_BF_TXSND_INFO: {
+ struct mt7996_mcu_tx_snd_info *info;
+ struct uni_event_bf_txsnd_sta_info *snd_sta_info;
+ int Idx;
+ int max_wtbl_size = mt7996_wtbl_size(dev);
+
+ info = (struct mt7996_mcu_tx_snd_info *)skb->data;
+ dev_info(dev->mt76.dev, "=================== Global Setting ===================\n");
+
+ dev_info(dev->mt76.dev, "VhtOpt = 0x%02X, HeOpt = 0x%02X, GloOpt = 0x%02X\n",
+ info->vht_opt, info->he_opt, info->glo_opt);
+
+ for (Idx = 0; Idx < BF_SND_CTRL_STA_DWORD_CNT; Idx++) {
+ dev_info(dev->mt76.dev, "SuSta[%d] = 0x%08X,", Idx,
+ info->snd_rec_su_sta[Idx]);
+ if ((Idx & 0x03) == 0x03)
+ dev_info(dev->mt76.dev, "\n");
+ }
+
+ if ((Idx & 0x03) != 0x03)
+ dev_info(dev->mt76.dev, "\n");
+
+
+ for (Idx = 0; Idx < BF_SND_CTRL_STA_DWORD_CNT; Idx++) {
+ dev_info(dev->mt76.dev, "VhtMuSta[%d] = 0x%08X,", Idx, info->snd_rec_vht_mu_sta[Idx]);
+ if ((Idx & 0x03) == 0x03)
+ dev_info(dev->mt76.dev, "\n");
+ }
+
+ if ((Idx & 0x03) != 0x03)
+ dev_info(dev->mt76.dev, "\n");
+
+ for (Idx = 0; Idx < BF_SND_CTRL_STA_DWORD_CNT; Idx++) {
+ dev_info(dev->mt76.dev, "HeTBSta[%d] = 0x%08X,", Idx, info->snd_rec_he_tb_sta[Idx]);
+ if ((Idx & 0x03) == 0x03)
+ dev_info(dev->mt76.dev, "\n");
+ }
+
+ if ((Idx & 0x03) != 0x03)
+ dev_info(dev->mt76.dev, "\n");
+
+ for (Idx = 0; Idx < BF_SND_CTRL_STA_DWORD_CNT; Idx++) {
+ dev_info(dev->mt76.dev, "EhtTBSta[%d] = 0x%08X,", Idx, info->snd_rec_eht_tb_sta[Idx]);
+ if ((Idx & 0x03) == 0x03)
+ dev_info(dev->mt76.dev, "\n");
+ }
+
+ if ((Idx & 0x03) != 0x03)
+ dev_info(dev->mt76.dev, "\n");
+
+ for (Idx = 0; Idx < CFG_WIFI_RAM_BAND_NUM; Idx++) {
+ dev_info(dev->mt76.dev, "Band%u:\n", Idx);
+ dev_info(dev->mt76.dev, " Wlan Idx For VHT MC Sounding = %u\n", info->wlan_idx_for_mc_snd[Idx]);
+ dev_info(dev->mt76.dev, " Wlan Idx For HE TB Sounding = %u\n", info->wlan_idx_for_he_tb_snd[Idx]);
+ dev_info(dev->mt76.dev, " Wlan Idx For EHT TB Sounding = %u\n", info->wlan_idx_for_eht_tb_snd[Idx]);
+ }
+
+ dev_info(dev->mt76.dev, "ULLen = %d, ULMcs = %d, ULLDCP = %d\n",
+ info->ul_length, info->mcs, info->ldpc);
+
+ dev_info(dev->mt76.dev, "=================== STA Info ===================\n");
+
+ for (Idx = 1; (Idx < 5 && (Idx < CFG_BF_STA_REC_NUM)); Idx++) {
+ snd_sta_info = &info->snd_sta_info[Idx];
+ dev_info(dev->mt76.dev, "Idx%2u Interval = %d, interval counter = %d, TxCnt = %d, StopReason = 0x%02X\n",
+ Idx,
+ snd_sta_info->snd_intv,
+ snd_sta_info->snd_intv_cnt,
+ snd_sta_info->snd_tx_cnt,
+ snd_sta_info->snd_stop_reason);
+ }
+
+ dev_info(dev->mt76.dev, "=================== STA Info Connected ===================\n");
+ // [ToDo] How to iterate and get AID info of station
+ // Check UniEventBFCtrlTxSndHandle() on Logan
+
+ //hardcode max_wtbl_size as 5
+ max_wtbl_size = 5;
+ for (Idx = 1; ((Idx < max_wtbl_size) && (Idx < CFG_BF_STA_REC_NUM)); Idx++) {
+
+ // [ToDo] We do not show AID info here
+ snd_sta_info = &info->snd_sta_info[Idx];
+ dev_info(dev->mt76.dev, " Interval = %d (%u ms), interval counter = %d (%u ms), TxCnt = %d, StopReason = 0x%02X\n",
+ snd_sta_info->snd_intv,
+ snd_sta_info->snd_intv * 10,
+ snd_sta_info->snd_intv_cnt,
+ snd_sta_info->snd_intv_cnt * 10,
+ snd_sta_info->snd_tx_cnt,
+ snd_sta_info->snd_stop_reason);
+ }
+
+ dev_info(dev->mt76.dev, "======================================\n");
+
+ break;
+ }
+ default:
+ dev_info(dev->mt76.dev, "%s: unknown bf event tag %d\n",
+ __func__, event->tag);
+ }
+
+}
+
+
+int mt7996_mcu_set_muru_fixed_rate_enable(struct mt7996_dev *dev, u8 action, int val)
+{
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ __le16 value;
+ __le16 rsv;
+ } __packed data = {
+ .tag = cpu_to_le16(action),
+ .len = cpu_to_le16(sizeof(data) - 4),
+ .value = cpu_to_le16(!!val),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &data, sizeof(data),
+ false);
+}
+
+int mt7996_mcu_set_muru_fixed_rate_parameter(struct mt7996_dev *dev, u8 action, void *para)
+{
+ char *buf = (char *)para;
+ u8 num_user = 0, recv_arg = 0, max_mcs = 0, usr_mcs[4] = {0};
+ __le16 bw;
+ int i;
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 cmd_version;
+ u8 cmd_revision;
+ __le16 rsv;
+
+ struct uni_muru_mum_set_group_tbl_entry entry;
+ } __packed data = {
+ .tag = cpu_to_le16(action),
+ .len = cpu_to_le16(sizeof(data) - 4),
+ };
+
+#define __RUALLOC_TYPE_CHECK_HE(BW) ((BW == RUALLOC_BW20) || (BW == RUALLOC_BW40) || (BW == RUALLOC_BW80) || (BW == RUALLOC_BW160))
+#define __RUALLOC_TYPE_CHECK_EHT(BW) (__RUALLOC_TYPE_CHECK_HE(BW) || (BW == RUALLOC_BW320))
+ /* [Num of user] - 1~4
+ * [RUAlloc] - BW320: 395, BW160: 137, BW80: 134, BW40: 130, BW20: 122
+ * [LTF/GI] - For VHT, short GI: 0, Long GI: 1; *
+ * For HE/EHT, 4xLTF+3.2us: 0, 4xLTF+0.8us: 1, 2xLTF+0.8us:2
+ * [Phy/FullBW] - VHT: 0 / HEFullBw: 1 / HEPartialBw: 2 / EHTFullBW: 3, EHTPartialBW: 4
+ * [DL/UL] DL: 0, UL: 1, DL_UL: 2
+ * [Wcid User0] - WCID 0
+ * [MCS of WCID0] - For HE/VHT, 0-11: 1ss MCS0-MCS11, 12-23: 2SS MCS0-MCS11
+ * For EHT, 0-13: 1ss MCS0-MCS13, 14-27: 2SS MCS0-MCS13
+ * [WCID 1]
+ * [MCS of WCID1]
+ * [WCID 2]
+ * [MCS of WCID2]
+ * [WCID 3]
+ * [MCS of WCID3]
+ */
+
+ recv_arg = sscanf(buf, "%hhu %hu %hhu %hhu %hhu %hu %hhu %hu %hhu %hu %hhu %hu %hhu",
+ &num_user, &bw, &data.entry.gi, &data.entry.capa, &data.entry.dl_ul,
+ &data.entry.wlan_idx0, &usr_mcs[0],
+ &data.entry.wlan_idx1, &usr_mcs[1],
+ &data.entry.wlan_idx2, &usr_mcs[2],
+ &data.entry.wlan_idx3, &usr_mcs[3]);
+
+ if (recv_arg != (5 + (2 * num_user))) {
+ dev_err(dev->mt76.dev, "The number of argument is invalid\n");
+ goto error;
+ }
+
+ if (num_user > 0 && num_user < 5)
+ data.entry.num_user = num_user - 1;
+ else {
+ dev_err(dev->mt76.dev, "The number of user count is invalid\n");
+ goto error;
+ }
+
+ /**
+ * Older chip shall be set as HE. Refer to getHWSupportByChip() in Logan
+ * driver to know the value for differnt chips
+ */
+ data.cmd_version = UNI_CMD_MURU_VER_EHT;
+
+ if (data.cmd_version == UNI_CMD_MURU_VER_EHT)
+ max_mcs = UNI_MAX_MCS_SUPPORT_EHT;
+ else
+ max_mcs = UNI_MAX_MCS_SUPPORT_HE;
+
+
+ // Parameter Check
+ if (data.cmd_version != UNI_CMD_MURU_VER_EHT) {
+ if ((data.entry.capa > MAX_MODBF_HE) || (bw == RUALLOC_BW320))
+ goto error;
+ } else {
+ if ((data.entry.capa <= MAX_MODBF_HE) && (bw == RUALLOC_BW320))
+ goto error;
+ }
+
+ if (data.entry.capa <= MAX_MODBF_HE)
+ max_mcs = UNI_MAX_MCS_SUPPORT_HE;
+
+ if (__RUALLOC_TYPE_CHECK_EHT(bw)) {
+ data.entry.ru_alloc = (u8)(bw & 0xFF);
+ if (bw == RUALLOC_BW320)
+ data.entry.ru_alloc_ext = (u8)(bw >> 8);
+ } else {
+ dev_err(dev->mt76.dev, "RU_ALLOC argument is invalid\n");
+ goto error;
+ }
+
+ if ((data.entry.gi > 2) ||
+ ((data.entry.gi > 1) && (data.entry.capa == MAX_MODBF_VHT))) {
+ dev_err(dev->mt76.dev, "GI argument is invalid\n");
+ goto error;
+ }
+
+ if (data.entry.dl_ul > 2) {
+ dev_err(dev->mt76.dev, "DL_UL argument is invalid\n");
+ goto error;
+ }
+
+#define __mcs_handler(_n) \
+ do { \
+ if (usr_mcs[_n] > max_mcs) { \
+ usr_mcs[_n] -= (max_mcs + 1); \
+ data.entry.nss##_n = 1; \
+ if (usr_mcs[_n] > max_mcs) \
+ usr_mcs[_n] = max_mcs; \
+ } \
+ if ((data.entry.dl_ul & 0x1) == 0) \
+ data.entry.dl_mcs_user##_n = usr_mcs[_n]; \
+ if ((data.entry.dl_ul & 0x3) > 0) \
+ data.entry.ul_mcs_user##_n = usr_mcs[_n]; \
+ } \
+ while (0)
+
+ for (i=0; i<= data.entry.num_user; i++) {
+ switch (i) {
+ case 0:
+ __mcs_handler(0);
+ break;
+ case 1:
+ __mcs_handler(1);
+ break;
+ case 2:
+ __mcs_handler(2);
+ break;
+ case 3:
+ __mcs_handler(3);
+ break;
+ default:
+ break;
+ }
+ }
+#undef __mcs_handler
+
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &data,
+ sizeof(data), false);
+
+error:
+ dev_err(dev->mt76.dev, "Command failed!\n");
+ return -EINVAL;
+}
+
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
index 098e63ae..27d6a05b 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -119,6 +119,348 @@ enum {
EDCCA_FCC = 1,
EDCCA_ETSI = 2,
EDCCA_JAPAN = 3
+
+struct bf_pfmu_tag {
+ __le16 tag;
+ __le16 len;
+
+ u8 pfmu_id;
+ bool bfer;
+ u8 band_idx;
+ u8 __rsv[5];
+ u8 buf[56];
+} __packed;
+
+struct bf_starec_read {
+ __le16 tag;
+ __le16 len;
+
+ __le16 wlan_idx;
+ u8 __rsv[2];
+} __packed;
+
+struct bf_fbk_rpt_info {
+ __le16 tag;
+ __le16 len;
+
+ __le16 wlan_idx; // Only need for dynamic_pfmu_update 0x4
+ u8 action;
+ u8 band_idx;
+ u8 __rsv[4];
+
+} __packed;
+
+struct bf_txsnd_info {
+ __le16 tag;
+ __le16 len;
+
+ u8 action;
+ u8 read_clr;
+ u8 vht_opt;
+ u8 he_opt;
+ __le16 wlan_idx;
+ u8 glo_opt;
+ u8 snd_intv;
+ u8 snd_stop;
+ u8 max_snd_stas;
+ u8 tx_time;
+ u8 mcs;
+ u8 ldpc;
+ u8 inf;
+ u8 man;
+ u8 ac_queue;
+ u8 sxn_protect;
+ u8 direct_fbk;
+ u8 __rsv[2];
+} __packed;
+
+struct mt7996_mcu_bf_basic_event {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+};
+
+struct mt7996_mcu_bf_starec_read {
+
+ struct mt7996_mcu_bf_basic_event event;
+
+ __le16 pfmu_id;
+ bool is_su_mu;
+ u8 txbf_cap;
+ u8 sounding_phy;
+ u8 ndpa_rate;
+ u8 ndp_rate;
+ u8 rpt_poll_rate;
+ u8 tx_mode;
+ u8 nc;
+ u8 nr;
+ u8 bw;
+ u8 total_mem_require;
+ u8 mem_require_20m;
+ u8 mem_row0;
+ u8 mem_col0:6;
+ u8 mem_row0_msb:2;
+ u8 mem_row1;
+ u8 mem_col1:6;
+ u8 mem_row1_msb:2;
+ u8 mem_row2;
+ u8 mem_col2:6;
+ u8 mem_row2_msb:2;
+ u8 mem_row3;
+ u8 mem_col3:6;
+ u8 mem_row3_msb:2;
+
+ __le16 smart_ant;
+ u8 se_idx;
+ u8 auto_sounding_ctrl;
+
+ u8 bf_timeout;
+ u8 bf_dbw;
+ u8 bf_ncol;
+ u8 bf_nrow;
+
+ u8 nr_lt_bw80;
+ u8 nc_lt_bw80;
+ u8 ru_start_idx;
+ u8 ru_end_idx;
+
+ bool trigger_su;
+ bool trigger_mu;
+
+ bool ng16_su;
+ bool ng16_mu;
+
+ bool codebook42_su;
+ bool codebook75_mu;
+
+ u8 he_ltf;
+ u8 rsv[3];
+};
+
+#define TXBF_PFMU_ID_NUM_MAX 48
+
+#define TXBF_PFMU_ID_NUM_MAX_TBTC_BAND0 TXBF_PFMU_ID_NUM_MAX
+#define TXBF_PFMU_ID_NUM_MAX_TBTC_BAND1 TXBF_PFMU_ID_NUM_MAX
+#define TXBF_PFMU_ID_NUM_MAX_TBTC_BAND2 TXBF_PFMU_ID_NUM_MAX
+
+/* CFG_BF_STA_REC shall be varied based on BAND Num */
+#define CFG_BF_STA_REC_NUM (TXBF_PFMU_ID_NUM_MAX_TBTC_BAND0 + TXBF_PFMU_ID_NUM_MAX_TBTC_BAND1 + TXBF_PFMU_ID_NUM_MAX_TBTC_BAND2)
+
+#define BF_SND_CTRL_STA_DWORD_CNT ((CFG_BF_STA_REC_NUM + 0x1F) >> 5)
+
+#ifndef ALIGN_4
+ #define ALIGN_4(_value) (((_value) + 3) & ~3u)
+#endif /* ALIGN_4 */
+
+#define CFG_WIFI_RAM_BAND_NUM 3
+
+struct uni_event_bf_txsnd_sta_info {
+ u8 snd_intv; /* Sounding interval upper bound, unit:15ms */
+ u8 snd_intv_cnt; /* Sounding interval counter */
+ u8 snd_tx_cnt; /* Tx sounding count for debug */
+ u8 snd_stop_reason; /* Bitwise reason to put in Stop Queue */
+};
+
+struct mt7996_mcu_tx_snd_info {
+
+ struct mt7996_mcu_bf_basic_event event;
+
+ u8 vht_opt;
+ u8 he_opt;
+ u8 glo_opt;
+ u8 __rsv;
+ __le32 snd_rec_su_sta[BF_SND_CTRL_STA_DWORD_CNT];
+ __le32 snd_rec_vht_mu_sta[BF_SND_CTRL_STA_DWORD_CNT];
+ __le32 snd_rec_he_tb_sta[BF_SND_CTRL_STA_DWORD_CNT];
+ __le32 snd_rec_eht_tb_sta[BF_SND_CTRL_STA_DWORD_CNT];
+ __le16 wlan_idx_for_mc_snd[ALIGN_4(CFG_WIFI_RAM_BAND_NUM)];
+ __le16 wlan_idx_for_he_tb_snd[ALIGN_4(CFG_WIFI_RAM_BAND_NUM)];
+ __le16 wlan_idx_for_eht_tb_snd[ALIGN_4(CFG_WIFI_RAM_BAND_NUM)];
+ __le16 ul_length;
+ u8 mcs;
+ u8 ldpc;
+ struct uni_event_bf_txsnd_sta_info snd_sta_info[CFG_BF_STA_REC_NUM];
+};
+
+struct mt7996_mcu_txbf_fbk_info {
+
+ struct mt7996_mcu_bf_basic_event event;
+
+ __le32 u4DeQInterval; /* By ms */
+ __le32 u4PollPFMUIntrStatTimeOut; /* micro-sec */
+ __le32 u4RptPktTimeOutListNum;
+ __le32 u4RptPktListNum;
+ __le32 u4PFMUWRTimeOutCnt;
+ __le32 u4PFMUWRFailCnt;
+ __le32 u4PFMUWRDoneCnt;
+ __le32 u4PFMUWRTimeoutFreeCnt;
+ __le32 u4FbRptPktDropCnt;
+ __le32 au4RxPerStaFbRptCnt[CFG_BF_STA_REC_NUM];
+};
+
+struct pfmu_ru_field {
+ __le32 ru_start_id:7;
+ __le32 _rsv1:1;
+ __le32 ru_end_id:7;
+ __le32 _rsv2:1;
+} __packed;
+
+struct pfmu_partial_bw_info {
+ __le32 partial_bw_info:9;
+ __le32 _rsv1:7;
+} __packed;
+
+struct mt7996_pfmu_tag1 {
+ __le32 pfmu_idx:10;
+ __le32 ebf:1;
+ __le32 data_bw:3;
+ __le32 lm:3;
+ __le32 is_mu:1;
+ __le32 nr:3;
+ __le32 nc:3;
+ __le32 codebook:2;
+ __le32 ngroup:2;
+ __le32 invalid_prof:1;
+ __le32 _rsv:3;
+
+ __le32 col_id1:7, row_id1:9;
+ __le32 col_id2:7, row_id2:9;
+ __le32 col_id3:7, row_id3:9;
+ __le32 col_id4:7, row_id4:9;
+
+ union {
+ struct pfmu_ru_field field;
+ struct pfmu_partial_bw_info bw_info;
+ };
+ __le32 mob_cal_en:1;
+ __le32 _rsv2:3;
+ __le32 mob_ru_alloc:9; /* EHT profile uses full 9 bit */
+ __le32 _rsv3:3;
+
+ __le32 snr_sts0:8, snr_sts1:8, snr_sts2:8, snr_sts3:8;
+ __le32 snr_sts4:8, snr_sts5:8, snr_sts6:8, snr_sts7:8;
+
+ __le32 _rsv4;
+} __packed;
+
+struct mt7996_pfmu_tag2 {
+ __le32 smart_ant:24;
+ __le32 se_idx:5;
+ __le32 _rsv:3;
+
+ __le32 _rsv1:16;
+ __le32 ibf_timeout:8;
+ __le32 _rsv2:8;
+
+ __le32 ibf_data_bw:3;
+ __le32 ibf_nc:3;
+ __le32 ibf_nr:3;
+ __le32 ibf_ru:9;
+ __le32 _rsv3:14;
+
+ __le32 mob_delta_t:8;
+ __le32 mob_lq_result:7;
+ __le32 _rsv5:1;
+ __le32 _rsv6:16;
+
+ __le32 _rsv7;
+} __packed;
+
+struct mt7996_pfmu_tag_event {
+ struct mt7996_mcu_bf_basic_event event;
+
+ u8 bfer;
+ u8 __rsv[3];
+
+ struct mt7996_pfmu_tag1 t1;
+ struct mt7996_pfmu_tag2 t2;
+};
+
+enum {
+ UNI_EVENT_BF_PFMU_TAG = 0x5,
+ UNI_EVENT_BF_PFMU_DATA = 0x7,
+ UNI_EVENT_BF_STAREC = 0xB,
+ UNI_EVENT_BF_CAL_PHASE = 0xC,
+ UNI_EVENT_BF_FBK_INFO = 0x17,
+ UNI_EVENT_BF_TXSND_INFO = 0x18,
+ UNI_EVENT_BF_PLY_INFO = 0x19,
+ UNI_EVENT_BF_METRIC_INFO = 0x1A,
+ UNI_EVENT_BF_TXCMD_CFG_INFO = 0x1B,
+ UNI_EVENT_BF_SND_CNT_INFO = 0x1D,
+ UNI_EVENT_BF_MAX_NUM
+};
+
+enum {
+ UNI_CMD_MURU_FIXED_RATE_CTRL = 0x11,
+ UNI_CMD_MURU_FIXED_GROUP_RATE_CTRL,
+};
+
+struct uni_muru_mum_set_group_tbl_entry {
+ __le16 wlan_idx0;
+ __le16 wlan_idx1;
+ __le16 wlan_idx2;
+ __le16 wlan_idx3;
+
+ u8 dl_mcs_user0:4;
+ u8 dl_mcs_user1:4;
+ u8 dl_mcs_user2:4;
+ u8 dl_mcs_user3:4;
+ u8 ul_mcs_user0:4;
+ u8 ul_mcs_user1:4;
+ u8 ul_mcs_user2:4;
+ u8 ul_mcs_user3:4;
+
+ u8 num_user:2;
+ u8 rsv:6;
+ u8 nss0:2;
+ u8 nss1:2;
+ u8 nss2:2;
+ u8 nss3:2;
+ u8 ru_alloc;
+ u8 ru_alloc_ext;
+
+ u8 capa;
+ u8 gi;
+ u8 dl_ul;
+ u8 _rsv2;
+};
+
+enum UNI_CMD_MURU_VER_T {
+ UNI_CMD_MURU_VER_LEG = 0,
+ UNI_CMD_MURU_VER_HE,
+ UNI_CMD_MURU_VER_EHT,
+ UNI_CMD_MURU_VER_MAX
+};
+
+#define UNI_MAX_MCS_SUPPORT_HE 11
+#define UNI_MAX_MCS_SUPPORT_EHT 13
+
+enum {
+ RUALLOC_BW20 = 122,
+ RUALLOC_BW40 = 130,
+ RUALLOC_BW80 = 134,
+ RUALLOC_BW160 = 137,
+ RUALLOC_BW320 = 395,
+};
+
+enum {
+ MAX_MODBF_VHT = 0,
+ MAX_MODBF_HE = 2,
+ MAX_MODBF_EHT = 4,
+};
+
+enum {
+ BF_SND_READ_INFO = 0,
+ BF_SND_CFG_OPT,
+ BF_SND_CFG_INTV,
+ BF_SND_STA_STOP,
+ BF_SND_CFG_MAX_STA,
+ BF_SND_CFG_BFRP,
+ BF_SND_CFG_INF,
+ BF_SND_CFG_TXOP_SND
};
enum {
--
2.45.2