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 e1e8c8f65611be87d2749dd67783f981a01ef4d7..2ca9d10f635a16612d3dd8409304ecd41557542e 100644 (file)
@@ -1,19 +1,40 @@
 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 an error occurs, free the
-buffer and allocate a new one. If allocation or mapping fails, retry as
-long as there is NAPI poll budget left (count every attempt instead of
-every frame).
+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
-@@ -404,51 +404,33 @@ 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 */
@@ -23,19 +44,19 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 -              /* Get info from the header */
 -              len = le16_to_cpu(rx->len);
 -              flags = le16_to_cpu(rx->flags);
-+              if (++handled >= weight - 1) /* Should never be greater */
-+                      break;
+-
                do {
 -                      dma_addr_t old_dma_addr = slot->dma_addr;
 -                      int err;
-+                      if (!slot->dma_addr)
++                      /* 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, slot->dma_addr,
++                      dma_unmap_single(dma_dev, dma_addr,
 +                                       BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
-+                      slot->dma_addr = 0;
 +
 +                      /* Get info from the header */
 +                      len = le16_to_cpu(rx->len);
@@ -49,7 +70,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 -                                                         slot->dma_addr,
 -                                                         BGMAC_RX_BUF_SIZE,
 -                                                         DMA_FROM_DEVICE);
-+                              kfree(buf);
++                              put_page(virt_to_head_page(buf));
                                break;
                        }
  
@@ -78,24 +99,32 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
                        skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
                        skb_put(skb, BGMAC_RX_FRAME_OFFSET +
                                BGMAC_RX_BUF_OFFSET + len);
-@@ -458,14 +440,16 @@ static int bgmac_dma_rx_read(struct bgma
-                       skb_checksum_none_assert(skb);
-                       skb->protocol = eth_type_trans(skb, bgmac->net_dev);
-                       napi_gro_receive(&bgmac->napi, skb);
--                      handled++;
+@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma
+                       handled++;
                } while (0);
  
-+              /* Prepare new skb as replacement */
-+              if (bgmac_dma_rx_skb_for_slot(bgmac, slot))
-+                      continue;
-+
 +              bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
 +
                if (++ring->start >= BGMAC_RX_RING_SLOTS)
                        ring->start = 0;
--
--              if (handled >= weight) /* Should never be greater */
--                      break;
+@@ -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;
        }
+ }
  
-       return handled;