amd-xgbe: Check Rx queue fifos before stopping Rx DMA
authorLendacky, Thomas <Thomas.Lendacky@amd.com>
Wed, 17 Feb 2016 17:49:16 +0000 (11:49 -0600)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Feb 2016 20:22:20 +0000 (15:22 -0500)
Check to be sure that the Rx queue fifos are empty before stopping the
Rx DMA channels.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-dev.c

index b6fa89102526b95e579d5dd16cbecad3fe9226d2..bbef95973c27355cad33c3e7ffc7c53d15964f24 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define MTL_Q_TQDR                     0x08
 #define MTL_Q_RQOMR                    0x40
 #define MTL_Q_RQMPOCR                  0x44
-#define MTL_Q_RQDR                     0x4c
+#define MTL_Q_RQDR                     0x48
 #define MTL_Q_RQFCR                    0x50
 #define MTL_Q_IER                      0x70
 #define MTL_Q_ISR                      0x74
 
 /* MTL queue register entry bit positions and sizes */
+#define MTL_Q_RQDR_PRXQ_INDEX          16
+#define MTL_Q_RQDR_PRXQ_WIDTH          14
+#define MTL_Q_RQDR_RXQSTS_INDEX                4
+#define MTL_Q_RQDR_RXQSTS_WIDTH                2
 #define MTL_Q_RQFCR_RFA_INDEX          1
 #define MTL_Q_RQFCR_RFA_WIDTH          6
 #define MTL_Q_RQFCR_RFD_INDEX          17
index 43273c9823aa31488495a7b3b3866edc0c23a1de..b48c6eca3e6b275c6bd9c5314139273e95c155fe 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);