summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/dp/txrx/ol_tx.c105
-rw-r--r--core/dp/txrx/ol_tx.h11
-rw-r--r--core/dp/txrx/ol_tx_desc.c130
-rw-r--r--core/dp/txrx/ol_tx_desc.h10
-rw-r--r--core/dp/txrx/ol_txrx.c3
-rw-r--r--core/dp/txrx/ol_txrx_types.h10
6 files changed, 237 insertions, 32 deletions
diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c
index 3edea3cb49ab..e7d1743db9c6 100644
--- a/core/dp/txrx/ol_tx.c
+++ b/core/dp/txrx/ol_tx.c
@@ -98,6 +98,9 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
msdu_info->tso_info.curr_seg = NULL;
if (qdf_nbuf_is_tso(msdu)) {
int num_seg = qdf_nbuf_get_tso_num_seg(msdu);
+ struct qdf_tso_num_seg_elem_t *tso_num_seg;
+
+ msdu_info->tso_info.tso_num_seg_list = NULL;
msdu_info->tso_info.tso_seg_list = NULL;
msdu_info->tso_info.num_segs = num_seg;
while (num_seg) {
@@ -123,6 +126,25 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
return 1;
}
}
+ tso_num_seg = ol_tso_num_seg_alloc(vdev->pdev);
+ if (tso_num_seg) {
+ tso_num_seg->next = msdu_info->tso_info.
+ tso_num_seg_list;
+ msdu_info->tso_info.tso_num_seg_list = tso_num_seg;
+ } else {
+ /* Free the already allocated num of segments */
+ struct qdf_tso_seg_elem_t *next_seg;
+ struct qdf_tso_seg_elem_t *free_seg =
+ msdu_info->tso_info.tso_seg_list;
+ qdf_print("TSO num of seg alloc for one jumbo skb failed!\n");
+ while (free_seg) {
+ next_seg = free_seg->next;
+ ol_tso_free_segment(vdev->pdev,
+ free_seg);
+ free_seg = next_seg;
+ }
+ return 1;
+ }
qdf_nbuf_get_tso_info(vdev->pdev->osdev,
msdu, &(msdu_info->tso_info));
msdu_info->tso_info.curr_seg =
@@ -394,6 +416,7 @@ ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev,
tx_desc->netbuf = msdu;
if (msdu_info->tso_info.is_tso) {
tx_desc->tso_desc = msdu_info->tso_info.curr_seg;
+ tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list;
tx_desc->pkt_type = OL_TX_FRM_TSO;
TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu);
} else {
@@ -1917,6 +1940,13 @@ qdf_nbuf_t ol_tx_reinject(struct ol_txrx_vdev_t *vdev,
}
#if defined(FEATURE_TSO)
+/**
+ * ol_tso_seg_list_init() - function to initialise the tso seg freelist
+ * @pdev: the data physical device sending the data
+ * @num_seg: number of segments needs to be intialised
+ *
+ * Return: none
+ */
void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg)
{
int i;
@@ -1948,6 +1978,12 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg)
qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex);
}
+/**
+ * ol_tso_seg_list_deinit() - function to de-initialise the tso seg freelist
+ * @pdev: the data physical device sending the data
+ *
+ * Return: none
+ */
void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
{
int i;
@@ -1982,4 +2018,73 @@ void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
c_element = temp;
}
}
+
+/**
+ * ol_tso_num_seg_list_init() - function to initialise the freelist of elements
+ * use to count the num of tso segments in jumbo
+ * skb packet freelist
+ * @pdev: the data physical device sending the data
+ * @num_seg: number of elements needs to be intialised
+ *
+ * Return: none
+ */
+void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg)
+{
+ int i;
+ struct qdf_tso_num_seg_elem_t *c_element;
+
+ c_element = qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t));
+ pdev->tso_num_seg_pool.freelist = c_element;
+ for (i = 0; i < (num_seg - 1); i++) {
+ if (qdf_unlikely(!c_element)) {
+ TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+ "%s: ERROR: c_element NULL for num of seg %d",
+ __func__, i);
+ QDF_BUG(0);
+ pdev->tso_num_seg_pool.num_seg_pool_size = i;
+ qdf_spinlock_create(&pdev->tso_num_seg_pool.
+ tso_num_seg_mutex);
+ return;
+ }
+
+ c_element->next =
+ qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t));
+ c_element = c_element->next;
+ c_element->next = NULL;
+ }
+ pdev->tso_num_seg_pool.num_seg_pool_size = num_seg;
+ qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+}
+
+/**
+ * ol_tso_num_seg_list_deinit() - function to de-initialise the freelist of
+ * elements use to count the num of tso segment
+ * in a jumbo skb packet freelist
+ * @pdev: the data physical device sending the data
+ *
+ * Return: none
+ */
+void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
+{
+ int i;
+ struct qdf_tso_num_seg_elem_t *c_element;
+ struct qdf_tso_num_seg_elem_t *temp;
+
+ qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+ c_element = pdev->tso_num_seg_pool.freelist;
+ i = pdev->tso_num_seg_pool.num_seg_pool_size;
+
+ pdev->tso_num_seg_pool.freelist = NULL;
+ pdev->tso_num_seg_pool.num_free = 0;
+ pdev->tso_num_seg_pool.num_seg_pool_size = 0;
+
+ qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+ qdf_spinlock_destroy(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+
+ while (i-- > 0 && c_element) {
+ temp = c_element->next;
+ qdf_mem_free(c_element);
+ c_element = temp;
+ }
+}
#endif /* FEATURE_TSO */
diff --git a/core/dp/txrx/ol_tx.h b/core/dp/txrx/ol_tx.h
index 5cb97e825d13..06b26edf8d30 100644
--- a/core/dp/txrx/ol_tx.h
+++ b/core/dp/txrx/ol_tx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -109,6 +109,8 @@ void ol_txrx_mgmt_tx_complete(void *ctxt, qdf_nbuf_t netbuf, int err);
#if defined(FEATURE_TSO)
void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg);
void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev);
+void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg);
+void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev);
#else
static inline void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev,
uint32_t num_seg)
@@ -119,6 +121,13 @@ static inline void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
{
return;
}
+static inline void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev,
+ uint32_t num_seg)
+{
+}
+static inline void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
+{
+}
#endif
#if defined(HELIUMPLUS_PADDR64)
diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c
index b354be2eac7a..a0f2ddc5fb5f 100644
--- a/core/dp/txrx/ol_tx_desc.c
+++ b/core/dp/txrx/ol_tx_desc.c
@@ -302,6 +302,48 @@ ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc)
}
#endif
+#ifdef FEATURE_TSO
+static void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev,
+ struct ol_tx_desc_t *tx_desc)
+{
+ if (qdf_unlikely(tx_desc->tso_desc == NULL)) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s %d TSO desc is NULL!",
+ __func__, __LINE__);
+ qdf_assert(0);
+ } else if (qdf_unlikely(tx_desc->tso_num_desc == NULL)) {
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "%s %d TSO common info is NULL!",
+ __func__, __LINE__);
+ qdf_assert(0);
+ } else {
+ struct qdf_tso_num_seg_elem_t *tso_num_desc =
+ (struct qdf_tso_num_seg_elem_t *)tx_desc->tso_num_desc;
+ if (tso_num_desc->num_seg.tso_cmn_num_seg > 1) {
+ tso_num_desc->num_seg.tso_cmn_num_seg--;
+ qdf_nbuf_unmap_tso_segment(pdev->osdev,
+ tx_desc->tso_desc, false);
+ } else {
+ tso_num_desc->num_seg.tso_cmn_num_seg--;
+ qdf_assert(tso_num_desc->num_seg.tso_cmn_num_seg == 0);
+ qdf_nbuf_unmap_tso_segment(pdev->osdev,
+ tx_desc->tso_desc, true);
+ ol_tso_num_seg_free(pdev, tx_desc->tso_num_desc);
+ tx_desc->tso_num_desc = NULL;
+ }
+ ol_tso_free_segment(pdev, tx_desc->tso_desc);
+ tx_desc->tso_desc = NULL;
+ }
+}
+
+#else
+static inline void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev,
+ struct ol_tx_desc_t *tx_desc)
+{
+}
+
+#endif
+
#ifndef QCA_LL_TX_FLOW_CONTROL_V2
/**
* ol_tx_desc_free() - put descriptor to freelist
@@ -314,16 +356,9 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
{
qdf_spin_lock_bh(&pdev->tx_mutex);
- if (tx_desc->pkt_type == OL_TX_FRM_TSO) {
- if (qdf_unlikely(tx_desc->tso_desc == NULL)) {
- qdf_print("%s %d TSO desc is NULL!\n",
- __func__, __LINE__);
- qdf_assert(0);
- } else {
- ol_tso_free_segment(pdev, tx_desc->tso_desc);
- tx_desc->tso_desc = NULL;
- }
- }
+ if (tx_desc->pkt_type == OL_TX_FRM_TSO)
+ ol_tx_tso_desc_free(pdev, tx_desc);
+
ol_tx_desc_dup_detect_reset(pdev, tx_desc);
ol_tx_desc_reset_pkt_type(tx_desc);
ol_tx_desc_reset_timestamp(tx_desc);
@@ -346,17 +381,9 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
{
struct ol_tx_flow_pool_t *pool = tx_desc->pool;
-#if defined(FEATURE_TSO)
- if (tx_desc->pkt_type == OL_TX_FRM_TSO) {
- if (qdf_unlikely(tx_desc->tso_desc == NULL))
- qdf_print("%s %d TSO desc is NULL!\n",
- __func__, __LINE__);
- else {
- ol_tso_free_segment(pdev, tx_desc->tso_desc);
- tx_desc->tso_desc = NULL;
- }
- }
-#endif
+ if (tx_desc->pkt_type == OL_TX_FRM_TSO)
+ ol_tx_tso_desc_free(pdev, tx_desc);
+
ol_tx_desc_reset_pkt_type(tx_desc);
ol_tx_desc_reset_timestamp(tx_desc);
@@ -492,6 +519,7 @@ struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev,
if (msdu_info->tso_info.is_tso) {
tx_desc->tso_desc = msdu_info->tso_info.curr_seg;
+ tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list;
tx_desc->pkt_type = OL_TX_FRM_TSO;
TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, netbuf);
} else {
@@ -713,15 +741,14 @@ void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev,
#if defined(FEATURE_TSO)
/**
- * htt_tso_alloc_segment() - function to allocate a TSO segment
+ * ol_tso_alloc_segment() - function to allocate a TSO segment
* element
- * @pdev: HTT pdev
- * @tso_seg: This is the output. The TSO segment element.
+ * @pdev: the data physical device sending the data
*
* Allocates a TSO segment element from the free list held in
- * the HTT pdev
+ * the pdev
*
- * Return: none
+ * Return: tso_seg
*/
struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev)
{
@@ -754,15 +781,14 @@ struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev)
/**
* ol_tso_free_segment() - function to free a TSO segment
* element
- * @pdev: HTT pdev
+ * @pdev: the data physical device sending the data
* @tso_seg: The TSO segment element to be freed
*
* Returns a TSO segment element to the free list held in the
- * HTT pdev
+ * pdev
*
* Return: none
*/
-
void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
struct qdf_tso_seg_elem_t *tso_seg)
{
@@ -785,4 +811,50 @@ void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
pdev->tso_seg_pool.num_free++;
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
}
+
+/**
+ * ol_tso_num_seg_alloc() - function to allocate a element to count TSO segments
+ * in a jumbo skb packet.
+ * @pdev: the data physical device sending the data
+ *
+ * Allocates a element to count TSO segments from the free list held in
+ * the pdev
+ *
+ * Return: tso_num_seg
+ */
+struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc(struct ol_txrx_pdev_t *pdev)
+{
+ struct qdf_tso_num_seg_elem_t *tso_num_seg = NULL;
+
+ qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+ if (pdev->tso_num_seg_pool.freelist) {
+ pdev->tso_num_seg_pool.num_free--;
+ tso_num_seg = pdev->tso_num_seg_pool.freelist;
+ pdev->tso_num_seg_pool.freelist =
+ pdev->tso_num_seg_pool.freelist->next;
+ }
+ qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+
+ return tso_num_seg;
+}
+
+/**
+ * ol_tso_num_seg_free() - function to free a TSO segment
+ * element
+ * @pdev: the data physical device sending the data
+ * @tso_seg: The TSO segment element to be freed
+ *
+ * Returns a element to the free list held in the pdev
+ *
+ * Return: none
+ */
+void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev,
+ struct qdf_tso_num_seg_elem_t *tso_num_seg)
+{
+ qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+ tso_num_seg->next = pdev->tso_num_seg_pool.freelist;
+ pdev->tso_num_seg_pool.freelist = tso_num_seg;
+ pdev->tso_num_seg_pool.num_free++;
+ qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex);
+}
#endif
diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h
index 466510ff5cb3..e7c958fc2716 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-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -228,9 +228,17 @@ struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev);
void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
struct qdf_tso_seg_elem_t *tso_seg);
+struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc(
+ struct ol_txrx_pdev_t *pdev);
+void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev,
+ struct qdf_tso_num_seg_elem_t *tso_num_seg);
+
#else
#define ol_tso_alloc_segment(pdev) /*no-op*/
#define ol_tso_free_segment(pdev, tso_seg) /*no-op*/
+#define ol_tso_num_seg_alloc(pdev) /*no-op*/
+#define ol_tso_num_seg_free(pdev, tso_num_seg) /*no-op*/
+
#endif
/**
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 9818dc605a26..abb012407a46 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -1522,6 +1522,8 @@ ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev)
ol_tso_seg_list_init(pdev, desc_pool_size);
+ ol_tso_num_seg_list_init(pdev, desc_pool_size);
+
ol_tx_register_flow_control(pdev);
return 0; /* success */
@@ -1618,6 +1620,7 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force)
#endif
#endif
ol_tso_seg_list_deinit(pdev);
+ ol_tso_num_seg_list_deinit(pdev);
if (force) {
/*
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 4032fbfdb2be..1979f1cf5837 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -203,6 +203,7 @@ struct ol_tx_desc_t {
struct ol_tx_flow_pool_t *pool;
#endif
void *tso_desc;
+ void *tso_num_desc;
};
typedef TAILQ_HEAD(some_struct_name, ol_tx_desc_t) ol_tx_desc_list;
@@ -918,6 +919,13 @@ struct ol_txrx_pdev_t {
/* tso mutex */
OL_TX_MUTEX_TYPE tso_mutex;
} tso_seg_pool;
+ struct {
+ uint16_t num_seg_pool_size;
+ uint16_t num_free;
+ struct qdf_tso_num_seg_elem_t *freelist;
+ /* tso mutex */
+ OL_TX_MUTEX_TYPE tso_num_seg_mutex;
+ } tso_num_seg_pool;
#endif
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)