aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 73fe38928c2b..62f55145fa44 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -552,11 +552,26 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
552 wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; 552 wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
553} 553}
554 554
555static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
556 struct sk_buff *skb)
557{
558 u8 vlan_prio;
559 u16 vlan_tag;
560
561 vlan_tag = vlan_tx_tag_get(skb);
562 vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
563 /* If vlan priority provided by OS is NOT in available bmap */
564 if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
565 vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
566 adapter->recommended_prio;
567
568 return vlan_tag;
569}
570
555static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, 571static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
556 struct sk_buff *skb, u32 wrb_cnt, u32 len) 572 struct sk_buff *skb, u32 wrb_cnt, u32 len)
557{ 573{
558 u8 vlan_prio = 0; 574 u16 vlan_tag;
559 u16 vlan_tag = 0;
560 575
561 memset(hdr, 0, sizeof(*hdr)); 576 memset(hdr, 0, sizeof(*hdr));
562 577
@@ -587,12 +602,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
587 602
588 if (vlan_tx_tag_present(skb)) { 603 if (vlan_tx_tag_present(skb)) {
589 AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); 604 AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
590 vlan_tag = vlan_tx_tag_get(skb); 605 vlan_tag = be_get_tx_vlan_tag(adapter, skb);
591 vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
592 /* If vlan priority provided by OS is NOT in available bmap */
593 if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
594 vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
595 adapter->recommended_prio;
596 AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); 606 AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
597 } 607 }
598 608
@@ -695,6 +705,25 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
695 u32 start = txq->head; 705 u32 start = txq->head;
696 bool dummy_wrb, stopped = false; 706 bool dummy_wrb, stopped = false;
697 707
708 /* For vlan tagged pkts, BE
709 * 1) calculates checksum even when CSO is not requested
710 * 2) calculates checksum wrongly for padded pkt less than
711 * 60 bytes long.
712 * As a workaround disable TX vlan offloading in such cases.
713 */
714 if (unlikely(vlan_tx_tag_present(skb) &&
715 (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) {
716 skb = skb_share_check(skb, GFP_ATOMIC);
717 if (unlikely(!skb))
718 goto tx_drop;
719
720 skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb));
721 if (unlikely(!skb))
722 goto tx_drop;
723
724 skb->vlan_tci = 0;
725 }
726
698 wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); 727 wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
699 728
700 copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); 729 copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
@@ -722,6 +751,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
722 txq->head = start; 751 txq->head = start;
723 dev_kfree_skb_any(skb); 752 dev_kfree_skb_any(skb);
724 } 753 }
754tx_drop:
725 return NETDEV_TX_OK; 755 return NETDEV_TX_OK;
726} 756}
727 757