gianfar: Fix reported number of sent bytes to BQL
authorFelix Fietkau <nbd@openwrt.org>
Sat, 22 Feb 2014 14:42:48 +0000 (14:42 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 22 Feb 2014 14:42:48 +0000 (14:42 +0000)
This is a backported patch for the gianfar ethernet driver
used in TPLink 4900 v1. It is supposed to fix the error which
show up in dmesg with:
NETDEV WATCHDOG: eth0 (fsl-gianfar): transmit queue xy timed out
Full upstream patch is at: http://patchwork.ozlabs.org/patch/271242

Signed-off-by: Thomas Huehn <thomas@net.t-labs.tu-berlin.de>
SVN-Revision: 39692

target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch [new file with mode: 0644]

diff --git a/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch b/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch
new file mode 100644 (file)
index 0000000..d0380ff
--- /dev/null
@@ -0,0 +1,77 @@
+--- a/drivers/net/ethernet/freescale/gianfar.c
++++ b/drivers/net/ethernet/freescale/gianfar.c
+@@ -2064,7 +2064,7 @@ static int gfar_start_xmit(struct sk_buf
+       int i, rq = 0, do_tstamp = 0;
+       u32 bufaddr;
+       unsigned long flags;
+-      unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
++      unsigned int nr_frags, nr_txbds, bytes_sent, fcb_length = GMAC_FCB_LEN;
+       /* TOE=1 frames larger than 2500 bytes may see excess delays
+        * before start of transmission.
+@@ -2130,7 +2130,10 @@ static int gfar_start_xmit(struct sk_buf
+       }
+       /* Update transmit stats */
+-      tx_queue->stats.tx_bytes += skb->len;
++      bytes_sent = skb->len;
++      tx_queue->stats.tx_bytes += bytes_sent;
++      /* keep Tx bytes on wire for BQL accounting */
++      GFAR_CB(skb)->bytes_sent = bytes_sent;
+       tx_queue->stats.tx_packets++;
+       txbdp = txbdp_start = tx_queue->cur_tx;
+@@ -2150,12 +2153,13 @@ static int gfar_start_xmit(struct sk_buf
+       } else {
+               /* Place the fragment addresses and lengths into the TxBDs */
+               for (i = 0; i < nr_frags; i++) {
++                      unsigned int frag_len;
+                       /* Point at the next BD, wrapping as needed */
+                       txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
+-                      length = skb_shinfo(skb)->frags[i].size;
++                      frag_len = skb_shinfo(skb)->frags[i].size;
+-                      lstatus = txbdp->lstatus | length |
++                      lstatus = txbdp->lstatus | frag_len |
+                                 BD_LFLAG(TXBD_READY);
+                       /* Handle the last BD specially */
+@@ -2165,7 +2169,7 @@ static int gfar_start_xmit(struct sk_buf
+                       bufaddr = skb_frag_dma_map(priv->dev,
+                                                  &skb_shinfo(skb)->frags[i],
+                                                  0,
+-                                                 length,
++                                                 frag_len,
+                                                  DMA_TO_DEVICE);
+                       /* set the TxBD length and buffer pointer */
+@@ -2231,7 +2235,7 @@ static int gfar_start_xmit(struct sk_buf
+               lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
+       }
+-      netdev_tx_sent_queue(txq, skb->len);
++      netdev_tx_sent_queue(txq, bytes_sent);
+       /* We can work in parallel with gfar_clean_tx_ring(), except
+        * when modifying num_txbdfree. Note that we didn't grab the lock
+@@ -2551,7 +2555,7 @@ static void gfar_clean_tx_ring(struct gf
+                       bdp = next_txbd(bdp, base, tx_ring_size);
+               }
+-              bytes_sent += skb->len;
++              bytes_sent += GFAR_CB(skb)->bytes_sent;
+               dev_kfree_skb_any(skb);
+--- a/drivers/net/ethernet/freescale/gianfar.h
++++ b/drivers/net/ethernet/freescale/gianfar.h
+@@ -571,7 +571,7 @@ struct rxfcb {
+ };
+ struct gianfar_skb_cb {
+-      int alignamount;
++      unsigned int bytes_sent; /* bytes-on-wire (i.e. no FCB) */
+ };
+ #define GFAR_CB(skb) ((struct gianfar_skb_cb *)((skb)->cb))