This bgmac patch was an attempt to fix/workaround bug reported in
https://dev.openwrt.org/ticket/7198 noticed on WNR3500L.
Patch assumed length reported by the hardware was 0 and was trying to
read it until getting a different value. This was actually the opposite.
Lenghts were some invalid & huge values that resulted in skb_over_panic.
For example:
skbuff: skb_over_panic: text:83b21074 len:57222 (...)
skbuff: skb_over_panic: text:87af1024 len:43226 (...)
skbuff: skb_over_panic: text:87af5024 len:8739 (...)

So instead of that not-working patch checking for 0, write a new one
checking for huge values. In case something like that happens, dump
hardware state and drop the packet.

Signed-off-by: Rafał Miłecki <zaj...@gmail.com>
---
 .../775-bgmac-check-length-of-received-frame.patch | 50 +++++++++++-----------
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git 
a/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch
 
b/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch
index f708e7d..c3d63b6 100644
--- 
a/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch
+++ 
b/target/linux/generic/patches-3.10/775-bgmac-check-length-of-received-frame.patch
@@ -9,33 +9,31 @@ Subject: [PATCH] bgmac: check length of received frame
 
 --- a/drivers/net/ethernet/broadcom/bgmac.c
 +++ b/drivers/net/ethernet/broadcom/bgmac.c
-@@ -349,6 +349,7 @@ static int bgmac_dma_rx_read(struct bgma
-               struct sk_buff *skb = slot->skb;
-               struct bgmac_rx_header *rx;
-               u16 len, flags;
-+              int count;
- 
-               /* Unmap buffer to make it accessible to the CPU */
-               dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
-@@ -357,6 +358,12 @@ static int bgmac_dma_rx_read(struct bgma
-               /* Get info from the header */
-               rx = (struct bgmac_rx_header *)skb->data;
-               len = le16_to_cpu(rx->len);
-+              for (count = 0; count < 200; count++) {
-+                      len = le16_to_cpu(rx->len);
-+                      if (len)
-+                              break;
-+                      udelay(1);
-+              }
-               flags = le16_to_cpu(rx->flags);
- 
-               do {
-@@ -364,7 +371,7 @@ static int bgmac_dma_rx_read(struct bgma
+@@ -363,6 +363,27 @@ static int bgmac_dma_rx_read(struct bgma
+                       dma_addr_t old_dma_addr = slot->dma_addr;
                        int err;
  
++                      if (len > BGMAC_RX_MAX_FRAME_SIZE) {
++                              struct bgmac_dma_desc *dma_desc = 
ring->cpu_base + ring->start;
++
++                              bgmac_err(bgmac, "Hardware reported invalid 
packet length %d for slot %d!\n", len, ring->start);
++                              bgmac_err(bgmac, "flags: 0x%04X\n", flags);
++                              bgmac_err(bgmac, "ctl0: 0x%08X\tctl1: 
0x%08X\n", le32_to_cpu(dma_desc->ctl0), le32_to_cpu(dma_desc->ctl1));
++
++                              bgmac_err(bgmac, "   BGMAC_DMA_RX_CTL: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL));
++                              bgmac_err(bgmac, " BGMAC_DMA_RX_INDEX: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX));
++                              bgmac_err(bgmac, "BGMAC_DMA_RX_RINGLO: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO));
++                              bgmac_err(bgmac, "BGMAC_DMA_RX_RINGHI: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI));
++                              bgmac_err(bgmac, "BGMAC_DMA_RX_STATUS: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS));
++                              bgmac_err(bgmac, " BGMAC_DMA_RX_ERROR: 
0x%08X\n", bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_ERROR));
++
++                              dma_sync_single_for_device(dma_dev,
++                                                         slot->dma_addr,
++                                                         BGMAC_RX_BUF_SIZE,
++                                                         DMA_FROM_DEVICE);
++                              break;
++                      }
++
                        /* Check for poison and drop or pass the packet */
--                      if (len == 0xdead && flags == 0xbeef) {
-+                      if (!len || (len == 0xdead && flags == 0xbeef)) {
+                       if (len == 0xdead && flags == 0xbeef) {
                                bgmac_err(bgmac, "Found poisoned packet at slot 
%d, DMA issue!\n",
-                                         ring->start);
-                               dma_sync_single_for_device(dma_dev,
-- 
1.8.4.5
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to