aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2012-04-30 02:47:37 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-01 13:39:13 -0400
commite072b3fad5f3915102c94628b4971f52ff99dd05 (patch)
tree291a67ab2643d26bcea10919869fbe3cce05ed6f
parent3f42941b5d1d13542b1a755a9e4f633aa72e4d3e (diff)
sky2: fix receive length error in mixed non-VLAN/VLAN traffic
Bug: The VLAN bit of the MAC RX Status Word is unreliable in several older supported chips. Sometimes the VLAN bit is not set for valid VLAN packets and also sometimes the VLAN bit is set for non-VLAN packets that came after a VLAN packet. This results in a receive length error when VLAN hardware tagging is enabled. Fix: Variation on original fix proposed by Mirko. The VLAN information is decoded in the status loop, and can be applied to the received SKB there. This eliminates the need for the separate tag field in the interface data structure. The tag has to be copied and cleared if packet is copied. This version checked out with vlan and normal traffic. Note: vlan_tx_tag_present should be renamed vlan_tag_present, but that is outside scope of this. Reported-by: Mirko Lindner <mlindner@marvell.com> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/marvell/sky2.c28
-rw-r--r--drivers/net/ethernet/marvell/sky2.h1
2 files changed, 17 insertions, 12 deletions
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 0ced3117abc6..487a6c8bd4ec 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -2495,9 +2495,11 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2,
2495 skb->ip_summed = re->skb->ip_summed; 2495 skb->ip_summed = re->skb->ip_summed;
2496 skb->csum = re->skb->csum; 2496 skb->csum = re->skb->csum;
2497 skb->rxhash = re->skb->rxhash; 2497 skb->rxhash = re->skb->rxhash;
2498 skb->vlan_tci = re->skb->vlan_tci;
2498 2499
2499 pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, 2500 pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr,
2500 length, PCI_DMA_FROMDEVICE); 2501 length, PCI_DMA_FROMDEVICE);
2502 re->skb->vlan_tci = 0;
2501 re->skb->rxhash = 0; 2503 re->skb->rxhash = 0;
2502 re->skb->ip_summed = CHECKSUM_NONE; 2504 re->skb->ip_summed = CHECKSUM_NONE;
2503 skb_put(skb, length); 2505 skb_put(skb, length);
@@ -2583,9 +2585,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
2583 struct sk_buff *skb = NULL; 2585 struct sk_buff *skb = NULL;
2584 u16 count = (status & GMR_FS_LEN) >> 16; 2586 u16 count = (status & GMR_FS_LEN) >> 16;
2585 2587
2586 if (status & GMR_FS_VLAN)
2587 count -= VLAN_HLEN; /* Account for vlan tag */
2588
2589 netif_printk(sky2, rx_status, KERN_DEBUG, dev, 2588 netif_printk(sky2, rx_status, KERN_DEBUG, dev,
2590 "rx slot %u status 0x%x len %d\n", 2589 "rx slot %u status 0x%x len %d\n",
2591 sky2->rx_next, status, length); 2590 sky2->rx_next, status, length);
@@ -2593,6 +2592,9 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
2593 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; 2592 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
2594 prefetch(sky2->rx_ring + sky2->rx_next); 2593 prefetch(sky2->rx_ring + sky2->rx_next);
2595 2594
2595 if (vlan_tx_tag_present(re->skb))
2596 count -= VLAN_HLEN; /* Account for vlan tag */
2597
2596 /* This chip has hardware problems that generates bogus status. 2598 /* This chip has hardware problems that generates bogus status.
2597 * So do only marginal checking and expect higher level protocols 2599 * So do only marginal checking and expect higher level protocols
2598 * to handle crap frames. 2600 * to handle crap frames.
@@ -2650,11 +2652,8 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
2650} 2652}
2651 2653
2652static inline void sky2_skb_rx(const struct sky2_port *sky2, 2654static inline void sky2_skb_rx(const struct sky2_port *sky2,
2653 u32 status, struct sk_buff *skb) 2655 struct sk_buff *skb)
2654{ 2656{
2655 if (status & GMR_FS_VLAN)
2656 __vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
2657
2658 if (skb->ip_summed == CHECKSUM_NONE) 2657 if (skb->ip_summed == CHECKSUM_NONE)
2659 netif_receive_skb(skb); 2658 netif_receive_skb(skb);
2660 else 2659 else
@@ -2708,6 +2707,14 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
2708 } 2707 }
2709} 2708}
2710 2709
2710static void sky2_rx_tag(struct sky2_port *sky2, u16 length)
2711{
2712 struct sk_buff *skb;
2713
2714 skb = sky2->rx_ring[sky2->rx_next].skb;
2715 __vlan_hwaccel_put_tag(skb, be16_to_cpu(length));
2716}
2717
2711static void sky2_rx_hash(struct sky2_port *sky2, u32 status) 2718static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
2712{ 2719{
2713 struct sk_buff *skb; 2720 struct sk_buff *skb;
@@ -2766,8 +2773,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
2766 } 2773 }
2767 2774
2768 skb->protocol = eth_type_trans(skb, dev); 2775 skb->protocol = eth_type_trans(skb, dev);
2769 2776 sky2_skb_rx(sky2, skb);
2770 sky2_skb_rx(sky2, status, skb);
2771 2777
2772 /* Stop after net poll weight */ 2778 /* Stop after net poll weight */
2773 if (++work_done >= to_do) 2779 if (++work_done >= to_do)
@@ -2775,11 +2781,11 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
2775 break; 2781 break;
2776 2782
2777 case OP_RXVLAN: 2783 case OP_RXVLAN:
2778 sky2->rx_tag = length; 2784 sky2_rx_tag(sky2, length);
2779 break; 2785 break;
2780 2786
2781 case OP_RXCHKSVLAN: 2787 case OP_RXCHKSVLAN:
2782 sky2->rx_tag = length; 2788 sky2_rx_tag(sky2, length);
2783 /* fall through */ 2789 /* fall through */
2784 case OP_RXCHKS: 2790 case OP_RXCHKS:
2785 if (likely(dev->features & NETIF_F_RXCSUM)) 2791 if (likely(dev->features & NETIF_F_RXCSUM))
diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h
index ff6f58bf822a..3c896ce80b71 100644
--- a/drivers/net/ethernet/marvell/sky2.h
+++ b/drivers/net/ethernet/marvell/sky2.h
@@ -2241,7 +2241,6 @@ struct sky2_port {
2241 u16 rx_pending; 2241 u16 rx_pending;
2242 u16 rx_data_size; 2242 u16 rx_data_size;
2243 u16 rx_nfrags; 2243 u16 rx_nfrags;
2244 u16 rx_tag;
2245 2244
2246 struct { 2245 struct {
2247 unsigned long last; 2246 unsigned long last;