}
 
 static u32
-mtk_wed_check_busy(struct mtk_wed_device *dev)
+mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
 {
-       if (wed_r32(dev, MTK_WED_GLO_CFG) & MTK_WED_GLO_CFG_TX_DMA_BUSY)
-               return true;
-
-       if (wed_r32(dev, MTK_WED_WPDMA_GLO_CFG) &
-           MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY)
-               return true;
-
-       if (wed_r32(dev, MTK_WED_CTRL) & MTK_WED_CTRL_WDMA_INT_AGENT_BUSY)
-               return true;
-
-       if (wed_r32(dev, MTK_WED_WDMA_GLO_CFG) &
-           MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY)
-               return true;
-
-       if (wdma_r32(dev, MTK_WDMA_GLO_CFG) &
-           MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY)
-               return true;
-
-       if (wed_r32(dev, MTK_WED_CTRL) &
-           (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY))
-               return true;
-
-       return false;
+       return !!(wed_r32(dev, reg) & mask);
 }
 
 static int
-mtk_wed_poll_busy(struct mtk_wed_device *dev)
+mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
 {
        int sleep = 15000;
        int timeout = 100 * sleep;
        u32 val;
 
        return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
-                                timeout, false, dev);
+                                timeout, false, dev, reg, mask);
+}
+
+static int
+mtk_wed_rx_reset(struct mtk_wed_device *dev)
+{
+       struct mtk_wed_wo *wo = dev->hw->wed_wo;
+       u8 val = MTK_WED_WO_STATE_SER_RESET;
+       int i, ret;
+
+       ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
+                                  MTK_WED_WO_CMD_CHANGE_STATE, &val,
+                                  sizeof(val), true);
+       if (ret)
+               return ret;
+
+       wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+       ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+                               MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
+       if (ret) {
+               mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+               mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
+       } else {
+               wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+                       MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
+                       MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
+
+               wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+                       MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
+                       MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
+               wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+                       MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
+                       MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
+
+               wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
+       }
+
+       /* reset rro qm */
+       wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN);
+       ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+                               MTK_WED_CTRL_RX_RRO_QM_BUSY);
+       if (ret) {
+               mtk_wed_reset(dev, MTK_WED_RESET_RX_RRO_QM);
+       } else {
+               wed_set(dev, MTK_WED_RROQM_RST_IDX,
+                       MTK_WED_RROQM_RST_IDX_MIOD |
+                       MTK_WED_RROQM_RST_IDX_FDBK);
+               wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
+       }
+
+       /* reset route qm */
+       wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+       ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+                               MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
+       if (ret)
+               mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
+       else
+               wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+                       MTK_WED_RTQM_Q_RST);
+
+       /* reset tx wdma */
+       mtk_wdma_tx_reset(dev);
+
+       /* reset tx wdma drv */
+       wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
+       mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+                         MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
+       mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
+
+       /* reset wed rx dma */
+       ret = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
+                               MTK_WED_GLO_CFG_RX_DMA_BUSY);
+       wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_RX_DMA_EN);
+       if (ret) {
+               mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
+       } else {
+               struct mtk_eth *eth = dev->hw->eth;
+
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+                       wed_set(dev, MTK_WED_RESET_IDX,
+                               MTK_WED_RESET_IDX_RX_V2);
+               else
+                       wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
+               wed_w32(dev, MTK_WED_RESET_IDX, 0);
+       }
+
+       /* reset rx bm */
+       wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
+       mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+                         MTK_WED_CTRL_WED_RX_BM_BUSY);
+       mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
+
+       /* wo change to enable state */
+       val = MTK_WED_WO_STATE_ENABLE;
+       ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
+                                  MTK_WED_WO_CMD_CHANGE_STATE, &val,
+                                  sizeof(val), true);
+       if (ret)
+               return ret;
+
+       /* wed_rx_ring_reset */
+       for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++) {
+               if (!dev->rx_ring[i].desc)
+                       continue;
+
+               mtk_wed_ring_reset(&dev->rx_ring[i], MTK_WED_RX_RING_SIZE,
+                                  false);
+       }
+       mtk_wed_free_rx_buffer(dev);
+
+       return 0;
 }
 
 static void
                                   true);
        }
 
-       if (mtk_wed_poll_busy(dev))
-               busy = mtk_wed_check_busy(dev);
-
+       /* 1. reset WED tx DMA */
+       wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_EN);
+       busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
+                                MTK_WED_GLO_CFG_TX_DMA_BUSY);
        if (busy) {
                mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
        } else {
-               wed_w32(dev, MTK_WED_RESET_IDX,
-                       MTK_WED_RESET_IDX_TX |
-                       MTK_WED_RESET_IDX_RX);
+               wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
                wed_w32(dev, MTK_WED_RESET_IDX, 0);
        }
 
-       mtk_wdma_rx_reset(dev);
+       /* 2. reset WDMA rx DMA */
+       busy = !!mtk_wdma_rx_reset(dev);
+       wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+       if (!busy)
+               busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
+                                        MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
 
        if (busy) {
                mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
                        MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE);
        }
 
+       /* 3. reset WED WPDMA tx */
+       wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+
        for (i = 0; i < 100; i++) {
                val = wed_r32(dev, MTK_WED_TX_BM_INTF);
                if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
        }
 
        mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
+       wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_BM_EN);
        mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
 
+       /* 4. reset WED WPDMA tx */
+       busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+                                MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
+       wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+               MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
+               MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
+       if (!busy)
+               busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+                                        MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY);
+
        if (busy) {
                mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
                mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
                        MTK_WED_WPDMA_RESET_IDX_RX);
                wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0);
        }
+
+       dev->init_done = false;
+       if (dev->hw->version == 1)
+               return;
+
+       if (!busy) {
+               wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_WPDMA_IDX_RX);
+               wed_w32(dev, MTK_WED_RESET_IDX, 0);
+       }
+
+       mtk_wed_rx_reset(dev);
 }
 
 static int
 {
        int i;
 
+       if (mtk_wed_get_rx_capa(dev) && mtk_wed_rx_buffer_alloc(dev))
+               return;
+
        for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
                if (!dev->rx_wdma[i].desc)
                        mtk_wed_wdma_rx_ring_setup(dev, i, 16);
                goto out;
 
        if (mtk_wed_get_rx_capa(dev)) {
-               ret = mtk_wed_rx_buffer_alloc(dev);
-               if (ret)
-                       goto out;
-
                ret = mtk_wed_rro_alloc(dev);
                if (ret)
                        goto out;