aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c66
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;