[][kernel][mt7987][eth][Add QDMAv1.4 support for the NETSYS v3.1]

[Description]
Add QDMAv1.4 support for the NETSYS v3.1.

This patch not only supports QDMAv1.4 but also relocates the QDMA
relavate functions to the ETH driver for future maintenance.

[Release-log]
N/A


Change-Id: I3317939ed08a6a1087beee80135057a66e885c7d
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9748202
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index 0f95a0a..f48720a 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -65,6 +65,394 @@
 
 struct mtk_eth_debug eth_debug;
 
+void qdma_qos_shaper_ebl(u32 id, bool enable)
+{
+	struct mtk_eth *eth = g_eth;
+	u32 val;
+
+	mtk_w32(eth, (id / MTK_QTX_PER_PAGE), MTK_QDMA_PAGE);
+	if (enable) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4)) {
+			val = MTK_QTX_SCH_MIN_RATE_EN | MTK_QTX_SCH_MAX_RATE_EN_V2;
+			val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V2, 1) |
+			       FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V2, 4) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V2, 1) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V2, 6) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V2, 4);
+		} else {
+			val = MTK_QTX_SCH_MIN_RATE_EN | MTK_QTX_SCH_MAX_RATE_EN;
+			val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+			       FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 6) |
+			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 4);
+		}
+
+		mtk_w32(eth, val, MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+	} else {
+		mtk_w32(eth, 0, MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+	}
+}
+
+void qdma_qos_disable(void)
+{
+	struct mtk_eth *eth = g_eth;
+	u32 num_of_sch = !MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1) ? 4 : 2;
+	u32 val, i;
+
+	for (i = 0; i < MAX_PPPQ_PORT_NUM; i++) {
+		qdma_qos_shaper_ebl(i, false);
+		mtk_w32(eth,
+			FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, 4) |
+			FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, 4),
+			MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+	}
+
+	val = (MTK_QDMA_TX_SCH_MAX_WFQ) | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
+	for (i = 0; i < num_of_sch; i += 2) {
+		if (num_of_sch == 4)
+			mtk_w32(eth, val, MTK_QDMA_TX_4SCH_BASE(i));
+		else
+			mtk_w32(eth, val, MTK_QDMA_TX_2SCH_BASE);
+	}
+}
+EXPORT_SYMBOL(qdma_qos_disable);
+
+void qdma_qos_pppq_ebl(u32 enable)
+{
+	struct mtk_eth *eth = g_eth;
+	u32 num_of_sch = !MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1) ? 4 : 2;
+	u32 val, i;
+
+	for (i = 0; i < MAX_PPPQ_PORT_NUM; i++) {
+		if (enable)
+			qdma_qos_shaper_ebl(i, true);
+		else
+			qdma_qos_shaper_ebl(i, false);
+
+		mtk_w32(eth,
+			FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, 4) |
+			FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, 4),
+			MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+	}
+
+	val = (MTK_QDMA_TX_SCH_MAX_WFQ) | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
+	for (i = 0; i < num_of_sch; i += 2) {
+		if (num_of_sch == 4)
+			mtk_w32(eth, val, MTK_QDMA_TX_4SCH_BASE(i));
+		else
+			mtk_w32(eth, val, MTK_QDMA_TX_2SCH_BASE);
+	}
+}
+EXPORT_SYMBOL(qdma_qos_pppq_ebl);
+
+static ssize_t qdma_sched_show(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct mtk_eth *eth = g_eth;
+	long id = (long)file->private_data;
+	char *buf;
+	unsigned int len = 0, buf_len = 1500;
+	u32 qdma_tx_sch, sch_reg;
+	int enable, scheduling, max_rate, scheduler, i;
+	ssize_t ret_cnt;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+		qdma_tx_sch = mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(id));
+	else
+		qdma_tx_sch = mtk_r32(eth, MTK_QDMA_TX_2SCH_BASE);
+
+	if (id & 0x1)
+		qdma_tx_sch >>= 16;
+
+	qdma_tx_sch &= MTK_QDMA_TX_SCH_MASK;
+	enable = FIELD_GET(MTK_QDMA_TX_SCH_RATE_EN, qdma_tx_sch);
+	scheduling = FIELD_GET(MTK_QDMA_TX_SCH_MAX_WFQ, qdma_tx_sch);
+	max_rate = FIELD_GET(MTK_QDMA_TX_SCH_RATE_MAN, qdma_tx_sch);
+	qdma_tx_sch = FIELD_GET(MTK_QDMA_TX_SCH_RATE_EXP, qdma_tx_sch);
+	while (qdma_tx_sch--)
+		max_rate *= 10;
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "EN\tScheduling\tMAX\tQueue#\n%d\t%s%16d\t", enable,
+			 (scheduling == 1) ? "WRR" : "SP", max_rate);
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		mtk_w32(eth, (i / MTK_QTX_PER_PAGE), MTK_QDMA_PAGE);
+		sch_reg = mtk_r32(eth, MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+		if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+			scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL_V2, sch_reg);
+		else
+			scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL, sch_reg);
+		if (id == scheduler)
+			len += scnprintf(buf + len, buf_len - len, "%d  ", i);
+	}
+
+	len += scnprintf(buf + len, buf_len - len, "\n");
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+
+	return ret_cnt;
+}
+
+static ssize_t qdma_sched_write(struct file *file, const char __user *buf,
+				size_t length, loff_t *offset)
+{
+	struct mtk_eth *eth = g_eth;
+	long id = (long)file->private_data;
+	char line[64] = {0}, scheduling[32];
+	int enable, rate, exp = 0, shift = 0;
+	size_t size;
+	u32 qdma_tx_sch, val = 0;
+
+	if (length >= sizeof(line))
+		return -EINVAL;
+
+	if (copy_from_user(line, buf, length))
+		return -EFAULT;
+
+	if (sscanf(line, "%1d %3s %9d", &enable, scheduling, &rate) != 3)
+		return -EFAULT;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_3) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4)) {
+		if (rate > 10000000 || rate < 0)
+			return -EINVAL;
+	} else {
+		if (rate > 1000000 || rate < 0)
+			return -EINVAL;
+	}
+
+	while (rate > 127) {
+		rate /= 10;
+		exp++;
+	}
+
+	line[length] = '\0';
+
+	if (enable)
+		val |= MTK_QDMA_TX_SCH_RATE_EN;
+	if (strcmp(scheduling, "sp") != 0)
+		val |= MTK_QDMA_TX_SCH_MAX_WFQ;
+	val |= FIELD_PREP(MTK_QDMA_TX_SCH_RATE_MAN, rate);
+	val |= FIELD_PREP(MTK_QDMA_TX_SCH_RATE_EXP, exp);
+	if (id & 0x1)
+		shift = 16;
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+		qdma_tx_sch = mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(id));
+	else
+		qdma_tx_sch = mtk_r32(eth, MTK_QDMA_TX_2SCH_BASE);
+
+	qdma_tx_sch &= ~(MTK_QDMA_TX_SCH_MASK << shift);
+	qdma_tx_sch |= val << shift;
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+		mtk_w32(eth, qdma_tx_sch, MTK_QDMA_TX_4SCH_BASE(id));
+	else
+		mtk_w32(eth, qdma_tx_sch, MTK_QDMA_TX_2SCH_BASE);
+
+	size = strlen(line);
+	*offset += size;
+
+	return length;
+}
+
+static const struct file_operations qdma_sched_fops = {
+	.open = simple_open,
+	.read = qdma_sched_show,
+	.write = qdma_sched_write,
+	.llseek = default_llseek,
+};
+
+static ssize_t qdma_queue_show(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct mtk_eth *eth = g_eth;
+	long id = (long)file->private_data;
+	char *buf;
+	unsigned int len = 0, buf_len = 1500;
+	u32 qtx_sch, qtx_cfg;
+	int scheduler;
+	int min_rate_en, min_rate, min_rate_exp;
+	int max_rate_en, max_weight, max_rate, max_rate_exp;
+	ssize_t ret_cnt;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	mtk_w32(eth, (id / MTK_QTX_PER_PAGE), MTK_QDMA_PAGE);
+	qtx_cfg = mtk_r32(eth, MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+	qtx_sch = mtk_r32(eth, MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+		scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL_V2, qtx_sch);
+	else
+		scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL, qtx_sch);
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4)) {
+		min_rate_en = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EN, qtx_sch);
+		min_rate = FIELD_GET(MTK_QTX_SCH_MIN_RATE_MAN_V2, qtx_sch);
+		min_rate_exp = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EXP_V2, qtx_sch);
+		max_rate_en = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EN_V2, qtx_sch);
+		max_weight = FIELD_GET(MTK_QTX_SCH_MAX_RATE_WEIGHT_V2, qtx_sch);
+		max_rate = FIELD_GET(MTK_QTX_SCH_MAX_RATE_MAN_V2, qtx_sch);
+		max_rate_exp = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EXP_V2, qtx_sch);
+	} else {
+		min_rate_en = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EN, qtx_sch);
+		min_rate = FIELD_GET(MTK_QTX_SCH_MIN_RATE_MAN, qtx_sch);
+		min_rate_exp = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EXP, qtx_sch);
+		max_rate_en = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EN, qtx_sch);
+		max_weight = FIELD_GET(MTK_QTX_SCH_MAX_RATE_WEIGHT, qtx_sch);
+		max_rate = FIELD_GET(MTK_QTX_SCH_MAX_RATE_MAN, qtx_sch);
+		max_rate_exp = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EXP, qtx_sch);
+	}
+	while (min_rate_exp--)
+		min_rate *= 10;
+
+	while (max_rate_exp--)
+		max_rate *= 10;
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "scheduler: %d\nhw resv: %d\nsw resv: %d\n", scheduler,
+			 (qtx_cfg >> 8) & 0xff, qtx_cfg & 0xff);
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1)) {
+		/* Switch to debug mode */
+		mtk_m32(eth, MTK_MIB_ON_QTX_CFG, MTK_MIB_ON_QTX_CFG, MTK_QTX_MIB_IF);
+		mtk_m32(eth, MTK_VQTX_MIB_EN, MTK_VQTX_MIB_EN, MTK_QTX_MIB_IF);
+		qtx_cfg = mtk_r32(eth, MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+		qtx_sch = mtk_r32(eth, MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+		len += scnprintf(buf + len, buf_len - len,
+				 "packet count: %u\n", qtx_cfg);
+		len += scnprintf(buf + len, buf_len - len,
+				 "packet drop: %u\n\n", qtx_sch);
+
+		/* Recover to normal mode */
+		mtk_m32(eth, MTK_MIB_ON_QTX_CFG, 0, MTK_QTX_MIB_IF);
+		mtk_m32(eth, MTK_VQTX_MIB_EN, 0, MTK_QTX_MIB_IF);
+	}
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "      EN     RATE     WEIGHT\n");
+	len += scnprintf(buf + len, buf_len - len,
+			 "----------------------------\n");
+	len += scnprintf(buf + len, buf_len - len,
+			 "max%5d%9d%9d\n", max_rate_en, max_rate, max_weight);
+	len += scnprintf(buf + len, buf_len - len,
+			 "min%5d%9d        -\n", min_rate_en, min_rate);
+
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+
+	return ret_cnt;
+}
+
+static ssize_t qdma_queue_write(struct file *file, const char __user *buf,
+				size_t length, loff_t *offset)
+{
+	struct mtk_eth *eth = g_eth;
+	long id = (long)file->private_data;
+	char line[64] = {0};
+	int max_enable, max_rate, max_exp = 0;
+	int min_enable, min_rate, min_exp = 0;
+	int weight;
+	int resv;
+	int scheduler;
+	size_t size;
+	u32 qtx_sch = 0;
+
+	mtk_w32(eth, (id / MTK_QTX_PER_PAGE), MTK_QDMA_PAGE);
+	if (length >= sizeof(line))
+		return -EINVAL;
+
+	if (copy_from_user(line, buf, length))
+		return -EFAULT;
+
+	if (sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate,
+		   &max_enable, &max_rate, &weight, &resv) != 7)
+		return -EFAULT;
+
+	line[length] = '\0';
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_3) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4)) {
+		if (max_rate > 10000000 || max_rate < 0 ||
+		    min_rate > 10000000 || min_rate < 0)
+			return -EINVAL;
+	} else {
+		if (max_rate > 1000000 || max_rate < 0 ||
+		    min_rate > 1000000 || min_rate < 0)
+			return -EINVAL;
+	}
+
+	while (max_rate > 127) {
+		max_rate /= 10;
+		max_exp++;
+	}
+
+	while (min_rate > 127) {
+		min_rate /= 10;
+		min_exp++;
+	}
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1))
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_TX_SEL_V2, scheduler);
+	else
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_TX_SEL, scheduler);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4)) {
+		if (min_enable)
+			qtx_sch |= MTK_QTX_SCH_MIN_RATE_EN;
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V2, min_rate);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V2, min_exp);
+		if (max_enable)
+			qtx_sch |= MTK_QTX_SCH_MAX_RATE_EN_V2;
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V2, weight);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V2, max_rate);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V2, max_exp);
+	} else {
+		if (min_enable)
+			qtx_sch |= MTK_QTX_SCH_MIN_RATE_EN;
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, min_rate);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, min_exp);
+		if (max_enable)
+			qtx_sch |= MTK_QTX_SCH_MAX_RATE_EN;
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, weight);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, max_rate);
+		qtx_sch |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, max_exp);
+	}
+	mtk_w32(eth, qtx_sch, MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+
+	qtx_sch = mtk_r32(eth, MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+	qtx_sch &= 0xffff0000;
+	qtx_sch |= FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, resv);
+	qtx_sch |= FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, resv);
+	mtk_w32(eth, qtx_sch, MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+
+	size = strlen(line);
+	*offset += size;
+
+	return length;
+}
+
+static const struct file_operations qdma_queue_fops = {
+	.open = simple_open,
+	.read = qdma_queue_show,
+	.write = qdma_queue_write,
+	.llseek = default_llseek,
+};
+
 int mt798x_iomap(void)
 {
 	struct device_node *np = NULL;
@@ -800,6 +1188,8 @@
 
 int mtketh_debugfs_init(struct mtk_eth *eth)
 {
+	char name[16];
+	long i;
 	int ret = 0;
 
 	eth_debug.root = debugfs_create_dir("mtketh", NULL);
@@ -828,6 +1218,31 @@
 				    eth_debug.root, eth,
 				    &fops_mt7530sw_reg_w);
 	}
