summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-03-11 11:09:13 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-10-17 14:34:52 +0100
commite3ce425b0ad0e862234cecec2695b8b35d5cc3ae (patch)
treee1e3af55961a968b23eea013e4bfa4ff9f4d1a7b
parent313c7fd3bb73c5ff942d48020bd6e3cc11a4f935 (diff)
net: fec: ensure that we dma unmap the transmit descriptors
On transmit timeout or close, dirty transmit descriptors were not being correctly cleaned: the only time that DMA mappings are cleaned is when scanning the TX ring after a transmit interrupt. Fix this. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index fd49bd70d15d..87120522ba66 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -364,6 +364,15 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
return 0;
}
+static void
+fec_enet_tx_unmap(struct bufdesc *bdp, struct fec_enet_private *fep)
+{
+ dma_addr_t addr = bdp->cbd_bufaddr;
+ size_t length = bdp->cbd_datlen;
+
+ dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
+}
+
static int
fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
{
@@ -806,11 +815,13 @@ static void fec_enet_bd_init(struct net_device *dev)
/* Initialize the BD for every fragment in the page. */
bdp->cbd_sc = 0;
+ if (bdp->cbd_bufaddr && !IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+ fec_enet_tx_unmap(bdp, fep);
+ bdp->cbd_bufaddr = 0;
if (fep->tx_skbuff[i]) {
dev_kfree_skb_any(fep->tx_skbuff[i]);
fep->tx_skbuff[i] = NULL;
}
- bdp->cbd_bufaddr = 0;
bdp = fec_enet_get_nextdesc(bdp, fep);
}
@@ -1107,8 +1118,7 @@ fec_enet_tx(struct net_device *ndev)
skb = fep->tx_skbuff[index];
fep->tx_skbuff[index] = NULL;
if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
- bdp->cbd_datlen, DMA_TO_DEVICE);
+ fec_enet_tx_unmap(bdp, fep);
bdp->cbd_bufaddr = 0;
if (!skb) {
bdp = fec_enet_get_nextdesc(bdp, fep);
@@ -2127,6 +2137,9 @@ static void fec_enet_free_buffers(struct net_device *ndev)
bdp = fep->tx_bd_base;
for (i = 0; i < fep->tx_ring_size; i++) {
+ if (bdp->cbd_bufaddr && !IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+ fec_enet_tx_unmap(bdp, fep);
+ bdp->cbd_bufaddr = 0;
kfree(fep->tx_bounce[i]);
fep->tx_bounce[i] = NULL;
skb = fep->tx_skbuff[i];