[][HIGH][kernel][common][eth][Fix HQoS is not functioning properly following the SER issue]

[Description]
Fix HQoS is not functioning properly following the SER issue.

Since SER will reset QDMA, it means that the HQoS configurations will
be cleared. The driver needs to save the HQoS configuration before the
SER and then restore the HQoS configuration afterward.

Without this patch, the HQoS is not functioning properly following the
SER.

[Release-log]
N/A


Change-Id: Ibbdc8476bc7081ffcc34bdc7a92babeb5891e6f2
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9095074
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
index 344c68a..396cdc0 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
@@ -22,6 +22,13 @@
 	[MTK_EVENT_RFIFO_UF]	= "RFIFO UF",
 };
 
+struct mtk_qdma_cfg {
+	u32 qtx_cfg[MTK_QDMA_TX_NUM];
+	u32 qtx_sch[MTK_QDMA_TX_NUM];
+	u32 tx_sch[2];
+};
+
+static struct mtk_qdma_cfg mtk_qdma_cfg_backup;
 static int mtk_wifi_num = 0;
 static int mtk_rest_cnt = 0;
 u32 mtk_reset_flag = MTK_FE_START_RESET;
@@ -719,6 +726,58 @@
 	mod_timer(&eth->mtk_dma_monitor_timer, jiffies + 1 * HZ);
 }
 
+void mtk_save_qdma_cfg(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		mtk_m32(eth, MTK_QTX_CFG_PAGE, (i / MTK_QTX_PER_PAGE),
+			MTK_QDMA_PAGE);
+
+		mtk_qdma_cfg_backup.qtx_cfg[i] =
+			mtk_r32(eth, MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+		mtk_qdma_cfg_backup.qtx_sch[i] =
+			mtk_r32(eth, MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+	}
+	mtk_m32(eth, MTK_QTX_CFG_PAGE, 0, MTK_QDMA_PAGE);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		mtk_qdma_cfg_backup.tx_sch[0] =
+			mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(0));
+		mtk_qdma_cfg_backup.tx_sch[1] =
+			mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(2));
+	} else
+		mtk_qdma_cfg_backup.tx_sch[0] =
+			mtk_r32(eth, MTK_QDMA_TX_2SCH_BASE);
+}
+
+void mtk_restore_qdma_cfg(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		mtk_m32(eth, MTK_QTX_CFG_PAGE, (i / MTK_QTX_PER_PAGE),
+			MTK_QDMA_PAGE);
+
+		mtk_w32(eth, mtk_qdma_cfg_backup.qtx_cfg[i],
+			MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+		mtk_w32(eth, mtk_qdma_cfg_backup.qtx_sch[i],
+			MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+	}
+	mtk_m32(eth, MTK_QTX_CFG_PAGE, 0, MTK_QDMA_PAGE);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[0],
+			MTK_QDMA_TX_4SCH_BASE(0));
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[1],
+			MTK_QDMA_TX_4SCH_BASE(2));
+	} else
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[0],
+			MTK_QDMA_TX_2SCH_BASE);
+}
+
 void mtk_prepare_reset_fe(struct mtk_eth *eth)
 {
 	u32 i = 0, val = 0, mcr = 0;
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
index ff7b1ea..dd8206a 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
@@ -87,6 +87,8 @@
 void mtk_reset_event_update(struct mtk_eth *eth, u32 id);
 void mtk_dump_netsys_info(void *_eth);
 void mtk_dma_monitor(struct timer_list *t);
+void mtk_save_qdma_cfg(struct mtk_eth *eth);
+void mtk_restore_qdma_cfg(struct mtk_eth *eth);
 void mtk_prepare_reset_fe(struct mtk_eth *eth);
 void mtk_prepare_reset_ppe(struct mtk_eth *eth, u32 ppe_id);
 
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 6aeb136..817920f 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
@@ -4568,6 +4568,10 @@
 
 	mtk_phy_config(eth, 0);
 
+	/* Store QDMA configurations to prepare for reset */
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_save_qdma_cfg(eth);
+
 	/* Adjust PPE configurations to prepare for reset */
 	mtk_prepare_reset_ppe(eth, 0);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
@@ -4657,6 +4661,10 @@
 		break;
 	}
 
+	/* Restore QDMA configurations */
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_restore_qdma_cfg(eth);
+
 	atomic_dec(&reset_lock);
 
 	timer_setup(&eth->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
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 395b059..5fe34dc 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
@@ -486,6 +486,9 @@
 #define FC_THRES_DROP_EN	(7 << 16)
 #define FC_THRES_MIN		0x4444
 
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_2SCH_BASE	(QDMA_BASE + 0x214)
+
 /* QDMA Interrupt Status Register */
 #define MTK_QDMA_INT_STATUS	(QDMA_BASE + 0x218)
 #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -556,6 +559,9 @@
 /* QDMA FQ Free Page Buffer Length Register */
 #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
 
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_4SCH_BASE(x)	(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
+
 /* WDMA Registers */
 #define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
 #define MTK_WDMA_DTX_PTR(x)	(WDMA_BASE(x) + 0xC)