[][[Jaguar][Eagle] reset recovery]

[Description]
Add ETH Reset for device recovery when detected erro

[Release-log]
-- sync panther-cheetah eth reset
-- refine error detect func
-- refine pending work flow


Change-Id: Ibac85bcca21f711586d9b9af246da1c789062425
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6969361
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index 69e92db..c914bc0 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -382,20 +382,31 @@
 				atomic_inc(&reset_lock);
 			break;
 		case 1:
-			if (atomic_read(&force) == 0)
+			if (atomic_read(&force) == 0) {
 				atomic_inc(&force);
-			schedule_work(&eth->pending_work);
+				schedule_work(&eth->pending_work);
+			} else
+				pr_info(" device resetting !!!\n");
 			break;
 		case 2:
 			if (atomic_read(&reset_lock) == 1)
 				atomic_dec(&reset_lock);
 			break;
+		case 3:
+			if (atomic_read(&force) == 0) {
+				atomic_inc(&force);
+				mtk_reset_flag = MTK_FE_STOP_TRAFFIC;
+				schedule_work(&eth->pending_work);
+			} else
+				pr_info(" device resetting !!!\n");
+			break;
 		default:
 			pr_info("Usage: echo [level] > /sys/kernel/debug/mtketh/reset\n");
-			pr_info("Commands:	 [level] \n");
-			pr_info("			   0	 disable reset \n");
-			pr_info("			   1	 force reset \n");
+			pr_info("Commands:	 [level]\n");
+			pr_info("			   0	 disable reset\n");
+			pr_info("			   1	 FE and WDMA reset\n");
 			pr_info("			   2	 enable reset\n");
+			pr_info("			   3	 FE reset\n");
 			break;
 	}
 	return count;
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
index e983d6e..02fd90b 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
@@ -24,6 +24,8 @@
 
 static int mtk_wifi_num = 0;
 static int mtk_rest_cnt = 0;
+u32 mtk_reset_flag = MTK_FE_START_RESET;
+typedef u32 (*mtk_monitor_xdma_func) (struct mtk_eth *eth);
 
 void mtk_reset_event_update(struct mtk_eth *eth, u32 id)
 {
@@ -69,12 +71,16 @@
 	}
 
 	if (i < 1000) {
-		reset_bits = 0;
-
+		reset_bits = RSTCTRL_ETH | RSTCTRL_PPE0;
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
-			reset_bits |= RSTCTRL_ETH | RSTCTRL_PPE0 | RSTCTRL_PPE1;
-		else
-			reset_bits |= RSTCTRL_ETH | RSTCTRL_PPE0;
+			reset_bits |= RSTCTRL_PPE1;
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE2))
+			reset_bits |= RSTCTRL_PPE2;
+		if (mtk_reset_flag == MTK_FE_START_RESET)
+			reset_bits |= RSTCTRL_WDMA0 |
+			RSTCTRL_WDMA1 | RSTCTRL_WDMA2;
+#endif
 
 		regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL,
 				   reset_bits, reset_bits);
@@ -195,84 +201,124 @@
 	mtk_dump_reg(eth, "GMAC", 0x10000, 0x300);
 }
 
