diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2014-08-12 04:35:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-13 23:04:46 -0400 |
commit | 10545937e866ccdbb7ab583031dbdcc6b14e4eb4 (patch) | |
tree | 7b9254702b49e25ada44dc95c72688c63ce2a5ce /drivers/net/ethernet | |
parent | 3791b3f6fb74d265c93d493d9bbf29c1e769ceae (diff) |
myri10ge: check for DMA mapping errors
On IOMMU systems DMA mapping can fail, we need to check for
that possibility.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 88 |
1 files changed, 58 insertions, 30 deletions
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 69c26f04d8ce..679db026f4be 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c | |||
@@ -873,6 +873,10 @@ static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type) | |||
873 | return -ENOMEM; | 873 | return -ENOMEM; |
874 | dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, | 874 | dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, |
875 | DMA_BIDIRECTIONAL); | 875 | DMA_BIDIRECTIONAL); |
876 | if (unlikely(pci_dma_mapping_error(mgp->pdev, dmatest_bus))) { | ||
877 | __free_page(dmatest_page); | ||
878 | return -ENOMEM; | ||
879 | } | ||
876 | 880 | ||
877 | /* Run a small DMA test. | 881 | /* Run a small DMA test. |
878 | * The magic multipliers to the length tell the firmware | 882 | * The magic multipliers to the length tell the firmware |
@@ -1294,6 +1298,7 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, | |||
1294 | int bytes, int watchdog) | 1298 | int bytes, int watchdog) |
1295 | { | 1299 | { |
1296 | struct page *page; | 1300 | struct page *page; |
1301 | dma_addr_t bus; | ||
1297 | int idx; | 1302 | int idx; |
1298 | #if MYRI10GE_ALLOC_SIZE > 4096 | 1303 | #if MYRI10GE_ALLOC_SIZE > 4096 |
1299 | int end_offset; | 1304 | int end_offset; |
@@ -1318,11 +1323,21 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, | |||
1318 | rx->watchdog_needed = 1; | 1323 | rx->watchdog_needed = 1; |
1319 | return; | 1324 | return; |
1320 | } | 1325 | } |
1326 | |||
1327 | bus = pci_map_page(mgp->pdev, page, 0, | ||
1328 | MYRI10GE_ALLOC_SIZE, | ||
1329 | PCI_DMA_FROMDEVICE); | ||
1330 | if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) { | ||
1331 | __free_pages(page, MYRI10GE_ALLOC_ORDER); | ||
1332 | if (rx->fill_cnt - rx->cnt < 16) | ||
1333 | rx->watchdog_needed = 1; | ||
1334 | return; | ||
1335 | } | ||
1336 | |||
1321 | rx->page = page; | 1337 | rx->page = page; |
1322 | rx->page_offset = 0; | 1338 | rx->page_offset = 0; |
1323 | rx->bus = pci_map_page(mgp->pdev, page, 0, | 1339 | rx->bus = bus; |
1324 | MYRI10GE_ALLOC_SIZE, | 1340 | |
1325 | PCI_DMA_FROMDEVICE); | ||
1326 | } | 1341 | } |
1327 | rx->info[idx].page = rx->page; | 1342 | rx->info[idx].page = rx->page; |
1328 | rx->info[idx].page_offset = rx->page_offset; | 1343 | rx->info[idx].page_offset = rx->page_offset; |
@@ -2764,6 +2779,35 @@ myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, | |||
2764 | mb(); | 2779 | mb(); |
2765 | } | 2780 | } |
2766 | 2781 | ||
2782 | static void myri10ge_unmap_tx_dma(struct myri10ge_priv *mgp, | ||
2783 | struct myri10ge_tx_buf *tx, int idx) | ||
2784 | { | ||
2785 | unsigned int len; | ||
2786 | int last_idx; | ||
2787 | |||
2788 | /* Free any DMA resources we've alloced and clear out the skb slot */ | ||
2789 | last_idx = (idx + 1) & tx->mask; | ||
2790 | idx = tx->req & tx->mask; | ||
2791 | do { | ||
2792 | len = dma_unmap_len(&tx->info[idx], len); | ||
2793 | if (len) { | ||
2794 | if (tx->info[idx].skb != NULL) | ||
2795 | pci_unmap_single(mgp->pdev, | ||
2796 | dma_unmap_addr(&tx->info[idx], | ||
2797 | bus), len, | ||
2798 | PCI_DMA_TODEVICE); | ||
2799 | else | ||
2800 | pci_unmap_page(mgp->pdev, | ||
2801 | dma_unmap_addr(&tx->info[idx], | ||
2802 | bus), len, | ||
2803 | PCI_DMA_TODEVICE); | ||
2804 | dma_unmap_len_set(&tx->info[idx], len, 0); | ||
2805 | tx->info[idx].skb = NULL; | ||
2806 | } | ||
2807 | idx = (idx + 1) & tx->mask; | ||
2808 | } while (idx != last_idx); | ||
2809 | } | ||
2810 | |||
2767 | /* | 2811 | /* |
2768 | * Transmit a packet. We need to split the packet so that a single | 2812 | * Transmit a packet. We need to split the packet so that a single |
2769 | * segment does not cross myri10ge->tx_boundary, so this makes segment | 2813 | * segment does not cross myri10ge->tx_boundary, so this makes segment |
@@ -2787,7 +2831,7 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, | |||
2787 | u32 low; | 2831 | u32 low; |
2788 | __be32 high_swapped; | 2832 | __be32 high_swapped; |
2789 | unsigned int len; | 2833 | unsigned int len; |
2790 | int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments; | 2834 | int idx, avail, frag_cnt, frag_idx, count, mss, max_segments; |
2791 | u16 pseudo_hdr_offset, cksum_offset, queue; | 2835 | u16 pseudo_hdr_offset, cksum_offset, queue; |
2792 | int cum_len, seglen, boundary, rdma_count; | 2836 | int cum_len, seglen, boundary, rdma_count; |
2793 | u8 flags, odd_flag; | 2837 | u8 flags, odd_flag; |
@@ -2884,9 +2928,12 @@ again: | |||
2884 | 2928 | ||
2885 | /* map the skb for DMA */ | 2929 | /* map the skb for DMA */ |
2886 | len = skb_headlen(skb); | 2930 | len = skb_headlen(skb); |
2931 | bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE); | ||
2932 | if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) | ||
2933 | goto drop; | ||
2934 | |||
2887 | idx = tx->req & tx->mask; | 2935 | idx = tx->req & tx->mask; |
2888 | tx->info[idx].skb = skb; | 2936 | tx->info[idx].skb = skb; |
2889 | bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE); | ||
2890 | dma_unmap_addr_set(&tx->info[idx], bus, bus); | 2937 | dma_unmap_addr_set(&tx->info[idx], bus, bus); |
2891 | dma_unmap_len_set(&tx->info[idx], len, len); | 2938 | dma_unmap_len_set(&tx->info[idx], len, len); |
2892 | 2939 | ||
@@ -2985,12 +3032,16 @@ again: | |||
2985 | break; | 3032 | break; |
2986 | 3033 | ||
2987 | /* map next fragment for DMA */ | 3034 | /* map next fragment for DMA */ |
2988 | idx = (count + tx->req) & tx->mask; | ||
2989 | frag = &skb_shinfo(skb)->frags[frag_idx]; | 3035 | frag = &skb_shinfo(skb)->frags[frag_idx]; |
2990 | frag_idx++; | 3036 | frag_idx++; |
2991 | len = skb_frag_size(frag); | 3037 | len = skb_frag_size(frag); |
2992 | bus = skb_frag_dma_map(&mgp->pdev->dev, frag, 0, len, | 3038 | bus = skb_frag_dma_map(&mgp->pdev->dev, frag, 0, len, |
2993 | DMA_TO_DEVICE); | 3039 | DMA_TO_DEVICE); |
3040 | if (unlikely(pci_dma_mapping_error(mgp->pdev, bus))) { | ||
3041 | myri10ge_unmap_tx_dma(mgp, tx, idx); | ||
3042 | goto drop; | ||
3043 | } | ||
3044 | idx = (count + tx->req) & tx->mask; | ||
2994 | dma_unmap_addr_set(&tx->info[idx], bus, bus); | 3045 | dma_unmap_addr_set(&tx->info[idx], bus, bus); |
2995 | dma_unmap_len_set(&tx->info[idx], len, len); | 3046 | dma_unmap_len_set(&tx->info[idx], len, len); |
2996 | } | 3047 | } |
@@ -3021,31 +3072,8 @@ again: | |||
3021 | return NETDEV_TX_OK; | 3072 | return NETDEV_TX_OK; |
3022 | 3073 | ||
3023 | abort_linearize: | 3074 | abort_linearize: |
3024 | /* Free any DMA resources we've alloced and clear out the skb | 3075 | myri10ge_unmap_tx_dma(mgp, tx, idx); |
3025 | * slot so as to not trip up assertions, and to avoid a | ||
3026 | * double-free if linearizing fails */ | ||
3027 | 3076 | ||
3028 | last_idx = (idx + 1) & tx->mask; | ||
3029 | idx = tx->req & tx->mask; | ||
3030 | tx->info[idx].skb = NULL; | ||
3031 | do { | ||
3032 | len = dma_unmap_len(&tx->info[idx], len); | ||
3033 | if (len) { | ||
3034 | if (tx->info[idx].skb != NULL) | ||
3035 | pci_unmap_single(mgp->pdev, | ||
3036 | dma_unmap_addr(&tx->info[idx], | ||
3037 | bus), len, | ||
3038 | PCI_DMA_TODEVICE); | ||
3039 | else | ||
3040 | pci_unmap_page(mgp->pdev, | ||
3041 | dma_unmap_addr(&tx->info[idx], | ||
3042 | bus), len, | ||
3043 | PCI_DMA_TODEVICE); | ||
3044 | dma_unmap_len_set(&tx->info[idx], len, 0); | ||
3045 | tx->info[idx].skb = NULL; | ||
3046 | } | ||
3047 | idx = (idx + 1) & tx->mask; | ||
3048 | } while (idx != last_idx); | ||
3049 | if (skb_is_gso(skb)) { | 3077 | if (skb_is_gso(skb)) { |
3050 | netdev_err(mgp->dev, "TSO but wanted to linearize?!?!?\n"); | 3078 | netdev_err(mgp->dev, "TSO but wanted to linearize?!?!?\n"); |
3051 | goto drop; | 3079 | goto drop; |