+
+	for (i = 0; i < (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_1) ? 4 : 2); i++) {
+		ret = snprintf(name, sizeof(name), "qdma_sch%ld", i);
+		if (ret != strlen(name)) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		debugfs_create_file(name, 0444, eth_debug.root, (void *)i,
+				    &qdma_sched_fops);
+	}
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		ret = snprintf(name, sizeof(name), "qdma_txq%ld", i);
+		if (ret != strlen(name)) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		debugfs_create_file(name, 0444, eth_debug.root, (void *)i,
+				    &qdma_queue_fops);
+	}
+
+	return 0;
+
+err:
+	debugfs_remove_recursive(eth_debug.root);
 	return ret;
 }
 
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
index 9887835..3c0a9ef 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
@@ -106,6 +106,8 @@
 #define PROCREG_HW_LRO_AUTO_TLB		"hw_lro_auto_tlb"
 #define PROCREG_RESET_EVENT		"reset_event"
 
+#define MAX_PPPQ_PORT_NUM		6
+
 /* XFI MAC MIB Register */
 #define MTK_XFI_MIB_BASE(x)		(MTK_XMAC_MCR(x))
 #define MTK_XFI_CNT_CTRL		0x100
@@ -424,5 +426,7 @@
 void hw_lro_stats_update(u32 ring_no, struct mtk_rx_dma_v2 *rxd);
 void hw_lro_flush_stats_update(u32 ring_no, struct mtk_rx_dma_v2 *rxd);
 void mt753x_set_port_link_state(bool up);