-void mtk_dma_monitor(struct timer_list *t)
+u32 mtk_monitor_wdma_tx(struct mtk_eth *eth)
 {
-	struct mtk_eth *eth = from_timer(eth, t, mtk_dma_monitor_timer);
-	static u32 timestamp = 0;
-	static u32 err_cnt1 = 0, err_cnt2 = 0, err_cnt3 = 0;
-	static u32 prev_wdidx = 0;
-	unsigned int mib_base = MTK_GDM1_TX_GBCNT;
+	static u32 pre_dtx[MTK_WDMA_CNT];
+	static u32 err_cnt[MTK_WDMA_CNT];
+	u32 i = 0, cur_dtx = 0, tx_busy = 0, tx_rdy = 0, err_flag = 0;
+	u32 dbg_mon = 0;
 
-	/*wdma tx path*/
-	u32 cur_wdidx = mtk_r32(eth, MTK_WDMA_DTX_PTR(0));
-	u32 is_wtx_busy = mtk_r32(eth, MTK_WDMA_GLO_CFG(0)) & MTK_TX_DMA_BUSY;
-	u32 is_oq_free = ((mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0x01FF0000) == 0) &&
-			 ((mtk_r32(eth, MTK_PSE_OQ_STA(1)) & 0x000001FF) == 0) &&
-			 ((mtk_r32(eth, MTK_PSE_OQ_STA(4)) & 0x01FF0000) == 0);
-	u32 is_cdm_full =
-		!(mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(0)) & MTK_CDM_TXFIFO_RDY);
-	/*qdma tx path*/
-	u32 is_qfsm_hang = mtk_r32(eth, MTK_QDMA_FSM) != 0;
-	u32 is_qfwd_hang = mtk_r32(eth, MTK_QDMA_FWD_CNT) == 0;
-	u32 is_qfq_hang = mtk_r32(eth, MTK_QDMA_FQ_CNT) !=
-			  ((MTK_DMA_SIZE << 16) | MTK_DMA_SIZE);
-	u32 is_gdm1_tx = (mtk_r32(eth, MTK_FE_GDM1_FSM) & 0xFFFF0000) > 0;
-	u32 is_gdm2_tx = (mtk_r32(eth, MTK_FE_GDM2_FSM) & 0xFFFF0000) > 0;
-	u32 is_gmac1_tx = (mtk_r32(eth, MTK_MAC_FSM(0)) & 0xFF000000) != 0x1000000;
-	u32 is_gmac2_tx = (mtk_r32(eth, MTK_MAC_FSM(1)) & 0xFF000000) != 0x1000000;
-	u32 gdm1_fc =  mtk_r32(eth, mib_base+0x24);
-	u32 gdm2_fc =  mtk_r32(eth, mib_base+0x64);
-	/*adma rx path*/
-	u32 is_oq0_stuck = (mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0x1FF) != 0;
-	u32 is_cdm1_busy = (mtk_r32(eth, MTK_FE_CDM1_FSM) & 0xFFFF0000) != 0;
-	u32 is_adma_busy = ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x1F) == 0) &&
-			   ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x40) == 0);
+	for (i = 0; i < MTK_WDMA_CNT; i++) {
+		cur_dtx = mtk_r32(eth, MTK_WDMA_DTX_PTR(i));
+		tx_busy = mtk_r32(eth, MTK_WDMA_GLO_CFG(i)) & MTK_TX_DMA_BUSY;
+		dbg_mon = mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(i));
+		tx_rdy = !(dbg_mon & MTK_CDM_TXFIFO_RDY);
+		if (cur_dtx == pre_dtx[i] && tx_busy && tx_rdy) {
+			err_cnt[i]++;
+			if (err_cnt[i] >= 3) {
+				pr_info("WDMA %d Info\n", i);
+				pr_info("err_cnt = %d", err_cnt[i]);
+				pr_info("prev_dtx = 0x%x	| cur_dtx = 0x%x\n",
+					pre_dtx[i], cur_dtx);
+				pr_info("WDMA_CTX_PTR = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_CTX_PTR(i)));
+				pr_info("WDMA_DTX_PTR = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_DTX_PTR(i)));
+				pr_info("WDMA_GLO_CFG = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_GLO_CFG(i)));
+				pr_info("WDMA_TX_DBG_MON0 = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(i)));
+				pr_info("==============================\n");
+				err_flag = 1;
+			}
+		} else
+			err_cnt[i] = 0;
+		pre_dtx[i] = cur_dtx;
+	}
 
-	if (cur_wdidx == prev_wdidx && is_wtx_busy &&
-	    is_oq_free && is_cdm_full) {
-		err_cnt1++;
-		if (err_cnt1 >= 3) {
-			pr_info("WDMA CDM Info\n");
-			pr_info("============== Time: %d ================\n",
-				timestamp);
-			pr_info("err_cnt1 = %d", err_cnt1);
-			pr_info("prev_wdidx = 0x%x	| cur_wdidx = 0x%x\n",
-				prev_wdidx, cur_wdidx);
-			pr_info("is_wtx_busy = %d | is_oq_free = %d	| is_cdm_full = %d\n",
-				is_wtx_busy, is_oq_free, is_cdm_full);
-			pr_info("-- -- -- -- -- -- --\n");
-			pr_info("WDMA_CTX_PTR = 0x%x\n", mtk_r32(eth, 0x4808));
-			pr_info("WDMA_DTX_PTR = 0x%x\n",
-				mtk_r32(eth, MTK_WDMA_DTX_PTR(0)));
-			pr_info("WDMA_GLO_CFG = 0x%x\n",
-				mtk_r32(eth, MTK_WDMA_GLO_CFG(0)));
-			pr_info("WDMA_TX_DBG_MON0 = 0x%x\n",
-				mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(0)));
-			pr_info("PSE_OQ_STA1 = 0x%x\n",
-				mtk_r32(eth, MTK_PSE_OQ_STA(0)));
-			pr_info("PSE_OQ_STA2 = 0x%x\n",
-				mtk_r32(eth, MTK_PSE_OQ_STA(1)));
-			pr_info("PSE_OQ_STA5 = 0x%x\n",
-				mtk_r32(eth, MTK_PSE_OQ_STA(4)));
-			pr_info("==============================\n");
+	if (err_flag)
+		return MTK_FE_START_RESET;
+	else
+		return 0;
+}
 
-			if ((atomic_read(&reset_lock) == 0) &&
-			    (atomic_read(&force) == 0)){
-				atomic_inc(&force);
-				schedule_work(&eth->pending_work);
+u32 mtk_monitor_wdma_rx(struct mtk_eth *eth)
+{
+	static u32 pre_drx[MTK_WDMA_CNT];
+	static u32 pre_opq[MTK_WDMA_CNT];
+	static u32 err_cnt[MTK_WDMA_CNT];
+	u32 i = 0, cur_drx = 0, rx_busy = 0, err_flag = 0;
+	u32 cur_opq = 0;
+
+	for (i = 0; i < MTK_WDMA_CNT; i++) {
+		cur_drx = mtk_r32(eth, MTK_WDMA_DRX_PTR(i));
+		rx_busy = mtk_r32(eth, MTK_WDMA_GLO_CFG(i)) & MTK_RX_DMA_BUSY;
+		if (i == 0)
+			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(5)) & 0x1FF);
+		else if (i == 1)
+			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(5)) & 0x1FF0000);
+		else
+			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(7)) & 0x1FF0000);
+
+		if (cur_drx == pre_drx[i] && rx_busy && cur_opq != 0 &&
+			cur_opq == pre_opq[i]) {
+			err_cnt[i]++;
+			if (err_cnt[i] >= 3) {
+				pr_info("WDMA %d Info\n", i);
+				pr_info("err_cnt = %d", err_cnt[i]);
+				pr_info("prev_drx = 0x%x	| cur_drx = 0x%x\n",
+					pre_drx[i], cur_drx);
+				pr_info("WDMA_CRX_PTR = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_CRX_PTR(i)));
+				pr_info("WDMA_DRX_PTR = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_DRX_PTR(i)));
+				pr_info("WDMA_GLO_CFG = 0x%x\n",
+					mtk_r32(eth, MTK_WDMA_GLO_CFG(i)));
+				pr_info("==============================\n");
+				err_flag = 1;
 			}
-		}
-	} else if (is_qfsm_hang && is_qfwd_hang &&
-		((is_gdm1_tx && is_gmac1_tx && (gdm1_fc < 1)) || (is_gdm2_tx && is_gmac2_tx && (gdm2_fc < 1)))) {
-		err_cnt2++;
-		if (err_cnt2 >= 3) {
+		} else
+			err_cnt[i] = 0;
+		pre_drx[i] = cur_drx;
+		pre_opq[i] = cur_opq;
+	}
+
+	if (err_flag)
+		return MTK_FE_START_RESET;
+	else
+		return 0;
+}
+
+u32 mtk_monitor_rx_fc(struct mtk_eth *eth)
+{
+	u32 i = 0, mib_base = 0, gdm_fc = 0;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		mib_base = MTK_GDM1_TX_GBCNT + MTK_STAT_OFFSET*i;
+		gdm_fc =  mtk_r32(eth, mib_base);
+		if (gdm_fc < 1)
+			return 1;
+	}
+	return 0;
+}
+
+u32 mtk_monitor_qdma_tx(struct mtk_eth *eth)
+{
+	static u32 err_cnt_qtx;
+	u32 err_flag = 0;
+	u32 i = 0, is_rx_fc = 0;
+
+	u32 is_qfsm_hang = (mtk_r32(eth, MTK_QDMA_FSM) & 0xF00) != 0;
+	u32 is_qfwd_hang = mtk_r32(eth, MTK_QDMA_FWD_CNT) == 0;
+
+	is_rx_fc = mtk_monitor_rx_fc(eth);
+	if (is_qfsm_hang && is_qfwd_hang && is_rx_fc) {
+		err_cnt_qtx++;
+		if (err_cnt_qtx >= 3) {
 			pr_info("QDMA Tx Info\n");
-			pr_info("============== Time: %d ================\n",
-				timestamp);
-			pr_info("err_cnt2 = %d", err_cnt2);
+			pr_info("err_cnt = %d", err_cnt_qtx);
 			pr_info("is_qfsm_hang = %d\n", is_qfsm_hang);
 			pr_info("is_qfwd_hang = %d\n", is_qfwd_hang);
-			pr_info("is_qfq_hang = %d\n", is_qfq_hang);
 			pr_info("-- -- -- -- -- -- --\n");
 			pr_info("MTK_QDMA_FSM = 0x%x\n",
 				mtk_r32(eth, MTK_QDMA_FSM));
@@ -280,27 +326,70 @@
 				mtk_r32(eth, MTK_QDMA_FWD_CNT));
 			pr_info("MTK_QDMA_FQ_CNT = 0x%x\n",
 				mtk_r32(eth, MTK_QDMA_FQ_CNT));
-			pr_info("GDM1 FC = 0x%x\n",gdm1_fc);
-			pr_info("GDM2 FC = 0x%x\n",gdm2_fc);
 			pr_info("==============================\n");
-
-			if ((atomic_read(&reset_lock) == 0) &&
-			    (atomic_read(&force) == 0)){
-				atomic_inc(&force);
-				schedule_work(&eth->pending_work);
-			}
+			err_flag = 1;
 		}
-	} else if (is_oq0_stuck && is_cdm1_busy && is_adma_busy) {
-		err_cnt3++;
-		if (err_cnt3 >= 3) {
+	} else
+		err_cnt_qtx = 0;
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+u32 mtk_monitor_qdma_rx(struct mtk_eth *eth)
+{
+	static u32 err_cnt_qrx;
+	static u32 pre_fq_head, pre_fq_tail;
+	u32 err_flag = 0;
+
+	u32 qrx_fsm = (mtk_r32(eth, MTK_QDMA_FSM) & 0x1F) == 9;
+	u32 fq_head = mtk_r32(eth, MTK_QDMA_FQ_HEAD);
+	u32 fq_tail = mtk_r32(eth, MTK_QDMA_FQ_TAIL);
+
+	if (qrx_fsm && fq_head == pre_fq_head &&
+			fq_tail == pre_fq_tail) {
+		err_cnt_qrx++;
+		if (err_cnt_qrx >= 3) {
+			pr_info("QDMA Rx Info\n");
+			pr_info("err_cnt = %d", err_cnt_qrx);
+			pr_info("MTK_QDMA_FSM = %d\n",
+				mtk_r32(eth, MTK_QDMA_FSM));
+			pr_info("FQ_HEAD = 0x%x\n",
+				mtk_r32(eth, MTK_QDMA_FQ_HEAD));
+			pr_info("FQ_TAIL = 0x%x\n",
+				mtk_r32(eth, MTK_QDMA_FQ_TAIL));
+			err_flag = 1;
+		} else
+			err_cnt_qrx = 0;
+	}
+	pre_fq_head = fq_head;
+	pre_fq_tail = fq_tail;
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+
+u32 mtk_monitor_adma_rx(struct mtk_eth *eth)
+{
+	static u32 err_cnt_arx;
+	u32 err_flag = 0;
+	u32 opq0 = (mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0x1FF) != 0;
+	u32 cdm1_fsm = (mtk_r32(eth, MTK_FE_CDM1_FSM) & 0xFFFF0000) != 0;
+	u32 cur_stat = ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x1F) == 0);
+	u32 fifo_rdy = ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x40) == 0);
+
+	if (opq0 && cdm1_fsm && cur_stat && fifo_rdy) {
+		err_cnt_arx++;
+		if (err_cnt_arx >= 3) {
 			pr_info("ADMA Rx Info\n");
-			pr_info("============== Time: %d ================\n",
-				timestamp);
-			pr_info("err_cnt3 = %d", err_cnt3);
-			pr_info("is_oq0_stuck = %d\n", is_oq0_stuck);
-			pr_info("is_cdm1_busy = %d\n", is_cdm1_busy);
-			pr_info("is_adma_busy = %d\n", is_adma_busy);
-			pr_info("-- -- -- -- -- -- --\n");
+			pr_info("err_cnt = %d", err_cnt_arx);
+			pr_info("CDM1_FSM = %d\n",
+				mtk_r32(eth, MTK_FE_CDM1_FSM));
 			pr_info("MTK_PSE_OQ_STA1 = 0x%x\n",
 				mtk_r32(eth, MTK_PSE_OQ_STA(0)));
 			pr_info("MTK_ADMA_RX_DBG0 = 0x%x\n",
@@ -308,25 +397,124 @@
 			pr_info("MTK_ADMA_RX_DBG1 = 0x%x\n",
 				mtk_r32(eth, MTK_ADMA_RX_DBG1));
 			pr_info("==============================\n");
+			err_flag = 1;
+		}
+	} else
+		err_cnt_arx = 0;
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+u32 mtk_monitor_tdma_tx(struct mtk_eth *eth)
+{
+	static u32 err_cnt_ttx;
+	static u32 pre_fsm;
+	u32 err_flag = 0;
+	u32 cur_fsm = 0;
+	u32 tx_busy = 0;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		cur_fsm = (mtk_r32(eth, MTK_FE_CDM6_FSM) & 0x1FFF) != 0;
+		tx_busy = ((mtk_r32(eth, MTK_TDMA_GLO_CFG) & 0x2) != 0);
+
+		if (cur_fsm == pre_fsm && cur_fsm != 0 && tx_busy) {
+			err_cnt_ttx++;
+			if (err_cnt_ttx >= 3) {
+				pr_info("TDMA Tx Info\n");
+				pr_info("err_cnt = %d", err_cnt_ttx);
+				pr_info("CDM6_FSM = %d\n",
+					mtk_r32(eth, MTK_FE_CDM6_FSM));
+				pr_info("DMA CFG = 0x%x\n",
+					mtk_r32(eth, MTK_TDMA_GLO_CFG));
+				pr_info("==============================\n");
+				err_flag = 1;
+			}
+		} else
+			err_cnt_ttx = 0;
+
+		pre_fsm = cur_fsm;
+	}
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+u32 mtk_monitor_tdma_rx(struct mtk_eth *eth)
+{
+	static u32 err_cnt_trx;
+	static u32 pre_fsm;
+	u32 err_flag = 0;
+	u32 cur_fsm = 0;
+	u32 rx_busy = 0;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		cur_fsm = (mtk_r32(eth, MTK_FE_CDM6_FSM) & 0xFFF0000) != 0;
+		rx_busy = ((mtk_r32(eth, MTK_TDMA_GLO_CFG) & 0x8) != 0);
+
+		if (cur_fsm == pre_fsm && cur_fsm != 0 && rx_busy) {
+			err_cnt_trx++;
+			if (err_cnt_trx >= 3) {
+				pr_info("TDMA Rx Info\n");
+				pr_info("err_cnt = %d", err_cnt_trx);
+				pr_info("CDM6_FSM = %d\n",
+					mtk_r32(eth, MTK_FE_CDM6_FSM));
+				pr_info("DMA CFG = 0x%x\n",
+					mtk_r32(eth, MTK_TDMA_GLO_CFG));
+				pr_info("==============================\n");
+				err_flag = 1;
+			}
+		} else
+			err_cnt_trx = 0;
+
+		pre_fsm = cur_fsm;
+	}
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+static const mtk_monitor_xdma_func mtk_reset_monitor_func[] = {
+	[0] = mtk_monitor_wdma_tx,
+	[1] = mtk_monitor_wdma_rx,
+	[2] = mtk_monitor_qdma_tx,
+	[3] = mtk_monitor_qdma_rx,
+	[4] = mtk_monitor_adma_rx,
+	[5] = mtk_monitor_tdma_tx,
+	[6] = mtk_monitor_tdma_rx,
+};
+
+void mtk_dma_monitor(struct timer_list *t)
+{
+	struct mtk_eth *eth = from_timer(eth, t, mtk_dma_monitor_timer);
+	u32 i = 0, ret = 0;
+
+	for (i = 0; i < 6; i++) {
+		ret = (*mtk_reset_monitor_func[i]) (eth);
+		if ((ret == MTK_FE_START_RESET) ||
+			(ret == MTK_FE_STOP_TRAFFIC)) {
 			if ((atomic_read(&reset_lock) == 0) &&
-			    (atomic_read(&force) == 0)){
+				(atomic_read(&force) == 0)) {
 				atomic_inc(&force);
+				mtk_reset_flag = ret;
 				schedule_work(&eth->pending_work);
 			}
+			break;
 		}
-	}else {
-		err_cnt1 = 0;
-		err_cnt2 = 0;
-		err_cnt3 = 0;
 	}
 
-	prev_wdidx = cur_wdidx;
 	mod_timer(&eth->mtk_dma_monitor_timer, jiffies + 1 * HZ);
 }
 
 void mtk_prepare_reset_fe(struct mtk_eth *eth)
 {
-	u32 i = 0, val = 0;
+	u32 i = 0, val = 0, mcr = 0;
 
 	/* Disable NETSYS Interrupt */
 	mtk_w32(eth, 0, MTK_FE_INT_ENABLE);
@@ -344,28 +532,26 @@
 	val = mtk_r32(eth, MTK_QDMA_GLO_CFG);
 	mtk_w32(eth, val & ~(MTK_TX_DMA_EN), MTK_QDMA_GLO_CFG);
 
-	/* Power down sgmii */
-	for (i = 0; i < MTK_MAX_DEVS; i++) {
-		if (!eth->xgmii->regmap_sgmii[i])
-			continue;
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		pr_info("[%s] i:%d type:%d id:%d\n",
+			__func__, i, eth->mac[i]->type, eth->mac[i]->id);
+		if (eth->mac[i]->type == MTK_XGDM_TYPE &&
+		    eth->mac[i]->id != MTK_GMAC1_ID) {
+			mcr = mtk_r32(eth, MTK_XMAC_MCR(eth->mac[i]->id));
+			mcr &= 0xfffffff0;
+			mcr |= XMAC_MCR_TRX_DISABLE;
+			pr_info("disable XMAC TX/RX\n");
+			mtk_w32(eth, mcr, MTK_XMAC_MCR(eth->mac[i]->id));
+		}
 
-		regmap_read(eth->xgmii->regmap_sgmii[i], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
-		val |= SGMII_PHYA_PWD;
-		regmap_write(eth->xgmii->regmap_sgmii[i], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+		if (eth->mac[i]->type == MTK_GDM_TYPE) {
+			mcr = mtk_r32(eth, MTK_MAC_MCR(eth->mac[i]->id));
+			mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
+			mtk_w32(eth, mcr, MTK_MAC_MCR(eth->mac[i]->id));
+			pr_info("disable GMAC TX/RX\n");
+		}
 	}
 
-	/* Force link down GMAC */
-	val = mtk_r32(eth, MTK_MAC_MCR(0));
-	mtk_w32(eth, val & ~(MAC_MCR_FORCE_LINK), MTK_MAC_MCR(0));
-	val = mtk_r32(eth, MTK_MAC_MCR(1));
-	mtk_w32(eth, val & ~(MAC_MCR_FORCE_LINK), MTK_MAC_MCR(1));
-
-	/* Disable GMAC Rx */
-	val = mtk_r32(eth, MTK_MAC_MCR(0));
-	mtk_w32(eth, val & ~(MAC_MCR_RX_EN), MTK_MAC_MCR(0));
-	val = mtk_r32(eth, MTK_MAC_MCR(1));
-	mtk_w32(eth, val & ~(MAC_MCR_RX_EN), MTK_MAC_MCR(1));
-
 	/* Enable GDM drop */
 	for (i = 0; i < MTK_MAC_COUNT; i++)
 		mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
@@ -418,6 +604,7 @@
 {
 	switch (event) {
 	case MTK_WIFI_RESET_DONE:
+	case MTK_FE_STOP_TRAFFIC_DONE:
 		mtk_rest_cnt--;
 		if(!mtk_rest_cnt) {
 			complete(&wait_ser_done);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
index 547d48f..096331b 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
@@ -15,6 +15,10 @@
 #define MTK_WIFI_CHIP_OFFLINE 	0x2004
 #define MTK_FE_RESET_NAT_DONE	0x4001
 
+#define MTK_FE_STOP_TRAFFIC	(0x2005)
+#define MTK_FE_STOP_TRAFFIC_DONE	(0x2006)
+#define MTK_FE_START_TRAFFIC	(0x2007)
+
 /* ADMA Rx Debug Monitor */
 #define MTK_ADMA_RX_DBG0	(PDMA_BASE + 0x238)
 #define MTK_ADMA_RX_DBG1	(PDMA_BASE + 0x23C)
@@ -33,6 +37,12 @@
 #define MTK_PPE_SCAN_MODE_MASK	(0x3 << 16)
 #define MTK_PPE_BUSY		BIT(31)
 
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+#define MTK_WDMA_CNT	(0x3)
+#else
+#define MTK_WDMA_CNT	(0x2)
+#endif
+
 enum mtk_reset_type {
 	MTK_TYPE_COLD_RESET	= 0,
 	MTK_TYPE_WARM_RESET,
@@ -55,6 +65,8 @@
 extern struct completion wait_ser_done;
 extern char* mtk_reset_event_name[32];
 extern atomic_t reset_lock;
+extern struct completion wait_nat_done;
+extern u32 mtk_reset_flag;
 
 irqreturn_t mtk_handle_fe_irq(int irq, void *_eth);
 u32 mtk_check_reset_event(struct mtk_eth *eth, u32 status);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 16c9a40..ffa8da6 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3537,6 +3537,41 @@
 	return -EOPNOTSUPP;
 }
 
+int mtk_phy_config(struct mtk_eth *eth, int enable)
+{
+	struct device_node *mii_np = NULL;
+	struct device_node *child = NULL;
+	int addr = 0;
+	u32 val = 0;
+
+	mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
+	if (!mii_np) {
+		dev_err(eth->dev, "no %s child node found", "mdio-bus");
+		return -ENODEV;
+	}
+
+	if (!of_device_is_available(mii_np)) {
+		dev_err(eth->dev, "device is not available\n");
+		return -ENODEV;
+	}
+
+	for_each_available_child_of_node(mii_np, child) {
+		addr = of_mdio_parse_addr(&eth->mii_bus->dev, child);
+		if (addr < 0)
+			continue;
+		pr_info("%s %d addr:%d name:%s\n",
+			__func__, __LINE__, addr, child->name);
+		val = _mtk_mdio_read(eth, addr, mdiobus_c45_addr(0x1e, 0));
+		if (enable)
+			val &= ~BMCR_PDOWN;
+		else
+			val |= BMCR_PDOWN;
+		_mtk_mdio_write(eth, addr, mdiobus_c45_addr(0x1e, 0), val);
+	}
+
+	return 0;
+}
+
 static void mtk_pending_work(struct work_struct *work)
 {
 	struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work);
@@ -3556,12 +3591,10 @@
 
 	rtnl_lock();
 
-	/* Disabe FE P3 and P4 */
-	val = mtk_r32(eth, MTK_FE_GLO_CFG);
-	val |= MTK_FE_LINK_DOWN_P3;
-	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
-		val |= MTK_FE_LINK_DOWN_P4;
-	mtk_w32(eth, val, MTK_FE_GLO_CFG);
+	while (test_and_set_bit_lock(MTK_RESETTING, &eth->state))
+		cpu_relax();
+
+	mtk_phy_config(eth, 0);
 
 	/* Adjust PPE configurations to prepare for reset */
 	mtk_prepare_reset_ppe(eth, 0);
@@ -3575,18 +3608,22 @@
 	for (i = 0; i < MTK_MAC_COUNT; i++) {
 		if (!eth->netdev[i])
 			continue;
-		call_netdevice_notifiers(MTK_FE_START_RESET, eth->netdev[i]);
+		if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
+			pr_info("send MTK_FE_STOP_TRAFFIC event\n");
+			call_netdevice_notifiers(MTK_FE_STOP_TRAFFIC,
+				eth->netdev[i]);
+		} else {
+			pr_info("send MTK_FE_START_RESET event\n");
+			call_netdevice_notifiers(MTK_FE_START_RESET,
+				eth->netdev[i]);
+		}
 		rtnl_unlock();
-		if (!wait_for_completion_timeout(&wait_ser_done, 5000))
-			pr_warn("[%s] wait for MTK_FE_START_RESET failed\n",
-				__func__);
+		if (!wait_for_completion_timeout(&wait_ser_done, 3000))
+			pr_warn("wait for MTK_FE_START_RESET failed\n");
 		rtnl_lock();
 		break;
 	}
 
-	while (test_and_set_bit_lock(MTK_RESETTING, &eth->state))
-		cpu_relax();
-
 	del_timer_sync(&eth->mtk_dma_monitor_timer);
 	pr_info("[%s] mtk_stop starts !\n", __func__);
 	/* stop all devices to make sure that dma is properly shut down */
@@ -3619,37 +3656,20 @@
 		}
 	}
 
-	/* Set KA tick select */
-	mtk_m32(eth, MTK_PPE_TICK_SEL_MASK, 0, MTK_PPE_TB_CFG(0));
-	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
-		mtk_m32(eth, MTK_PPE_TICK_SEL_MASK, 0, MTK_PPE_TB_CFG(1));
-
-	/* Enabe FE P3 and P4*/
-	val = mtk_r32(eth, MTK_FE_GLO_CFG);
-	val &= ~MTK_FE_LINK_DOWN_P3;
-	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
-		val &= ~MTK_FE_LINK_DOWN_P4;
-	mtk_w32(eth, val, MTK_FE_GLO_CFG);
-
-	/* Power up sgmii */
 	for (i = 0; i < MTK_MAC_COUNT; i++) {
 		if (!eth->netdev[i])
 			continue;
-		mac = netdev_priv(eth->netdev[i]);
-		phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
-		if (!phy_node && eth->xgmii->regmap_sgmii[i]) {
-			mtk_gmac_sgmii_path_setup(eth, i);
-			regmap_write(eth->xgmii->regmap_sgmii[i], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+		if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
+			pr_info("send MTK_FE_START_TRAFFIC event\n");
+			call_netdevice_notifiers(MTK_FE_START_TRAFFIC,
+				eth->netdev[i]);
+		} else {
+			pr_info("send MTK_FE_RESET_DONE event\n");
+			call_netdevice_notifiers(MTK_FE_RESET_DONE,
+				eth->netdev[i]);
 		}
-	}
-
-	for (i = 0; i < MTK_MAC_COUNT; i++) {
-		if (!eth->netdev[i])
-			continue;
-		call_netdevice_notifiers(MTK_FE_RESET_NAT_DONE, eth->netdev[i]);
-		pr_info("[%s] HNAT reset done !\n", __func__);
-		call_netdevice_notifiers(MTK_FE_RESET_DONE, eth->netdev[i]);
-		pr_info("[%s] WiFi SER reset done !\n", __func__);
+		call_netdevice_notifiers(MTK_FE_RESET_NAT_DONE,
+			eth->netdev[i]);
 		break;
 	}
 
@@ -3660,6 +3680,9 @@
 	timer_setup(&eth->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
 	eth->mtk_dma_monitor_timer.expires = jiffies;
 	add_timer(&eth->mtk_dma_monitor_timer);
+
+	mtk_phy_config(eth, 1);
+	mtk_reset_flag = 0;
 	clear_bit_unlock(MTK_RESETTING, &eth->state);
 
 	rtnl_unlock();
@@ -4348,7 +4371,7 @@
 	platform_set_drvdata(pdev, eth);
 
 	register_netdevice_notifier(&mtk_eth_netdevice_nb);
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
 	timer_setup(&eth->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
 	eth->mtk_dma_monitor_timer.expires = jiffies;
 	add_timer(&eth->mtk_dma_monitor_timer);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index b617c13..dc02870 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -494,11 +494,18 @@
 #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
 
 /* WDMA Registers */
+#define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
 #define MTK_WDMA_DTX_PTR(x)	(WDMA_BASE(x) + 0xC)
 #define MTK_WDMA_GLO_CFG(x)	(WDMA_BASE(x) + 0x204)
 #define MTK_WDMA_TX_DBG_MON0(x)	(WDMA_BASE(x) + 0x230)
+#define MTK_WDMA_RX_DBG_MON1(x)	(WDMA_BASE(x) + 0x3c4)
+#define MTK_WDMA_CRX_PTR(x)	(WDMA_BASE(x) + 0x108)
+#define MTK_WDMA_DRX_PTR(x)	(WDMA_BASE(x) + 0x10C)
 #define MTK_CDM_TXFIFO_RDY	BIT(7)
 
+/*TDMA Register*/
+#define MTK_TDMA_GLO_CFG	(0x6204)
+
 /* GMA1 Received Good Byte Count Register */
 #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
 #define MTK_GDM1_TX_GBCNT       0x1C00
@@ -754,9 +761,16 @@
 #if defined(CONFIG_MEDIATEK_NETSYS_V2)
 #define RSTCTRL_PPE0	BIT(30)
 #define RSTCTRL_PPE1 	BIT(31)
+#elif defined(CONFIG_MEDIATEK_NETSYS_V3)
+#define RSTCTRL_PPE0	BIT(29)
+#define RSTCTRL_PPE1	BIT(30)
+#define RSTCTRL_PPE2	BIT(31)
+#define RSTCTRL_WDMA0	BIT(24)
+#define RSTCTRL_WDMA1	BIT(25)
+#define RSTCTRL_WDMA2	BIT(26)
 #else
 #define RSTCTRL_PPE0	BIT(31)
-#define RSTCTRL_PPE1 	0
+#define RSTCTRL_PPE1	0
 #endif
 
 /* ethernet reset check idle register */
@@ -1241,6 +1255,7 @@
 	MTK_NETSYS_V3_BIT,
 	MTK_SOC_MT7628_BIT,
 	MTK_RSTCTRL_PPE1_BIT,
+	MTK_RSTCTRL_PPE2_BIT,
 	MTK_U3_COPHY_V2_BIT,
 	MTK_8GB_ADDRESSING_BIT,
 
@@ -1290,6 +1305,7 @@
 #define MTK_NETSYS_V3		BIT_ULL(MTK_NETSYS_V3_BIT)
 #define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
 #define MTK_RSTCTRL_PPE1	BIT_ULL(MTK_RSTCTRL_PPE1_BIT)
+#define MTK_RSTCTRL_PPE2	BIT_ULL(MTK_RSTCTRL_PPE2_BIT)
 #define MTK_U3_COPHY_V2		BIT_ULL(MTK_U3_COPHY_V2_BIT)
 #define MTK_8GB_ADDRESSING	BIT_ULL(MTK_8GB_ADDRESSING_BIT)
 
@@ -1401,7 +1417,7 @@
 
 #define MT7988_CAPS   (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC3_SGMII | \
 		       MTK_MUX_GMAC123_TO_GEPHY_SGMII | MTK_QDMA | \
-		       MTK_NETSYS_V3 | MTK_RSTCTRL_PPE1 | \
+		       MTK_NETSYS_V3 | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | \
 		       MTK_GMAC1_USXGMII | MTK_GMAC2_USXGMII | \
 		       MTK_GMAC3_USXGMII | MTK_MUX_GMAC123_TO_USXGMII | \
 		       MTK_GMAC2_XGMII | MTK_MUX_GMAC2_TO_XGMII | MTK_RSS)
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
index 37c5587..9c40ac8 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
@@ -682,8 +682,9 @@
 		hnat_hw_init(ppe_id);
 	}
 
-	set_gmac_ppe_fwd(0, 1);
-	set_gmac_ppe_fwd(1, 1);
+	set_gmac_ppe_fwd(NR_GMAC1_PORT, 1);
+	set_gmac_ppe_fwd(NR_GMAC2_PORT, 1);
+	set_gmac_ppe_fwd(NR_GMAC3_PORT, 1);
 	register_netevent_notifier(&nf_hnat_netevent_nb);
 
 	return 0;