From 4d602b85220d70f83848a9367dcc80dc3f8f5269 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 3002/3010] wifi: 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

Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
 mt7996/debugfs.c       |   1 +
 mt7996/mcu.h           |   4 +
 mt7996/mt7996.h        |   6 +
 mt7996/mtk_debugfs_i.c | 126 +++++++++
 mt7996/mtk_mcu_i.c     | 626 +++++++++++++++++++++++++++++++++++++++++
 mt7996/mtk_mcu_i.h     | 342 ++++++++++++++++++++++
 6 files changed, 1105 insertions(+)

diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
index bacb9a7..2bf9bb1 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
@@ -864,6 +864,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
 #ifdef CONFIG_MTK_DEBUG
 	debugfs_create_u16("wlan_idx", 0600, dir, &dev->wlan_idx);
 	mt7996_mtk_init_debugfs(phy, dir);
+	mt7996_mtk_init_all_debugfs_internal(phy, dir);
 #endif
 
 	return 0;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
index 5e75585..feadfc8 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -628,8 +628,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 f9942f6..8872087 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -915,6 +915,12 @@ void mt7996_packet_log_to_host(struct mt7996_dev *dev, const void *data, int len
 void mt7996_dump_bmac_rxd_info(struct mt7996_dev *dev, __le32 *rxd);
 void mt7996_dump_bmac_txd_info(struct mt7996_dev *dev, __le32 *txd, bool is_hif_txd, bool dump_txp);
 int mt7996_mtk_init_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir);
+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);
+int mt7996_mtk_init_all_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir);
 #endif
 
 #endif
diff --git a/mt7996/mtk_debugfs_i.c b/mt7996/mtk_debugfs_i.c
index 9b73970..5a29112 100644
--- a/mt7996/mtk_debugfs_i.c
+++ b/mt7996/mtk_debugfs_i.c
@@ -1626,6 +1626,117 @@ mt7996_drr_info(struct seq_file *s, void *data)
 	return 0;
 }
 
+static int
+mt7996_starec_bf_read_set(void *data, u64 wlan_idx)
+{
+	struct mt7996_phy *phy = data;
+
+	return mt7996_mcu_set_txbf_internal(phy, BF_STA_REC_READ, wlan_idx);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_starec_bf_read, NULL,
+			 mt7996_starec_bf_read_set, "%lld\n");
+
+static ssize_t
+mt7996_bf_txsnd_info_set(struct file *file,
+			 const char __user *user_buf,
+			 size_t count, loff_t *ppos)
+{
+	struct mt7996_phy *phy = file->private_data;
+	char buf[40];
+	int ret;
+
+	if (count >= sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (count && buf[count - 1] == '\n')
+		buf[count - 1] = '\0';
+	else
+		buf[count] = '\0';
+
+	ret = mt7996_mcu_set_txbf_snd_info(phy, buf);
+
+	if (ret) return -EFAULT;
+
+	return count;
+}
+
+static const struct file_operations fops_bf_txsnd_info = {
+	.write = mt7996_bf_txsnd_info_set,
+	.read = NULL,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static int
+mt7996_bf_fbk_rpt_set(void *data, u64 wlan_idx)
+{
+	struct mt7996_phy *phy = data;
+
+	return mt7996_mcu_set_txbf_internal(phy, BF_FBRPT_DBG_INFO_READ, wlan_idx);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_fbk_rpt, NULL,
+			 mt7996_bf_fbk_rpt_set, "%lld\n");
+
+static int
+mt7996_bf_pfmu_tag_read_set(void *data, u64 wlan_idx)
+{
+	struct mt7996_phy *phy = data;
+
+	return mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, wlan_idx);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_pfmu_tag_read, NULL,
+			 mt7996_bf_pfmu_tag_read_set, "%lld\n");
+
+static int
+mt7996_muru_fixed_rate_set(void *data, u64 val)
+{
+	struct mt7996_dev *dev = data;
+
+	return mt7996_mcu_set_muru_fixed_rate_enable(dev, UNI_CMD_MURU_FIXED_RATE_CTRL,
+						     val);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_fixed_rate_enable, NULL,
+			 mt7996_muru_fixed_rate_set, "%lld\n");
+
+static ssize_t
+mt7996_muru_fixed_rate_parameter_set(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct mt7996_dev *dev = file->private_data;
+	char buf[40];
+	int ret;
+
+	if (count >= sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (count && buf[count - 1] == '\n')
+		buf[count - 1] = '\0';
+	else
+		buf[count] = '\0';
+
+
+	ret = mt7996_mcu_set_muru_fixed_rate_parameter(dev, UNI_CMD_MURU_FIXED_GROUP_RATE_CTRL,
+						       buf);
+
+	if (ret) return -EFAULT;
+
+	return count;
+}
+
+static const struct file_operations fops_muru_fixed_group_rate = {
+	.write = mt7996_muru_fixed_rate_parameter_set,
+	.read = NULL,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
 int mt7996_mtk_init_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir)
 {
 	struct mt7996_dev *dev = phy->dev;
@@ -1663,7 +1774,22 @@ int mt7996_mtk_init_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir)
 	debugfs_create_file("amsdu_para", 0600, dir, dev, &fops_amsdu_para);
 
 	debugfs_create_u8("dump_ple_txd", 0600, dir, &dev->dbg.dump_ple_txd);
+
+	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);
+
 	return 0;
 }
 
+int mt7996_mtk_init_all_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir)
+{
+	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;
+}
 #endif
diff --git a/mt7996/mtk_mcu_i.c b/mt7996/mtk_mcu_i.c
index 64badf5..4a159b7 100644
--- a/mt7996/mtk_mcu_i.c
+++ b/mt7996/mtk_mcu_i.c
@@ -13,5 +13,631 @@
 
 #ifdef CONFIG_MTK_DEBUG
 
+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"
+					"rStaRecBf.pp_fd_val 	  = %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,
+					r->pp_fd_val);
+		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),
+	};
+
+	if (val != 1)
+		return -EINVAL;
+
+	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_idx2, &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_i.h b/mt7996/mtk_mcu_i.h
index 38a007d..a61cb3d 100644
--- a/mt7996/mtk_mcu_i.h
+++ b/mt7996/mtk_mcu_i.h
@@ -10,6 +10,348 @@
 
 #ifdef CONFIG_MTK_DEBUG
 
+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 pp_fd_val;
+};
+
+#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
+};
 
 #endif
 
-- 
2.18.0