+void qdma_qos_disable(void);
+void qdma_qos_pppq_ebl(u32 hook_toggle);
 
 #endif /* MTK_ETH_DBG_H */
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 8196f2b..e11f07d 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -240,6 +240,7 @@
 		.fq_tail	= 0x4724,
 		.fq_count	= 0x4728,
 		.fq_blen	= 0x472c,
+		.fq_fast_cfg	= 0x4738,
 		.tx_sch_rate	= 0x4798,
 	},
 	.gdm1_cnt		= 0x1c00,
@@ -4130,6 +4131,11 @@
 		val = mtk_r32(eth, reg_map->qdma.glo_cfg);
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
 		    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4))
+				mtk_m32(eth, MTK_QDMA_FQ_FASTPATH_EN,
+					MTK_QDMA_FQ_FASTPATH_EN,
+					reg_map->qdma.fq_fast_cfg);
+
 			val &= ~(MTK_RESV_BUF_MASK | MTK_DMA_SIZE_MASK);
 			mtk_w32(eth,
 				val | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
@@ -4396,6 +4402,7 @@
 
 static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 val;
 	int i;
 
@@ -4415,6 +4422,45 @@
 		}
 		break;
 	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA_V1_4) &&
+	    (glo_cfg == eth->soc->reg_map->qdma.glo_cfg)) {
+		spin_lock_bh(&eth->page_lock);
+		/* stop the dma fastpath agent */
+		mtk_m32(eth, MTK_QDMA_FQ_FASTPATH_EN, 0,
+			reg_map->qdma.fq_fast_cfg);
+		/* enable the dma tx engine */
+		mtk_m32(eth, MTK_TX_DMA_EN, MTK_TX_DMA_EN, glo_cfg);
+		/* enable the dma flush mode */
+		mtk_m32(eth, MTK_QDMA_FQ_FLUSH_MODE, MTK_QDMA_FQ_FLUSH_MODE,
+			reg_map->qdma.fq_fast_cfg);
+		spin_unlock_bh(&eth->page_lock);
+
+		/* wait for dma flush complete */
+		for (i = 0; i < 10; i++) {
+			val = mtk_r32(eth, reg_map->qdma.fq_fast_cfg);
+			if (val & MTK_QDMA_FQ_FLUSH_MODE) {
+				mdelay(20);
+				continue;
+			}
+			break;
+		}
+
+		spin_lock_bh(&eth->page_lock);
+		/* disable the dma tx engine */
+		mtk_m32(eth, MTK_TX_DMA_EN, 0, glo_cfg);
+		spin_unlock_bh(&eth->page_lock);
+
+		/* wait for dma tx stop */
+		for (i = 0; i < 10; i++) {
+			val = mtk_r32(eth, glo_cfg);
+			if (val & MTK_TX_DMA_BUSY) {
+				mdelay(20);
+				continue;
+			}
+			break;
+		}
+	}
 }
 
 static int mtk_stop(struct net_device *dev)
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 05c113d..e18f037 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -400,11 +400,17 @@
 #define MTK_QTX_SCH_LEAKY_BUCKET_SIZE	GENMASK(29, 28)
 #define MTK_QTX_SCH_MIN_RATE_EN		BIT(27)
 #define MTK_QTX_SCH_MIN_RATE_MAN	GENMASK(26, 20)
