diff options
Diffstat (limited to 'drivers/net/wireless/b43/dma.c')
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index e228c1de6e11..eae680b53052 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -555,11 +555,32 @@ address_error: | |||
555 | return 1; | 555 | return 1; |
556 | } | 556 | } |
557 | 557 | ||
558 | static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb) | ||
559 | { | ||
560 | unsigned char *f = skb->data + ring->frameoffset; | ||
561 | |||
562 | return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7]) == 0xFF); | ||
563 | } | ||
564 | |||
565 | static void b43_poison_rx_buffer(struct b43_dmaring *ring, struct sk_buff *skb) | ||
566 | { | ||
567 | struct b43_rxhdr_fw4 *rxhdr; | ||
568 | unsigned char *frame; | ||
569 | |||
570 | /* This poisons the RX buffer to detect DMA failures. */ | ||
571 | |||
572 | rxhdr = (struct b43_rxhdr_fw4 *)(skb->data); | ||
573 | rxhdr->frame_len = 0; | ||
574 | |||
575 | B43_WARN_ON(ring->rx_buffersize < ring->frameoffset + sizeof(struct b43_plcp_hdr6) + 2); | ||
576 | frame = skb->data + ring->frameoffset; | ||
577 | memset(frame, 0xFF, sizeof(struct b43_plcp_hdr6) + 2 /* padding */); | ||
578 | } | ||
579 | |||
558 | static int setup_rx_descbuffer(struct b43_dmaring *ring, | 580 | static int setup_rx_descbuffer(struct b43_dmaring *ring, |
559 | struct b43_dmadesc_generic *desc, | 581 | struct b43_dmadesc_generic *desc, |
560 | struct b43_dmadesc_meta *meta, gfp_t gfp_flags) | 582 | struct b43_dmadesc_meta *meta, gfp_t gfp_flags) |
561 | { | 583 | { |
562 | struct b43_rxhdr_fw4 *rxhdr; | ||
563 | dma_addr_t dmaaddr; | 584 | dma_addr_t dmaaddr; |
564 | struct sk_buff *skb; | 585 | struct sk_buff *skb; |
565 | 586 | ||
@@ -568,6 +589,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, | |||
568 | skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); | 589 | skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); |
569 | if (unlikely(!skb)) | 590 | if (unlikely(!skb)) |
570 | return -ENOMEM; | 591 | return -ENOMEM; |
592 | b43_poison_rx_buffer(ring, skb); | ||
571 | dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); | 593 | dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); |
572 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { | 594 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { |
573 | /* ugh. try to realloc in zone_dma */ | 595 | /* ugh. try to realloc in zone_dma */ |
@@ -578,6 +600,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, | |||
578 | skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); | 600 | skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); |
579 | if (unlikely(!skb)) | 601 | if (unlikely(!skb)) |
580 | return -ENOMEM; | 602 | return -ENOMEM; |
603 | b43_poison_rx_buffer(ring, skb); | ||
581 | dmaaddr = map_descbuffer(ring, skb->data, | 604 | dmaaddr = map_descbuffer(ring, skb->data, |
582 | ring->rx_buffersize, 0); | 605 | ring->rx_buffersize, 0); |
583 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { | 606 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { |
@@ -592,9 +615,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, | |||
592 | ring->ops->fill_descriptor(ring, desc, dmaaddr, | 615 | ring->ops->fill_descriptor(ring, desc, dmaaddr, |
593 | ring->rx_buffersize, 0, 0, 0); | 616 | ring->rx_buffersize, 0, 0, 0); |
594 | 617 | ||
595 | rxhdr = (struct b43_rxhdr_fw4 *)(skb->data); | ||
596 | rxhdr->frame_len = 0; | ||
597 | |||
598 | return 0; | 618 | return 0; |
599 | } | 619 | } |
600 | 620 | ||
@@ -1483,12 +1503,17 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1483 | len = le16_to_cpu(rxhdr->frame_len); | 1503 | len = le16_to_cpu(rxhdr->frame_len); |
1484 | } while (len == 0 && i++ < 5); | 1504 | } while (len == 0 && i++ < 5); |
1485 | if (unlikely(len == 0)) { | 1505 | if (unlikely(len == 0)) { |
1486 | /* recycle the descriptor buffer. */ | 1506 | dmaaddr = meta->dmaaddr; |
1487 | sync_descbuffer_for_device(ring, meta->dmaaddr, | 1507 | goto drop_recycle_buffer; |
1488 | ring->rx_buffersize); | ||
1489 | goto drop; | ||
1490 | } | 1508 | } |
1491 | } | 1509 | } |
1510 | if (unlikely(b43_rx_buffer_is_poisoned(ring, skb))) { | ||
1511 | /* Something went wrong with the DMA. | ||
1512 | * The device did not touch the buffer and did not overwrite the poison. */ | ||
1513 | b43dbg(ring->dev->wl, "DMA RX: Dropping poisoned buffer.\n"); | ||
1514 | dmaaddr = meta->dmaaddr; | ||
1515 | goto drop_recycle_buffer; | ||
1516 | } | ||
1492 | if (unlikely(len > ring->rx_buffersize)) { | 1517 | if (unlikely(len > ring->rx_buffersize)) { |
1493 | /* The data did not fit into one descriptor buffer | 1518 | /* The data did not fit into one descriptor buffer |
1494 | * and is split over multiple buffers. | 1519 | * and is split over multiple buffers. |
@@ -1501,6 +1526,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1501 | while (1) { | 1526 | while (1) { |
1502 | desc = ops->idx2desc(ring, *slot, &meta); | 1527 | desc = ops->idx2desc(ring, *slot, &meta); |
1503 | /* recycle the descriptor buffer. */ | 1528 | /* recycle the descriptor buffer. */ |
1529 | b43_poison_rx_buffer(ring, meta->skb); | ||
1504 | sync_descbuffer_for_device(ring, meta->dmaaddr, | 1530 | sync_descbuffer_for_device(ring, meta->dmaaddr, |
1505 | ring->rx_buffersize); | 1531 | ring->rx_buffersize); |
1506 | *slot = next_slot(ring, *slot); | 1532 | *slot = next_slot(ring, *slot); |
@@ -1519,8 +1545,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1519 | err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); | 1545 | err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); |
1520 | if (unlikely(err)) { | 1546 | if (unlikely(err)) { |
1521 | b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n"); | 1547 | b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n"); |
1522 | sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize); | 1548 | goto drop_recycle_buffer; |
1523 | goto drop; | ||
1524 | } | 1549 | } |
1525 | 1550 | ||
1526 | unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); | 1551 | unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); |
@@ -1530,6 +1555,11 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) | |||
1530 | b43_rx(ring->dev, skb, rxhdr); | 1555 | b43_rx(ring->dev, skb, rxhdr); |
1531 | drop: | 1556 | drop: |
1532 | return; | 1557 | return; |
1558 | |||
1559 | drop_recycle_buffer: | ||
1560 | /* Poison and recycle the RX buffer. */ | ||
1561 | b43_poison_rx_buffer(ring, skb); | ||
1562 | sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize); | ||
1533 | } | 1563 | } |
1534 | 1564 | ||
1535 | void b43_dma_rx(struct b43_dmaring *ring) | 1565 | void b43_dma_rx(struct b43_dmaring *ring) |