76 lines
2.7 KiB
Diff
76 lines
2.7 KiB
Diff
From 2c2a9cbd64387d6b70ac5db013e9bfe9412c7354 Mon Sep 17 00:00:00 2001
|
|
From: Karl Beldan <karl.beldan@rivierawaves.com>
|
|
Date: Wed, 5 Nov 2014 15:32:59 +0100
|
|
Subject: [PATCH] net: mv643xx_eth: reclaim TX skbs only when released by the
|
|
HW
|
|
Origin: https://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=2c2a9cbd64387d6b70ac5db013e9bfe9412c7354
|
|
|
|
ATM, txq_reclaim will dequeue and free an skb for each tx desc released
|
|
by the hw that has TX_LAST_DESC set. However, in case of TSO, each
|
|
hw desc embedding the last part of a segment has TX_LAST_DESC set,
|
|
losing the one-to-one 'last skb frag'/'TX_LAST_DESC set' correspondance,
|
|
which causes data corruption.
|
|
|
|
Fix this by checking TX_ENABLE_INTERRUPT instead of TX_LAST_DESC, and
|
|
warn when trying to dequeue from an empty txq (which can be symptomatic
|
|
of releasing skbs prematurely).
|
|
|
|
Fixes: 3ae8f4e0b98 ('net: mv643xx_eth: Implement software TSO')
|
|
Reported-by: Slawomir Gajzner <slawomir.gajzner@gmail.com>
|
|
Reported-by: Julien D'Ascenzio <jdascenzio@yahoo.fr>
|
|
Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
|
|
Cc: Ian Campbell <ijc@hellion.org.uk>
|
|
Cc: Eric Dumazet <eric.dumazet@gmail.com>
|
|
Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
|
Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
drivers/net/ethernet/marvell/mv643xx_eth.c | 18 ++++++++++--------
|
|
1 file changed, 10 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
|
|
index b151a94..d44560d 100644
|
|
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
|
|
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
|
|
@@ -1047,7 +1047,6 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
|
|
int tx_index;
|
|
struct tx_desc *desc;
|
|
u32 cmd_sts;
|
|
- struct sk_buff *skb;
|
|
|
|
tx_index = txq->tx_used_desc;
|
|
desc = &txq->tx_desc_area[tx_index];
|
|
@@ -1066,19 +1065,22 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
|
|
reclaimed++;
|
|
txq->tx_desc_count--;
|
|
|
|
- skb = NULL;
|
|
- if (cmd_sts & TX_LAST_DESC)
|
|
- skb = __skb_dequeue(&txq->tx_skb);
|
|
+ if (!IS_TSO_HEADER(txq, desc->buf_ptr))
|
|
+ dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
|
|
+ desc->byte_cnt, DMA_TO_DEVICE);
|
|
+
|
|
+ if (cmd_sts & TX_ENABLE_INTERRUPT) {
|
|
+ struct sk_buff *skb = __skb_dequeue(&txq->tx_skb);
|
|
+
|
|
+ if (!WARN_ON(!skb))
|
|
+ dev_kfree_skb(skb);
|
|
+ }
|
|
|
|
if (cmd_sts & ERROR_SUMMARY) {
|
|
netdev_info(mp->dev, "tx error\n");
|
|
mp->dev->stats.tx_errors++;
|
|
}
|
|
|
|
- if (!IS_TSO_HEADER(txq, desc->buf_ptr))
|
|
- dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
|
|
- desc->byte_cnt, DMA_TO_DEVICE);
|
|
- dev_kfree_skb(skb);
|
|
}
|
|
|
|
__netif_tx_unlock_bh(nq);
|
|
--
|
|
1.7.10.4
|
|
|