diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a6ddfc1a9cb2..72c92495a9b3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1103,18 +1103,39 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re, | |||
1103 | int i; | 1103 | int i; |
1104 | 1104 | ||
1105 | re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE); | 1105 | re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE); |
1106 | if (unlikely(pci_dma_mapping_error(pdev, re->data_addr))) | 1106 | if (pci_dma_mapping_error(pdev, re->data_addr)) |
1107 | return -EIO; | 1107 | goto mapping_error; |
1108 | 1108 | ||
1109 | pci_unmap_len_set(re, data_size, size); | 1109 | pci_unmap_len_set(re, data_size, size); |
1110 | 1110 | ||
1111 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 1111 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
1112 | re->frag_addr[i] = pci_map_page(pdev, | 1112 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
1113 | skb_shinfo(skb)->frags[i].page, | 1113 | |
1114 | skb_shinfo(skb)->frags[i].page_offset, | 1114 | re->frag_addr[i] = pci_map_page(pdev, frag->page, |
1115 | skb_shinfo(skb)->frags[i].size, | 1115 | frag->page_offset, |
1116 | frag->size, | ||
1116 | PCI_DMA_FROMDEVICE); | 1117 | PCI_DMA_FROMDEVICE); |
1118 | |||
1119 | if (pci_dma_mapping_error(pdev, re->frag_addr[i])) | ||
1120 | goto map_page_error; | ||
1121 | } | ||
1117 | return 0; | 1122 | return 0; |
1123 | |||
1124 | map_page_error: | ||
1125 | while (--i >= 0) { | ||
1126 | pci_unmap_page(pdev, re->frag_addr[i], | ||
1127 | skb_shinfo(skb)->frags[i].size, | ||
1128 | PCI_DMA_FROMDEVICE); | ||
1129 | } | ||
1130 | |||
1131 | pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size), | ||
1132 | PCI_DMA_FROMDEVICE); | ||
1133 | |||
1134 | mapping_error: | ||
1135 | if (net_ratelimit()) | ||
1136 | dev_warn(&pdev->dev, "%s: rx mapping error\n", | ||
1137 | skb->dev->name); | ||
1138 | return -EIO; | ||
1118 | } | 1139 | } |
1119 | 1140 | ||
1120 | static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re) | 1141 | static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re) |
@@ -2306,30 +2327,32 @@ static struct sk_buff *receive_new(struct sky2_port *sky2, | |||
2306 | struct rx_ring_info *re, | 2327 | struct rx_ring_info *re, |
2307 | unsigned int length) | 2328 | unsigned int length) |
2308 | { | 2329 | { |
2309 | struct sk_buff *skb, *nskb; | 2330 | struct sk_buff *skb; |
2331 | struct rx_ring_info nre; | ||
2310 | unsigned hdr_space = sky2->rx_data_size; | 2332 | unsigned hdr_space = sky2->rx_data_size; |
2311 | 2333 | ||
2312 | /* Don't be tricky about reusing pages (yet) */ | 2334 | nre.skb = sky2_rx_alloc(sky2); |
2313 | nskb = sky2_rx_alloc(sky2); | 2335 | if (unlikely(!nre.skb)) |
2314 | if (unlikely(!nskb)) | 2336 | goto nobuf; |
2315 | return NULL; | 2337 | |
2338 | if (sky2_rx_map_skb(sky2->hw->pdev, &nre, hdr_space)) | ||
2339 | goto nomap; | ||
2316 | 2340 | ||
2317 | skb = re->skb; | 2341 | skb = re->skb; |
2318 | sky2_rx_unmap_skb(sky2->hw->pdev, re); | 2342 | sky2_rx_unmap_skb(sky2->hw->pdev, re); |
2319 | |||
2320 | prefetch(skb->data); | 2343 | prefetch(skb->data); |
2321 | re->skb = nskb; | 2344 | *re = nre; |
2322 | if (sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space)) { | ||
2323 | dev_kfree_skb(nskb); | ||
2324 | re->skb = skb; | ||
2325 | return NULL; | ||
2326 | } | ||
2327 | 2345 | ||
2328 | if (skb_shinfo(skb)->nr_frags) | 2346 | if (skb_shinfo(skb)->nr_frags) |
2329 | skb_put_frags(skb, hdr_space, length); | 2347 | skb_put_frags(skb, hdr_space, length); |
2330 | else | 2348 | else |
2331 | skb_put(skb, length); | 2349 | skb_put(skb, length); |
2332 | return skb; | 2350 | return skb; |
2351 | |||
2352 | nomap: | ||
2353 | dev_kfree_skb(nre.skb); | ||
2354 | nobuf: | ||
2355 | return NULL; | ||
2333 | } | 2356 | } |
2334 | 2357 | ||
2335 | /* | 2358 | /* |