qcacld-3.0: TSO (TCP Segmentation Offload) Clean-up
propagation from qcacld-3.0 to qcacld-3.1
Changes for TSO clean-up to address:
- conditional compile within function bodies
- change function return value
- convert macro to static inline function, etc
- Enable TSO for SAP mode
Change-Id: I29e764f64f7866d4c016ac31cd701c54526cc75d
CRs-Fixed: 881090
diff --git a/config/WCNSS_qcom_cfg.ini b/config/WCNSS_qcom_cfg.ini
index 0890d6a..a4184f5 100644
--- a/config/WCNSS_qcom_cfg.ini
+++ b/config/WCNSS_qcom_cfg.ini
@@ -588,6 +588,11 @@
# 1 - enable
gEnableFastPath=1
+# Enable TCP Segmentation Offload
+# 0 - disable
+# 1 - enable
+TSOEnable=1
+
END
# Note: Configuration parser would not read anything past the END marker
diff --git a/core/cdf/inc/cdf_nbuf.h b/core/cdf/inc/cdf_nbuf.h
index ba16cdd..61d535d 100644
--- a/core/cdf/inc/cdf_nbuf.h
+++ b/core/cdf/inc/cdf_nbuf.h
@@ -940,9 +940,9 @@
* cdf_nbuf_is_tso() - is the network buffer a jumbo packet?
* @buf: Network buffer
*
- * Return: 1 - this is a jumbo packet 0 - not a jumbo packet
+ * Return: true - jumbo packet false - not a jumbo packet
*/
-static inline uint8_t cdf_nbuf_is_tso(cdf_nbuf_t nbuf)
+static inline bool cdf_nbuf_is_tso(cdf_nbuf_t nbuf)
{
return __cdf_nbuf_is_tso(nbuf);
}
@@ -992,9 +992,9 @@
*
* Return: the network buffer
*/
-static inline cdf_nbuf_t cdf_nbuf_inc_users(cdf_nbuf_t nbuf)
+static inline void cdf_nbuf_inc_users(cdf_nbuf_t nbuf)
{
- return __cdf_nbuf_inc_users(nbuf);
+ __cdf_nbuf_inc_users(nbuf);
}
#endif /*TSO*/
diff --git a/core/cdf/src/cdf_nbuf.c b/core/cdf/src/cdf_nbuf.c
index 382ff2b..005d6e7 100644
--- a/core/cdf/src/cdf_nbuf.c
+++ b/core/cdf/src/cdf_nbuf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -35,6 +35,11 @@
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/module.h>
+#if defined(FEATURE_TSO)
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#endif /* FEATURE_TSO */
#include <cdf_types.h>
#include <cdf_nbuf.h>
#include <cdf_memory.h>
@@ -42,14 +47,6 @@
#include <cdf_status.h>
#include <cdf_lock.h>
-#if defined(FEATURE_TSO)
-#include <net/ipv6.h>
-#include <linux/ipv6.h>
-#include <linux/tcp.h>
-#include <linux/if_vlan.h>
-#include <linux/ip.h>
-#endif /* FEATURE_TSO */
-
/* Packet Counter */
static uint32_t nbuf_tx_mgmt[NBUF_TX_PKT_STATE_MAX];
static uint32_t nbuf_tx_data[NBUF_TX_PKT_STATE_MAX];
@@ -837,7 +834,7 @@
curr_seg = tso_info->tso_seg_list;
/* length of the first chunk of data in the skb */
- skb_proc = skb_frag_len = skb->len - skb->data_len;
+ skb_proc = skb_frag_len = skb_headlen(skb);
/* the 0th tso segment's 0th fragment always contains the EIT header */
/* update the remaining skb fragment length and TSO segment length */
@@ -1008,10 +1005,4 @@
return num_segs;
}
-struct sk_buff *__cdf_nbuf_inc_users(struct sk_buff *skb)
-{
- atomic_inc(&skb->users);
- return skb;
-}
-
#endif /* FEATURE_TSO */
diff --git a/core/cdf/src/i_cdf_nbuf.h b/core/cdf/src/i_cdf_nbuf.h
index c174435..a78fb1e 100644
--- a/core/cdf/src/i_cdf_nbuf.h
+++ b/core/cdf/src/i_cdf_nbuf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -1008,12 +1008,16 @@
uint32_t __cdf_nbuf_get_tso_num_seg(struct sk_buff *skb);
-static inline uint8_t __cdf_nbuf_is_tso(struct sk_buff *skb)
+static inline bool __cdf_nbuf_is_tso(struct sk_buff *skb)
{
return skb_is_gso(skb);
}
-struct sk_buff *__cdf_nbuf_inc_users(struct sk_buff *skb);
+static inline void __cdf_nbuf_inc_users(struct sk_buff *skb)
+{
+ atomic_inc(&skb->users);
+ return;
+}
#endif /* TSO */
/**
diff --git a/core/dp/htt/htt_tx.c b/core/dp/htt/htt_tx.c
index 1aa28f9..83551b7 100644
--- a/core/dp/htt/htt_tx.c
+++ b/core/dp/htt/htt_tx.c
@@ -1159,8 +1159,6 @@
if (tso_seg->seg.num_frags < FRAG_NUM_MAX) {
*word = 0;
- word++;
- *word = 0;
}
}
#endif /* FEATURE_TSO */
diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h
index b30f722..26fecb3 100644
--- a/core/dp/htt/htt_types.h
+++ b/core/dp/htt/htt_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -175,16 +175,7 @@
#if defined(HELIUMPLUS_PADDR64)
struct msdu_ext_desc_t {
-#if defined(FEATURE_TSO)
struct cdf_tso_flags_t tso_flags;
-#else
- u_int32_t tso_flag0;
- u_int32_t tso_flag1;
- u_int32_t tso_flag2;
- u_int32_t tso_flag3;
- u_int32_t tso_flag4;
- u_int32_t tso_flag5;
-#endif
u_int32_t frag_ptr0;
u_int32_t frag_len0;
u_int32_t frag_ptr1;
diff --git a/core/dp/ol/inc/ol_htt_tx_api.h b/core/dp/ol/inc/ol_htt_tx_api.h
index baacfdb..cd9ac7d 100644
--- a/core/dp/ol/inc/ol_htt_tx_api.h
+++ b/core/dp/ol/inc/ol_htt_tx_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -608,11 +608,9 @@
local_word1 = 0;
-#if defined(FEATURE_TSO)
if (tso_info->is_tso)
HTT_TX_DESC_FRM_LEN_SET(local_word1, tso_info->total_len);
else
-#endif
HTT_TX_DESC_FRM_LEN_SET(local_word1, cdf_nbuf_len(msdu));
HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id);
diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c
index f63ee4d..0cff3cf 100644
--- a/core/dp/txrx/ol_tx.c
+++ b/core/dp/txrx/ol_tx.c
@@ -80,36 +80,59 @@
} \
} while (0)
-#define ol_tx_prepare_tso(vdev, msdu, msdu_info) \
- do { \
- msdu_info.tso_info.curr_seg = NULL; \
- if (cdf_nbuf_is_tso(msdu)) { \
- int num_seg = cdf_nbuf_get_tso_num_seg(msdu); \
- msdu_info.tso_info.tso_seg_list = NULL; \
- msdu_info.tso_info.num_segs = num_seg; \
- while (num_seg) { \
- struct cdf_tso_seg_elem_t *tso_seg = \
- ol_tso_alloc_segment(vdev->pdev); \
- if (tso_seg) { \
- tso_seg->next = \
- msdu_info.tso_info.tso_seg_list; \
- msdu_info.tso_info.tso_seg_list \
- = tso_seg; \
- num_seg--; \
- } else {\
- cdf_print("TSO seg alloc failed!\n"); \
- } \
- } \
- cdf_nbuf_get_tso_info(vdev->pdev->osdev, \
- msdu, &msdu_info.tso_info); \
- msdu_info.tso_info.curr_seg = \
- msdu_info.tso_info.tso_seg_list; \
- num_seg = msdu_info.tso_info.num_segs; \
- } else { \
- msdu_info.tso_info.is_tso = 0; \
- msdu_info.tso_info.num_segs = 1; \
- } \
- } while (0)
+#if defined(FEATURE_TSO)
+/**
+ * ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO
+ * related information in the msdu_info meta data
+ * @vdev: virtual device handle
+ * @msdu: network buffer
+ * @msdu_info: meta data associated with the msdu
+ *
+ * Return: 0 - success, >0 - error
+ */
+static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
+ cdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info)
+{
+ msdu_info->tso_info.curr_seg = NULL;
+ if (cdf_nbuf_is_tso(msdu)) {
+ int num_seg = cdf_nbuf_get_tso_num_seg(msdu);
+ msdu_info->tso_info.tso_seg_list = NULL;
+ msdu_info->tso_info.num_segs = num_seg;
+ while (num_seg) {
+ struct cdf_tso_seg_elem_t *tso_seg =
+ ol_tso_alloc_segment(vdev->pdev);
+ if (tso_seg) {
+ tso_seg->next =
+ msdu_info->tso_info.tso_seg_list;
+ msdu_info->tso_info.tso_seg_list
+ = tso_seg;
+ num_seg--;
+ } else {
+ struct cdf_tso_seg_elem_t *next_seg;
+ struct cdf_tso_seg_elem_t *free_seg =
+ msdu_info->tso_info.tso_seg_list;
+ cdf_print("TSO seg alloc failed!\n");
+ while (free_seg) {
+ next_seg = free_seg->next;
+ ol_tso_free_segment(vdev->pdev,
+ free_seg);
+ free_seg = next_seg;
+ }
+ return 1;
+ }
+ }
+ cdf_nbuf_get_tso_info(vdev->pdev->osdev,
+ msdu, &(msdu_info->tso_info));
+ msdu_info->tso_info.curr_seg =
+ msdu_info->tso_info.tso_seg_list;
+ num_seg = msdu_info->tso_info.num_segs;
+ } else {
+ msdu_info->tso_info.is_tso = 0;
+ msdu_info->tso_info.num_segs = 1;
+ }
+ return 0;
+}
+#endif
/**
* ol_tx_send_data_frame() - send data frame
@@ -246,7 +269,13 @@
msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu);
msdu_info.peer = NULL;
- ol_tx_prepare_tso(vdev, msdu, msdu_info);
+ if (cdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) {
+ cdf_print("ol_tx_prepare_tso failed\n");
+ TXRX_STATS_MSDU_LIST_INCR(vdev->pdev,
+ tx.dropped.host_reject, msdu);
+ return msdu;
+ }
+
segments = msdu_info.tso_info.num_segs;
/*
@@ -508,7 +537,13 @@
msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu);
msdu_info.peer = NULL;
- ol_tx_prepare_tso(vdev, msdu, msdu_info);
+ if (cdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) {
+ cdf_print("ol_tx_prepare_tso failed\n");
+ TXRX_STATS_MSDU_LIST_INCR(vdev->pdev,
+ tx.dropped.host_reject, msdu);
+ return msdu;
+ }
+
segments = msdu_info.tso_info.num_segs;
/*
diff --git a/core/dp/txrx/ol_tx.h b/core/dp/txrx/ol_tx.h
index 77ae56d..e60d883 100644
--- a/core/dp/txrx/ol_tx.h
+++ b/core/dp/txrx/ol_tx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -89,4 +89,5 @@
return;
}
#endif
+
#endif /* _OL_TX__H_ */
diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c
index 591b660..9ea20bb 100644
--- a/core/dp/txrx/ol_tx_desc.c
+++ b/core/dp/txrx/ol_tx_desc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -230,15 +230,16 @@
void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
{
cdf_spin_lock_bh(&pdev->tx_mutex);
-#if defined(FEATURE_TSO)
+
if (tx_desc->pkt_type == ol_tx_frm_tso) {
- if (cdf_unlikely(tx_desc->tso_desc == NULL))
+ if (cdf_unlikely(tx_desc->tso_desc == NULL)) {
cdf_print("%s %d TSO desc is NULL!\n",
__func__, __LINE__);
- else
+ cdf_assert(0);
+ } else {
ol_tso_free_segment(pdev, tx_desc->tso_desc);
+ }
}
-#endif
ol_tx_desc_reset_pkt_type(tx_desc);
ol_tx_desc_reset_timestamp(tx_desc);
diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h
index c96c47a..fa154f8 100644
--- a/core/dp/txrx/ol_tx_desc.h
+++ b/core/dp/txrx/ol_tx_desc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -163,6 +163,9 @@
void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
struct cdf_tso_seg_elem_t *tso_seg);
+#else
+#define ol_tso_alloc_segment(pdev) /*no-op*/
+#define ol_tso_free_segment(pdev, tso_seg) /*no-op*/
#endif
/**
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index be7623e..e421684 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -916,7 +916,9 @@
/* Thermal Mitigation */
ol_tx_throttle_init(pdev);
+
ol_tso_seg_list_init(pdev, desc_pool_size);
+
ol_tx_register_flow_control(pdev);
htt_pkt_log_init(pdev, osc);
@@ -2405,6 +2407,12 @@
}
}
}
+#else
+void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev)
+{
+ CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
+ "TSO is not supported\n");
+}
#endif
/**
@@ -2927,12 +2935,7 @@
ol_txrx_stats_display(pdev);
break;
case WLAN_TXRX_TSO_STATS:
-#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG)
ol_txrx_stats_display_tso(pdev);
-#else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: TSO not supported", __func__);
-#endif
break;
case WLAN_DUMP_TX_FLOW_POOL_INFO:
ol_tx_dump_flow_pool_info();
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 30c514a..6eca669 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1526,4 +1526,30 @@
uint8_t wlan_hdd_find_opclass(tHalHandle hal, uint8_t channel,
uint8_t bw_offset);
void hdd_update_config(hdd_context_t *hdd_ctx);
+
+#ifdef FEATURE_TSO
+/**
+ * hdd_set_tso_flags() - enable TSO flags in the network device
+ * @hdd_ctx: HDD context
+ * @wlan_dev: network device structure
+ *
+ * This function enables the TSO related feature flags in the
+ * given network device.
+ *
+ * Return: none
+ */
+static inline void hdd_set_tso_flags(hdd_context_t *hdd_ctx,
+ struct net_device *wlan_dev)
+{
+ if (hdd_ctx->config->tso_enable) {
+ hdd_info("TSO Enabled");
+ wlan_dev->features |=
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG;
+ }
+}
+#else
+static inline void hdd_set_tso_flags(hdd_context_t *hdd_ctx,
+ struct net_device *wlan_dev){}
+#endif /* FEATURE_TSO */
#endif /* end #if !defined(WLAN_HDD_MAIN_H) */
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 97a3142..0a568e5 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -6167,6 +6167,7 @@
pWlanHostapdDev->ieee80211_ptr = &pHostapdAdapter->wdev;
pHostapdAdapter->wdev.wiphy = pHddCtx->wiphy;
pHostapdAdapter->wdev.netdev = pWlanHostapdDev;
+ hdd_set_tso_flags(pHddCtx, pWlanHostapdDev);
init_completion(&pHostapdAdapter->tx_action_cnf_event);
init_completion(&pHostapdAdapter->cancel_rem_on_chan_var);
init_completion(&pHostapdAdapter->rem_on_chan_ready_event);
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 8a292a3..854ea7e 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -1913,14 +1913,8 @@
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
pWlanDev->features |= NETIF_F_RXCSUM;
-#if defined(FEATURE_TSO)
- if (hdd_ctx->config->tso_enable) {
- hddLog(CDF_TRACE_LEVEL_INFO, FL("TSO Enabled\n"));
- pWlanDev->features |=
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG;
- }
-#endif
+ hdd_set_tso_flags(hdd_ctx, pWlanDev);
+
hdd_set_station_ops(adapter->dev);
pWlanDev->destructor = free_netdev;