Skip to content

Commit

Permalink
sky2: fix receive length error in mixed non-VLAN/VLAN traffic
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
stephen hemminger authored and David S. Miller committed May 1, 2012
1 parent 3f42941 commit e072b3f
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 12 deletions.
28 changes: 17 additions & 11 deletions drivers/net/ethernet/marvell/sky2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2583,16 +2585,16 @@ 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);

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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2766,20 +2773,19 @@ 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)
goto exit_loop;
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))
Expand Down
1 change: 0 additions & 1 deletion drivers/net/ethernet/marvell/sky2.h
Original file line number Diff line number Diff line change
Expand Up @@ -2241,7 +2241,6 @@ struct sky2_port {
u16 rx_pending;
u16 rx_data_size;
u16 rx_nfrags;
u16 rx_tag;

struct {
unsigned long last;
Expand Down

0 comments on commit e072b3f

Please sign in to comment.