diff options
author | Sriharsha Basavapatna <sriharsha.basavapatna@emulex.com> | 2015-02-15 21:33:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-20 14:06:57 -0500 |
commit | 804abcdbdbb68df5ca8cf7e70366522f02298029 (patch) | |
tree | 490961cb191ae80d1b598cc893fa9e00cb02ae48 /drivers/net/ethernet/emulex | |
parent | 69994d17abe90c4ae449dfcefbae9754f92c36bd (diff) |
be2net: Refactor wrb_fill_hdr() routine
The WRB header is setup by wrb_fill_hdr() routine. This routine currently
gets some of the WRB params as args and figures out rest of the WRB params
by looking at various fields in skb (like gso, checksum, vlan-tag etc).
All these params could instead be retrieved from the skb into a structure
and passed to this routine. This separates wrb_fill_hdr() to only provide
chip-specific code to fill the WRB. This also makes it simple to support
chips with different WRB formats.
Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/emulex')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 33 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 105 |
2 files changed, 99 insertions, 39 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 27de37aa90af..bc7f3d6872f4 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h | |||
@@ -417,6 +417,39 @@ struct rss_info { | |||
417 | u8 rss_hkey[RSS_HASH_KEY_LEN]; | 417 | u8 rss_hkey[RSS_HASH_KEY_LEN]; |
418 | }; | 418 | }; |
419 | 419 | ||
420 | /* Macros to read/write the 'features' word of be_wrb_params structure. | ||
421 | */ | ||
422 | #define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT | ||
423 | #define BE_WRB_F_MASK(name) BIT_MASK(BE_WRB_F_##name##_BIT) | ||
424 | |||
425 | #define BE_WRB_F_GET(word, name) \ | ||
426 | (((word) & (BE_WRB_F_MASK(name))) >> BE_WRB_F_BIT(name)) | ||
427 | |||
428 | #define BE_WRB_F_SET(word, name, val) \ | ||
429 | ((word) |= (((val) << BE_WRB_F_BIT(name)) & BE_WRB_F_MASK(name))) | ||
430 | |||
431 | /* Feature/offload bits */ | ||
432 | enum { | ||
433 | BE_WRB_F_CRC_BIT, /* Ethernet CRC */ | ||
434 | BE_WRB_F_IPCS_BIT, /* IP csum */ | ||
435 | BE_WRB_F_TCPCS_BIT, /* TCP csum */ | ||
436 | BE_WRB_F_UDPCS_BIT, /* UDP csum */ | ||
437 | BE_WRB_F_LSO_BIT, /* LSO */ | ||
438 | BE_WRB_F_LSO6_BIT, /* LSO6 */ | ||
439 | BE_WRB_F_VLAN_BIT, /* VLAN */ | ||
440 | BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */ | ||
441 | }; | ||
442 | |||
443 | /* The structure below provides a HW-agnostic abstraction of WRB params | ||
444 | * retrieved from a TX skb. This is in turn passed to chip specific routines | ||
445 | * during transmit, to set the corresponding params in the WRB. | ||
446 | */ | ||
447 | struct be_wrb_params { | ||
448 | u32 features; /* Feature bits */ | ||
449 | u16 vlan_tag; /* VLAN tag */ | ||
450 | u16 lso_mss; /* MSS for LSO */ | ||
451 | }; | ||
452 | |||
420 | struct be_adapter { | 453 | struct be_adapter { |
421 | struct pci_dev *pdev; | 454 | struct pci_dev *pdev; |
422 | struct net_device *netdev; | 455 | struct net_device *netdev; |
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 0a816859aca5..8477fb4de614 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -727,48 +727,71 @@ static u16 skb_ip_proto(struct sk_buff *skb) | |||
727 | ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr; | 727 | ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr; |
728 | } | 728 | } |
729 | 729 | ||
730 | static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, | 730 | static void be_get_wrb_params_from_skb(struct be_adapter *adapter, |
731 | struct sk_buff *skb, u32 wrb_cnt, u32 len, | 731 | struct sk_buff *skb, |
732 | bool skip_hw_vlan) | 732 | struct be_wrb_params *wrb_params) |
733 | { | 733 | { |
734 | u16 vlan_tag, proto; | 734 | u16 proto; |
735 | |||
736 | memset(hdr, 0, sizeof(*hdr)); | ||
737 | |||
738 | SET_TX_WRB_HDR_BITS(crc, hdr, 1); | ||
739 | 735 | ||
740 | if (skb_is_gso(skb)) { | 736 | if (skb_is_gso(skb)) { |
741 | SET_TX_WRB_HDR_BITS(lso, hdr, 1); | 737 | BE_WRB_F_SET(wrb_params->features, LSO, 1); |
742 | SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size); | 738 | wrb_params->lso_mss = skb_shinfo(skb)->gso_size; |
743 | if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) | 739 | if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) |
744 | SET_TX_WRB_HDR_BITS(lso6, hdr, 1); | 740 | BE_WRB_F_SET(wrb_params->features, LSO6, 1); |
745 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | 741 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
746 | if (skb->encapsulation) { | 742 | if (skb->encapsulation) { |
747 | SET_TX_WRB_HDR_BITS(ipcs, hdr, 1); | 743 | BE_WRB_F_SET(wrb_params->features, IPCS, 1); |
748 | proto = skb_inner_ip_proto(skb); | 744 | proto = skb_inner_ip_proto(skb); |
749 | } else { | 745 | } else { |
750 | proto = skb_ip_proto(skb); | 746 | proto = skb_ip_proto(skb); |
751 | } | 747 | } |
752 | if (proto == IPPROTO_TCP) | 748 | if (proto == IPPROTO_TCP) |
753 | SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1); | 749 | BE_WRB_F_SET(wrb_params->features, TCPCS, 1); |
754 | else if (proto == IPPROTO_UDP) | 750 | else if (proto == IPPROTO_UDP) |
755 | SET_TX_WRB_HDR_BITS(udpcs, hdr, 1); | 751 | BE_WRB_F_SET(wrb_params->features, UDPCS, 1); |
756 | } | 752 | } |
757 | 753 | ||
758 | if (skb_vlan_tag_present(skb)) { | 754 | if (skb_vlan_tag_present(skb)) { |
759 | SET_TX_WRB_HDR_BITS(vlan, hdr, 1); | 755 | BE_WRB_F_SET(wrb_params->features, VLAN, 1); |
760 | vlan_tag = be_get_tx_vlan_tag(adapter, skb); | 756 | wrb_params->vlan_tag = be_get_tx_vlan_tag(adapter, skb); |
761 | SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag); | ||
762 | } | 757 | } |
763 | 758 | ||
764 | SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt); | 759 | BE_WRB_F_SET(wrb_params->features, CRC, 1); |
765 | SET_TX_WRB_HDR_BITS(len, hdr, len); | 760 | } |
761 | |||
762 | static void wrb_fill_hdr(struct be_adapter *adapter, | ||
763 | struct be_eth_hdr_wrb *hdr, | ||
764 | struct be_wrb_params *wrb_params, | ||
765 | struct sk_buff *skb) | ||
766 | { | ||
767 | memset(hdr, 0, sizeof(*hdr)); | ||
766 | 768 | ||
767 | /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0 | 769 | SET_TX_WRB_HDR_BITS(crc, hdr, |
768 | * When this hack is not needed, the evt bit is set while ringing DB | 770 | BE_WRB_F_GET(wrb_params->features, CRC)); |
771 | SET_TX_WRB_HDR_BITS(ipcs, hdr, | ||
772 | BE_WRB_F_GET(wrb_params->features, IPCS)); | ||
773 | SET_TX_WRB_HDR_BITS(tcpcs, hdr, | ||
774 | BE_WRB_F_GET(wrb_params->features, TCPCS)); | ||
775 | SET_TX_WRB_HDR_BITS(udpcs, hdr, | ||
776 | BE_WRB_F_GET(wrb_params->features, UDPCS)); | ||
777 | |||
778 | SET_TX_WRB_HDR_BITS(lso, hdr, | ||
779 | BE_WRB_F_GET(wrb_params->features, LSO)); | ||
780 | SET_TX_WRB_HDR_BITS(lso6, hdr, | ||
781 | BE_WRB_F_GET(wrb_params->features, LSO6)); | ||
782 | SET_TX_WRB_HDR_BITS(lso_mss, hdr, wrb_params->lso_mss); | ||
783 | |||
784 | /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0. When this | ||
785 | * hack is not needed, the evt bit is set while ringing DB. | ||
769 | */ | 786 | */ |
770 | if (skip_hw_vlan) | 787 | SET_TX_WRB_HDR_BITS(event, hdr, |
771 | SET_TX_WRB_HDR_BITS(event, hdr, 1); | 788 | BE_WRB_F_GET(wrb_params->features, VLAN_SKIP_HW)); |
789 | SET_TX_WRB_HDR_BITS(vlan, hdr, | ||
790 | BE_WRB_F_GET(wrb_params->features, VLAN)); | ||
791 | SET_TX_WRB_HDR_BITS(vlan_tag, hdr, wrb_params->vlan_tag); | ||
792 | |||
793 | SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb)); | ||
794 | SET_TX_WRB_HDR_BITS(len, hdr, skb->len); | ||
772 | } | 795 | } |
773 | 796 | ||
774 | static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, | 797 | static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, |
@@ -790,7 +813,8 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, | |||
790 | 813 | ||
791 | /* Returns the number of WRBs used up by the skb */ | 814 | /* Returns the number of WRBs used up by the skb */ |
792 | static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, | 815 | static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, |
793 | struct sk_buff *skb, bool skip_hw_vlan) | 816 | struct sk_buff *skb, |
817 | struct be_wrb_params *wrb_params) | ||
794 | { | 818 | { |
795 | u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); | 819 | u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); |
796 | struct device *dev = &adapter->pdev->dev; | 820 | struct device *dev = &adapter->pdev->dev; |
@@ -802,7 +826,7 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, | |||
802 | u16 head = txq->head; | 826 | u16 head = txq->head; |
803 | 827 | ||
804 | hdr = queue_head_node(txq); | 828 | hdr = queue_head_node(txq); |
805 | wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan); | 829 | wrb_fill_hdr(adapter, hdr, wrb_params, skb); |
806 | be_dws_cpu_to_le(hdr, sizeof(*hdr)); | 830 | be_dws_cpu_to_le(hdr, sizeof(*hdr)); |
807 | 831 | ||
808 | queue_head_inc(txq); | 832 | queue_head_inc(txq); |
@@ -869,7 +893,8 @@ static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) | |||
869 | 893 | ||
870 | static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, | 894 | static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, |
871 | struct sk_buff *skb, | 895 | struct sk_buff *skb, |
872 | bool *skip_hw_vlan) | 896 | struct be_wrb_params |
897 | *wrb_params) | ||
873 | { | 898 | { |
874 | u16 vlan_tag = 0; | 899 | u16 vlan_tag = 0; |
875 | 900 | ||
@@ -886,8 +911,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, | |||
886 | /* f/w workaround to set skip_hw_vlan = 1, informs the F/W to | 911 | /* f/w workaround to set skip_hw_vlan = 1, informs the F/W to |
887 | * skip VLAN insertion | 912 | * skip VLAN insertion |
888 | */ | 913 | */ |
889 | if (skip_hw_vlan) | 914 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
890 | *skip_hw_vlan = true; | ||
891 | } | 915 | } |
892 | 916 | ||
893 | if (vlan_tag) { | 917 | if (vlan_tag) { |
@@ -905,8 +929,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, | |||
905 | vlan_tag); | 929 | vlan_tag); |
906 | if (unlikely(!skb)) | 930 | if (unlikely(!skb)) |
907 | return skb; | 931 | return skb; |
908 | if (skip_hw_vlan) | 932 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
909 | *skip_hw_vlan = true; | ||
910 | } | 933 | } |
911 | 934 | ||
912 | return skb; | 935 | return skb; |
@@ -946,7 +969,8 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) | |||
946 | 969 | ||
947 | static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | 970 | static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, |
948 | struct sk_buff *skb, | 971 | struct sk_buff *skb, |
949 | bool *skip_hw_vlan) | 972 | struct be_wrb_params |
973 | *wrb_params) | ||
950 | { | 974 | { |
951 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; | 975 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; |
952 | unsigned int eth_hdr_len; | 976 | unsigned int eth_hdr_len; |
@@ -970,7 +994,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
970 | */ | 994 | */ |
971 | if (be_pvid_tagging_enabled(adapter) && | 995 | if (be_pvid_tagging_enabled(adapter) && |
972 | veh->h_vlan_proto == htons(ETH_P_8021Q)) | 996 | veh->h_vlan_proto == htons(ETH_P_8021Q)) |
973 | *skip_hw_vlan = true; | 997 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
974 | 998 | ||
975 | /* HW has a bug wherein it will calculate CSUM for VLAN | 999 | /* HW has a bug wherein it will calculate CSUM for VLAN |
976 | * pkts even though it is disabled. | 1000 | * pkts even though it is disabled. |
@@ -978,7 +1002,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
978 | */ | 1002 | */ |
979 | if (skb->ip_summed != CHECKSUM_PARTIAL && | 1003 | if (skb->ip_summed != CHECKSUM_PARTIAL && |
980 | skb_vlan_tag_present(skb)) { | 1004 | skb_vlan_tag_present(skb)) { |
981 | skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); | 1005 | skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params); |
982 | if (unlikely(!skb)) | 1006 | if (unlikely(!skb)) |
983 | goto err; | 1007 | goto err; |
984 | } | 1008 | } |
@@ -1000,7 +1024,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
1000 | */ | 1024 | */ |
1001 | if (be_ipv6_tx_stall_chk(adapter, skb) && | 1025 | if (be_ipv6_tx_stall_chk(adapter, skb) && |
1002 | be_vlan_tag_tx_chk(adapter, skb)) { | 1026 | be_vlan_tag_tx_chk(adapter, skb)) { |
1003 | skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); | 1027 | skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params); |
1004 | if (unlikely(!skb)) | 1028 | if (unlikely(!skb)) |
1005 | goto err; | 1029 | goto err; |
1006 | } | 1030 | } |
@@ -1014,7 +1038,7 @@ err: | |||
1014 | 1038 | ||
1015 | static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, | 1039 | static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, |
1016 | struct sk_buff *skb, | 1040 | struct sk_buff *skb, |
1017 | bool *skip_hw_vlan) | 1041 | struct be_wrb_params *wrb_params) |
1018 | { | 1042 | { |
1019 | /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or | 1043 | /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or |
1020 | * less may cause a transmit stall on that port. So the work-around is | 1044 | * less may cause a transmit stall on that port. So the work-around is |
@@ -1026,7 +1050,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, | |||
1026 | } | 1050 | } |
1027 | 1051 | ||
1028 | if (BEx_chip(adapter) || lancer_chip(adapter)) { | 1052 | if (BEx_chip(adapter) || lancer_chip(adapter)) { |
1029 | skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan); | 1053 | skb = be_lancer_xmit_workarounds(adapter, skb, wrb_params); |
1030 | if (!skb) | 1054 | if (!skb) |
1031 | return NULL; | 1055 | return NULL; |
1032 | } | 1056 | } |
@@ -1060,18 +1084,21 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) | |||
1060 | 1084 | ||
1061 | static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) | 1085 | static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) |
1062 | { | 1086 | { |
1063 | bool skip_hw_vlan = false, flush = !skb->xmit_more; | ||
1064 | struct be_adapter *adapter = netdev_priv(netdev); | 1087 | struct be_adapter *adapter = netdev_priv(netdev); |
1065 | u16 q_idx = skb_get_queue_mapping(skb); | 1088 | u16 q_idx = skb_get_queue_mapping(skb); |
1066 | struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; | 1089 | struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; |
1090 | struct be_wrb_params wrb_params = { 0 }; | ||
1067 | struct be_queue_info *txq = &txo->q; | 1091 | struct be_queue_info *txq = &txo->q; |
1092 | bool flush = !skb->xmit_more; | ||
1068 | u16 wrb_cnt; | 1093 | u16 wrb_cnt; |
1069 | 1094 | ||
1070 | skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); | 1095 | skb = be_xmit_workarounds(adapter, skb, &wrb_params); |
1071 | if (unlikely(!skb)) | 1096 | if (unlikely(!skb)) |
1072 | goto drop; | 1097 | goto drop; |
1073 | 1098 | ||
1074 | wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan); | 1099 | be_get_wrb_params_from_skb(adapter, skb, &wrb_params); |
1100 | |||
1101 | wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params); | ||
1075 | if (unlikely(!wrb_cnt)) { | 1102 | if (unlikely(!wrb_cnt)) { |
1076 | dev_kfree_skb_any(skb); | 1103 | dev_kfree_skb_any(skb); |
1077 | goto drop; | 1104 | goto drop; |