kernel/3.18: update to version 3.18.25
[openwrt/openwrt.git] / target / linux / generic / patches-3.18 / 077-07-bgmac-simplify-rx-DMA-error-handling.patch
index f26e42c20da9884d2de26b447c1ce73a0a099e08..2ca9d10f635a16612d3dd8409304ecd41557542e 100644 (file)
@@ -1,31 +1,66 @@
 From: Felix Fietkau <nbd@openwrt.org>
 Date: Sun, 12 Apr 2015 22:23:07 +0200
-Subject: [PATCH] bgmac: simplify rx DMA error handling
+Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling
 
-Unmap the DMA buffer before checking it. If it is poisoned, map it again
-and pass it back to the hardware.
+Allocate a new buffer before processing the completed one. If allocation
+fails, reuse the old buffer.
 
 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 ---
 
 --- a/drivers/net/ethernet/broadcom/bgmac.c
 +++ b/drivers/net/ethernet/broadcom/bgmac.c
-@@ -405,25 +405,20 @@ static int bgmac_dma_rx_read(struct bgma
+@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru
+       dma_desc->ctl1 = cpu_to_le32(ctl1);
+ }
++static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
++                                  struct bgmac_slot_info *slot)
++{
++      struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
++
++      dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
++                              DMA_FROM_DEVICE);
++      rx->len = cpu_to_le16(0xdead);
++      rx->flags = cpu_to_le16(0xbeef);
++      dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
++                                 DMA_FROM_DEVICE);
++}
++
+ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
+                            int weight)
+ {
+@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma
+               struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
+               struct sk_buff *skb;
+               void *buf = slot->buf;
++              dma_addr_t dma_addr = slot->dma_addr;
                u16 len, flags;
  
-               /* Unmap buffer to make it accessible to the CPU */
+-              /* Unmap buffer to make it accessible to the CPU */
 -              dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
 -                                      BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
-+              dma_unmap_single(dma_dev, slot->dma_addr,
-+                               BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
-               /* Get info from the header */
-               len = le16_to_cpu(rx->len);
-               flags = le16_to_cpu(rx->flags);
+-
+-              /* Get info from the header */
+-              len = le16_to_cpu(rx->len);
+-              flags = le16_to_cpu(rx->flags);
+-
                do {
 -                      dma_addr_t old_dma_addr = slot->dma_addr;
-                       int err;
+-                      int err;
++                      /* Prepare new skb as replacement */
++                      if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) {
++                              bgmac_dma_rx_poison_buf(dma_dev, slot);
++                              break;
++                      }
++
++                      /* Unmap buffer to make it accessible to the CPU */
++                      dma_unmap_single(dma_dev, dma_addr,
++                                       BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
++
++                      /* Get info from the header */
++                      len = le16_to_cpu(rx->len);
++                      flags = le16_to_cpu(rx->flags);
  
                        /* Check for poison and drop or pass the packet */
                        if (len == 0xdead && flags == 0xbeef) {
@@ -35,29 +70,36 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 -                                                         slot->dma_addr,
 -                                                         BGMAC_RX_BUF_SIZE,
 -                                                         DMA_FROM_DEVICE);
++                              put_page(virt_to_head_page(buf));
                                break;
                        }
  
-@@ -436,18 +431,8 @@ static int bgmac_dma_rx_read(struct bgma
-                               /* Poison the old skb */
-                               rx->len = cpu_to_le16(0xdead);
-                               rx->flags = cpu_to_le16(0xbeef);
+                       /* Omit CRC. */
+                       len -= ETH_FCS_LEN;
+-                      /* Prepare new skb as replacement */
+-                      err = bgmac_dma_rx_skb_for_slot(bgmac, slot);
+-                      if (err) {
+-                              /* Poison the old skb */
+-                              rx->len = cpu_to_le16(0xdead);
+-                              rx->flags = cpu_to_le16(0xbeef);
 -
 -                              dma_sync_single_for_device(dma_dev,
 -                                                         slot->dma_addr,
 -                                                         BGMAC_RX_BUF_SIZE,
 -                                                         DMA_FROM_DEVICE);
-                               break;
-                       }
+-                              break;
+-                      }
 -                      bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
 -
 -                      /* Unmap old skb, we'll pass it to the netfif */
 -                      dma_unmap_single(dma_dev, old_dma_addr,
 -                                       BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+-
                        skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
                        skb_put(skb, BGMAC_RX_FRAME_OFFSET +
-@@ -461,6 +446,8 @@ static int bgmac_dma_rx_read(struct bgma
+                               BGMAC_RX_BUF_OFFSET + len);
+@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma
                        handled++;
                } while (0);
  
@@ -66,3 +108,23 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
                if (++ring->start >= BGMAC_RX_RING_SLOTS)
                        ring->start = 0;
  
+@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc
+       for (i = 0; i < ring->num_slots; i++) {
+               slot = &ring->slots[i];
+-              if (!slot->buf)
++              if (!slot->dma_addr)
+                       continue;
+-              if (slot->dma_addr)
+-                      dma_unmap_single(dma_dev, slot->dma_addr,
+-                                       BGMAC_RX_BUF_SIZE,
+-                                       DMA_FROM_DEVICE);
++              dma_unmap_single(dma_dev, slot->dma_addr,
++                               BGMAC_RX_BUF_SIZE,
++                               DMA_FROM_DEVICE);
+               put_page(virt_to_head_page(slot->buf));
++              slot->dma_addr = 0;
+       }
+ }