Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Lendacky, Thomas and committed by
David S. Miller
20a41fba d2fd719b

+4 -2
+1 -1
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
··· 1595 1595 packet->rdesc_count, 1); 1596 1596 1597 1597 /* Make sure ownership is written to the descriptor */ 1598 - dma_wmb(); 1598 + wmb(); 1599 1599 1600 1600 ring->cur = cur_index + 1; 1601 1601 if (!packet->skb->xmit_more ||
+3 -1
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
··· 1807 1807 struct netdev_queue *txq; 1808 1808 int processed = 0; 1809 1809 unsigned int tx_packets = 0, tx_bytes = 0; 1810 + unsigned int cur; 1810 1811 1811 1812 DBGPR("-->xgbe_tx_poll\n"); 1812 1813 ··· 1815 1814 if (!ring) 1816 1815 return 0; 1817 1816 1817 + cur = ring->cur; 1818 1818 txq = netdev_get_tx_queue(netdev, channel->queue_index); 1819 1819 1820 1820 while ((processed < XGBE_TX_DESC_MAX_PROC) && 1821 - (ring->dirty != ring->cur)) { 1821 + (ring->dirty != cur)) { 1822 1822 rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); 1823 1823 rdesc = rdata->rdesc; 1824 1824