aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLendacky, Thomas <Thomas.Lendacky@amd.com>2015-10-21 16:37:05 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-23 05:59:04 -0400
commit20a41fba679d665cdae2808e2b9cae97c073351f (patch)
tree953d8bbad9cc0bd690448e6858a3c40703cf66fb
parentd2fd719bcb0e83cb39cfee22ee800f98a56eceb3 (diff)
amd-xgbe: Use wmb before updating current descriptor count
The code currently uses the lightweight dma_wmb barrier before updating the current descriptor count. Under heavy load, the Tx cleanup routine was seeing the updated current descriptor count before the updated descriptor information. As a result, the Tx descriptor was being cleaned up before it was used because it was not "owned" by the hardware yet, resulting in a Tx queue hang. Using the wmb barrier insures that the descriptor is updated before the descriptor counter preventing the Tx queue hang. For extra insurance, the Tx cleanup routine is changed to grab the current decriptor count on entry and uses that initial value in the processing loop rather than trying to chase the current value. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Tested-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c4
2 files changed, 4 insertions, 2 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index a4473d8ff4fa..e9ab8b9f3b9c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1595,7 +1595,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
1595 packet->rdesc_count, 1); 1595 packet->rdesc_count, 1);
1596 1596
1597 /* Make sure ownership is written to the descriptor */ 1597 /* Make sure ownership is written to the descriptor */
1598 dma_wmb(); 1598 wmb();
1599 1599
1600 ring->cur = cur_index + 1; 1600 ring->cur = cur_index + 1;
1601 if (!packet->skb->xmit_more || 1601 if (!packet->skb->xmit_more ||
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index aae9d5ecd182..d2b77d985441 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1807,6 +1807,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
1807 struct netdev_queue *txq; 1807 struct netdev_queue *txq;
1808 int processed = 0; 1808 int processed = 0;
1809 unsigned int tx_packets = 0, tx_bytes = 0; 1809 unsigned int tx_packets = 0, tx_bytes = 0;
1810 unsigned int cur;
1810 1811
1811 DBGPR("-->xgbe_tx_poll\n"); 1812 DBGPR("-->xgbe_tx_poll\n");
1812 1813
@@ -1814,10 +1815,11 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
1814 if (!ring) 1815 if (!ring)
1815 return 0; 1816 return 0;
1816 1817
1818 cur = ring->cur;
1817 txq = netdev_get_tx_queue(netdev, channel->queue_index); 1819 txq = netdev_get_tx_queue(netdev, channel->queue_index);
1818 1820
1819 while ((processed < XGBE_TX_DESC_MAX_PROC) && 1821 while ((processed < XGBE_TX_DESC_MAX_PROC) &&
1820 (ring->dirty != ring->cur)) { 1822 (ring->dirty != cur)) {
1821 rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); 1823 rdata = XGBE_GET_DESC_DATA(ring, ring->dirty);
1822 rdesc = rdata->rdesc; 1824 rdesc = rdata->rdesc;
1823 1825