amd-xgbe: Check Rx queue fifos before stopping Rx DMA
[cascardo/linux.git] / drivers / net / ethernet / amd / xgbe / xgbe-dev.c
index 43273c9..b48c6ec 100644 (file)
@@ -2656,6 +2656,32 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata)
        }
 }
 
+static void xgbe_prepare_rx_stop(struct xgbe_prv_data *pdata,
+                                unsigned int queue)
+{
+       unsigned int rx_status;
+       unsigned long rx_timeout;
+
+       /* The Rx engine cannot be stopped if it is actively processing
+        * packets. Wait for the Rx queue to empty the Rx fifo.  Don't
+        * wait forever though...
+        */
+       rx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
+       while (time_before(jiffies, rx_timeout)) {
+               rx_status = XGMAC_MTL_IOREAD(pdata, queue, MTL_Q_RQDR);
+               if ((XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, PRXQ) == 0) &&
+                   (XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, RXQSTS) == 0))
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
+       if (!time_before(jiffies, rx_timeout))
+               netdev_info(pdata->netdev,
+                           "timed out waiting for Rx queue %u to empty\n",
+                           queue);
+}
+
 static void xgbe_enable_rx(struct xgbe_prv_data *pdata)
 {
        struct xgbe_channel *channel;
@@ -2694,6 +2720,10 @@ static void xgbe_disable_rx(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 0);
        XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 0);
 
+       /* Prepare for Rx DMA channel stop */
+       for (i = 0; i < pdata->rx_q_count; i++)
+               xgbe_prepare_rx_stop(pdata, i);
+
        /* Disable each Rx queue */
        XGMAC_IOWRITE(pdata, MAC_RQC0R, 0);