+#define MTK_QTX_SCH_MIN_RATE_MAN_V2	GENMASK(25, 19)
 #define MTK_QTX_SCH_MIN_RATE_EXP	GENMASK(19, 16)
+#define MTK_QTX_SCH_MIN_RATE_EXP_V2	GENMASK(18, 16)
 #define MTK_QTX_SCH_MAX_RATE_WEIGHT	GENMASK(15, 12)
+#define MTK_QTX_SCH_MAX_RATE_WEIGHT_V2	GENMASK(15, 10)
 #define MTK_QTX_SCH_MAX_RATE_EN		BIT(11)
+#define MTK_QTX_SCH_MAX_RATE_EN_V2	BIT(26)
 #define MTK_QTX_SCH_MAX_RATE_MAN	GENMASK(10, 4)
+#define MTK_QTX_SCH_MAX_RATE_MAN_V2	GENMASK(9, 3)
 #define MTK_QTX_SCH_MAX_RATE_EXP	GENMASK(3, 0)
+#define MTK_QTX_SCH_MAX_RATE_EXP_V2	GENMASK(2, 0)
 
 /* QDMA RX Base Pointer Register */
 #define MTK_QRX_BASE_PTR0	(QDMA_BASE + 0x100)
@@ -508,6 +514,11 @@
 /* QDMA Interrupt Mask Register */
 #define MTK_QDMA_HRED2		(QDMA_BASE + 0x244)
 
+/* QDMA TX Queue MIB Interface Register */
+#define MTK_QTX_MIB_IF		(QDMA_BASE + 0x2bc)
+#define MTK_MIB_ON_QTX_CFG	BIT(31)
+#define MTK_VQTX_MIB_EN		BIT(28)
+
 /* QDMA TX Forward CPU Pointer Register */
 #define MTK_QTX_CTX_PTR		(QDMA_BASE +0x300)
 
@@ -535,9 +546,17 @@
 /* QDMA FQ Free Page Buffer Length Register */
 #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
 
+/* QDMA FQ Free Page Fast Path Configuration Register */
+#define MTK_QDMA_FQ_FLUSH_MODE		BIT(3)
+#define MTK_QDMA_FQ_FASTPATH_EN		BIT(0)
+
 /* QDMA TX Scheduler Rate Control Register */
 #define MTK_QDMA_TX_4SCH_BASE(x)	(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
 #define MTK_QDMA_TX_SCH_MASK		GENMASK(15, 0)
+#define MTK_QDMA_TX_SCH_MAX_WFQ		BIT(15)
+#define MTK_QDMA_TX_SCH_RATE_EN		BIT(11)
+#define MTK_QDMA_TX_SCH_RATE_MAN	GENMASK(10, 4)
+#define MTK_QDMA_TX_SCH_RATE_EXP	GENMASK(3, 0)
 
 /* WDMA Registers */
 #define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
@@ -1427,6 +1446,14 @@
 	MTK_GDM_TYPE_MAX
 };
 
+enum mtk_qdma_version {
+	MTK_QDMA_V1_1 = 0,
+	MTK_QDMA_V1_2,
+	MTK_QDMA_V1_3,
+	MTK_QDMA_V1_4,
+	MTK_QDMA_MAX
+};
+
 enum mtk_hw_id {
 	MTK_HWID_V1 = 0,
 	MTK_HWID_V2,
@@ -1562,6 +1589,10 @@
 	MTK_PDMA_INT_BIT,
 	MTK_TRGMII_MT7621_CLK_BIT,
 	MTK_QDMA_BIT,
+	MTK_QDMA_V1_1_BIT,
+	MTK_QDMA_V1_2_BIT,
+	MTK_QDMA_V1_3_BIT,
+	MTK_QDMA_V1_4_BIT,
 	MTK_NETSYS_V1_BIT,
 	MTK_NETSYS_V2_BIT,
 	MTK_NETSYS_RX_V2_BIT,
@@ -1672,6 +1703,10 @@
 #define MTK_GMAC1_USXGMII	(MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII | MTK_XGMAC)
 #define MTK_GMAC2_USXGMII	(MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII | MTK_XGMAC)
 #define MTK_GMAC3_USXGMII	(MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII | MTK_XGMAC)
+#define MTK_QDMA_V1_1		(BIT_ULL(MTK_QDMA_V1_1_BIT) | MTK_QDMA)
+#define MTK_QDMA_V1_2		(BIT_ULL(MTK_QDMA_V1_2_BIT) | MTK_QDMA)
+#define MTK_QDMA_V1_3		(BIT_ULL(MTK_QDMA_V1_3_BIT) | MTK_QDMA)
+#define MTK_QDMA_V1_4		(BIT_ULL(MTK_QDMA_V1_4_BIT) | MTK_QDMA)
 
 /* MUXes present on SoCs */
 /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
@@ -1708,15 +1743,15 @@
 
 #define MT7621_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
 		      MTK_GMAC2_RGMII | MTK_SHARED_INT | \
-		      MTK_TRGMII_MT7621_CLK | MTK_QDMA | MTK_NETSYS_V1)
+		      MTK_TRGMII_MT7621_CLK | MTK_QDMA_V1_1 | MTK_NETSYS_V1)
 
 #define MT7622_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \
 		      MTK_GMAC2_SGMII | MTK_GDM1_ESW | \
 		      MTK_MUX_GDM1_TO_GMAC1_ESW | MTK_NETSYS_V1 | \
