From: Andy Gospodarek <gospo@redhat.com> Date: Fri, 22 Jan 2010 22:44:47 -0500 Subject: [net] e1000e: fix broken wol Message-id: <20100122224447.GD21335@gospo.rdu.redhat.com> Patchwork-id: 22774 O-Subject: [RHEL5.5 PATCH] e1000e: fix broken wol Bugzilla: 557974 RH-Acked-by: Jarod Wilson <jwilson@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: David S. Miller <davem@redhat.com> RH-Acked-by: Dean Nelson <dnelson@redhat.com> When trying to figure out why WoL wouldn't work on 2.6.18-185.el5, I discovered that this RHEL patch: commit d853981d68f507ee30bd826727ef8002c536aebd Author: Amerigo Wang <amwang@redhat.com> Date: Thu Jan 14 15:36:38 2010 -0500 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 This will resolve RHBZ 557974. diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 1f753c7..1bb922a 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -416,6 +416,7 @@ struct e1000_info { /* CRC Stripping defines */ #define FLAG2_CRC_STRIPPING (1 << 0) #define FLAG2_HAS_PHY_WAKEUP (1 << 1) +#define FLAG2_IS_DISCARDING (1 << 2) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -427,8 +428,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 239ace8..f911baa 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -484,23 +484,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; } @@ -760,10 +761,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; } @@ -1133,6 +1140,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);