From e3ce425b0ad0e862234cecec2695b8b35d5cc3ae Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 11 Mar 2014 11:09:13 +0000 Subject: 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 --- drivers/net/ethernet/freescale/fec_main.c | 19 ++++++++++++++++--- 1 file 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]; -- cgit