Title: [7875] trunk/drivers/net/bfin_mac.c: Bug[#5716] handler rx error status in bfin mac driver
Revision
7875
Author
sonicz
Date
2009-11-25 05:25:20 -0500 (Wed, 25 Nov 2009)

Log Message

Bug[#5716] handler rx error status in bfin mac driver
Apply patch from Peter Meerwald<[email protected]>

Modified Paths

Diff

Modified: trunk/drivers/net/bfin_mac.c (7874 => 7875)


--- trunk/drivers/net/bfin_mac.c	2009-11-25 07:03:06 UTC (rev 7874)
+++ trunk/drivers/net/bfin_mac.c	2009-11-25 10:25:20 UTC (rev 7875)
@@ -910,6 +910,7 @@
 	do {
 		tx_list_head->desc_a.config &= ~DMAEN;
 		tx_list_head->status.status_word = 0;
+#ifndef CONFIG_BFIN_EXTMEM_WRITEBACK
 		if (tx_list_head->skb) {
 			dev_kfree_skb(tx_list_head->skb);
 			tx_list_head->skb = NULL;
@@ -917,6 +918,7 @@
 			printk(KERN_ERR DRV_NAME
 			       ": no sk_buff in a transmitted frame!\n");
 		}
+#endif
 		tx_list_head = tx_list_head->next;
 	} while (tx_list_head->status.status_word != 0
 		 && current_tx_ptr != tx_list_head);
@@ -927,13 +929,29 @@
 static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
 				struct net_device *dev)
 {
+#ifndef CONFIG_BFIN_EXTMEM_WRITEBACK
 	u16 *data;
 	u32 data_align = (unsigned long)(skb->data) & 0x3;
+#endif
 	union skb_shared_tx *shtx = skb_tx(skb);
 
 	if (current_tx_ptr->next == tx_list_head)
 		return NETDEV_TX_BUSY;
 
+	/*
+	 * Temporary walk around for RX skb buffer corruption issue
+	 * when writeback dcache is enabled. Should be removed after
+	 * the root cause of this issue is figured out.
+	 *
+	 * With writeback dcache option, if TX skb is not freed until
+	 * its DMA is done and until this xmit function is called for
+	 * next TX skb, RX skb buffer may be corrupted after RX DMA is
+	 * done. If free TX skb immediately before xmit exits, this issue
+	 * disappears. This walk around takes effect at the cost of
+	 * copying each tx skb buffer to tx ring other than 4-byte
+	 * aligned ones only.
+	 */
+#ifndef CONFIG_BFIN_EXTMEM_WRITEBACK
 	current_tx_ptr->skb = skb;
 
 	if (data_align == 0x2) {
@@ -954,6 +972,7 @@
 		blackfin_dcache_flush_range((u32)data,
 				(u32)((u8 *)data + skb->len + 4));
 	} else {
+#endif
 		*((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
 		/* enable timestamping for the sent packet */
 		if (shtx->hardware)
@@ -967,7 +986,9 @@
 		blackfin_dcache_flush_range(
 			(u32)current_tx_ptr->packet,
 			(u32)(current_tx_ptr->packet + skb->len + 2));
+#ifndef CONFIG_BFIN_EXTMEM_WRITEBACK
 	}
+#endif
 
 	/* make sure the internal data buffers in the core are drained
 	 * so that the DMA descriptors are completely written when the
@@ -994,14 +1015,20 @@
 
 	bfin_tx_hwtstamp(dev, skb);
 
-	current_tx_ptr = current_tx_ptr->next;
 	dev->trans_start = jiffies;
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += (skb->len);
+#ifdef CONFIG_BFIN_EXTMEM_WRITEBACK
+	dev_kfree_skb(skb);
+#endif
+	current_tx_ptr = current_tx_ptr->next;
+
 	return NETDEV_TX_OK;
 }
 
 #define ETH_FCS_LENGTH 4
+#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \
+	RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE)
 
 static void bfin_mac_rx(struct net_device *dev)
 {
@@ -1012,6 +1039,15 @@
 	unsigned int i;
 	unsigned char fcs[ETH_FCS_LENGTH + 1];
 #endif
+	/* check if frame status word reports an error condition
+	 * we which case we simply drop the packet
+	 */
+	if (current_rx_ptr->status.status_word & RX_ERROR_MASK) {
+		printk(KERN_NOTICE DRV_NAME
+		       ": rx: receive error - packet dropped\n");
+		dev->stats.rx_dropped++;
+		goto out;
+	}
 
 	/* allocate a new skb for next time receive */
 	skb = current_rx_ptr->skb;
@@ -1068,10 +1104,10 @@
 	netif_rx(skb);
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += len;
+out:
 	current_rx_ptr->status.status_word = 0x00000000;
 	current_rx_ptr = current_rx_ptr->next;
 
-out:
 	return;
 }
 
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to