sky2: fix receive length error in mixed non-VLAN/VLAN traffic
[pandora-kernel.git] / drivers / net / ethernet / marvell / sky2.c
index 0ced311..487a6c8 100644 (file)
@@ -2495,9 +2495,11 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2,
                skb->ip_summed = re->skb->ip_summed;
                skb->csum = re->skb->csum;
                skb->rxhash = re->skb->rxhash;
+               skb->vlan_tci = re->skb->vlan_tci;
 
                pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr,
                                               length, PCI_DMA_FROMDEVICE);
+               re->skb->vlan_tci = 0;
                re->skb->rxhash = 0;
                re->skb->ip_summed = CHECKSUM_NONE;
                skb_put(skb, length);
@@ -2583,9 +2585,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
        struct sk_buff *skb = NULL;
        u16 count = (status & GMR_FS_LEN) >> 16;
 
-       if (status & GMR_FS_VLAN)
-               count -= VLAN_HLEN;     /* Account for vlan tag */
-
        netif_printk(sky2, rx_status, KERN_DEBUG, dev,
                     "rx slot %u status 0x%x len %d\n",
                     sky2->rx_next, status, length);
@@ -2593,6 +2592,9 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
        sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
        prefetch(sky2->rx_ring + sky2->rx_next);
 
+       if (vlan_tx_tag_present(re->skb))
+               count -= VLAN_HLEN;     /* Account for vlan tag */
+
        /* This chip has hardware problems that generates bogus status.
         * So do only marginal checking and expect higher level protocols
         * to handle crap frames.
@@ -2650,11 +2652,8 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
 }
 
 static inline void sky2_skb_rx(const struct sky2_port *sky2,
-                              u32 status, struct sk_buff *skb)
+                              struct sk_buff *skb)
 {
-       if (status & GMR_FS_VLAN)
-               __vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
-
        if (skb->ip_summed == CHECKSUM_NONE)
                netif_receive_skb(skb);
        else
@@ -2708,6 +2707,14 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
        }
 }
 
+static void sky2_rx_tag(struct sky2_port *sky2, u16 length)
+{
+       struct sk_buff *skb;
+
+       skb = sky2->rx_ring[sky2->rx_next].skb;
+       __vlan_hwaccel_put_tag(skb, be16_to_cpu(length));
+}
+
 static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
 {
        struct sk_buff *skb;
@@ -2766,8 +2773,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                        }
 
                        skb->protocol = eth_type_trans(skb, dev);
-
-                       sky2_skb_rx(sky2, status, skb);
+                       sky2_skb_rx(sky2, skb);
 
                        /* Stop after net poll weight */
                        if (++work_done >= to_do)
@@ -2775,11 +2781,11 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                        break;
 
                case OP_RXVLAN:
-                       sky2->rx_tag = length;
+                       sky2_rx_tag(sky2, length);
                        break;
 
                case OP_RXCHKSVLAN:
-                       sky2->rx_tag = length;
+                       sky2_rx_tag(sky2, length);
                        /* fall through */
                case OP_RXCHKS:
                        if (likely(dev->features & NETIF_F_RXCSUM))