iwlwifi: mvm: prepare the code towards TSO implementation
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 14 Oct 2015 11:16:35 +0000 (14:16 +0300)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 20 Dec 2015 12:48:23 +0000 (14:48 +0200)
Differentiate between the cases where the skb is a large
send and the other cases.
Advertise TSO even if, at this stage, skb_gso_segment will
be called and it will do all the work.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index 0227b29d43c8fca2db0452791fc17c85c89c44d4..d239e97ab98a766f90f4bd95d2cea8d1582cd916 100644 (file)
@@ -668,7 +668,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->netdev_features &= ~NETIF_F_RXCSUM;
 
        if (IWL_MVM_SW_TX_CSUM_OFFLOAD)
-               hw->netdev_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+               hw->netdev_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                       NETIF_F_TSO | NETIF_F_TSO6;
 
        ret = ieee80211_register_hw(mvm->hw);
        if (ret)
index 4d13df1b843bb4f5bb79db67aa7992969252cad1..04e921fcc0fbd7f9bb6f4adf2a648522ff0c2f34 100644 (file)
@@ -64,6 +64,7 @@
  *****************************************************************************/
 #include <linux/ieee80211.h>
 #include <linux/etherdevice.h>
+#include <linux/tcp.h>
 
 #include "iwl-trans.h"
 #include "iwl-eeprom-parse.h"
@@ -425,11 +426,39 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
        return 0;
 }
 
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb_gso,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff_head *mpdus_skb)
+{
+       struct sk_buff *tmp, *next;
+       char cb[sizeof(skb_gso->cb)];
+
+       memcpy(cb, skb_gso->cb, sizeof(cb));
+       next = skb_gso_segment(skb_gso, 0);
+       if (IS_ERR(next))
+               return -EINVAL;
+       else if (next)
+               consume_skb(skb_gso);
+
+       while (next) {
+               tmp = next;
+               next = tmp->next;
+               memcpy(tmp->cb, cb, sizeof(tmp->cb));
+
+               tmp->prev = NULL;
+               tmp->next = NULL;
+
+               __skb_queue_tail(mpdus_skb, tmp);
+       }
+
+       return 0;
+}
+
 /*
  * Sets the fields in the Tx cmd that are crypto related
  */
-int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
-                  struct ieee80211_sta *sta)
+static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+                          struct ieee80211_sta *sta)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -525,6 +554,51 @@ drop:
        return -1;
 }
 
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+                  struct ieee80211_sta *sta)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct sk_buff_head mpdus_skbs;
+       unsigned int payload_len;
+       int ret;
+
+       if (WARN_ON_ONCE(!mvmsta))
+               return -1;
+
+       if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
+               return -1;
+
+       if (!skb_is_gso(skb))
+               return iwl_mvm_tx_mpdu(mvm, skb, sta);
+
+       payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
+               tcp_hdrlen(skb) + skb->data_len;
+
+       if (payload_len <= skb_shinfo(skb)->gso_size)
+               return iwl_mvm_tx_mpdu(mvm, skb, sta);
+
+       __skb_queue_head_init(&mpdus_skbs);
+
+       ret = iwl_mvm_tx_tso(mvm, skb, sta, &mpdus_skbs);
+       if (ret)
+               return ret;
+
+       if (WARN_ON(skb_queue_empty(&mpdus_skbs)))
+               return ret;
+
+       while (!skb_queue_empty(&mpdus_skbs)) {
+               struct sk_buff *skb = __skb_dequeue(&mpdus_skbs);
+
+               ret = iwl_mvm_tx_mpdu(mvm, skb, sta);
+               if (ret) {
+                       __skb_queue_purge(&mpdus_skbs);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
                                      struct ieee80211_sta *sta, u8 tid)
 {