diff options
| -rw-r--r-- | drivers/net/ethernet/broadcom/bgmac.c | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 4f9beed54506..a98778e3af84 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c | |||
| @@ -315,7 +315,6 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, | |||
| 315 | struct device *dma_dev = bgmac->core->dma_dev; | 315 | struct device *dma_dev = bgmac->core->dma_dev; |
| 316 | struct bgmac_slot_info *slot = &ring->slots[ring->start]; | 316 | struct bgmac_slot_info *slot = &ring->slots[ring->start]; |
| 317 | struct sk_buff *skb = slot->skb; | 317 | struct sk_buff *skb = slot->skb; |
| 318 | struct sk_buff *new_skb; | ||
| 319 | struct bgmac_rx_header *rx; | 318 | struct bgmac_rx_header *rx; |
| 320 | u16 len, flags; | 319 | u16 len, flags; |
| 321 | 320 | ||
| @@ -328,38 +327,51 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, | |||
| 328 | len = le16_to_cpu(rx->len); | 327 | len = le16_to_cpu(rx->len); |
| 329 | flags = le16_to_cpu(rx->flags); | 328 | flags = le16_to_cpu(rx->flags); |
| 330 | 329 | ||
| 331 | /* Check for poison and drop or pass the packet */ | 330 | do { |
| 332 | if (len == 0xdead && flags == 0xbeef) { | 331 | dma_addr_t old_dma_addr = slot->dma_addr; |
| 333 | bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", | 332 | int err; |
| 334 | ring->start); | 333 | |
| 335 | } else { | 334 | /* Check for poison and drop or pass the packet */ |
| 335 | if (len == 0xdead && flags == 0xbeef) { | ||
| 336 | bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", | ||
| 337 | ring->start); | ||
| 338 | dma_sync_single_for_device(dma_dev, | ||
| 339 | slot->dma_addr, | ||
| 340 | BGMAC_RX_BUF_SIZE, | ||
| 341 | DMA_FROM_DEVICE); | ||
| 342 | break; | ||
| 343 | } | ||
| 344 | |||
| 336 | /* Omit CRC. */ | 345 | /* Omit CRC. */ |
| 337 | len -= ETH_FCS_LEN; | 346 | len -= ETH_FCS_LEN; |
| 338 | 347 | ||
| 339 | new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len); | 348 | /* Prepare new skb as replacement */ |
| 340 | if (new_skb) { | 349 | err = bgmac_dma_rx_skb_for_slot(bgmac, slot); |
| 341 | skb_put(new_skb, len); | 350 | if (err) { |
| 342 | skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET, | 351 | /* Poison the old skb */ |
| 343 | new_skb->data, | 352 | rx->len = cpu_to_le16(0xdead); |
| 344 | len); | 353 | rx->flags = cpu_to_le16(0xbeef); |
| 345 | skb_checksum_none_assert(skb); | 354 | |
| 346 | new_skb->protocol = | 355 | dma_sync_single_for_device(dma_dev, |
| 347 | eth_type_trans(new_skb, bgmac->net_dev); | 356 | slot->dma_addr, |
| 348 | netif_receive_skb(new_skb); | 357 | BGMAC_RX_BUF_SIZE, |
| 349 | handled++; | 358 | DMA_FROM_DEVICE); |
| 350 | } else { | 359 | break; |
| 351 | bgmac->net_dev->stats.rx_dropped++; | ||
| 352 | bgmac_err(bgmac, "Allocation of skb for copying packet failed!\n"); | ||
| 353 | } | 360 | } |
| 361 | bgmac_dma_rx_setup_desc(bgmac, ring, ring->start); | ||
| 354 | 362 | ||
| 355 | /* Poison the old skb */ | 363 | /* Unmap old skb, we'll pass it to the netfif */ |
| 356 | rx->len = cpu_to_le16(0xdead); | 364 | dma_unmap_single(dma_dev, old_dma_addr, |
| 357 | rx->flags = cpu_to_le16(0xbeef); | 365 | BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); |
| 358 | } | 366 | |
| 367 | skb_put(skb, BGMAC_RX_FRAME_OFFSET + len); | ||
| 368 | skb_pull(skb, BGMAC_RX_FRAME_OFFSET); | ||
| 359 | 369 | ||
| 360 | /* Make it back accessible to the hardware */ | 370 | skb_checksum_none_assert(skb); |
| 361 | dma_sync_single_for_device(dma_dev, slot->dma_addr, | 371 | skb->protocol = eth_type_trans(skb, bgmac->net_dev); |
| 362 | BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); | 372 | netif_receive_skb(skb); |
| 373 | handled++; | ||
| 374 | } while (0); | ||
| 363 | 375 | ||
| 364 | if (++ring->start >= BGMAC_RX_RING_SLOTS) | 376 | if (++ring->start >= BGMAC_RX_RING_SLOTS) |
| 365 | ring->start = 0; | 377 | ring->start = 0; |
