Skip to content

Commit 08f7d8b

Browse files
sara-slucacoelho
authored andcommitted
iwlwifi: mvm: bring back mvm GSO code
We have a slightly better TCP performance with GSO. Add it back, it can co-exist with the code that builds AMSDUs in mac80211. Signed-off-by: Sara Sharon <[email protected]> Signed-off-by: Luca Coelho <[email protected]>
1 parent d6f9c77 commit 08f7d8b

File tree

2 files changed

+223
-2
lines changed

2 files changed

+223
-2
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
754754
}
755755

756756
hw->netdev_features |= mvm->cfg->features;
757-
hw->netdev_features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
758757
if (!iwl_mvm_is_csum_supported(mvm)) {
759758
hw->netdev_features &= ~(IWL_TX_CSUM_NETIF_FLAGS |
760759
NETIF_F_RXCSUM);

drivers/net/wireless/intel/iwlwifi/mvm/tx.c

Lines changed: 223 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,197 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
808808
mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
809809
}
810810

811+
#ifdef CONFIG_INET
812+
813+
static int
814+
iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
815+
netdev_features_t netdev_flags,
816+
struct sk_buff_head *mpdus_skb)
817+
{
818+
struct sk_buff *tmp, *next;
819+
struct ieee80211_hdr *hdr = (void *)skb->data;
820+
char cb[sizeof(skb->cb)];
821+
u16 i = 0;
822+
unsigned int tcp_payload_len;
823+
unsigned int mss = skb_shinfo(skb)->gso_size;
824+
bool ipv4 = (skb->protocol == htons(ETH_P_IP));
825+
u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
826+
827+
skb_shinfo(skb)->gso_size = num_subframes * mss;
828+
memcpy(cb, skb->cb, sizeof(cb));
829+
830+
next = skb_gso_segment(skb, netdev_flags);
831+
skb_shinfo(skb)->gso_size = mss;
832+
if (WARN_ON_ONCE(IS_ERR(next)))
833+
return -EINVAL;
834+
else if (next)
835+
consume_skb(skb);
836+
837+
while (next) {
838+
tmp = next;
839+
next = tmp->next;
840+
841+
memcpy(tmp->cb, cb, sizeof(tmp->cb));
842+
/*
843+
* Compute the length of all the data added for the A-MSDU.
844+
* This will be used to compute the length to write in the TX
845+
* command. We have: SNAP + IP + TCP for n -1 subframes and
846+
* ETH header for n subframes.
847+
*/
848+
tcp_payload_len = skb_tail_pointer(tmp) -
849+
skb_transport_header(tmp) -
850+
tcp_hdrlen(tmp) + tmp->data_len;
851+
852+
if (ipv4)
853+
ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
854+
855+
if (tcp_payload_len > mss) {
856+
skb_shinfo(tmp)->gso_size = mss;
857+
} else {
858+
if (ieee80211_is_data_qos(hdr->frame_control)) {
859+
u8 *qc;
860+
861+
if (ipv4)
862+
ip_send_check(ip_hdr(tmp));
863+
864+
qc = ieee80211_get_qos_ctl((void *)tmp->data);
865+
*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
866+
}
867+
skb_shinfo(tmp)->gso_size = 0;
868+
}
869+
870+
tmp->prev = NULL;
871+
tmp->next = NULL;
872+
873+
__skb_queue_tail(mpdus_skb, tmp);
874+
i++;
875+
}
876+
877+
return 0;
878+
}
879+
880+
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
881+
struct ieee80211_tx_info *info,
882+
struct ieee80211_sta *sta,
883+
struct sk_buff_head *mpdus_skb)
884+
{
885+
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
886+
struct ieee80211_hdr *hdr = (void *)skb->data;
887+
unsigned int mss = skb_shinfo(skb)->gso_size;
888+
unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
889+
u16 snap_ip_tcp, pad;
890+
unsigned int dbg_max_amsdu_len;
891+
netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
892+
u8 tid;
893+
894+
snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
895+
tcp_hdrlen(skb);
896+
897+
dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len);
898+
899+
if (!mvmsta->max_amsdu_len ||
900+
!ieee80211_is_data_qos(hdr->frame_control) ||
901+
(!mvmsta->amsdu_enabled && !dbg_max_amsdu_len))
902+
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
903+
904+
/*
905+
* Do not build AMSDU for IPv6 with extension headers.
906+
* ask stack to segment and checkum the generated MPDUs for us.
907+
*/
908+
if (skb->protocol == htons(ETH_P_IPV6) &&
909+
((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=
910+
IPPROTO_TCP) {
911+
netdev_flags &= ~NETIF_F_CSUM_MASK;
912+
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
913+
}
914+
915+
tid = ieee80211_get_tid(hdr);
916+
if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
917+
return -EINVAL;
918+
919+
/*
920+
* No need to lock amsdu_in_ampdu_allowed since it can't be modified
921+
* during an BA session.
922+
*/
923+
if (info->flags & IEEE80211_TX_CTL_AMPDU &&
924+
!mvmsta->tid_data[tid].amsdu_in_ampdu_allowed)
925+
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
926+
927+
if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(mvmsta->vif)) ||
928+
!(mvmsta->amsdu_enabled & BIT(tid)))
929+
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
930+
931+
max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid);
932+
933+
if (unlikely(dbg_max_amsdu_len))
934+
max_amsdu_len = min_t(unsigned int, max_amsdu_len,
935+
dbg_max_amsdu_len);
936+
937+
/*
938+
* Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
939+
* supported. This is a spec requirement (IEEE 802.11-2015
940+
* section 8.7.3 NOTE 3).
941+
*/
942+
if (info->flags & IEEE80211_TX_CTL_AMPDU &&
943+
!sta->vht_cap.vht_supported)
944+
max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095);
945+
946+
/* Sub frame header + SNAP + IP header + TCP header + MSS */
947+
subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss;
948+
pad = (4 - subf_len) & 0x3;
949+
950+
/*
951+
* If we have N subframes in the A-MSDU, then the A-MSDU's size is
952+
* N * subf_len + (N - 1) * pad.
953+
*/
954+
num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
955+
956+
if (sta->max_amsdu_subframes &&
957+
num_subframes > sta->max_amsdu_subframes)
958+
num_subframes = sta->max_amsdu_subframes;
959+
960+
tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
961+
tcp_hdrlen(skb) + skb->data_len;
962+
963+
/*
964+
* Make sure we have enough TBs for the A-MSDU:
965+
* 2 for each subframe
966+
* 1 more for each fragment
967+
* 1 more for the potential data in the header
968+
*/
969+
if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) >
970+
mvm->trans->max_skb_frags)
971+
num_subframes = 1;
972+
973+
if (num_subframes > 1)
974+
*ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
975+
976+
/* This skb fits in one single A-MSDU */
977+
if (num_subframes * mss >= tcp_payload_len) {
978+
__skb_queue_tail(mpdus_skb, skb);
979+
return 0;
980+
}
981+
982+
/*
983+
* Trick the segmentation function to make it
984+
* create SKBs that can fit into one A-MSDU.
985+
*/
986+
return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags,
987+
mpdus_skb);
988+
}
989+
#else /* CONFIG_INET */
990+
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
991+
struct ieee80211_tx_info *info,
992+
struct ieee80211_sta *sta,
993+
struct sk_buff_head *mpdus_skb)
994+
{
995+
/* Impossible to get TSO with CONFIG_INET */
996+
WARN_ON(1);
997+
998+
return -1;
999+
}
1000+
#endif
1001+
8111002
/* Check if there are any timed-out TIDs on a given shared TXQ */
8121003
static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id)
8131004
{
@@ -986,6 +1177,9 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
9861177
{
9871178
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
9881179
struct ieee80211_tx_info info;
1180+
struct sk_buff_head mpdus_skbs;
1181+
unsigned int payload_len;
1182+
int ret;
9891183

9901184
if (WARN_ON_ONCE(!mvmsta))
9911185
return -1;
@@ -995,7 +1189,35 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
9951189

9961190
memcpy(&info, skb->cb, sizeof(info));
9971191

998-
return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
1192+
if (!skb_is_gso(skb))
1193+
return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
1194+
1195+
payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
1196+
tcp_hdrlen(skb) + skb->data_len;
1197+
1198+
if (payload_len <= skb_shinfo(skb)->gso_size)
1199+
return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
1200+
1201+
__skb_queue_head_init(&mpdus_skbs);
1202+
1203+
ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs);
1204+
if (ret)
1205+
return ret;
1206+
1207+
if (WARN_ON(skb_queue_empty(&mpdus_skbs)))
1208+
return ret;
1209+
1210+
while (!skb_queue_empty(&mpdus_skbs)) {
1211+
skb = __skb_dequeue(&mpdus_skbs);
1212+
1213+
ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
1214+
if (ret) {
1215+
__skb_queue_purge(&mpdus_skbs);
1216+
return ret;
1217+
}
1218+
}
1219+
1220+
return 0;
9991221
}
10001222

10011223
static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,

0 commit comments

Comments
 (0)