aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSomnath Kotur <somnath.kotur@emulex.com>2012-06-26 18:32:10 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-27 04:35:49 -0400
commit93040ae5cc8dcc893eca4a4366dc8415af278edf (patch)
treee178db19e2948d1faa58d1e6f5b0c03b9cc6b5c0
parent525b8075edda9c2ab4b81e210505bd7487ea6e56 (diff)
be2net: Fix to trim skb for padded vlan packets to workaround an ASIC Bug
Fixed spelling error in a comment as pointed out by DaveM. Also refactored existing code a bit to provide placeholders for another ASIC Bug workaround that will be checked-in soon after this. Signed-off-by: Somnath Kotur <somnath.kotur@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h5
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c56
2 files changed, 47 insertions, 14 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 7b5cc2b212e5..7a71fb66c6dc 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -573,6 +573,11 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
573 return val; 573 return val;
574} 574}
575 575
576static inline bool is_ipv4_pkt(struct sk_buff *skb)
577{
578 return skb->protocol == ntohs(ETH_P_IP) && ip_hdr(skb)->version == 4;
579}
580
576static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) 581static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
577{ 582{
578 u32 addr; 583 u32 addr;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index a28896d4411d..edce7af97c87 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -577,6 +577,11 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
577 return vlan_tag; 577 return vlan_tag;
578} 578}
579 579
580static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb)
581{
582 return vlan_tx_tag_present(skb) || adapter->pvid;
583}
584
580static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, 585static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
581 struct sk_buff *skb, u32 wrb_cnt, u32 len) 586 struct sk_buff *skb, u32 wrb_cnt, u32 len)
582{ 587{
@@ -704,33 +709,56 @@ dma_err:
704 return 0; 709 return 0;
705} 710}
706 711
712static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
713 struct sk_buff *skb)
714{
715 u16 vlan_tag = 0;
716
717 skb = skb_share_check(skb, GFP_ATOMIC);
718 if (unlikely(!skb))
719 return skb;
720
721 if (vlan_tx_tag_present(skb)) {
722 vlan_tag = be_get_tx_vlan_tag(adapter, skb);
723 __vlan_put_tag(skb, vlan_tag);
724 skb->vlan_tci = 0;
725 }
726
727 return skb;
728}
729
707static netdev_tx_t be_xmit(struct sk_buff *skb, 730static netdev_tx_t be_xmit(struct sk_buff *skb,
708 struct net_device *netdev) 731 struct net_device *netdev)
709{ 732{
710 struct be_adapter *adapter = netdev_priv(netdev); 733 struct be_adapter *adapter = netdev_priv(netdev);
711 struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; 734 struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
712 struct be_queue_info *txq = &txo->q; 735 struct be_queue_info *txq = &txo->q;
736 struct iphdr *ip = NULL;
713 u32 wrb_cnt = 0, copied = 0; 737 u32 wrb_cnt = 0, copied = 0;
714 u32 start = txq->head; 738 u32 start = txq->head, eth_hdr_len;
715 bool dummy_wrb, stopped = false; 739 bool dummy_wrb, stopped = false;
716 740
717 /* For vlan tagged pkts, BE 741 eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
718 * 1) calculates checksum even when CSO is not requested 742 VLAN_ETH_HLEN : ETH_HLEN;
719 * 2) calculates checksum wrongly for padded pkt less than 743
720 * 60 bytes long. 744 /* HW has a bug which considers padding bytes as legal
721 * As a workaround disable TX vlan offloading in such cases. 745 * and modifies the IPv4 hdr's 'tot_len' field
722 */ 746 */
723 if (vlan_tx_tag_present(skb) && 747 if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) &&
724 (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60)) { 748 is_ipv4_pkt(skb)) {
725 skb = skb_share_check(skb, GFP_ATOMIC); 749 ip = (struct iphdr *)ip_hdr(skb);
726 if (unlikely(!skb)) 750 pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
727 goto tx_drop; 751 }
728 752
729 skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb)); 753 /* HW has a bug wherein it will calculate CSUM for VLAN
754 * pkts even though it is disabled.
755 * Manually insert VLAN in pkt.
756 */
757 if (skb->ip_summed != CHECKSUM_PARTIAL &&
758 be_vlan_tag_chk(adapter, skb)) {
759 skb = be_insert_vlan_in_pkt(adapter, skb);
730 if (unlikely(!skb)) 760 if (unlikely(!skb))
731 goto tx_drop; 761 goto tx_drop;
732
733 skb->vlan_tci = 0;
734 } 762 }
735 763
736 wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); 764 wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);