-		      MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_QDMA)
+		      MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_QDMA_V1_1)
 
 #define MT7623_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII | \
-		      MTK_QDMA | MTK_NETSYS_V1)
+		      MTK_QDMA_V1_1 | MTK_NETSYS_V1)
 
 #define MT7628_CAPS  (MTK_SHARED_INT | MTK_SOC_MT7628 | MTK_NETSYS_V1)
 
@@ -1724,19 +1759,19 @@
 		      MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \
 		      MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \
 		      MTK_MUX_U3_GMAC23_TO_QPHY | MTK_NETSYS_V1 | \
-		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA)
+		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA_V1_1)
 
 #define MT7986_CAPS   (MTK_PDMA_INT | MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
-                       MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+		       MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA_V1_2 | \
 		       MTK_NETSYS_V2 | MTK_RSS)
 
 #define MT7981_CAPS   (MTK_PDMA_INT | MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
-		       MTK_GMAC2_GEPHY | MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+		       MTK_GMAC2_GEPHY | MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA_V1_2 | \
 		       MTK_MUX_U3_GMAC23_TO_QPHY | MTK_U3_COPHY_V2 | \
 		       MTK_NETSYS_V2 | MTK_RSS)
 
 #define MT7988_CAPS   (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC3_SGMII | \
-		       MTK_PDMA_INT | MTK_MUX_GMAC123_TO_GEPHY_SGMII | MTK_QDMA | \
+		       MTK_PDMA_INT | MTK_MUX_GMAC123_TO_GEPHY_SGMII | MTK_QDMA_V1_3 | \
 		       MTK_NETSYS_V3 | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | \
 		       MTK_ESW | MTK_GMAC1_USXGMII | MTK_GMAC2_USXGMII | \
 		       MTK_GMAC3_USXGMII | MTK_MUX_GMAC123_TO_USXGMII | \
@@ -1806,6 +1841,7 @@
 		u32	fq_tail;	/* fq tail pointer */
 		u32	fq_count;	/* fq free page count */
 		u32	fq_blen;	/* fq free page buffer length */
+		u32	fq_fast_cfg;	/* fq free page fast path configuration */
 		u32	tx_sch_rate;	/* tx scheduler rate control
 					   registers */
 	} qdma;
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index 534fc03..0393c10 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -112,27 +112,6 @@
 #define GDMA2_FWD_CFG 0x1500
 #define GDMA3_FWD_CFG 0x540
 
-/* QDMA Tx queue configuration */
-#define QTX_CFG(x)			(QDMA_BASE + ((x) * 0x10))
-#define QTX_CFG_HW_RESV_CNT_OFFSET	(8)
-#define QTX_CFG_SW_RESV_CNT_OFFSET	(0)
-
-#define QTX_SCH(x)			(QDMA_BASE + 0x4 + ((x) * 0x10))
-#define QTX_SCH_MIN_RATE_EN		BIT(27)
-#define QTX_SCH_MAX_RATE_EN		BIT(11)
-#define QTX_SCH_MIN_RATE_MAN_OFFSET	(20)
-#define QTX_SCH_MIN_RATE_EXP_OFFSET	(16)
-#define QTX_SCH_MAX_RATE_WGHT_OFFSET	(12)
-#define QTX_SCH_MAX_RATE_MAN_OFFSET	(4)
-#define QTX_SCH_MAX_RATE_EXP_OFFSET	(0)
-
-/* QDMA Tx scheduler configuration */
-#define QDMA_PAGE			(QDMA_BASE + 0x1f0)
-#define QDMA_TX_2SCH_BASE		(QDMA_BASE + 0x214)
-#define QTX_MIB_IF			(QDMA_BASE + 0x2bc)
-#define QDMA_TX_4SCH_BASE(x)		(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
-#define QDMA_TX_SCH_WFQ_EN		BIT(15)
-
 /*--------------------------------------------------------------------------*/
 /* Register Mask*/
 /*--------------------------------------------------------------------------*/
@@ -213,13 +192,6 @@
 #define GDM_ALL_FRC_MASK                                                      \
 	(GDM_UFRC_MASK | GDM_BFRC_MASK | GDM_MFRC_MASK | GDM_OFRC_MASK)
 
-/*QDMA_PAGE mask*/
-#define QTX_CFG_PAGE (0xf << 0) /* RW */
-
-/*QTX_MIB_IF mask*/
-#define MIB_ON_QTX_CFG (0x1 << 31) /* RW */
-#define VQTX_MIB_EN (0x1 << 28) /* RW */
-
 /* PPE Side Band FIFO Debug Mask */
 #define SB_MED_FULL_DRP_EN (0x1 << 11)
 
@@ -1238,9 +1210,6 @@
 #define IPV6_SNAT	0
 #define IPV6_DNAT	1
 
