Sophie

Sophie

distrib > Scientific%20Linux > 5x > i386 > by-pkgid > 351d529f9beeb4e5d936a6d5e3e7813a > files > 1458

kernel-2.6.18-128.29.1.el5.src.rpm

From: Andy Gospodarek <gospo@redhat.com>
Date: Tue, 9 Feb 2010 16:54:28 -0500
Subject: [net] e1000e: fix broken wol
Message-ID: <20100209215427.GK24578@gospo.rdu.redhat.com>
O-Subject: [RHEL5.3.z PATCH] e1000e: fix broken wol
Bugzilla: 559334
RH-Acked-by: Jiri Pirko <jpirko@redhat.com>
RH-Acked-by: Dean Nelson <dnelson@redhat.com>
RH-Acked-by: David Miller <davem@redhat.com>

WoL is currently broken on e1000e-based devices RHEL5.3.z because the
following commit:

	commit 928e294ab6bf312fd703dcd07402df8c7e592684
	Author: Amerigo Wang <amwang@redhat.com>
	Date:   Wed Dec 30 05:00:02 2009 -0500

	    [net] e1000e: fix rx length check errors

took the patch that was posted upstream that made a crucial error and
added a new value to state while modifying adapter flags instead of
adding a new state and modifying state.  The maintainers at Intel
noticed this and before posting the patch that fixed it so the one
included upstream is correct.  This patch is based on that upstream
commit:

	commit b94b50289622e816adc9f94111cfc2679c80177c
	Author: Jesse Brandeburg <jesse brandeburg intel com>
	Date:   Tue Jan 19 14:15:59 2010 +0000

	    e1000e: enhance frame fragment detection

and a few bits needed for support picked from:

	commit eb7c3adb1ca92450870dbb0d347fc986cd5e2af4
	Author: Jeff Kirsher <jeffrey t kirsher intel com>
	Date:   Fri Nov 14 06:45:23 2008 +0000

	    e1000e: fix IPMI traffic

I have tested this on patch and my system running 2.6.18-128.13.1 is now
able to configure WoL and actually wake when requested.

This will resolve RHBZ 559334.

---
 drivers/net/e1000e/e1000.h  |    7 +++++--
 drivers/net/e1000e/netdev.c |   25 +++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index a413cc3..556abe5 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -299,11 +299,13 @@ struct e1000_adapter {
 	unsigned long led_status;
 
 	unsigned int flags;
+	unsigned int flags2;
 };
 
 struct e1000_info {
 	enum e1000_mac_type	mac;
 	unsigned int		flags;
+	unsigned int		flags2;
 	u32			pba;
 	s32			(*get_variants)(struct e1000_adapter *);
 	struct e1000_mac_operations *mac_ops;
@@ -345,6 +347,8 @@ struct e1000_info {
 #define FLAG_MSI_TEST_FAILED              (1 << 30)
 #define FLAG_RX_RESTART_NOW               (1 << 31)
 
+#define FLAG2_IS_DISCARDING               (1 << 0)
+
 #define E1000_RX_DESC_PS(R, i)	    \
 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
 #define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
@@ -355,8 +359,7 @@ struct e1000_info {
 enum e1000_state_t {
 	__E1000_TESTING,
 	__E1000_RESETTING,
-	__E1000_DOWN,
-	__E1000_DISCARDING
+	__E1000_DOWN
 };
 
 enum latency_range {
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 0849a45..856e161 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -482,23 +482,24 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
 		length = le16_to_cpu(rx_desc->length);
 
-		/* !EOP means multiple descriptors were used to store a single
-		 * packet, if thats the case we need to toss it.  In fact, we
-		 * to toss every packet with the EOP bit clear and the next
-		 * frame that _does_ have the EOP bit set, as it is by
+		/*
+		 * !EOP means multiple descriptors were used to store a single
+		 * packet, if that's the case we need to toss it.  In fact, we
+		 * need to toss every packet with the EOP bit clear and the
+		 * next frame that _does_ have the EOP bit set, as it is by
 		 * definition only a frame fragment
 		 */
 		if (unlikely(!(status & E1000_RXD_STAT_EOP)))
-			set_bit(__E1000_DISCARDING, &adapter->flags);
+			adapter->flags2 |= FLAG2_IS_DISCARDING;
 
-		if (test_bit(__E1000_DISCARDING, &adapter->flags)) {
+		if (adapter->flags2 & FLAG2_IS_DISCARDING) {
 			/* All receives must fit into a single buffer */
 			e_dbg("%s: Receive packet consumed multiple buffers\n",
 			      netdev->name);
 			/* recycle */
 			buffer_info->skb = skb;
 			if (status & E1000_RXD_STAT_EOP)
-				clear_bit(__E1000_DISCARDING, &adapter->flags);
+				adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 			goto next_desc;
 		}
 
@@ -758,10 +759,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
 				 PCI_DMA_FROMDEVICE);
 		buffer_info->dma = 0;
 
-		if (!(staterr & E1000_RXD_STAT_EOP)) {
+		/* see !EOP comment in other rx routine */
+		if (!(staterr & E1000_RXD_STAT_EOP))
+			adapter->flags2 |= FLAG2_IS_DISCARDING;
+
+		if (adapter->flags2 & FLAG2_IS_DISCARDING) {
 			e_dbg("%s: Packet Split buffers didn't pick up the "
 			      "full packet\n", netdev->name);
 			dev_kfree_skb_irq(skb);
+			if (staterr & E1000_RXD_STAT_EOP)
+				adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 			goto next_desc;
 		}
 
@@ -1121,6 +1128,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
 
 	rx_ring->next_to_clean = 0;
 	rx_ring->next_to_use = 0;
+	adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 
 	writel(0, adapter->hw.hw_addr + rx_ring->head);
 	writel(0, adapter->hw.hw_addr + rx_ring->tail);
@@ -4776,6 +4784,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	adapter->ei = ei;
 	adapter->pba = ei->pba;
 	adapter->flags = ei->flags;
+	adapter->flags2 = ei->flags2;
 	adapter->hw.adapter = adapter;
 	adapter->hw.mac.type = ei->mac;
 	adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;