diff options
author | Duan Fugang-B38611 <B38611@freescale.com> | 2013-11-13 20:57:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-14 16:37:33 -0500 |
commit | d842a31f121eccaba639ff26a1757649abd7d58e (patch) | |
tree | 1f51bdeb7b9dfc401a92e6dce02e4620dbe545e4 /drivers/net/ethernet/freescale | |
parent | d30a58ba2ef5092f10985d357d22acab232b6dcc (diff) |
net:fec: fix WARNING caused by lack of calls to dma_mapping_error()
The driver fails to check the results of DMA mapping and results in
the following warning: (with kernel config "CONFIG_DMA_API_DEBUG" enable)
------------[ cut here ]------------
WARNING: at lib/dma-debug.c:937 check_unmap+0x43c/0x7d8()
fec 2188000.ethernet: DMA-API: device driver failed to check map
error[device address=0x00000000383a8040] [size=2048 bytes] [mapped as single]
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.10.17-16827-g9cdb0ba-dirty #188
[<80013c4c>] (unwind_backtrace+0x0/0xf8) from [<80011704>] (show_stack+0x10/0x14)
[<80011704>] (show_stack+0x10/0x14) from [<80025614>] (warn_slowpath_common+0x4c/0x6c)
[<80025614>] (warn_slowpath_common+0x4c/0x6c) from [<800256c8>] (warn_slowpath_fmt+0x30/0x40)
[<800256c8>] (warn_slowpath_fmt+0x30/0x40) from [<8026bfdc>] (check_unmap+0x43c/0x7d8)
[<8026bfdc>] (check_unmap+0x43c/0x7d8) from [<8026c584>] (debug_dma_unmap_page+0x6c/0x78)
[<8026c584>] (debug_dma_unmap_page+0x6c/0x78) from [<8038049c>] (fec_enet_rx_napi+0x254/0x8a8)
[<8038049c>] (fec_enet_rx_napi+0x254/0x8a8) from [<804dc8c0>] (net_rx_action+0x94/0x160)
[<804dc8c0>] (net_rx_action+0x94/0x160) from [<8002c758>] (__do_softirq+0xe8/0x1d0)
[<8002c758>] (__do_softirq+0xe8/0x1d0) from [<8002c8e8>] (do_softirq+0x4c/0x58)
[<8002c8e8>] (do_softirq+0x4c/0x58) from [<8002cb50>] (irq_exit+0x90/0xc8)
[<8002cb50>] (irq_exit+0x90/0xc8) from [<8000ea88>] (handle_IRQ+0x3c/0x94)
[<8000ea88>] (handle_IRQ+0x3c/0x94) from [<8000855c>] (gic_handle_irq+0x28/0x5c)
[<8000855c>] (gic_handle_irq+0x28/0x5c) from [<8000de00>] (__irq_svc+0x40/0x50)
Exception stack(0x815a5f38 to 0x815a5f80)
5f20: 815a5f80 3b9aca00
5f40: 0fe52383 00000002 0dd8950e 00000002 81e7b080 00000000 00000000 815ac4d8
5f60: 806032ec 00000000 00000017 815a5f80 80059028 8041fc4c 60000013 ffffffff
[<8000de00>] (__irq_svc+0x40/0x50) from [<8041fc4c>] (cpuidle_enter_state+0x50/0xf0)
[<8041fc4c>] (cpuidle_enter_state+0x50/0xf0) from [<8041fd94>] (cpuidle_idle_call+0xa8/0x14c)
[<8041fd94>] (cpuidle_idle_call+0xa8/0x14c) from [<8000edac>] (arch_cpu_idle+0x10/0x4c)
[<8000edac>] (arch_cpu_idle+0x10/0x4c) from [<800582f8>] (cpu_startup_entry+0x60/0x130)
[<800582f8>] (cpu_startup_entry+0x60/0x130) from [<80bc7a48>] (start_kernel+0x2d0/0x328)
[<80bc7a48>] (start_kernel+0x2d0/0x328) from [<10008074>] (0x10008074)
---[ end trace c6edec32436e0042 ]---
Because dma-debug add new interfaces to debug dma mapping errors, pls refer
to: http://lwn.net/Articles/516640/
After dma mapping, it must call dma_mapping_error() to check mapping error,
otherwise the map_err_type alway is MAP_ERR_NOT_CHECKED, check_unmap() define
the mapping is not checked and dump the error msg. So,add dma_mapping_error()
checking to fix the WARNING
And RX DMA buffers are used repeatedly and the driver copies it into an skb,
fec_enet_rx() should not map or unmap, use dma_sync_single_for_cpu()/dma_sync_single_for_device()
instead of dma_map_single()/dma_unmap_single().
There have another potential issue: fec_enet_rx() passes the DMA address to __va().
Physical and DMA addresses are *not* the same thing. They may differ if the device
is behind an IOMMU or bounce buffering was required, or just because there is a fixed
offset between the device and host physical addresses. Also fix it in this patch.
=============================================
V2: add net_ratelimit() to limit map err message.
use dma_sync_single_for_cpu() instead of dma_map_single().
fix the issue that pass DMA addresses to __va() to get virture address.
V1: initial send
=============================================
Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index b2793b91cc55..4cbebf3d80eb 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c | |||
@@ -386,7 +386,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
386 | */ | 386 | */ |
387 | bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, | 387 | bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, |
388 | FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); | 388 | FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); |
389 | 389 | if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { | |
390 | bdp->cbd_bufaddr = 0; | ||
391 | fep->tx_skbuff[index] = NULL; | ||
392 | dev_kfree_skb_any(skb); | ||
393 | if (net_ratelimit()) | ||
394 | netdev_err(ndev, "Tx DMA memory map failed\n"); | ||
395 | return NETDEV_TX_OK; | ||
396 | } | ||
390 | /* Send it on its way. Tell FEC it's ready, interrupt when done, | 397 | /* Send it on its way. Tell FEC it's ready, interrupt when done, |
391 | * it's the last BD of the frame, and to put the CRC on the end. | 398 | * it's the last BD of the frame, and to put the CRC on the end. |
392 | */ | 399 | */ |
@@ -861,6 +868,7 @@ fec_enet_rx(struct net_device *ndev, int budget) | |||
861 | struct bufdesc_ex *ebdp = NULL; | 868 | struct bufdesc_ex *ebdp = NULL; |
862 | bool vlan_packet_rcvd = false; | 869 | bool vlan_packet_rcvd = false; |
863 | u16 vlan_tag; | 870 | u16 vlan_tag; |
871 | int index = 0; | ||
864 | 872 | ||
865 | #ifdef CONFIG_M532x | 873 | #ifdef CONFIG_M532x |
866 | flush_cache_all(); | 874 | flush_cache_all(); |
@@ -916,10 +924,15 @@ fec_enet_rx(struct net_device *ndev, int budget) | |||
916 | ndev->stats.rx_packets++; | 924 | ndev->stats.rx_packets++; |
917 | pkt_len = bdp->cbd_datlen; | 925 | pkt_len = bdp->cbd_datlen; |
918 | ndev->stats.rx_bytes += pkt_len; | 926 | ndev->stats.rx_bytes += pkt_len; |
919 | data = (__u8*)__va(bdp->cbd_bufaddr); | ||
920 | 927 | ||
921 | dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, | 928 | if (fep->bufdesc_ex) |
922 | FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); | 929 | index = (struct bufdesc_ex *)bdp - |
930 | (struct bufdesc_ex *)fep->rx_bd_base; | ||
931 | else | ||
932 | index = bdp - fep->rx_bd_base; | ||
933 | data = fep->rx_skbuff[index]->data; | ||
934 | dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, | ||
935 | FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); | ||
923 | 936 | ||
924 | if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) | 937 | if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) |
925 | swap_buffer(data, pkt_len); | 938 | swap_buffer(data, pkt_len); |
@@ -999,8 +1012,8 @@ fec_enet_rx(struct net_device *ndev, int budget) | |||
999 | napi_gro_receive(&fep->napi, skb); | 1012 | napi_gro_receive(&fep->napi, skb); |
1000 | } | 1013 | } |
1001 | 1014 | ||
1002 | bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, | 1015 | dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, |
1003 | FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); | 1016 | FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); |
1004 | rx_processing_done: | 1017 | rx_processing_done: |
1005 | /* Clear the status flags for this buffer */ | 1018 | /* Clear the status flags for this buffer */ |
1006 | status &= ~BD_ENET_RX_STATS; | 1019 | status &= ~BD_ENET_RX_STATS; |
@@ -1719,6 +1732,12 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) | |||
1719 | 1732 | ||
1720 | bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, | 1733 | bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, |
1721 | FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); | 1734 | FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); |
1735 | if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { | ||
1736 | fec_enet_free_buffers(ndev); | ||
1737 | if (net_ratelimit()) | ||
1738 | netdev_err(ndev, "Rx DMA memory map failed\n"); | ||
1739 | return -ENOMEM; | ||
1740 | } | ||
1722 | bdp->cbd_sc = BD_ENET_RX_EMPTY; | 1741 | bdp->cbd_sc = BD_ENET_RX_EMPTY; |
1723 | 1742 | ||
1724 | if (fep->bufdesc_ex) { | 1743 | if (fep->bufdesc_ex) { |