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;