diff options
author | David S. Miller <davem@davemloft.net> | 2015-02-20 14:07:02 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-20 14:07:02 -0500 |
commit | 50036ccf3deeb8f0ffd7311a50a8586ae62bc8b1 (patch) | |
tree | dced16a37b682ff635940c45a34a251bfb4b4473 | |
parent | 69994d17abe90c4ae449dfcefbae9754f92c36bd (diff) | |
parent | cf5671e6999829933aa4b9b8eefc7d3b8b85c5cb (diff) |
Merge branch 'be2net-next'
Sriharsha Basavapatna says:
====================
be2net patch-set
This patch set contains a few code refactoring changes to make it easy to
support new TX WRB formats in future ASICs. Please consider applying it to
net-next tree.
Patch 1: Refactors chip specific code to setup tx wrb into a separate routine.
Patch 2: Refactors tx enqueue function to remove a bit of duplicate code and
improves wrb setup steps.
Patch 3: Minor refactoring in tx compl to limit CQE accesses to 1 routine.
Patch 4: Adds a few inline functions.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 40 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 294 |
2 files changed, 231 insertions, 103 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 27de37aa90af..ad33bf1f1df1 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h | |||
@@ -238,10 +238,17 @@ struct be_tx_stats { | |||
238 | struct u64_stats_sync sync_compl; | 238 | struct u64_stats_sync sync_compl; |
239 | }; | 239 | }; |
240 | 240 | ||
241 | /* Structure to hold some data of interest obtained from a TX CQE */ | ||
242 | struct be_tx_compl_info { | ||
243 | u8 status; /* Completion status */ | ||
244 | u16 end_index; /* Completed TXQ Index */ | ||
245 | }; | ||
246 | |||
241 | struct be_tx_obj { | 247 | struct be_tx_obj { |
242 | u32 db_offset; | 248 | u32 db_offset; |
243 | struct be_queue_info q; | 249 | struct be_queue_info q; |
244 | struct be_queue_info cq; | 250 | struct be_queue_info cq; |
251 | struct be_tx_compl_info txcp; | ||
245 | /* Remember the skbs that were transmitted */ | 252 | /* Remember the skbs that were transmitted */ |
246 | struct sk_buff *sent_skb_list[TX_Q_LEN]; | 253 | struct sk_buff *sent_skb_list[TX_Q_LEN]; |
247 | struct be_tx_stats stats; | 254 | struct be_tx_stats stats; |
@@ -417,6 +424,39 @@ struct rss_info { | |||
417 | u8 rss_hkey[RSS_HASH_KEY_LEN]; | 424 | u8 rss_hkey[RSS_HASH_KEY_LEN]; |
418 | }; | 425 | }; |
419 | 426 | ||
427 | /* Macros to read/write the 'features' word of be_wrb_params structure. | ||
428 | */ | ||
429 | #define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT | ||
430 | #define BE_WRB_F_MASK(name) BIT_MASK(BE_WRB_F_##name##_BIT) | ||
431 | |||
432 | #define BE_WRB_F_GET(word, name) \ | ||
433 | (((word) & (BE_WRB_F_MASK(name))) >> BE_WRB_F_BIT(name)) | ||
434 | |||
435 | #define BE_WRB_F_SET(word, name, val) \ | ||
436 | ((word) |= (((val) << BE_WRB_F_BIT(name)) & BE_WRB_F_MASK(name))) | ||
437 | |||
438 | /* Feature/offload bits */ | ||
439 | enum { | ||
440 | BE_WRB_F_CRC_BIT, /* Ethernet CRC */ | ||
441 | BE_WRB_F_IPCS_BIT, /* IP csum */ | ||
442 | BE_WRB_F_TCPCS_BIT, /* TCP csum */ | ||
443 | BE_WRB_F_UDPCS_BIT, /* UDP csum */ | ||
444 | BE_WRB_F_LSO_BIT, /* LSO */ | ||
445 | BE_WRB_F_LSO6_BIT, /* LSO6 */ | ||
446 | BE_WRB_F_VLAN_BIT, /* VLAN */ | ||
447 | BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */ | ||
448 | }; | ||
449 | |||
450 | /* The structure below provides a HW-agnostic abstraction of WRB params | ||
451 | * retrieved from a TX skb. This is in turn passed to chip specific routines | ||
452 | * during transmit, to set the corresponding params in the WRB. | ||
453 | */ | ||
454 | struct be_wrb_params { | ||
455 | u32 features; /* Feature bits */ | ||
456 | u16 vlan_tag; /* VLAN tag */ | ||
457 | u16 lso_mss; /* MSS for LSO */ | ||
458 | }; | ||
459 | |||
420 | struct be_adapter { | 460 | struct be_adapter { |
421 | struct pci_dev *pdev; | 461 | struct pci_dev *pdev; |
422 | struct net_device *netdev; | 462 | 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..c1553fba7916 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -727,48 +727,86 @@ 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 inline bool be_is_txq_full(struct be_tx_obj *txo) |
731 | struct sk_buff *skb, u32 wrb_cnt, u32 len, | ||
732 | bool skip_hw_vlan) | ||
733 | { | 731 | { |
734 | u16 vlan_tag, proto; | 732 | return atomic_read(&txo->q.used) + BE_MAX_TX_FRAG_COUNT >= txo->q.len; |
733 | } | ||
735 | 734 | ||
736 | memset(hdr, 0, sizeof(*hdr)); | 735 | static inline bool be_can_txq_wake(struct be_tx_obj *txo) |
736 | { | ||
737 | return atomic_read(&txo->q.used) < txo->q.len / 2; | ||
738 | } | ||
737 | 739 | ||
738 | SET_TX_WRB_HDR_BITS(crc, hdr, 1); | 740 | static inline bool be_is_tx_compl_pending(struct be_tx_obj *txo) |
741 | { | ||
742 | return atomic_read(&txo->q.used) > txo->pend_wrb_cnt; | ||
743 | } | ||
744 | |||
745 | static void be_get_wrb_params_from_skb(struct be_adapter *adapter, | ||
746 | struct sk_buff *skb, | ||
747 | struct be_wrb_params *wrb_params) | ||
748 | { | ||
749 | u16 proto; | ||
739 | 750 | ||
740 | if (skb_is_gso(skb)) { | 751 | if (skb_is_gso(skb)) { |
741 | SET_TX_WRB_HDR_BITS(lso, hdr, 1); | 752 | BE_WRB_F_SET(wrb_params->features, LSO, 1); |
742 | SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size); | 753 | wrb_params->lso_mss = skb_shinfo(skb)->gso_size; |
743 | if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) | 754 | if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) |
744 | SET_TX_WRB_HDR_BITS(lso6, hdr, 1); | 755 | BE_WRB_F_SET(wrb_params->features, LSO6, 1); |
745 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | 756 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
746 | if (skb->encapsulation) { | 757 | if (skb->encapsulation) { |
747 | SET_TX_WRB_HDR_BITS(ipcs, hdr, 1); | 758 | BE_WRB_F_SET(wrb_params->features, IPCS, 1); |
748 | proto = skb_inner_ip_proto(skb); | 759 | proto = skb_inner_ip_proto(skb); |
749 | } else { | 760 | } else { |
750 | proto = skb_ip_proto(skb); | 761 | proto = skb_ip_proto(skb); |
751 | } | 762 | } |
752 | if (proto == IPPROTO_TCP) | 763 | if (proto == IPPROTO_TCP) |
753 | SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1); | 764 | BE_WRB_F_SET(wrb_params->features, TCPCS, 1); |
754 | else if (proto == IPPROTO_UDP) | 765 | else if (proto == IPPROTO_UDP) |
755 | SET_TX_WRB_HDR_BITS(udpcs, hdr, 1); | 766 | BE_WRB_F_SET(wrb_params->features, UDPCS, 1); |
756 | } | 767 | } |
757 | 768 | ||
758 | if (skb_vlan_tag_present(skb)) { | 769 | if (skb_vlan_tag_present(skb)) { |
759 | SET_TX_WRB_HDR_BITS(vlan, hdr, 1); | 770 | BE_WRB_F_SET(wrb_params->features, VLAN, 1); |
760 | vlan_tag = be_get_tx_vlan_tag(adapter, skb); | 771 | wrb_params->vlan_tag = be_get_tx_vlan_tag(adapter, skb); |
761 | SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag); | ||
762 | } | 772 | } |
763 | 773 | ||
764 | SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt); | 774 | BE_WRB_F_SET(wrb_params->features, CRC, 1); |
765 | SET_TX_WRB_HDR_BITS(len, hdr, len); | 775 | } |
776 | |||
777 | static void wrb_fill_hdr(struct be_adapter *adapter, | ||
778 | struct be_eth_hdr_wrb *hdr, | ||
779 | struct be_wrb_params *wrb_params, | ||
780 | struct sk_buff *skb) | ||
781 | { | ||
782 | memset(hdr, 0, sizeof(*hdr)); | ||
766 | 783 | ||
767 | /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0 | 784 | SET_TX_WRB_HDR_BITS(crc, hdr, |
768 | * When this hack is not needed, the evt bit is set while ringing DB | 785 | BE_WRB_F_GET(wrb_params->features, CRC)); |
786 | SET_TX_WRB_HDR_BITS(ipcs, hdr, | ||
787 | BE_WRB_F_GET(wrb_params->features, IPCS)); | ||
788 | SET_TX_WRB_HDR_BITS(tcpcs, hdr, | ||
789 | BE_WRB_F_GET(wrb_params->features, TCPCS)); | ||
790 | SET_TX_WRB_HDR_BITS(udpcs, hdr, | ||
791 | BE_WRB_F_GET(wrb_params->features, UDPCS)); | ||
792 | |||
793 | SET_TX_WRB_HDR_BITS(lso, hdr, | ||
794 | BE_WRB_F_GET(wrb_params->features, LSO)); | ||
795 | SET_TX_WRB_HDR_BITS(lso6, hdr, | ||
796 | BE_WRB_F_GET(wrb_params->features, LSO6)); | ||
797 | SET_TX_WRB_HDR_BITS(lso_mss, hdr, wrb_params->lso_mss); | ||
798 | |||
799 | /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0. When this | ||
800 | * hack is not needed, the evt bit is set while ringing DB. | ||
769 | */ | 801 | */ |
770 | if (skip_hw_vlan) | 802 | SET_TX_WRB_HDR_BITS(event, hdr, |
771 | SET_TX_WRB_HDR_BITS(event, hdr, 1); | 803 | BE_WRB_F_GET(wrb_params->features, VLAN_SKIP_HW)); |
804 | SET_TX_WRB_HDR_BITS(vlan, hdr, | ||
805 | BE_WRB_F_GET(wrb_params->features, VLAN)); | ||
806 | SET_TX_WRB_HDR_BITS(vlan_tag, hdr, wrb_params->vlan_tag); | ||
807 | |||
808 | SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb)); | ||
809 | SET_TX_WRB_HDR_BITS(len, hdr, skb->len); | ||
772 | } | 810 | } |
773 | 811 | ||
774 | static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, | 812 | static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, |
@@ -788,77 +826,124 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, | |||
788 | } | 826 | } |
789 | } | 827 | } |
790 | 828 | ||
791 | /* Returns the number of WRBs used up by the skb */ | 829 | /* Grab a WRB header for xmit */ |
830 | static u16 be_tx_get_wrb_hdr(struct be_tx_obj *txo) | ||
831 | { | ||
832 | u16 head = txo->q.head; | ||
833 | |||
834 | queue_head_inc(&txo->q); | ||
835 | return head; | ||
836 | } | ||
837 | |||
838 | /* Set up the WRB header for xmit */ | ||
839 | static void be_tx_setup_wrb_hdr(struct be_adapter *adapter, | ||
840 | struct be_tx_obj *txo, | ||
841 | struct be_wrb_params *wrb_params, | ||
842 | struct sk_buff *skb, u16 head) | ||
843 | { | ||
844 | u32 num_frags = skb_wrb_cnt(skb); | ||
845 | struct be_queue_info *txq = &txo->q; | ||
846 | struct be_eth_hdr_wrb *hdr = queue_index_node(txq, head); | ||
847 | |||
848 | wrb_fill_hdr(adapter, hdr, wrb_params, skb); | ||
849 | be_dws_cpu_to_le(hdr, sizeof(*hdr)); | ||
850 | |||
851 | BUG_ON(txo->sent_skb_list[head]); | ||
852 | txo->sent_skb_list[head] = skb; | ||
853 | txo->last_req_hdr = head; | ||
854 | atomic_add(num_frags, &txq->used); | ||
855 | txo->last_req_wrb_cnt = num_frags; | ||
856 | txo->pend_wrb_cnt += num_frags; | ||
857 | } | ||
858 | |||
859 | /* Setup a WRB fragment (buffer descriptor) for xmit */ | ||
860 | static void be_tx_setup_wrb_frag(struct be_tx_obj *txo, dma_addr_t busaddr, | ||
861 | int len) | ||
862 | { | ||
863 | struct be_eth_wrb *wrb; | ||
864 | struct be_queue_info *txq = &txo->q; | ||
865 | |||
866 | wrb = queue_head_node(txq); | ||
867 | wrb_fill(wrb, busaddr, len); | ||
868 | queue_head_inc(txq); | ||
869 | } | ||
870 | |||
871 | /* Bring the queue back to the state it was in before be_xmit_enqueue() routine | ||
872 | * was invoked. The producer index is restored to the previous packet and the | ||
873 | * WRBs of the current packet are unmapped. Invoked to handle tx setup errors. | ||
874 | */ | ||
875 | static void be_xmit_restore(struct be_adapter *adapter, | ||
876 | struct be_tx_obj *txo, u16 head, bool map_single, | ||
877 | u32 copied) | ||
878 | { | ||
879 | struct device *dev; | ||
880 | struct be_eth_wrb *wrb; | ||
881 | struct be_queue_info *txq = &txo->q; | ||
882 | |||
883 | dev = &adapter->pdev->dev; | ||
884 | txq->head = head; | ||
885 | |||
886 | /* skip the first wrb (hdr); it's not mapped */ | ||
887 | queue_head_inc(txq); | ||
888 | while (copied) { | ||
889 | wrb = queue_head_node(txq); | ||
890 | unmap_tx_frag(dev, wrb, map_single); | ||
891 | map_single = false; | ||
892 | copied -= le32_to_cpu(wrb->frag_len); | ||
893 | queue_head_inc(txq); | ||
894 | } | ||
895 | |||
896 | txq->head = head; | ||
897 | } | ||
898 | |||
899 | /* Enqueue the given packet for transmit. This routine allocates WRBs for the | ||
900 | * packet, dma maps the packet buffers and sets up the WRBs. Returns the number | ||
901 | * of WRBs used up by the packet. | ||
902 | */ | ||
792 | static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, | 903 | static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, |
793 | struct sk_buff *skb, bool skip_hw_vlan) | 904 | struct sk_buff *skb, |
905 | struct be_wrb_params *wrb_params) | ||
794 | { | 906 | { |
795 | u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); | 907 | u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); |
796 | struct device *dev = &adapter->pdev->dev; | 908 | struct device *dev = &adapter->pdev->dev; |
797 | struct be_queue_info *txq = &txo->q; | 909 | struct be_queue_info *txq = &txo->q; |
798 | struct be_eth_hdr_wrb *hdr; | ||
799 | bool map_single = false; | 910 | bool map_single = false; |
800 | struct be_eth_wrb *wrb; | ||
801 | dma_addr_t busaddr; | ||
802 | u16 head = txq->head; | 911 | u16 head = txq->head; |
912 | dma_addr_t busaddr; | ||
913 | int len; | ||
803 | 914 | ||
804 | hdr = queue_head_node(txq); | 915 | head = be_tx_get_wrb_hdr(txo); |
805 | wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan); | ||
806 | be_dws_cpu_to_le(hdr, sizeof(*hdr)); | ||
807 | |||
808 | queue_head_inc(txq); | ||
809 | 916 | ||
810 | if (skb->len > skb->data_len) { | 917 | if (skb->len > skb->data_len) { |
811 | int len = skb_headlen(skb); | 918 | len = skb_headlen(skb); |
812 | 919 | ||
813 | busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); | 920 | busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); |
814 | if (dma_mapping_error(dev, busaddr)) | 921 | if (dma_mapping_error(dev, busaddr)) |
815 | goto dma_err; | 922 | goto dma_err; |
816 | map_single = true; | 923 | map_single = true; |
817 | wrb = queue_head_node(txq); | 924 | be_tx_setup_wrb_frag(txo, busaddr, len); |
818 | wrb_fill(wrb, busaddr, len); | ||
819 | queue_head_inc(txq); | ||
820 | copied += len; | 925 | copied += len; |
821 | } | 926 | } |
822 | 927 | ||
823 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 928 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
824 | const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; | 929 | const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; |
930 | len = skb_frag_size(frag); | ||
825 | 931 | ||
826 | busaddr = skb_frag_dma_map(dev, frag, 0, | 932 | busaddr = skb_frag_dma_map(dev, frag, 0, len, DMA_TO_DEVICE); |
827 | skb_frag_size(frag), DMA_TO_DEVICE); | ||
828 | if (dma_mapping_error(dev, busaddr)) | 933 | if (dma_mapping_error(dev, busaddr)) |
829 | goto dma_err; | 934 | goto dma_err; |
830 | wrb = queue_head_node(txq); | 935 | be_tx_setup_wrb_frag(txo, busaddr, len); |
831 | wrb_fill(wrb, busaddr, skb_frag_size(frag)); | 936 | copied += len; |
832 | queue_head_inc(txq); | ||
833 | copied += skb_frag_size(frag); | ||
834 | } | 937 | } |
835 | 938 | ||
836 | BUG_ON(txo->sent_skb_list[head]); | 939 | be_tx_setup_wrb_hdr(adapter, txo, wrb_params, skb, head); |
837 | txo->sent_skb_list[head] = skb; | ||
838 | txo->last_req_hdr = head; | ||
839 | atomic_add(wrb_cnt, &txq->used); | ||
840 | txo->last_req_wrb_cnt = wrb_cnt; | ||
841 | txo->pend_wrb_cnt += wrb_cnt; | ||
842 | 940 | ||
843 | be_tx_stats_update(txo, skb); | 941 | be_tx_stats_update(txo, skb); |
844 | return wrb_cnt; | 942 | return wrb_cnt; |
845 | 943 | ||
846 | dma_err: | 944 | dma_err: |
847 | /* Bring the queue back to the state it was in before this | 945 | adapter->drv_stats.dma_map_errors++; |
848 | * routine was invoked. | 946 | be_xmit_restore(adapter, txo, head, map_single, copied); |
849 | */ | ||
850 | txq->head = head; | ||
851 | /* skip the first wrb (hdr); it's not mapped */ | ||
852 | queue_head_inc(txq); | ||
853 | while (copied) { | ||
854 | wrb = queue_head_node(txq); | ||
855 | unmap_tx_frag(dev, wrb, map_single); | ||
856 | map_single = false; | ||
857 | copied -= le32_to_cpu(wrb->frag_len); | ||
858 | adapter->drv_stats.dma_map_errors++; | ||
859 | queue_head_inc(txq); | ||
860 | } | ||
861 | txq->head = head; | ||
862 | return 0; | 947 | return 0; |
863 | } | 948 | } |
864 | 949 | ||
@@ -869,7 +954,8 @@ static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) | |||
869 | 954 | ||
870 | static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, | 955 | static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, |
871 | struct sk_buff *skb, | 956 | struct sk_buff *skb, |
872 | bool *skip_hw_vlan) | 957 | struct be_wrb_params |
958 | *wrb_params) | ||
873 | { | 959 | { |
874 | u16 vlan_tag = 0; | 960 | u16 vlan_tag = 0; |
875 | 961 | ||
@@ -886,8 +972,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 | 972 | /* f/w workaround to set skip_hw_vlan = 1, informs the F/W to |
887 | * skip VLAN insertion | 973 | * skip VLAN insertion |
888 | */ | 974 | */ |
889 | if (skip_hw_vlan) | 975 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
890 | *skip_hw_vlan = true; | ||
891 | } | 976 | } |
892 | 977 | ||
893 | if (vlan_tag) { | 978 | if (vlan_tag) { |
@@ -905,8 +990,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, | |||
905 | vlan_tag); | 990 | vlan_tag); |
906 | if (unlikely(!skb)) | 991 | if (unlikely(!skb)) |
907 | return skb; | 992 | return skb; |
908 | if (skip_hw_vlan) | 993 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
909 | *skip_hw_vlan = true; | ||
910 | } | 994 | } |
911 | 995 | ||
912 | return skb; | 996 | return skb; |
@@ -946,7 +1030,8 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) | |||
946 | 1030 | ||
947 | static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | 1031 | static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, |
948 | struct sk_buff *skb, | 1032 | struct sk_buff *skb, |
949 | bool *skip_hw_vlan) | 1033 | struct be_wrb_params |
1034 | *wrb_params) | ||
950 | { | 1035 | { |
951 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; | 1036 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; |
952 | unsigned int eth_hdr_len; | 1037 | unsigned int eth_hdr_len; |
@@ -970,7 +1055,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
970 | */ | 1055 | */ |
971 | if (be_pvid_tagging_enabled(adapter) && | 1056 | if (be_pvid_tagging_enabled(adapter) && |
972 | veh->h_vlan_proto == htons(ETH_P_8021Q)) | 1057 | veh->h_vlan_proto == htons(ETH_P_8021Q)) |
973 | *skip_hw_vlan = true; | 1058 | BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1); |
974 | 1059 | ||
975 | /* HW has a bug wherein it will calculate CSUM for VLAN | 1060 | /* HW has a bug wherein it will calculate CSUM for VLAN |
976 | * pkts even though it is disabled. | 1061 | * pkts even though it is disabled. |
@@ -978,7 +1063,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
978 | */ | 1063 | */ |
979 | if (skb->ip_summed != CHECKSUM_PARTIAL && | 1064 | if (skb->ip_summed != CHECKSUM_PARTIAL && |
980 | skb_vlan_tag_present(skb)) { | 1065 | skb_vlan_tag_present(skb)) { |
981 | skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); | 1066 | skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params); |
982 | if (unlikely(!skb)) | 1067 | if (unlikely(!skb)) |
983 | goto err; | 1068 | goto err; |
984 | } | 1069 | } |
@@ -1000,7 +1085,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, | |||
1000 | */ | 1085 | */ |
1001 | if (be_ipv6_tx_stall_chk(adapter, skb) && | 1086 | if (be_ipv6_tx_stall_chk(adapter, skb) && |
1002 | be_vlan_tag_tx_chk(adapter, skb)) { | 1087 | be_vlan_tag_tx_chk(adapter, skb)) { |
1003 | skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); | 1088 | skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params); |
1004 | if (unlikely(!skb)) | 1089 | if (unlikely(!skb)) |
1005 | goto err; | 1090 | goto err; |
1006 | } | 1091 | } |
@@ -1014,7 +1099,7 @@ err: | |||
1014 | 1099 | ||
1015 | static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, | 1100 | static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, |
1016 | struct sk_buff *skb, | 1101 | struct sk_buff *skb, |
1017 | bool *skip_hw_vlan) | 1102 | struct be_wrb_params *wrb_params) |
1018 | { | 1103 | { |
1019 | /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or | 1104 | /* 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 | 1105 | * less may cause a transmit stall on that port. So the work-around is |
@@ -1026,7 +1111,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, | |||
1026 | } | 1111 | } |
1027 | 1112 | ||
1028 | if (BEx_chip(adapter) || lancer_chip(adapter)) { | 1113 | if (BEx_chip(adapter) || lancer_chip(adapter)) { |
1029 | skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan); | 1114 | skb = be_lancer_xmit_workarounds(adapter, skb, wrb_params); |
1030 | if (!skb) | 1115 | if (!skb) |
1031 | return NULL; | 1116 | return NULL; |
1032 | } | 1117 | } |
@@ -1060,24 +1145,26 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) | |||
1060 | 1145 | ||
1061 | static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) | 1146 | static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) |
1062 | { | 1147 | { |
1063 | bool skip_hw_vlan = false, flush = !skb->xmit_more; | ||
1064 | struct be_adapter *adapter = netdev_priv(netdev); | 1148 | struct be_adapter *adapter = netdev_priv(netdev); |
1065 | u16 q_idx = skb_get_queue_mapping(skb); | 1149 | u16 q_idx = skb_get_queue_mapping(skb); |
1066 | struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; | 1150 | struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; |
1067 | struct be_queue_info *txq = &txo->q; | 1151 | struct be_wrb_params wrb_params = { 0 }; |
1152 | bool flush = !skb->xmit_more; | ||
1068 | u16 wrb_cnt; | 1153 | u16 wrb_cnt; |
1069 | 1154 | ||
1070 | skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); | 1155 | skb = be_xmit_workarounds(adapter, skb, &wrb_params); |
1071 | if (unlikely(!skb)) | 1156 | if (unlikely(!skb)) |
1072 | goto drop; | 1157 | goto drop; |
1073 | 1158 | ||
1074 | wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan); | 1159 | be_get_wrb_params_from_skb(adapter, skb, &wrb_params); |
1160 | |||
1161 | wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params); | ||
1075 | if (unlikely(!wrb_cnt)) { | 1162 | if (unlikely(!wrb_cnt)) { |
1076 | dev_kfree_skb_any(skb); | 1163 | dev_kfree_skb_any(skb); |
1077 | goto drop; | 1164 | goto drop; |
1078 | } | 1165 | } |
1079 | 1166 | ||
1080 | if ((atomic_read(&txq->used) + BE_MAX_TX_FRAG_COUNT) >= txq->len) { | 1167 | if (be_is_txq_full(txo)) { |
1081 | netif_stop_subqueue(netdev, q_idx); | 1168 | netif_stop_subqueue(netdev, q_idx); |
1082 | tx_stats(txo)->tx_stops++; | 1169 | tx_stats(txo)->tx_stops++; |
1083 | } | 1170 | } |
@@ -1991,18 +2078,23 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp, u32 frags_needed) | |||
1991 | } | 2078 | } |
1992 | } | 2079 | } |
1993 | 2080 | ||
1994 | static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) | 2081 | static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo) |
1995 | { | 2082 | { |
1996 | struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); | 2083 | struct be_queue_info *tx_cq = &txo->cq; |
2084 | struct be_tx_compl_info *txcp = &txo->txcp; | ||
2085 | struct be_eth_tx_compl *compl = queue_tail_node(tx_cq); | ||
1997 | 2086 | ||
1998 | if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) | 2087 | if (compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) |
1999 | return NULL; | 2088 | return NULL; |
2000 | 2089 | ||
2090 | /* Ensure load ordering of valid bit dword and other dwords below */ | ||
2001 | rmb(); | 2091 | rmb(); |
2002 | be_dws_le_to_cpu(txcp, sizeof(*txcp)); | 2092 | be_dws_le_to_cpu(compl, sizeof(*compl)); |
2003 | 2093 | ||
2004 | txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0; | 2094 | txcp->status = GET_TX_COMPL_BITS(status, compl); |
2095 | txcp->end_index = GET_TX_COMPL_BITS(wrb_index, compl); | ||
2005 | 2096 | ||
2097 | compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0; | ||
2006 | queue_tail_inc(tx_cq); | 2098 | queue_tail_inc(tx_cq); |
2007 | return txcp; | 2099 | return txcp; |
2008 | } | 2100 | } |
@@ -2123,9 +2215,9 @@ static void be_tx_compl_clean(struct be_adapter *adapter) | |||
2123 | { | 2215 | { |
2124 | u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0; | 2216 | u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0; |
2125 | struct device *dev = &adapter->pdev->dev; | 2217 | struct device *dev = &adapter->pdev->dev; |
2126 | struct be_tx_obj *txo; | 2218 | struct be_tx_compl_info *txcp; |
2127 | struct be_queue_info *txq; | 2219 | struct be_queue_info *txq; |
2128 | struct be_eth_tx_compl *txcp; | 2220 | struct be_tx_obj *txo; |
2129 | int i, pending_txqs; | 2221 | int i, pending_txqs; |
2130 | 2222 | ||
2131 | /* Stop polling for compls when HW has been silent for 10ms */ | 2223 | /* Stop polling for compls when HW has been silent for 10ms */ |
@@ -2136,10 +2228,10 @@ static void be_tx_compl_clean(struct be_adapter *adapter) | |||
2136 | cmpl = 0; | 2228 | cmpl = 0; |
2137 | num_wrbs = 0; | 2229 | num_wrbs = 0; |
2138 | txq = &txo->q; | 2230 | txq = &txo->q; |
2139 | while ((txcp = be_tx_compl_get(&txo->cq))) { | 2231 | while ((txcp = be_tx_compl_get(txo))) { |
2140 | end_idx = GET_TX_COMPL_BITS(wrb_index, txcp); | 2232 | num_wrbs += |
2141 | num_wrbs += be_tx_compl_process(adapter, txo, | 2233 | be_tx_compl_process(adapter, txo, |
2142 | end_idx); | 2234 | txcp->end_index); |
2143 | cmpl++; | 2235 | cmpl++; |
2144 | } | 2236 | } |
2145 | if (cmpl) { | 2237 | if (cmpl) { |
@@ -2147,7 +2239,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) | |||
2147 | atomic_sub(num_wrbs, &txq->used); | 2239 | atomic_sub(num_wrbs, &txq->used); |
2148 | timeo = 0; | 2240 | timeo = 0; |
2149 | } | 2241 | } |
2150 | if (atomic_read(&txq->used) == txo->pend_wrb_cnt) | 2242 | if (!be_is_tx_compl_pending(txo)) |
2151 | pending_txqs--; | 2243 | pending_txqs--; |
2152 | } | 2244 | } |
2153 | 2245 | ||
@@ -2498,7 +2590,7 @@ loop_continue: | |||
2498 | return work_done; | 2590 | return work_done; |
2499 | } | 2591 | } |
2500 | 2592 | ||
2501 | static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status) | 2593 | static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status) |
2502 | { | 2594 | { |
2503 | switch (status) { | 2595 | switch (status) { |
2504 | case BE_TX_COMP_HDR_PARSE_ERR: | 2596 | case BE_TX_COMP_HDR_PARSE_ERR: |
@@ -2513,7 +2605,7 @@ static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status) | |||
2513 | } | 2605 | } |
2514 | } | 2606 | } |
2515 | 2607 | ||
2516 | static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status) | 2608 | static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status) |
2517 | { | 2609 | { |
2518 | switch (status) { | 2610 | switch (status) { |
2519 | case LANCER_TX_COMP_LSO_ERR: | 2611 | case LANCER_TX_COMP_LSO_ERR: |
@@ -2538,22 +2630,18 @@ static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status) | |||
2538 | static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, | 2630 | static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, |
2539 | int idx) | 2631 | int idx) |
2540 | { | 2632 | { |
2541 | struct be_eth_tx_compl *txcp; | ||
2542 | int num_wrbs = 0, work_done = 0; | 2633 | int num_wrbs = 0, work_done = 0; |
2543 | u32 compl_status; | 2634 | struct be_tx_compl_info *txcp; |
2544 | u16 last_idx; | ||
2545 | 2635 | ||
2546 | while ((txcp = be_tx_compl_get(&txo->cq))) { | 2636 | while ((txcp = be_tx_compl_get(txo))) { |
2547 | last_idx = GET_TX_COMPL_BITS(wrb_index, txcp); | 2637 | num_wrbs += be_tx_compl_process(adapter, txo, txcp->end_index); |
2548 | num_wrbs += be_tx_compl_process(adapter, txo, last_idx); | ||
2549 | work_done++; | 2638 | work_done++; |
2550 | 2639 | ||
2551 | compl_status = GET_TX_COMPL_BITS(status, txcp); | 2640 | if (txcp->status) { |
2552 | if (compl_status) { | ||
2553 | if (lancer_chip(adapter)) | 2641 | if (lancer_chip(adapter)) |
2554 | lancer_update_tx_err(txo, compl_status); | 2642 | lancer_update_tx_err(txo, txcp->status); |
2555 | else | 2643 | else |
2556 | be_update_tx_err(txo, compl_status); | 2644 | be_update_tx_err(txo, txcp->status); |
2557 | } | 2645 | } |
2558 | } | 2646 | } |
2559 | 2647 | ||
@@ -2564,7 +2652,7 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, | |||
2564 | /* As Tx wrbs have been freed up, wake up netdev queue | 2652 | /* As Tx wrbs have been freed up, wake up netdev queue |
2565 | * if it was stopped due to lack of tx wrbs. */ | 2653 | * if it was stopped due to lack of tx wrbs. */ |
2566 | if (__netif_subqueue_stopped(adapter->netdev, idx) && | 2654 | if (__netif_subqueue_stopped(adapter->netdev, idx) && |
2567 | atomic_read(&txo->q.used) < txo->q.len / 2) { | 2655 | be_can_txq_wake(txo)) { |
2568 | netif_wake_subqueue(adapter->netdev, idx); | 2656 | netif_wake_subqueue(adapter->netdev, idx); |
2569 | } | 2657 | } |
2570 | 2658 | ||