[][MT76][HW ATF support for mt7986]

[Description]
Add HW ATF support for mt7986

[Release-log]
N/A


Change-Id: I893e96fd892497c93e787a28466b88b9d456da4c
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6754287
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/3011-mt76-HW-ATF-support-for-mt7986.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/3011-mt76-HW-ATF-support-for-mt7986.patch
new file mode 100755
index 0000000..ea175e0
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/3011-mt76-HW-ATF-support-for-mt7986.patch
@@ -0,0 +1,1015 @@
+From 8db1f707b2644b1ae0c0881502c811d3ddc00c72 Mon Sep 17 00:00:00 2001
+From: Lian Chen <lian.chen@mediatek.com>
+Date: Mon, 7 Nov 2022 14:47:44 +0800
+Subject: [PATCH] mt76: HW ATF support for mt7986
+
+Signed-off-by: Lian Chen <lian.chen@mediatek.com>
+---
+ mt76_connac_mcu.h    |   2 +
+ mt7915/debugfs.c     | 405 +++++++++++++++++++++++++++++++++++++++++++
+ mt7915/init.c        |  39 +++++
+ mt7915/main.c        |  16 ++
+ mt7915/mcu.c         | 165 ++++++++++++++++++
+ mt7915/mt7915.h      |  68 ++++++++
+ mt7915/mtk_debugfs.c | 133 +++++++++++++-
+ 7 files changed, 827 insertions(+), 1 deletion(-)
+ mode change 100755 => 100644 mt7915/debugfs.c
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index c7e28e3e..c2c17f06 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1117,6 +1117,7 @@ enum {
+ 	MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
+ 	MCU_EXT_CMD_WTBL_UPDATE = 0x32,
+ 	MCU_EXT_CMD_SET_DRR_CTRL = 0x36,
++	MCU_EXT_CMD_SET_FEATURE_CTRL = 0x38,
+ 	MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
+ 	MCU_EXT_CMD_ATE_CTRL = 0x3d,
+ 	MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
+@@ -1126,6 +1127,7 @@ enum {
+ 	MCU_EXT_CMD_MUAR_UPDATE = 0x48,
+ 	MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
+ 	MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a,
++	MCU_EXT_CMD_AT_PROC_MODULE = 0x4b,
+ 	MCU_EXT_CMD_SET_RX_PATH = 0x4e,
+ 	MCU_EXT_CMD_EFUSE_FREE_BLOCK = 0x4f,
+ 	MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
+diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
+old mode 100755
+new mode 100644
+index f585eb93..71eee310
+--- a/mt7915/debugfs.c
++++ b/mt7915/debugfs.c
+@@ -12,6 +12,10 @@
+ #define FW_BIN_LOG_MAGIC_V2	0x44d9c99a
+ #endif
+ 
++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
++#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
++
++
+ /** global debugfs **/
+ 
+ struct hw_queue_map {
+@@ -209,6 +213,406 @@ static const struct file_operations mt7915_fw_ser_ops = {
+ 	.llseek = default_llseek,
+ };
+ 
++static ssize_t mt7915_vow_get(struct file *file, char __user *user_buf,
++                              size_t count, loff_t *ppos)
++{
++	char *buff;
++	int desc = 0;
++	ssize_t ret;
++	static const size_t bufsz = 1000;
++
++	buff = kmalloc(bufsz, GFP_KERNEL);
++	if (!buff)
++		return -ENOMEM;
++
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "======== Control =============\n"
++			  "vow_atf_en=<0/1> 0:disable, 1:enable\n"
++			  "vow_watf_en=<0/1> 0:disable, 1:enable\n"
++			  "vow_watf_quantum=<level>-<quantum> unit 256us\n"
++			  "======== Station table =============\n"
++			  "vow_sta_dwrr_quantum_id=<wlanidx>-<WMM AC>-<Qid>\n"
++			  "vow_dwrr_max_wait_time=<time> 256us\n"
++			  "======== Debug =============\n"
++			  "vow_show_en=<0/1> 0:dieable, 1:enable\n"
++			  "vow_show_sta=<STA num>\n"
++			  "show_vow_info\n"
++			  "show_vow_sta_conf=<STA num> 0:all\n");
++	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
++	kfree(buff);
++	return ret;
++}
++
++static int mt7915_set_vow_sta_dwrr_quantum_id(struct mt7915_dev *dev,
++                                              u32 wcid_id,
++                                              u32 ac, u32 val)
++{
++	struct mt7915_sta *msta;
++	struct mt76_wcid *wcid;
++	int ret;
++
++	wcid = rcu_dereference(dev->mt76.wcid[wcid_id]);
++	if ((!wcid) || (!wcid->sta)) {
++		dev_err(dev->mt76.dev, "%s: error station.\n", __func__);
++		return 0;
++	}
++
++	msta = container_of(wcid, struct mt7915_sta, wcid);
++
++	msta->vow_sta_cfg.dwrr_quantum[ac] = val;
++
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_STA_AC0_QUA_ID + ac);
++	dev_info(dev->mt76.dev, "%s: set sta %d, ac %d, quantum id %u.\n",
++                 __func__, wcid_id, ac, val);
++
++	return ret;
++}
++
++static int mt7915_set_vow_atf_en(struct mt7915_dev *dev, u32 val)
++{
++	int ret;
++
++	dev->vow_cfg.vow_atf_en = !!val;
++	dev->vow_cfg.sta_max_wait_time = val ? 0x40 : 0x1;
++	ret = mt7915_mcu_set_vow_feature_ctrl(dev);
++        dev_info(dev->mt76.dev, "%s: set vow_atf_en %u.\n",
++                 __func__, val);
++
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++                                          VOW_DRR_AIRTIME_DEFICIT_BOUND);
++	dev_info(dev->mt76.dev, "%s: set vow_dwrr_max_wait_time %u.\n",
++                 __func__, dev->vow_cfg.sta_max_wait_time);
++
++	return ret;
++}
++
++static int mt7915_set_vow_dwrr_max_wait_time(struct mt7915_dev *dev,
++                                             u32 val)
++{
++	int ret;
++
++	dev->vow_cfg.sta_max_wait_time = val;
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++		                          VOW_DRR_AIRTIME_DEFICIT_BOUND);
++	dev_info(dev->mt76.dev, "%s: set vow_dwrr_max_wait_time %u.\n",
++		 __func__, val);
++
++	return ret;
++}
++
++static int mt7915_set_vow_watf_en(struct mt7915_dev *dev, u32 val)
++{
++	int ret;
++
++	dev->vow_cfg.vow_watf_en = !!val;
++	ret = mt7915_mcu_set_vow_feature_ctrl(dev);
++	dev_info(dev->mt76.dev, "%s: set vow_watf_en %u.\n", __func__, val);
++
++	return ret;
++}
++
++static int mt7915_set_vow_watf_quantum(struct mt7915_dev *dev,
++                                       u32 id, u32 val)
++{
++	int ret;
++
++	dev->vow_cfg.vow_sta_dwrr_quantum[id] = val;
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++				          VOW_DRR_AIRTIME_QUANTUM_L0 + id);
++	dev_info(dev->mt76.dev, "%s: set quantum id %u, val %d.\n",
++                 __func__, id, val);
++
++	return ret;
++}
++
++extern int mt7915_vow_pleinfo_read(struct mt7915_dev *dev);
++static void mt7915_show_station_tx_airtime(struct work_struct *work){
++	struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
++					      vow_work.work);
++	static u32 vow_last_tx_time[MT7916_WTBL_SIZE];
++	struct ieee80211_sta *ieee80211_sta;
++	struct mt7915_sta *msta;
++	struct mt76_wcid *wcid;
++	int idx = 0;
++	int i = 0;
++	u32 addr;
++	int tx_airtime_sum = 0;
++	int tx_add_airtime = 0;
++
++	if (!dev->vow_cfg.vow_show_en)
++		return;
++
++	rcu_read_lock();
++	for (idx = 1; (idx < dev->vow_cfg.vow_show_sta) &&
++	     (idx < MT7915_WTBL_STA); idx++) {
++		if (idx >= ARRAY_SIZE(dev->mt76.wcid))
++			return;
++
++		wcid = rcu_dereference(dev->mt76.wcid[idx]);
++		if (!wcid || !wcid->sta)
++			continue;
++
++		msta = container_of(wcid, struct mt7915_sta, wcid);
++		addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20);
++		tx_airtime_sum = 0;
++
++		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
++			tx_airtime_sum += mt76_rr(dev, addr);
++			addr += 8;
++		}
++		tx_add_airtime = tx_airtime_sum - vow_last_tx_time[idx];
++		vow_last_tx_time[idx] = tx_airtime_sum;
++
++		ieee80211_sta = container_of((void *)msta, struct ieee80211_sta,
++					     drv_priv);
++
++		dev_info(dev->mt76.dev, "sta%u:" MACSTR " tx -> %u)\n",
++                         idx, MAC2STR(ieee80211_sta->addr), tx_add_airtime);
++	}
++	mt7915_vow_pleinfo_read(dev);
++	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->vow_work, 1 * HZ);
++	rcu_read_unlock();
++	return;
++}
++
++
++static int mt7915_set_vow_show_en(struct mt7915_dev *dev, u32 val)
++{
++	if (!!dev->vow_cfg.vow_show_en == !!val)
++		return 0;
++	dev->vow_cfg.vow_show_en = val;
++	mt7915_mcu_set_vow_feature_ctrl(dev);
++	if (dev->vow_cfg.vow_show_en) {
++		INIT_DELAYED_WORK(&dev->vow_work, mt7915_show_station_tx_airtime);
++		ieee80211_queue_delayed_work(mt76_hw(dev), &dev->vow_work, 1 * HZ);
++	}
++	else {
++		cancel_delayed_work_sync(&dev->vow_work);
++	}
++	return 0;
++}
++
++static int mt7915_set_vow_show_sta(struct mt7915_dev *dev, u32 val)
++{
++	dev->vow_cfg.vow_show_sta = val;
++	dev_info(dev->mt76.dev, "%s: show station up to %d.\n",
++		 __func__, dev->vow_cfg.vow_show_sta);
++	return 0;
++}
++static int mt7915_set_show_vow_info(struct mt7915_dev *dev)
++{
++	dev_info(dev->mt76.dev, "====== VOW Control Information ======\n");
++	dev_info(dev->mt76.dev, "ATF Enbale: %d\n",
++                 dev->vow_cfg.vow_atf_en);
++	dev_info(dev->mt76.dev, "WATF Enable: %d\n",
++                 dev->vow_cfg.vow_watf_en);
++	dev_info(dev->mt76.dev, "refill_period: %d\n",
++                 dev->vow_cfg.refill_period);
++	dev_info(dev->mt76.dev, "===== VOW Max Deficit Information =====\n");
++	dev_info(dev->mt76.dev, "VOW Max Deficit(unit 256us): %d\n",
++                 dev->vow_cfg.sta_max_wait_time);
++	dev_info(dev->mt76.dev, "===== VOW Quantum Information =====\n");
++	dev_info(dev->mt76.dev, "Quantum ID 0 value(unit 256us): %d\n",
++                 dev->vow_cfg.vow_sta_dwrr_quantum[0]);
++	dev_info(dev->mt76.dev, "Quantum ID 1 value(unit 256us): %d\n",
++                 dev->vow_cfg.vow_sta_dwrr_quantum[1]);
++	dev_info(dev->mt76.dev, "Quantum ID 2 value(unit 256us): %d\n",
++                 dev->vow_cfg.vow_sta_dwrr_quantum[2]);
++	dev_info(dev->mt76.dev, "Quantum ID 3 value(unit 256us): %d\n",
++                 dev->vow_cfg.vow_sta_dwrr_quantum[3]);
++	return 0;
++}
++
++static int mt7915_show_vow_sta_conf(struct mt7915_dev *dev, u32 val)
++{
++	struct ieee80211_sta *ieee80211_sta;
++	struct mt7915_sta *msta;
++	struct mt76_wcid *wcid;
++	u32 i;
++	u8 q;
++
++	if (val > 0 && val < MT7915_WTBL_STA) {
++		wcid = rcu_dereference(dev->mt76.wcid[val]);
++		if (!wcid || !wcid->sta)
++			return 0;
++		msta = container_of(wcid, struct mt7915_sta, wcid);
++		ieee80211_sta = container_of((void *)msta, struct ieee80211_sta,
++					     drv_priv);
++		dev_info(dev->mt76.dev, "%s: ****** sta%d: "MACSTR"******\n",
++			 __func__, val, MAC2STR(ieee80211_sta->addr));
++		q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VO];
++		dev_info(dev->mt76.dev, "Ac0 --> %uus(%u)\n",
++			 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++		q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VI];
++		dev_info(dev->mt76.dev, "Ac1 --> %uus(%u)\n",
++			 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++		q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BE];
++		dev_info(dev->mt76.dev, "Ac2 --> %uus(%u)\n",
++			 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++		q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BK];
++		dev_info(dev->mt76.dev, "Ac3 --> %uus(%u)\n",
++			 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++	}
++	else{
++		for (i = 1; i < MT7915_WTBL_STA; i++) {
++			wcid = rcu_dereference(dev->mt76.wcid[i]);
++			if (!wcid || !wcid->sta)
++				continue;
++			msta = container_of(wcid, struct mt7915_sta, wcid);
++			ieee80211_sta = container_of((void *)msta, struct ieee80211_sta,
++						     drv_priv);
++			dev_info(dev->mt76.dev, "%s: ****** sta%d: "MACSTR"******\n",
++				 __func__, i, MAC2STR(ieee80211_sta->addr));
++			q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VO];
++			dev_info(dev->mt76.dev, "Ac0 --> %uus(%u)\n",
++				 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++			q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VI];
++			dev_info(dev->mt76.dev, "Ac1 --> %uus(%u)\n",
++				 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++			q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BE];
++			dev_info(dev->mt76.dev, "Ac2 --> %uus(%u)\n",
++				 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++			q = msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BK];
++			dev_info(dev->mt76.dev, "Ac3 --> %uus(%u)\n",
++				 (dev->vow_cfg.vow_sta_dwrr_quantum[q] << 8), q);
++		}
++	}
++	return 0;
++}
++
++static ssize_t
++mt7915_vow_set(struct file *file, const char __user *user_buf,
++		  size_t count, loff_t *ppos)
++{
++	struct mt7915_phy *phy = file->private_data;
++	struct mt7915_dev *dev = phy->dev;
++	u32 rv, param1, param2, param3;
++	char buf[128];
++	int ret = 0;
++
++	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';
++
++	if (!strncmp(buf, "vow_sta_dwrr_quantum_id",
++		strlen("vow_sta_dwrr_quantum_id")))
++	{
++		rv = sscanf(buf, "vow_sta_dwrr_quantum_id=%d-%d-%d",
++			    &param1, &param2, &param3);
++		if ((rv > 2) && (param2 < IEEE80211_NUM_ACS) &&
++                    (param3 < VOW_WATF_LEVEL_NUM)) {
++			ret = mt7915_set_vow_sta_dwrr_quantum_id(dev, param1,
++								 param2, param3);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_atf_en", strlen("vow_atf_en")))
++	{
++		rv = sscanf(buf, "vow_atf_en=%d", &param1);
++		if (rv > 0) {
++			ret = mt7915_set_vow_atf_en(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_dwrr_max_wait_time",
++		 strlen("vow_dwrr_max_wait_time")))
++	{
++		rv = sscanf(buf, "vow_dwrr_max_wait_time=%d", &param1);
++		if (rv > 0) {
++			ret = mt7915_set_vow_dwrr_max_wait_time(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_watf_en", strlen("vow_watf_en")))
++	{
++		rv = sscanf(buf, "vow_watf_en=%d", &param1);
++		if (rv > 0) {
++			ret = mt7915_set_vow_watf_en(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_watf_quantum",
++		 strlen("vow_watf_quantum")))
++	{
++		rv = sscanf(buf, "vow_watf_quantum=%d-%d",
++			    &param1, &param2);
++		if ((dev->vow_cfg.vow_watf_en) && (rv > 1) &&
++                    (param1 < VOW_WATF_LEVEL_NUM)) {
++			ret = mt7915_set_vow_watf_quantum(dev, param1, param2);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_show_en", strlen("vow_show_en")))
++	{
++		rv = sscanf(buf, "vow_show_en=%d", &param1);
++		if (rv > 0) {
++			ret = mt7915_set_vow_show_en(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "vow_show_sta", strlen("vow_show_sta")))
++	{
++		rv = sscanf(buf, "vow_show_sta=%d", &param1);
++		if ((rv > 0)&& (param1 < MT7915_WTBL_STA)) {
++			ret = mt7915_set_vow_show_sta(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "show_vow_info", strlen("show_vow_info")))
++	{
++		if (rv == 0) {
++			ret = mt7915_set_show_vow_info(dev);
++		}
++		else {
++			dev_err(dev->mt76.dev, "show_vow_info\n");
++			goto out;
++		}
++	}
++	else if (!strncmp(buf, "show_vow_sta_conf", strlen("show_vow_sta_conf")))
++	{
++		rv = sscanf(buf, "show_vow_sta_conf=%d", &param1);
++		if ((rv > 0) && (param1 < MT7915_WTBL_STA)) {
++			ret = mt7915_show_vow_sta_conf(dev, param1);
++		}
++		else {
++			goto out;
++		}
++	}
++
++	if (ret)
++		return ret;
++out:
++	return count;
++}
++
++static const struct file_operations mt7915_vow_ops = {
++	.write = mt7915_vow_set,
++	.read = mt7915_vow_get,
++	.open = simple_open,
++	.llseek = default_llseek,
++};
++
+ static int
+ mt7915_radar_trigger(void *data, u64 val)
+ {
+@@ -1109,6 +1513,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
+ 	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
+ 				    mt7915_twt_stats);
+ 	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
++	debugfs_create_file("vow", 0600, dir, phy, &mt7915_vow_ops);
+ 
+ 	if (!dev->dbdc_support || phy->band_idx) {
+ 		debugfs_create_u32("dfs_hw_pattern", 0400, dir,
+diff --git a/mt7915/init.c b/mt7915/init.c
+index eb62816b..01f41a7a 100755
+--- a/mt7915/init.c
++++ b/mt7915/init.c
+@@ -449,10 +449,46 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
+ 	mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
+ }
+ 
++void mt7915_vow_init(struct mt7915_dev *dev)
++{
++	struct mt7915_vow_cfg *vow_cfg = &dev->vow_cfg;
++	bool ret;
++	int i;
++
++	if (!(is_mt7915(&dev->mt76)))
++		vow_cfg->vow_feature |= VOW_FEATURE_BWCG;
++
++	vow_cfg->vow_atf_en = 0x1;
++	vow_cfg->sta_max_wait_time = 0x40;
++	vow_cfg->refill_period = 0x5;
++
++	vow_cfg->vow_sta_dwrr_quantum[0] = 0x06;
++	vow_cfg->vow_sta_dwrr_quantum[1] = 0x0c;
++	vow_cfg->vow_sta_dwrr_quantum[2] = 0x10;
++	vow_cfg->vow_sta_dwrr_quantum[3] = 0x14;
++	vow_cfg->vow_sta_dwrr_quantum[4] = 0x18;
++	vow_cfg->vow_sta_dwrr_quantum[5] = 0x1c;
++	vow_cfg->vow_sta_dwrr_quantum[6] = 0x20;
++	vow_cfg->vow_sta_dwrr_quantum[7] = 0x24;
++
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++					  VOW_DRR_AIRTIME_DEFICIT_BOUND);
++	ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++					  VOW_DRR_AIRTIME_QUANTUM_ALL);
++
++	for(i = 0; i < 4; i++)
++		ret = mt7915_mcu_set_vow_drr_ctrl(dev, NULL,
++						  VOW_DRR_AIRTIME_QUANTUM_L0 + i);
++
++	ret = mt7915_mcu_set_vow_feature_ctrl(dev);
++	return;
++}
++
+ void mt7915_mac_init(struct mt7915_dev *dev)
+ {
+ 	int i;
+ 	u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
++	struct wiphy *wiphy = dev->phy.mt76->hw->wiphy;
+ 
+ 	/* config pse qid6 wfdma port selection */
+ 	if (!is_mt7915(&dev->mt76) && dev->hif2)
+@@ -477,6 +513,9 @@ void mt7915_mac_init(struct mt7915_dev *dev)
+ 		i = dev->mt76.led_pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2;
+ 		mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4);
+ 	}
++
++	if (mt7915_is_atf_defult_on(wiphy, dev))
++		mt7915_vow_init(dev);
+ }
+ 
+ int mt7915_txbf_init(struct mt7915_dev *dev)
+diff --git a/mt7915/main.c b/mt7915/main.c
+index aa18e557..ca018766 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -196,6 +196,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
+ {
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
++	struct wiphy *wiphy = dev->phy.mt76->hw->wiphy;
+ 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ 	struct mt76_txq *mtxq;
+ 	bool ext_phy = phy != &dev->phy;
+@@ -265,6 +266,10 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
+ 	mt7915_mcu_add_sta(dev, vif, NULL, true);
+ 	rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
+ 
++	if (mt7915_is_atf_defult_on(wiphy, dev)) {
++		mt7915_mcu_set_vow_band(dev, mvif);
++	}
++
+ out:
+ 	mutex_unlock(&dev->mt76.mutex);
+ 
+@@ -683,6 +688,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ 	bool ext_phy = mvif->phy != &dev->phy;
++	struct wiphy *wiphy = dev->phy.mt76->hw->wiphy;
+ #ifdef CONFIG_MTK_VENDOR
+ 	struct mt7915_phy *phy;
+ #endif
+@@ -735,6 +741,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ 		mt7915_mcu_set_mimo(phy, 0);
+ 	}
+ #endif
++	if (mt7915_is_atf_defult_on(wiphy, dev)) {
++		msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VO] = 2;
++		msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VI] = 2;
++		msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BE] = 1;
++		msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BK] = 0;
++		mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_STA_BSS_GROUP);
++		mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_STA_PAUSE_SETTING);
++		mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_STA_ALL);
++	}
++
+ 	return 0;
+ }
+ 
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 4c42a575..a75e62bc 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -3378,6 +3378,171 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
+ 				 &req, sizeof(req), false);
+ }
+ 
++int mt7915_mcu_set_vow_drr_ctrl(struct mt7915_dev *dev,
++                                struct mt7915_sta *msta,
++                                u32 subcmd)
++{
++	u32 setting = 0;
++	u32 i;
++
++	struct {
++		__le32 action;
++		u8 wlan_idx_lo;
++		u8 status;
++		u8 wlan_idx_hi;
++		u8 rsv0[5];
++		union {
++			__le32 com_value;
++			struct {
++				u8 air_time_quantum[VOW_MAX_STA_DWRR_NUM];
++			}air_time_quantum_all;
++		}air_time_ctrl;
++	} __packed req = {
++		.action = cpu_to_le32(subcmd),
++		.wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : to_wcid_lo(0x0),
++		.wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : to_wcid_hi(0x0),
++	};
++
++	switch (subcmd) {
++		case VOW_DRR_STA_ALL:{
++			setting |= 0x00;
++			setting |= msta->vif->mt76.idx;
++			setting |= msta->vow_sta_cfg.ac_change_rule << 4;
++			setting |= (msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VO] << 8);
++			setting |= (msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VI] << 12);
++			setting |= (msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BE] << 16);
++			setting |= (msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BK] << 20);
++			if (dev->vow_cfg.vow_feature & VOW_FEATURE_BWCG)
++                                setting |= ((UMAC_BWC_GROUP_MIN) << 24);
++			req.air_time_ctrl.com_value = cpu_to_le32(setting);
++			break;
++		}
++
++		case VOW_DRR_STA_BSS_GROUP:
++			req.air_time_ctrl.com_value = cpu_to_le32(0x0);
++			break;
++
++		case VOW_DRR_STA_PAUSE_SETTING:
++			req.air_time_ctrl.com_value = cpu_to_le32(msta->vow_sta_cfg.paused);
++			break;
++
++		case VOW_DRR_STA_AC0_QUA_ID:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VO]);
++			break;
++
++		case VOW_DRR_STA_AC1_QUA_ID:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_VI]);
++			break;
++
++		case VOW_DRR_STA_AC2_QUA_ID:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BE]);
++			break;
++
++		case VOW_DRR_STA_AC3_QUA_ID:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(msta->vow_sta_cfg.dwrr_quantum[IEEE80211_AC_BK]);
++			break;
++
++		case VOW_DRR_AIRTIME_DEFICIT_BOUND:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(dev->vow_cfg.sta_max_wait_time);
++			break;
++
++		case VOW_DRR_AIRTIME_QUANTUM_L0:
++		case VOW_DRR_AIRTIME_QUANTUM_L1:
++		case VOW_DRR_AIRTIME_QUANTUM_L2:
++		case VOW_DRR_AIRTIME_QUANTUM_L3:
++		case VOW_DRR_AIRTIME_QUANTUM_L4:
++		case VOW_DRR_AIRTIME_QUANTUM_L5:
++		case VOW_DRR_AIRTIME_QUANTUM_L6:
++		case VOW_DRR_AIRTIME_QUANTUM_L7:
++			req.air_time_ctrl.com_value =
++				cpu_to_le32(dev->vow_cfg.vow_sta_dwrr_quantum[subcmd -
++				            VOW_DRR_AIRTIME_QUANTUM_L0]);
++			break;
++
++		case VOW_DRR_AIRTIME_QUANTUM_ALL: {
++			for (i = 0; i < VOW_MAX_STA_DWRR_NUM; i++) {
++				req.air_time_ctrl.air_time_quantum_all.air_time_quantum[i] =
++					dev->vow_cfg.vow_sta_dwrr_quantum[i];
++			}
++			break;
++		}
++
++		default:
++			break;
++	}
++
++	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL),
++				 &req, sizeof(req), false);
++}
++
++int mt7915_mcu_set_vow_feature_ctrl(struct mt7915_dev *dev)
++{
++	u16 value = 0;
++	u32 sch_value = 0;
++
++	struct vow_feature_ctrl {
++		__le16 bss_flag;
++		__le16 vow_ctrl_flag;
++		__le16 bss_value[9];
++		__le16 vow_ctrl_val;
++		__le16 time_token_value[2];
++                __le16 length_token_value[2];
++		__le32 tx_ctrl;
++		__le32 sch_ctrl;
++	} __packed req = {
++		.bss_flag = cpu_to_le16(0xffff),
++		.vow_ctrl_flag = cpu_to_le16(0xf231),
++		.bss_value[0] = cpu_to_le16(0xffff),
++		.bss_value[2] = cpu_to_le16(0xffff),
++		.bss_value[8] = cpu_to_le16(0xffff),
++		.time_token_value[0] = cpu_to_le16(0xffff),
++	};
++
++	value |= dev->vow_cfg.refill_period;
++	value |= 1 << 4;
++	value |= 1 << 5;
++	value |= dev->vow_cfg.vow_watf_en << 9;
++	value |= 1 << 12;
++	value |= dev->vow_cfg.vow_atf_en << 13;
++	value |= 1 << 14;
++	req.vow_ctrl_val = value;
++	if (dev->vow_cfg.vow_atf_en)
++		req.tx_ctrl = cpu_to_le32(0x6bf69e1f);
++	sch_value |= 1 << 6;
++	sch_value |= (((dev->vow_cfg.vow_show_en == 0) ? 0 :
++                      (dev->vow_cfg.vow_show_en - 1 )) << 4);
++	req.sch_ctrl = sch_value;
++
++	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_FEATURE_CTRL),
++							 &req, sizeof(req), false);
++}
++
++int mt7915_mcu_set_vow_band(struct mt7915_dev *dev, struct mt7915_vif *mvif)
++{
++	struct module_ctrl {
++		__le16 action;
++		__le16 sub_action;
++		__le32 rsv1[5];
++		u8 rsv2[72];
++		u8 group_idx;
++		u8 band_idx;
++		u8 rsv3[2];
++	} __packed req = {
++		.action = cpu_to_le16(0x1),
++		.sub_action = cpu_to_le16(0x4),
++		.group_idx = mvif->mt76.band_idx * 4 + mvif->mt76.omac_idx % 4,
++		.band_idx = mvif->mt76.band_idx,
++	};
++
++	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(AT_PROC_MODULE),
++				 &req, sizeof(req), false);
++}
++
+ int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
+ {
+ 	struct {
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 2874afa9..f708246f 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -129,6 +129,58 @@ struct mt7915_twt_flow {
+ 	u8 sched:1;
+ };
+ 
++#define VOW_MAX_STA_DWRR_NUM    8
++#define VOW_WATF_LEVEL_NUM      4
++#define VOW_FEATURE_BWCG        BIT(3)
++#define UMAC_BWC_GROUP_MIN      40
++
++
++enum ext_cmd_vow_drr_ctrl {
++	/* Type 1 */
++	VOW_DRR_STA_ALL             	= 0x00,
++	VOW_DRR_STA_BSS_GROUP           = 0x01,
++	VOW_DRR_STA_AC0_QUA_ID      	= 0x03,
++	VOW_DRR_STA_AC1_QUA_ID      	= 0x04,
++	VOW_DRR_STA_AC2_QUA_ID      	= 0x05,
++	VOW_DRR_STA_AC3_QUA_ID      	= 0x06,
++
++	/* Type 2 */
++	VOW_DRR_AIRTIME_DEFICIT_BOUND   = 0x10,
++
++	/* Type 3 */
++	VOW_DRR_AIRTIME_QUANTUM_L0  	= 0x20,
++	VOW_DRR_AIRTIME_QUANTUM_L1  	= 0x21,
++	VOW_DRR_AIRTIME_QUANTUM_L2  	= 0x22,
++	VOW_DRR_AIRTIME_QUANTUM_L3  	= 0x23,
++	VOW_DRR_AIRTIME_QUANTUM_L4  	= 0x24,
++	VOW_DRR_AIRTIME_QUANTUM_L5  	= 0x25,
++	VOW_DRR_AIRTIME_QUANTUM_L6  	= 0x26,
++	VOW_DRR_AIRTIME_QUANTUM_L7  	= 0x27,
++	VOW_DRR_AIRTIME_QUANTUM_ALL 	= 0x28,
++	VOW_DRR_STA_PAUSE_SETTING       = 0x30,
++};
++
++struct mt7915_vow_sta_cfg{
++	u8 dwrr_quantum[IEEE80211_NUM_ACS];
++	u8 ac_change_rule;
++	bool paused;
++};
++
++struct mt7915_vow_cfg{
++	/*ATF setting */
++	u32  vow_feature;
++	bool vow_atf_en;
++	u8   refill_period;
++	u8   sta_max_wait_time;
++	u8   vow_sta_dwrr_quantum[VOW_MAX_STA_DWRR_NUM];
++	u8   vow_show_en;
++	u32  vow_show_sta;
++
++	/*WATF setting */
++	bool	vow_watf_en;
++};
++
++
+ struct mt7915_sta {
+ 	struct mt76_wcid wcid; /* must be first */
+ 
+@@ -148,6 +200,7 @@ struct mt7915_sta {
+ 		u8 flowid_mask;
+ 		struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT];
+ 	} twt;
++	struct mt7915_vow_sta_cfg vow_sta_cfg;
+ };
+ 
+ struct mt7915_vif_cap {
+@@ -444,6 +497,8 @@ struct mt7915_dev {
+ 	} dbg;
+ 	const struct mt7915_dbg_reg_desc *dbg_reg;
+ #endif
++	struct delayed_work vow_work;
++	struct mt7915_vow_cfg vow_cfg;
+ };
+ 
+ enum {
+@@ -482,6 +537,15 @@ enum mt7915_rdd_cmd {
+ 	RDD_IRQ_OFF,
+ };
+ 
++static inline bool
++mt7915_is_atf_defult_on(struct wiphy *wiphy, struct mt7915_dev *dev)
++{
++	return ((!wiphy_ext_feature_isset(wiphy,
++                NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) ||
++                mtk_wed_device_active(&dev->mt76.mmio.wed));
++}
++
++
+ static inline struct mt7915_phy *
+ mt7915_hw_phy(struct ieee80211_hw *hw)
+ {
+@@ -614,6 +678,10 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
+ int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
+ 			      u8 en);
+ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
++int mt7915_mcu_set_vow_drr_ctrl(struct mt7915_dev *dev, struct mt7915_sta *msta,
++                                u32 subcmd);
++int mt7915_mcu_set_vow_feature_ctrl(struct mt7915_dev *dev);
++int mt7915_mcu_set_vow_band(struct mt7915_dev *dev, struct mt7915_vif *mvif);
+ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
+ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
+ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len);
+diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
+index 41bd0ff1..12251d91 100644
+--- a/mt7915/mtk_debugfs.c
++++ b/mt7915/mtk_debugfs.c
+@@ -1300,7 +1300,6 @@ static EMPTY_QUEUE_INFO_T ple_txcmd_queue_empty_info[] = {
+ };
+ 
+ 
+-
+ static char* sta_ctrl_reg[] = {"ENABLE", "DISABLE", "PAUSE"};
+ static u32 chip_show_sta_acq_info(struct seq_file *s, struct mt7915_dev *dev, u32 *ple_stat,
+ 				  u32 *sta_pause, u32 *dis_sta_map,
+@@ -1454,6 +1453,138 @@ static void chip_get_sta_pause(struct mt7915_dev *dev, u32 *sta_pause)
+ 	}
+ }
+ 
++u32 vow_chip_show_sta_acq_info(struct mt7915_dev *dev, u32 *ple_stat,
++			       u32 *sta_pause, u32 *dis_sta_map,
++			       u32 dumptxd)
++{
++	int i, j;
++	u32 total_nonempty_cnt = 0;
++	u32 ac_num = 9, all_ac_num;
++	static char* sta_ctrl_reg[] = {"ENABLE", "DISABLE", "PAUSE"};
++	if (!is_mt7915(&dev->mt76))
++		ac_num = 17;
++
++	all_ac_num = ac_num * 4;
++
++	for (j = 0; j < all_ac_num; j++) { /* show AC Q info */
++		for (i = 0; i < 32; i++) {
++			if (((ple_stat[j + 1] & (0x1 << i)) >> i) == 0) {
++				u32 hfid, tfid, pktcnt, ac_n = j / ac_num, ctrl = 0;
++				u32 sta_num = i + (j % ac_num) * 32, fl_que_ctrl[3] = {0};
++				u32 wmmidx = 0;
++				struct mt7915_sta *msta;
++				struct mt76_wcid *wcid;
++				struct ieee80211_sta *sta = NULL;
++
++				wcid = rcu_dereference(dev->mt76.wcid[sta_num]);
++				sta = wcid_to_sta(wcid);
++				if (!sta) {
++					printk("ERROR!! no found STA wcid=%d\n", sta_num);
++					continue;
++				}
++				msta = container_of(wcid, struct mt7915_sta, wcid);
++				wmmidx = msta->vif->mt76.wmm_idx;
++
++				dev_info(dev->mt76.dev, "\tSTA%d AC%d: ", sta_num, ac_n);
++
++				fl_que_ctrl[0] |= MT_DBG_PLE_FL_QUE_CTRL0_EXECUTE_MASK;
++				fl_que_ctrl[0] |= (ENUM_UMAC_LMAC_PORT_2 <<
++						   MT_PLE_FL_QUE_CTRL0_Q_BUF_PID_SHFT);
++				fl_que_ctrl[0] |= (ac_n << MT_PLE_FL_QUE_CTRL0_Q_BUF_QID_SHFT);
++				fl_que_ctrl[0] |= sta_num;
++				mt76_wr(dev, MT_DBG_PLE_FL_QUE_CTRL0, fl_que_ctrl[0]);
++				fl_que_ctrl[1] = mt76_rr(dev, MT_DBG_PLE_FL_QUE_CTRL2);
++				fl_que_ctrl[2] = mt76_rr(dev, MT_DBG_PLE_FL_QUE_CTRL3);
++				hfid = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL2_Q_HEAD_FID_MASK,
++						 fl_que_ctrl[1]);
++				tfid = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL2_Q_TAIL_FID_MASK,
++						 fl_que_ctrl[1]);
++				pktcnt = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL3_Q_PKT_NUM_MASK,
++						   fl_que_ctrl[2]);
++				dev_info(dev->mt76.dev, "tail/head fid = 0x%03x/0x%03x, pkt cnt = 0x%03x",
++					 tfid, hfid, pktcnt);
++
++				if (((sta_pause[j % 6] & 0x1 << i) >> i) == 1)
++					ctrl = 2;
++
++				if (((dis_sta_map[j % 6] & 0x1 << i) >> i) == 1)
++					ctrl = 1;
++
++				dev_info(dev->mt76.dev, " ctrl = %s", sta_ctrl_reg[ctrl]);
++				dev_info(dev->mt76.dev, " (wmmidx=%d)\n", wmmidx);
++
++				total_nonempty_cnt++;
++			}
++		}
++	}
++
++	return total_nonempty_cnt;
++}
++
++int mt7915_vow_pleinfo_read(struct mt7915_dev *dev)
++{
++	u32 ple_stat[70] = {0}, pg_flow_ctrl[8] = {0};
++	u32 ple_txcmd_stat;
++	u32 sta_pause[CR_NUM_OF_AC] = {0}, dis_sta_map[CR_NUM_OF_AC] = {0};
++	int i;
++
++	chip_get_ple_acq_stat(dev, ple_stat);
++	ple_txcmd_stat = mt76_rr(dev, MT_DBG_PLE_TXCMD_Q_EMPTY);
++	pg_flow_ctrl[0] = mt76_rr(dev, MT_DBG_PLE_FREEPG_CNT);
++	pg_flow_ctrl[1] = mt76_rr(dev, MT_DBG_PLE_FREEPG_HEAD_TAIL);
++	pg_flow_ctrl[2] = mt76_rr(dev, MT_DBG_PLE_PG_HIF_GROUP);
++	pg_flow_ctrl[3] = mt76_rr(dev, MT_DBG_PLE_HIF_PG_INFO);
++	pg_flow_ctrl[4] = mt76_rr(dev, MT_DBG_PLE_PG_CPU_GROUP);
++	pg_flow_ctrl[5] = mt76_rr(dev, MT_DBG_PLE_CPU_PG_INFO);
++	pg_flow_ctrl[6] = mt76_rr(dev, MT_DBG_PLE_PG_HIF_TXCMD_GROUP);
++	pg_flow_ctrl[7] = mt76_rr(dev, MT_DBG_PLE_HIF_TXCMD_PG_INFO);
++	chip_get_dis_sta_map(dev, dis_sta_map);
++	chip_get_sta_pause(dev, sta_pause);
++
++	dev_info(dev->mt76.dev, "PLE Configuration Info:\n");
++
++	for (i = 0; i < 32; i++) {
++		if (((ple_stat[0] & (0x1 << i)) >> i) == 0) {
++			u32 hfid, tfid, pktcnt, fl_que_ctrl[3] = {0};
++
++			if (ple_queue_empty_info[i].QueueName != NULL) {
++				fl_que_ctrl[0] |= MT_DBG_PLE_FL_QUE_CTRL0_EXECUTE_MASK;
++				fl_que_ctrl[0] |= (ple_queue_empty_info[i].Portid <<
++						   MT_PLE_FL_QUE_CTRL0_Q_BUF_PID_SHFT);
++				fl_que_ctrl[0] |= (ple_queue_empty_info[i].Queueid <<
++						   MT_PLE_FL_QUE_CTRL0_Q_BUF_QID_SHFT);
++			} else
++				continue;
++
++			if (ple_queue_empty_info[i].Queueid >=
++			    ENUM_UMAC_LMAC_PLE_TX_Q_ALTX_0 &&
++		            ple_queue_empty_info[i].Queueid <=
++			    ENUM_UMAC_LMAC_PLE_TX_Q_PSMP_0)
++			    /* band0 set TGID 0, bit31 = 0 */
++			    mt76_wr(dev, MT_DBG_PLE_FL_QUE_CTRL1, 0x0);
++			else if (ple_queue_empty_info[i].Queueid >=
++				 ENUM_UMAC_LMAC_PLE_TX_Q_ALTX_1 &&
++				 ple_queue_empty_info[i].Queueid <=
++				 ENUM_UMAC_LMAC_PLE_TX_Q_PSMP_1)
++				/* band1 set TGID 1, bit31 = 1 */
++				mt76_wr(dev, MT_DBG_PLE_FL_QUE_CTRL1, 0x80000000);
++
++			mt76_wr(dev, MT_DBG_PLE_FL_QUE_CTRL0, fl_que_ctrl[0]);
++			fl_que_ctrl[1] = mt76_rr(dev, MT_DBG_PLE_FL_QUE_CTRL2);
++			fl_que_ctrl[2] = mt76_rr(dev, MT_DBG_PLE_FL_QUE_CTRL3);
++			hfid = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL2_Q_HEAD_FID_MASK,
++					 fl_que_ctrl[1]);
++			tfid = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL2_Q_TAIL_FID_MASK,
++					 fl_que_ctrl[1]);
++			pktcnt = FIELD_GET(MT_DBG_PLE_FL_QUE_CTRL3_Q_PKT_NUM_MASK,
++					   fl_que_ctrl[2]);
++		}
++	}
++
++	vow_chip_show_sta_acq_info(dev, ple_stat, sta_pause, dis_sta_map, 0);
++
++	return 0;
++}
+ static int mt7915_pleinfo_read(struct seq_file *s, void *data)
+ {
+ 	struct mt7915_dev *dev = dev_get_drvdata(s->private);
+-- 
+2.18.0
+