diff options
| -rw-r--r-- | drivers/net/e1000e/e1000.h | 1 | ||||
| -rw-r--r-- | drivers/net/e1000e/netdev.c | 25 |
2 files changed, 22 insertions, 4 deletions
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index d6ee28f6ea08..d236efaf7478 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
| @@ -421,6 +421,7 @@ struct e1000_info { | |||
| 421 | /* CRC Stripping defines */ | 421 | /* CRC Stripping defines */ |
| 422 | #define FLAG2_CRC_STRIPPING (1 << 0) | 422 | #define FLAG2_CRC_STRIPPING (1 << 0) |
| 423 | #define FLAG2_HAS_PHY_WAKEUP (1 << 1) | 423 | #define FLAG2_HAS_PHY_WAKEUP (1 << 1) |
| 424 | #define FLAG2_IS_DISCARDING (1 << 2) | ||
| 424 | 425 | ||
| 425 | #define E1000_RX_DESC_PS(R, i) \ | 426 | #define E1000_RX_DESC_PS(R, i) \ |
| 426 | (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) | 427 | (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index f91f247ed6af..1ea395b6c992 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
| @@ -450,13 +450,23 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, | |||
| 450 | 450 | ||
| 451 | length = le16_to_cpu(rx_desc->length); | 451 | length = le16_to_cpu(rx_desc->length); |
| 452 | 452 | ||
| 453 | /* !EOP means multiple descriptors were used to store a single | 453 | /* |
| 454 | * packet, also make sure the frame isn't just CRC only */ | 454 | * !EOP means multiple descriptors were used to store a single |
| 455 | if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { | 455 | * packet, if that's the case we need to toss it. In fact, we |
| 456 | * need to toss every packet with the EOP bit clear and the | ||
| 457 | * next frame that _does_ have the EOP bit set, as it is by | ||
| 458 | * definition only a frame fragment | ||
| 459 | */ | ||
| 460 | if (unlikely(!(status & E1000_RXD_STAT_EOP))) | ||
| 461 | adapter->flags2 |= FLAG2_IS_DISCARDING; | ||
| 462 | |||
| 463 | if (adapter->flags2 & FLAG2_IS_DISCARDING) { | ||
| 456 | /* All receives must fit into a single buffer */ | 464 | /* All receives must fit into a single buffer */ |
| 457 | e_dbg("Receive packet consumed multiple buffers\n"); | 465 | e_dbg("Receive packet consumed multiple buffers\n"); |
| 458 | /* recycle */ | 466 | /* recycle */ |
| 459 | buffer_info->skb = skb; | 467 | buffer_info->skb = skb; |
| 468 | if (status & E1000_RXD_STAT_EOP) | ||
| 469 | adapter->flags2 &= ~FLAG2_IS_DISCARDING; | ||
| 460 | goto next_desc; | 470 | goto next_desc; |
| 461 | } | 471 | } |
| 462 | 472 | ||
| @@ -745,10 +755,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, | |||
| 745 | PCI_DMA_FROMDEVICE); | 755 | PCI_DMA_FROMDEVICE); |
| 746 | buffer_info->dma = 0; | 756 | buffer_info->dma = 0; |
| 747 | 757 | ||
| 748 | if (!(staterr & E1000_RXD_STAT_EOP)) { | 758 | /* see !EOP comment in other rx routine */ |
| 759 | if (!(staterr & E1000_RXD_STAT_EOP)) | ||
| 760 | adapter->flags2 |= FLAG2_IS_DISCARDING; | ||
| 761 | |||
| 762 | if (adapter->flags2 & FLAG2_IS_DISCARDING) { | ||
| 749 | e_dbg("Packet Split buffers didn't pick up the full " | 763 | e_dbg("Packet Split buffers didn't pick up the full " |
| 750 | "packet\n"); | 764 | "packet\n"); |
| 751 | dev_kfree_skb_irq(skb); | 765 | dev_kfree_skb_irq(skb); |
| 766 | if (staterr & E1000_RXD_STAT_EOP) | ||
| 767 | adapter->flags2 &= ~FLAG2_IS_DISCARDING; | ||
| 752 | goto next_desc; | 768 | goto next_desc; |
| 753 | } | 769 | } |
| 754 | 770 | ||
| @@ -1118,6 +1134,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) | |||
| 1118 | 1134 | ||
| 1119 | rx_ring->next_to_clean = 0; | 1135 | rx_ring->next_to_clean = 0; |
| 1120 | rx_ring->next_to_use = 0; | 1136 | rx_ring->next_to_use = 0; |
| 1137 | adapter->flags2 &= ~FLAG2_IS_DISCARDING; | ||
| 1121 | 1138 | ||
| 1122 | writel(0, adapter->hw.hw_addr + rx_ring->head); | 1139 | writel(0, adapter->hw.hw_addr + rx_ring->head); |
| 1123 | writel(0, adapter->hw.hw_addr + rx_ring->tail); | 1140 | writel(0, adapter->hw.hw_addr + rx_ring->tail); |