-/*QDMA_PAGE value*/
-#define NUM_OF_Q_PER_PAGE 16
-
 /*IPv6 Header*/
 #ifndef NEXTHDR_IPIP
 #define NEXTHDR_IPIP 4
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index 29ea69b..38838a4 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -26,6 +26,7 @@
 #include "hnat.h"
 #include "nf_hnat_mtk.h"
 #include "../mtk_eth_soc.h"
+#include "../mtk_eth_dbg.h"
 
 int dbg_entry_state = BIND;
 typedef int (*debugfs_write_func)(int par1);
@@ -2232,297 +2233,6 @@
 	.release = single_release,
 };
 
-static ssize_t hnat_sched_show(struct file *file, char __user *user_buf,
-			       size_t count, loff_t *ppos)
-{
-	long id = (long)file->private_data;
-	struct mtk_hnat *h = hnat_priv;
-	u32 qdma_tx_sch;
-	int enable;
-	int scheduling;
-	int max_rate;
-	char *buf;
-	unsigned int len = 0, buf_len = 1500;
-	ssize_t ret_cnt;
-	int scheduler, i;
-	u32 sch_reg;
-
-	buf = kzalloc(buf_len, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	if (hnat_priv->data->num_of_sch == 4)
-		qdma_tx_sch = readl(h->fe_base + QDMA_TX_4SCH_BASE(id));
-	else
-		qdma_tx_sch = readl(h->fe_base + QDMA_TX_2SCH_BASE);
-
-	if (id & 0x1)
-		qdma_tx_sch >>= 16;
-	qdma_tx_sch &= MTK_QDMA_TX_SCH_MASK;
-	enable = !!(qdma_tx_sch & BIT(11));
-	scheduling = !!(qdma_tx_sch & BIT(15));
-	max_rate = ((qdma_tx_sch >> 4) & 0x7f);
-	qdma_tx_sch &= 0xf;
-	while (qdma_tx_sch--)
-		max_rate *= 10;
-
-	len += scnprintf(buf + len, buf_len - len,
-			 "EN\tScheduling\tMAX\tQueue#\n%d\t%s%16d\t", enable,
-			 (scheduling == 1) ? "WRR" : "SP", max_rate);
-
-	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
-		cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE,
-			     (i / NUM_OF_Q_PER_PAGE));
-		sch_reg = readl(h->fe_base + QTX_SCH(i % NUM_OF_Q_PER_PAGE));
-		if (hnat_priv->data->num_of_sch == 4)
-			scheduler = (sch_reg >> 30) & 0x3;
-		else
-			scheduler = !!(sch_reg & BIT(31));
-		if (id == scheduler)
-			len += scnprintf(buf + len, buf_len - len, "%d  ", i);
-	}
-
-	len += scnprintf(buf + len, buf_len - len, "\n");
-	if (len > buf_len)
-		len = buf_len;
-
-	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-
-	kfree(buf);
-	return ret_cnt;
-}
-
-static ssize_t hnat_sched_write(struct file *file, const char __user *buf,
-				size_t length, loff_t *offset)
-{
-	long id = (long)file->private_data;
-	struct mtk_hnat *h = hnat_priv;
-	char line[64] = {0};
-	int enable, rate, exp = 0, shift = 0;
-	char scheduling[32];
-	size_t size;
-	u32 qdma_tx_sch;
-	u32 val = 0;
-
-	if (length >= sizeof(line))
-		return -EINVAL;
-
-	if (copy_from_user(line, buf, length))
-		return -EFAULT;
-
-	if (sscanf(line, "%1d %3s %9d", &enable, scheduling, &rate) != 3)
-		return -EFAULT;
-
-#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-	if (rate > 10000000 || rate < 0)
-#else
-	if (rate > 1000000 || rate < 0)
-#endif
-		return -EINVAL;
-
-	while (rate > 127) {
-		rate /= 10;
-		exp++;
-	}
-
-	line[length] = '\0';
-
-	if (enable)
-		val |= BIT(11);
-	if (strcmp(scheduling, "sp") != 0)
-		val |= BIT(15);
-	val |= (rate & 0x7f) << 4;
-	val |= exp & 0xf;
-	if (id & 0x1)
-		shift = 16;
-
-	if (hnat_priv->data->num_of_sch == 4)
-		qdma_tx_sch = readl(h->fe_base + QDMA_TX_4SCH_BASE(id));
-	else
-		qdma_tx_sch = readl(h->fe_base + QDMA_TX_2SCH_BASE);
-
-	qdma_tx_sch &= ~(MTK_QDMA_TX_SCH_MASK << shift);
-	qdma_tx_sch |= val << shift;
-	if (hnat_priv->data->num_of_sch == 4)
-		writel(qdma_tx_sch, h->fe_base + QDMA_TX_4SCH_BASE(id));
-	else
-		writel(qdma_tx_sch, h->fe_base + QDMA_TX_2SCH_BASE);
-
-	size = strlen(line);
-	*offset += size;
-
-	return length;
-}
-
-static const struct file_operations hnat_sched_fops = {
-	.open = simple_open,
-	.read = hnat_sched_show,
-	.write = hnat_sched_write,
-	.llseek = default_llseek,
-};
-
-static ssize_t hnat_queue_show(struct file *file, char __user *user_buf,
-			       size_t count, loff_t *ppos)
-{
-	struct mtk_hnat *h = hnat_priv;
-	long id = (long)file->private_data;
-	u32 qtx_sch;
-	u32 qtx_cfg;
-	int scheduler;
-	int min_rate_en;
-	int min_rate;
-	int min_rate_exp;
-	int max_rate_en;
-	int max_weight;
-	int max_rate;
-	int max_rate_exp;
-	char *buf;
-	unsigned int len = 0, buf_len = 1500;
-	ssize_t ret_cnt;
-
-	buf = kzalloc(buf_len, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE, (id / NUM_OF_Q_PER_PAGE));
-	qtx_cfg = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-	qtx_sch = readl(h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
-	if (hnat_priv->data->num_of_sch == 4)
-		scheduler = (qtx_sch >> 30) & 0x3;
-	else
-		scheduler = !!(qtx_sch & BIT(31));
-	min_rate_en = !!(qtx_sch & BIT(27));
-	min_rate = (qtx_sch >> 20) & 0x7f;
-	min_rate_exp = (qtx_sch >> 16) & 0xf;
-	max_rate_en = !!(qtx_sch & BIT(11));
-	max_weight = (qtx_sch >> 12) & 0xf;
-	max_rate = (qtx_sch >> 4) & 0x7f;
-	max_rate_exp = qtx_sch & 0xf;
-	while (min_rate_exp--)
-		min_rate *= 10;
-
-	while (max_rate_exp--)
-		max_rate *= 10;
-
-	len += scnprintf(buf + len, buf_len - len,
-			 "scheduler: %d\nhw resv: %d\nsw resv: %d\n", scheduler,
-			 (qtx_cfg >> 8) & 0xff, qtx_cfg & 0xff);
-
-	if (hnat_priv->data->version != MTK_HNAT_V1_1) {
-		/* Switch to debug mode */
-		cr_set_field(h->fe_base + QTX_MIB_IF, MIB_ON_QTX_CFG, 1);
-		cr_set_field(h->fe_base + QTX_MIB_IF, VQTX_MIB_EN, 1);
-		qtx_cfg = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-		qtx_sch = readl(h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
-		len += scnprintf(buf + len, buf_len - len,
-				 "packet count: %u\n", qtx_cfg);
-		len += scnprintf(buf + len, buf_len - len,
-				 "packet drop: %u\n\n", qtx_sch);
-
-		/* Recover to normal mode */
-		cr_set_field(hnat_priv->fe_base + QTX_MIB_IF,
-			     MIB_ON_QTX_CFG, 0);
-		cr_set_field(hnat_priv->fe_base + QTX_MIB_IF, VQTX_MIB_EN, 0);
-	}
-
-	len += scnprintf(buf + len, buf_len - len,
-			 "      EN     RATE     WEIGHT\n");
-	len += scnprintf(buf + len, buf_len - len,
-			 "----------------------------\n");
-	len += scnprintf(buf + len, buf_len - len,
-			 "max%5d%9d%9d\n", max_rate_en, max_rate, max_weight);
-	len += scnprintf(buf + len, buf_len - len,
-			 "min%5d%9d        -\n", min_rate_en, min_rate);
-
-	if (len > buf_len)
-		len = buf_len;
-
-	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-
-	kfree(buf);
-	return ret_cnt;
-}
-
-static ssize_t hnat_queue_write(struct file *file, const char __user *buf,
-				size_t length, loff_t *offset)
-{
-	long id = (long)file->private_data;
-	struct mtk_hnat *h = hnat_priv;
-	char line[64] = {0};
-	int max_enable, max_rate, max_exp = 0;
-	int min_enable, min_rate, min_exp = 0;
-	int weight;
-	int resv;
-	int scheduler;
-	size_t size;
-	u32 qtx_sch = 0;
-
-	cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE, (id / NUM_OF_Q_PER_PAGE));
-	if (length >= sizeof(line))
-		return -EINVAL;
-
-	if (copy_from_user(line, buf, length))
-		return -EFAULT;
-
-	if (sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate,
-		   &max_enable, &max_rate, &weight, &resv) != 7)
-		return -EFAULT;
-
-	line[length] = '\0';
-
-#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-	if (max_rate > 10000000 || max_rate < 0 ||
-	    min_rate > 10000000 || min_rate < 0)
-#else
-	if (max_rate > 1000000 || max_rate < 0 ||
-	    min_rate > 1000000 || min_rate < 0)
-#endif
-		return -EINVAL;
-
-	while (max_rate > 127) {
-		max_rate /= 10;
-		max_exp++;
-	}
-
-	while (min_rate > 127) {
-		min_rate /= 10;
-		min_exp++;
-	}
-
-	if (hnat_priv->data->num_of_sch == 4)
-		qtx_sch |= (scheduler & 0x3) << 30;
-	else
-		qtx_sch |= (scheduler & 0x1) << 31;
-	if (min_enable)
-		qtx_sch |= BIT(27);
-	qtx_sch |= (min_rate & 0x7f) << 20;
-	qtx_sch |= (min_exp & 0xf) << 16;
-	if (max_enable)
-		qtx_sch |= BIT(11);
-	qtx_sch |= (weight & 0xf) << 12;
-	qtx_sch |= (max_rate & 0x7f) << 4;
-	qtx_sch |= max_exp & 0xf;
-	writel(qtx_sch, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
-
-	resv &= 0xff;
-	qtx_sch = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-	qtx_sch &= 0xffff0000;
-	qtx_sch |= (resv << 8) | resv;
-	writel(qtx_sch, h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-
-	size = strlen(line);
-	*offset += size;
-
-	return length;
-}
-
-static const struct file_operations hnat_queue_fops = {
-	.open = simple_open,
-	.read = hnat_queue_show,
-	.write = hnat_queue_write,
-	.llseek = default_llseek,
-};
-
 static ssize_t hnat_ppd_if_write(struct file *file, const char __user *buffer,
 				 size_t count, loff_t *data)
 {
@@ -2654,7 +2364,6 @@
 {
 	char buf[8] = {0};
 	int len = count;
-	u32 id;
 
 	if ((len > 8) || copy_from_user(buf, buffer, len))
 		return -EFAULT;
@@ -2663,18 +2372,14 @@
 		pr_info("hook is going to be enabled !\n");
 		hnat_enable_hook();
 
-		if (IS_PPPQ_MODE) {
-			for (id = 0; id < MAX_PPPQ_PORT_NUM; id++)
-				hnat_qos_shaper_ebl(id, 1);
-		}
+		if (IS_PPPQ_MODE)
+			qdma_qos_pppq_ebl(true);
 	} else if (buf[0] == '0' && hook_toggle) {
 		pr_info("hook is going to be disabled !\n");
 		hnat_disable_hook();
 
-		if (IS_PPPQ_MODE) {
-			for (id = 0; id < MAX_PPPQ_PORT_NUM; id++)
-				hnat_qos_shaper_ebl(id, 0);
-		}
+		if (IS_PPPQ_MODE)
+			qdma_qos_pppq_ebl(false);
 	}
 
 	return len;
@@ -2975,72 +2680,6 @@
 	return single_open(file, hnat_qos_toggle_read, file->private_data);
 }
 
-void hnat_qos_shaper_ebl(u32 id, u32 enable)
-{
-	struct mtk_hnat *h = hnat_priv;
-	u32 cfg;
-
-	cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE, (id / NUM_OF_Q_PER_PAGE));
-	if (enable) {
-		cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;
-		cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |
-		       (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |
-		       (25 << QTX_SCH_MAX_RATE_MAN_OFFSET) |
-		       (5 << QTX_SCH_MAX_RATE_EXP_OFFSET) |
-		       (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);
-
-		writel(cfg, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
-	} else {
-		writel(0, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
-	}
-}
-
-static void hnat_qos_disable(void)
-{
-	struct mtk_hnat *h = hnat_priv;
-	u32 id, cfg;
-
-	for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
-		hnat_qos_shaper_ebl(id, 0);
-		writel((4 << QTX_CFG_HW_RESV_CNT_OFFSET) |
-		       (4 << QTX_CFG_SW_RESV_CNT_OFFSET),
-		       h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-	}
-
-	cfg = (QDMA_TX_SCH_WFQ_EN) | (QDMA_TX_SCH_WFQ_EN << 16);
-	for (id = 0; id < h->data->num_of_sch; id += 2) {
-		if (h->data->num_of_sch == 4)
-			writel(cfg, h->fe_base + QDMA_TX_4SCH_BASE(id));
-		else
-			writel(cfg, h->fe_base + QDMA_TX_2SCH_BASE);
-	}
-}
-
-static void hnat_qos_pppq_enable(void)
-{
-	struct mtk_hnat *h = hnat_priv;
-	u32 id, cfg;
-
-	for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
-		if (hook_toggle)
-			hnat_qos_shaper_ebl(id, 1);
-		else
-			hnat_qos_shaper_ebl(id, 0);
-
-		writel((4 << QTX_CFG_HW_RESV_CNT_OFFSET) |
-		       (4 << QTX_CFG_SW_RESV_CNT_OFFSET),
-		       h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
-	}
-
-	cfg = (QDMA_TX_SCH_WFQ_EN) | (QDMA_TX_SCH_WFQ_EN << 16);
-	for (id = 0; id < h->data->num_of_sch; id+= 2) {
-		if (h->data->num_of_sch == 4)
-                        writel(cfg, h->fe_base + QDMA_TX_4SCH_BASE(id));
-                else
-                        writel(cfg, h->fe_base + QDMA_TX_2SCH_BASE);
-	}
-}
-
 static ssize_t hnat_qos_toggle_write(struct file *file, const char __user *buffer,
 				     size_t count, loff_t *data)
 {
@@ -3061,7 +2700,7 @@
 		qos_toggle = 0;
 		qos_dl_toggle = 0;
 		qos_ul_toggle = 0;
-		hnat_qos_disable();
+		qdma_qos_disable();
 	} else if (buf[0] == '1') {
 		p_buf = buf;
 		p_token = strsep(&p_buf, " \t");
@@ -3095,7 +2734,7 @@
 		qos_toggle = 2;
 		qos_dl_toggle = 1;
 		qos_ul_toggle = 1;
-		hnat_qos_pppq_enable();
+		qdma_qos_pppq_ebl(hook_toggle);
 	} else if (buf[0] == '3') {
 		hnat_qos_toggle_usage();
 	} else {
@@ -3505,7 +3144,7 @@
 	struct dentry *root;
 	struct dentry *file;
 	long i;
-	char name[16];
+	char name[16], name_symlink[48];
 
 	root = debugfs_create_dir("hnat", NULL);
 	if (!root) {
@@ -3578,8 +3217,13 @@
 			ret = -ENOMEM;
 			goto err1;
 		}
+		ret = snprintf(name_symlink, sizeof(name_symlink),
+			       "/sys/kernel/debug/mtketh/qdma_sch%ld", i);
+		if (ret != strlen(name_symlink)) {
+			ret = -ENOMEM;
+			goto err1;
+		}
-		debugfs_create_file(name, 0444, root, (void *)i,
-				    &hnat_sched_fops);
+		debugfs_create_symlink(name, root, name_symlink);
 	}
 
 	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
@@ -3588,8 +3232,13 @@
 			ret = -ENOMEM;
 			goto err1;
 		}
+		ret = snprintf(name_symlink, sizeof(name_symlink),
+			       "/sys/kernel/debug/mtketh/qdma_txq%ld", i);
+		if (ret != strlen(name_symlink)) {
+			ret = -ENOMEM;
+			goto err1;
+		}
-		debugfs_create_file(name, 0444, root, (void *)i,
-				    &hnat_queue_fops);
+		debugfs_create_symlink(name, root, name_symlink);
 	}
 
 	return 0;
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 1de70af..72df937 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -959,13 +959,13 @@
 	}
 
 setup_rate_limit:
-	cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;
-	cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |
-	       (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |
-	       (max_man << QTX_SCH_MAX_RATE_MAN_OFFSET) |
-	       (max_exp << QTX_SCH_MAX_RATE_EXP_OFFSET) |
-	       (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);
-	writel(cfg, hnat_priv->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+	cfg = MTK_QTX_SCH_MIN_RATE_EN | MTK_QTX_SCH_MAX_RATE_EN;
+	cfg |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+	       FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
+	       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, max_man) |
+	       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, max_exp) |
+	       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 4);
+	writel(cfg, hnat_priv->fe_base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
 }
 
 static unsigned int