gianfar: Fix reported number of sent bytes to BQL
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
This commit is contained in:
		@@ -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))
 | 
				
			||||||
		Reference in New Issue
	
	Block a user