wifi: iwlwifi: mvm: Move TSO code to shared utility
authorDaniel Gabay <daniel.gabay@intel.com>
Thu, 2 Jan 2025 14:39:18 +0000 (16:39 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 Jan 2025 13:00:55 +0000 (14:00 +0100)
Move TSO segment logic from mvm to the iwlwifi level, as this code is
not opmode-dependent and can be shared with the mld driver.

Signed-off-by: Daniel Gabay <daniel.gabay@intel.com>
Link: https://patch.msgid.link/20250102163748.56efefb9566e.Ib7188572f18afb31840d193a348c17c9b292c7af@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/Makefile
drivers/net/wireless/intel/iwlwifi/iwl-utils.c [new file with mode: 0644]
drivers/net/wireless/intel/iwlwifi/iwl-utils.h [new file with mode: 0644]
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index a305268..19c4ce6 100644 (file)
@@ -5,6 +5,7 @@ iwlwifi-objs            += iwl-io.o
 iwlwifi-objs           += iwl-drv.o
 iwlwifi-objs           += iwl-debug.o
 iwlwifi-objs           += iwl-nvm-utils.o
+iwlwifi-objs           += iwl-utils.o
 iwlwifi-objs           += iwl-phy-db.o iwl-nvm-parse.o
 iwlwifi-objs           += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
 iwlwifi-objs           += pcie/ctxt-info.o pcie/ctxt-info-gen3.o
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
new file mode 100644 (file)
index 0000000..b14ec98
--- /dev/null
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2024 Intel Corporation
+ */
+#include <net/gso.h>
+#include <linux/ieee80211.h>
+#include <net/gso.h>
+#include <net/ip.h>
+
+#include "iwl-drv.h"
+#include "iwl-utils.h"
+
+#ifdef CONFIG_INET
+int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
+                      netdev_features_t netdev_flags,
+                      struct sk_buff_head *mpdus_skbs)
+{
+       struct sk_buff *tmp, *next;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       char cb[sizeof(skb->cb)];
+       u16 i = 0;
+       unsigned int tcp_payload_len;
+       unsigned int mss = skb_shinfo(skb)->gso_size;
+       bool ipv4 = (skb->protocol == htons(ETH_P_IP));
+       bool qos = ieee80211_is_data_qos(hdr->frame_control);
+       u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
+
+       skb_shinfo(skb)->gso_size = num_subframes * mss;
+       memcpy(cb, skb->cb, sizeof(cb));
+
+       next = skb_gso_segment(skb, netdev_flags);
+       skb_shinfo(skb)->gso_size = mss;
+       skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
+
+       if (IS_ERR(next) && PTR_ERR(next) == -ENOMEM)
+               return -ENOMEM;
+
+       if (WARN_ONCE(IS_ERR(next),
+                     "skb_gso_segment error: %d\n", (int)PTR_ERR(next)))
+               return PTR_ERR(next);
+
+       if (next)
+               consume_skb(skb);
+
+       skb_list_walk_safe(next, tmp, next) {
+               memcpy(tmp->cb, cb, sizeof(tmp->cb));
+               /*
+                * Compute the length of all the data added for the A-MSDU.
+                * This will be used to compute the length to write in the TX
+                * command. We have: SNAP + IP + TCP for n -1 subframes and
+                * ETH header for n subframes.
+                */
+               tcp_payload_len = skb_tail_pointer(tmp) -
+                       skb_transport_header(tmp) -
+                       tcp_hdrlen(tmp) + tmp->data_len;
+
+               if (ipv4)
+                       ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
+
+               if (tcp_payload_len > mss) {
+                       skb_shinfo(tmp)->gso_size = mss;
+                       skb_shinfo(tmp)->gso_type = ipv4 ? SKB_GSO_TCPV4 :
+                                                          SKB_GSO_TCPV6;
+               } else {
+                       if (qos) {
+                               u8 *qc;
+
+                               if (ipv4)
+                                       ip_send_check(ip_hdr(tmp));
+
+                               qc = ieee80211_get_qos_ctl((void *)tmp->data);
+                               *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+                       }
+                       skb_shinfo(tmp)->gso_size = 0;
+               }
+
+               skb_mark_not_on_list(tmp);
+               __skb_queue_tail(mpdus_skbs, tmp);
+               i++;
+       }
+
+       return 0;
+}
+IWL_EXPORT_SYMBOL(iwl_tx_tso_segment);
+#endif /* CONFIG_INET */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
new file mode 100644 (file)
index 0000000..e3dbe63
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2024 Intel Corporation
+ */
+#ifndef __iwl_utils_h__
+#define __iwl_utils_h__
+
+#ifdef CONFIG_INET
+/**
+ * iwl_tx_tso_segment - Segments a TSO packet into subframes for A-MSDU.
+ * @skb: buffer to segment.
+ * @num_subframes: number of subframes to create.
+ * @netdev_flags: netdev feature flags.
+ * @mpdus_skbs: list to hold the segmented subframes.
+ *
+ * This function segments a large TCP packet into subframes.
+ * subframes are added to the mpdus_skbs list
+ *
+ * Returns: 0 on success and negative value on failure.
+ */
+int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
+                      netdev_features_t netdev_flags,
+                      struct sk_buff_head *mpdus_skbs);
+#else
+static inline
+int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
+                      netdev_features_t netdev_flags,
+                      struct sk_buff_head *mpdus_skbs)
+{
+       WARN_ON(1);
+
+       return -1;
+}
+#endif /* CONFIG_INET */
+
+#endif /* __iwl_utils_h__ */
index f1a8f4a..b5f6bb9 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "iwl-trans.h"
 #include "iwl-nvm-utils.h"
