[][Refine QDMA rate control shaper when running PPPQ]

[Description]
Refactor QDMA Per-Port-Per-Queue(PPPQ) mode.
Because QDMA scheduler has 1Gbps rate limitation, the rate control
shaper must be fine-tuned when activating PPPQ mode.

[Release-log]
N/A

Change-Id: Ie7a1c6292e8e3b302deb97e2e78145ce9171cf4d
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5355282
diff --git a/feed/mtkhnat_util/files/mtkhnat.config b/feed/mtkhnat_util/files/mtkhnat.config
index c971c59..f252a98 100755
--- a/feed/mtkhnat_util/files/mtkhnat.config
+++ b/feed/mtkhnat_util/files/mtkhnat.config
@@ -7,7 +7,7 @@
 ####################################################################
 config global global
 	option enable 1
-	option hqos 1
+	option hqos 0
 	option txq_num 16
 	option scheduling 'wrr'
 	option sch0_bw 1000000
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index f10b169..0e1e91b 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -105,19 +105,24 @@
 #define GDMA2_FWD_CFG 0x1500
 
 /* QDMA Tx queue configuration */
-#define QTX_CFG(x)		(QDMA_BASE + ((x) * 0x10))
-#define QTX_SCH(x)		(QDMA_BASE + 0x4 + ((x) * 0x10))
-#define QTX_TX_SCH_SEL_OFFSET	(30)
+#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_MAX_WFQ	BIT(15)
-#define QDMA_TX_SCH_RATE_EN	BIT(11)
-#define QDMA_RATE_MAN_OFFSET	(4)
-#define QDMA_RATE_EXP_OFFSET	(0)
+#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))
 
 /*--------------------------------------------------------------------------*/
 /* Register Mask*/
@@ -855,6 +860,7 @@
 #define IS_GMAC1_MODE ((hnat_priv->gmac_num == 1) ? 1 : 0)
 #define IS_HQOS_MODE (qos_toggle == 1)
 #define IS_PPPQ_MODE (qos_toggle == 2)		/* Per Port Per Queue */
+#define MAX_PPPQ_PORT_NUM	6
 
 #define es(entry) (entry_state[entry->bfib1.state])
 #define ei(entry, end) (hnat_priv->foe_etry_num - (int)(end - entry))
@@ -948,6 +954,7 @@
 int hnat_enable_hook(void);
 int hnat_disable_hook(void);
 void hnat_cache_ebl(int enable);
+void hnat_qos_shaper_ebl(u32 id, u32 enable);
 void set_gmac_ppe_fwd(int gmac_no, int enable);
 int entry_detail(u32 ppe_id, int index);
 int entry_delete_by_mac(u8 *mac);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index c6978fa..a7453af 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -1951,6 +1951,7 @@
 {
 	char buf[8] = {0};
 	int len = count;
+	u32 id;
 
 	if ((len > 8) || copy_from_user(buf, buffer, len))
 		return -EFAULT;
@@ -1958,9 +1959,19 @@
 	if (buf[0] == '1' && !hook_toggle) {
 		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);
+		}
 	} 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);
+		}
 	}
 
 	return len;
@@ -1986,26 +1997,67 @@
 	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;
+
+	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;
+
+	for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
+		hnat_qos_shaper_ebl(id, 0);
+		writel(0, h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+	}
+
+	writel((4 << QTX_CFG_HW_RESV_CNT_OFFSET) |
+	       (4 << QTX_CFG_SW_RESV_CNT_OFFSET), h->fe_base + QTX_CFG(0));
+
+	for (id = 0; id < h->data->num_of_sch; id += 2) {
+		if (h->data->num_of_sch == 4)
+			writel(0, h->fe_base + QDMA_TX_4SCH_BASE(id));
+		else
+			writel(0, h->fe_base + QDMA_TX_2SCH_BASE);
+	}
+}
+
 static void hnat_qos_pppq_enable(void)
 {
-	u32 cfg, id;
+	struct mtk_hnat *h = hnat_priv;
+	u32 id;
 
-	for (id = 0; id < hnat_priv->data->num_of_sch; id++) {
-		writel(id << QTX_TX_SCH_SEL_OFFSET,
-		       hnat_priv->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+	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);
 
-		if (id & 0x1) {
-			cfg = 0;
-			cfg |= QDMA_TX_SCH_MAX_WFQ | QDMA_TX_SCH_RATE_EN;
-			cfg |= 25 << QDMA_RATE_MAN_OFFSET;
-			cfg |= 5 << QDMA_RATE_EXP_OFFSET;
-			cfg |= cfg << 16;
+		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));
+	}
 
-			if (hnat_priv->data->num_of_sch == 4)
-				writel(cfg, hnat_priv->fe_base + QDMA_TX_4SCH_BASE(id));
-			else
-				writel(cfg, hnat_priv->fe_base + QDMA_TX_2SCH_BASE);
-		}
+	for (id = 0; id < h->data->num_of_sch; id+= 2) {
+		if (h->data->num_of_sch == 4)
+                        writel(0, h->fe_base + QDMA_TX_4SCH_BASE(id));
+                else
+                        writel(0, h->fe_base + QDMA_TX_2SCH_BASE);
 	}
 }
 
@@ -2021,6 +2073,7 @@
 	if (buf[0] == '0') {
 		pr_info("HQoS is going to be disabled !\n");
 		qos_toggle = 0;
+		hnat_qos_disable();
 	} else if (buf[0] == '1') {
 		pr_info("HQoS mode is going to be enabled !\n");
 		qos_toggle = 1;