@@ -577,6 +577,11 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
577
577
return vlan_tag ;
578
578
}
579
579
580
+ static 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
+
580
585
static void wrb_fill_hdr (struct be_adapter * adapter , struct be_eth_hdr_wrb * hdr ,
581
586
struct sk_buff * skb , u32 wrb_cnt , u32 len )
582
587
{
@@ -704,33 +709,56 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
704
709
return 0 ;
705
710
}
706
711
712
+ static 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
+
707
730
static netdev_tx_t be_xmit (struct sk_buff * skb ,
708
731
struct net_device * netdev )
709
732
{
710
733
struct be_adapter * adapter = netdev_priv (netdev );
711
734
struct be_tx_obj * txo = & adapter -> tx_obj [skb_get_queue_mapping (skb )];
712
735
struct be_queue_info * txq = & txo -> q ;
736
+ struct iphdr * ip = NULL ;
713
737
u32 wrb_cnt = 0 , copied = 0 ;
714
- u32 start = txq -> head ;
738
+ u32 start = txq -> head , eth_hdr_len ;
715
739
bool dummy_wrb , stopped = false;
716
740
717
- /* For vlan tagged pkts, BE
718
- * 1) calculates checksum even when CSO is not requested
719
- * 2) calculates checksum wrongly for padded pkt less than
720
- * 60 bytes long.
721
- * As a workaround disable TX vlan offloading in such cases.
741
+ eth_hdr_len = ntohs ( skb -> protocol ) == ETH_P_8021Q ?
742
+ VLAN_ETH_HLEN : ETH_HLEN ;
743
+
744
+ /* HW has a bug which considers padding bytes as legal
745
+ * and modifies the IPv4 hdr's 'tot_len' field
722
746
*/
723
- if (vlan_tx_tag_present ( skb ) &&
724
- (skb -> ip_summed != CHECKSUM_PARTIAL || skb -> len <= 60 )) {
725
- skb = skb_share_check ( skb , GFP_ATOMIC );
726
- if ( unlikely (! skb ))
727
- goto tx_drop ;
747
+ if (skb -> len <= 60 && be_vlan_tag_chk ( adapter , skb ) &&
748
+ is_ipv4_pkt (skb )) {
749
+ ip = ( struct iphdr * ) ip_hdr ( skb );
750
+ pskb_trim ( skb , eth_hdr_len + ntohs ( ip -> tot_len ));
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
760
if (unlikely (!skb ))
731
761
goto tx_drop ;
732
-
733
- skb -> vlan_tci = 0 ;
734
762
}
735
763
736
764
wrb_cnt = wrb_cnt_for_skb (adapter , skb , & dummy_wrb );
0 commit comments