+#include "iwl-utils.h"
 #include "mvm.h"
 #include "sta.h"
 #include "time-sync.h"
@@ -938,78 +939,6 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
 
 #ifdef CONFIG_INET
 
-static int
-iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
-                      netdev_features_t netdev_flags,
-                      struct sk_buff_head *mpdus_skb)
-{
-       struct sk_buff *tmp, *next;
-       struct ieee80211_hdr *hdr = (void *)skb->data;
-       char cb[sizeof(skb->cb)];
-       u16 i = 0;
-       unsigned int tcp_payload_len;
-       unsigned int mss = skb_shinfo(skb)->gso_size;
-       bool ipv4 = (skb->protocol == htons(ETH_P_IP));
-       bool qos = ieee80211_is_data_qos(hdr->frame_control);
-       u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
-
-       skb_shinfo(skb)->gso_size = num_subframes * mss;
-       memcpy(cb, skb->cb, sizeof(cb));
-
-       next = skb_gso_segment(skb, netdev_flags);
-       skb_shinfo(skb)->gso_size = mss;
-       skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
-
-       if (IS_ERR(next) && PTR_ERR(next) == -ENOMEM)
-               return -ENOMEM;
-
-       if (WARN_ONCE(IS_ERR(next),
-                     "skb_gso_segment error: %d\n", (int)PTR_ERR(next)))
-               return PTR_ERR(next);
-
-       if (next)
-               consume_skb(skb);
-
-       skb_list_walk_safe(next, tmp, next) {
-               memcpy(tmp->cb, cb, sizeof(tmp->cb));
-               /*
-                * Compute the length of all the data added for the A-MSDU.
-                * This will be used to compute the length to write in the TX
-                * command. We have: SNAP + IP + TCP for n -1 subframes and
-                * ETH header for n subframes.
-                */
-               tcp_payload_len = skb_tail_pointer(tmp) -
-                       skb_transport_header(tmp) -
-                       tcp_hdrlen(tmp) + tmp->data_len;
-
-               if (ipv4)
-                       ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
-
-               if (tcp_payload_len > mss) {
-                       skb_shinfo(tmp)->gso_size = mss;
-                       skb_shinfo(tmp)->gso_type = ipv4 ? SKB_GSO_TCPV4 :
-                                                          SKB_GSO_TCPV6;
-               } else {
-                       if (qos) {
-                               u8 *qc;
-
-                               if (ipv4)
-                                       ip_send_check(ip_hdr(tmp));
-
-                               qc = ieee80211_get_qos_ctl((void *)tmp->data);
-                               *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
-                       }
-                       skb_shinfo(tmp)->gso_size = 0;
-               }
-
-               skb_mark_not_on_list(tmp);
-               __skb_queue_tail(mpdus_skb, tmp);
-               i++;
-       }
-
-       return 0;
-}
-
 static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
                          struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
@@ -1028,7 +957,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
        if (!mvmsta->max_amsdu_len ||
            !ieee80211_is_data_qos(hdr->frame_control) ||
            !mvmsta->amsdu_enabled)
-               return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
+               return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
 
        /*
         * Do not build AMSDU for IPv6 with extension headers.
@@ -1038,7 +967,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
            ((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=
            IPPROTO_TCP) {
                netdev_flags &= ~NETIF_F_CSUM_MASK;
-               return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
+               return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
        }
 
        tid = ieee80211_get_tid(hdr);
@@ -1052,7 +981,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
        if ((info->flags & IEEE80211_TX_CTL_AMPDU &&
             !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) ||
            !(mvmsta->amsdu_enabled & BIT(tid)))
-               return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
+               return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
 
        /*
         * Take the min of ieee80211 station and mvm station
@@ -1110,8 +1039,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
         * Trick the segmentation function to make it
         * create SKBs that can fit into one A-MSDU.
         */
-       return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags,
-                                     mpdus_skb);
+       return iwl_tx_tso_segment(skb, num_subframes, netdev_flags, mpdus_skb);
 }
 #else /* CONFIG_INET */
 static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,