summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimanshu Agarwal <himanaga@codeaurora.org>2017-03-30 17:16:55 +0530
committerSandeep Puligilla <spuligil@codeaurora.org>2017-04-04 15:27:06 -0700
commit2b53b6e6cb3418e6040124a5ab693fecee5fb71e (patch)
tree150a0ed679d7ef70aeab9d8649199a89e53e61ce
parent9e2b4feabb6bf85233dac03642f5279764765314 (diff)
qcacld-3.0: Add ref_cnt implementation for flow pool
Add ref_cnt implementation for flow pool to synchronize usage and deletion of flow pool. Change-Id: Idb52c74df6a771b776e3df6bf4aea5c150b5fc7a CRs-Fixed: 2025757
-rw-r--r--core/dp/ol/inc/ol_txrx_ctrl_api.h39
-rw-r--r--core/dp/txrx/ol_txrx_flow_control.c247
-rw-r--r--core/dp/txrx/ol_txrx_types.h2
3 files changed, 192 insertions, 96 deletions
diff --git a/core/dp/ol/inc/ol_txrx_ctrl_api.h b/core/dp/ol/inc/ol_txrx_ctrl_api.h
index a9fdf25b097c..ab55ac39dc22 100644
--- a/core/dp/ol/inc/ol_txrx_ctrl_api.h
+++ b/core/dp/ol/inc/ol_txrx_ctrl_api.h
@@ -642,7 +642,33 @@ void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type,
uint8_t flow_pool_id);
struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id,
uint16_t flow_pool_size);
-int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force);
+
+/**
+ * ol_tx_inc_pool_ref() - increment pool ref count
+ * @pool: flow pool pointer
+ *
+ * Increments pool's ref count, used to make sure that no one is using
+ * pool when it is being deleted.
+ * As this function is taking pool->flow_pool_lock inside it, it should
+ * always be called outside this spinlock.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool);
+
+/**
+ * ol_tx_dec_pool_ref() - decrement pool ref count
+ * @pool: flow pool pointer
+ * @force: free pool forcefully
+ *
+ * Decrements pool's ref count and deletes the pool if ref count gets 0.
+ * As this function is taking pdev->tx_desc.flow_pool_list_lock and
+ * pool->flow_pool_lock inside it, it should always be called outside
+ * these two spinlocks.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force);
#else
static inline void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev)
@@ -676,10 +702,15 @@ static inline struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(
{
return NULL;
}
-static inline int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool,
- bool force)
+static inline QDF_STATUS
+ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool)
+{
+ return QDF_STATUS_SUCCESS;
+}
+static inline QDF_STATUS
+ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force)
{
- return 0;
+ return QDF_STATUS_SUCCESS;
}
#endif
diff --git a/core/dp/txrx/ol_txrx_flow_control.c b/core/dp/txrx/ol_txrx_flow_control.c
index 7ce33d6e558e..826697cfbab7 100644
--- a/core/dp/txrx/ol_txrx_flow_control.c
+++ b/core/dp/txrx/ol_txrx_flow_control.c
@@ -81,7 +81,7 @@ ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev)
static void
ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev)
{
- ol_tx_delete_flow_pool(pdev->mgmt_pool, false);
+ ol_tx_dec_pool_ref(pdev->mgmt_pool, false);
return;
}
#else
@@ -135,7 +135,7 @@ void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev)
ol_txrx_info("flow pool list is not empty %d!!!\n", i++);
if (i == 1)
ol_tx_dump_flow_pool_info();
- ol_tx_delete_flow_pool(pool, true);
+ ol_tx_dec_pool_ref(pool, true);
qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
}
qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
@@ -143,6 +143,138 @@ void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev)
}
/**
+ * ol_tx_delete_flow_pool() - delete flow pool
+ * @pool: flow pool pointer
+ * @force: free pool forcefully
+ *
+ * Delete flow_pool if all tx descriptors are available.
+ * Otherwise put it in FLOW_POOL_INVALID state.
+ * If force is set then pull all available descriptors to
+ * global pool.
+ *
+ * Return: 0 for success or error
+ */
+static int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force)
+{
+ struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+ uint16_t i, size;
+ union ol_tx_desc_list_elem_t *temp_list = NULL;
+ struct ol_tx_desc_t *tx_desc = NULL;
+
+ if (!pool) {
+ ol_txrx_err(
+ "%s: pool is NULL\n", __func__);
+ QDF_ASSERT(0);
+ return -ENOMEM;
+ }
+ if (!pdev) {
+ ol_txrx_err(
+ "%s: pdev is NULL\n", __func__);
+ QDF_ASSERT(0);
+ return -ENOMEM;
+ }
+
+ qdf_spin_lock_bh(&pool->flow_pool_lock);
+ if (pool->avail_desc == pool->flow_pool_size || force == true)
+ pool->status = FLOW_POOL_INACTIVE;
+ else
+ pool->status = FLOW_POOL_INVALID;
+
+ /* Take all free descriptors and put it in temp_list */
+ temp_list = pool->freelist;
+ size = pool->avail_desc;
+ pool->freelist = NULL;
+ pool->avail_desc = 0;
+
+ if (pool->status == FLOW_POOL_INACTIVE) {
+ qdf_spin_unlock_bh(&pool->flow_pool_lock);
+ /* Free flow_pool */
+ qdf_spinlock_destroy(&pool->flow_pool_lock);
+ qdf_mem_free(pool);
+ } else { /* FLOW_POOL_INVALID case*/
+ pool->flow_pool_size -= size;
+ pool->flow_pool_id = INVALID_FLOW_ID;
+ qdf_spin_unlock_bh(&pool->flow_pool_lock);
+ ol_tx_inc_pool_ref(pool);
+
+ pdev->tx_desc.num_invalid_bin++;
+ ol_txrx_info(
+ "%s: invalid pool created %d\n",
+ __func__, pdev->tx_desc.num_invalid_bin);
+ if (pdev->tx_desc.num_invalid_bin > MAX_INVALID_BIN)
+ ASSERT(0);
+
+ qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool,
+ flow_pool_list_elem);
+ qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ }
+
+ /* put free descriptors to global pool */
+ qdf_spin_lock_bh(&pdev->tx_mutex);
+ for (i = 0; i < size; i++) {
+ tx_desc = &temp_list->tx_desc;
+ temp_list = temp_list->next;
+
+ ol_tx_put_desc_global_pool(pdev, tx_desc);
+ }
+ qdf_spin_unlock_bh(&pdev->tx_mutex);
+
+ return 0;
+}
+
+QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool)
+{
+ if (!pool) {
+ ol_txrx_err("flow pool is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ qdf_spin_lock_bh(&pool->flow_pool_lock);
+ qdf_atomic_inc(&pool->ref_cnt);
+ qdf_spin_unlock_bh(&pool->flow_pool_lock);
+ ol_txrx_dbg("pool %p, ref_cnt %x",
+ pool, qdf_atomic_read(&pool->ref_cnt));
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force)
+{
+ struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
+
+ if (!pool) {
+ ol_txrx_err("flow pool is NULL");
+ QDF_ASSERT(0);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!pdev) {
+ ol_txrx_err("pdev is NULL");
+ QDF_ASSERT(0);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ qdf_spin_lock_bh(&pool->flow_pool_lock);
+ if (qdf_atomic_dec_and_test(&pool->ref_cnt)) {
+ qdf_spin_unlock_bh(&pool->flow_pool_lock);
+ TAILQ_REMOVE(&pdev->tx_desc.flow_pool_list, pool,
+ flow_pool_list_elem);
+ qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ ol_txrx_dbg("Deleting pool %p", pool);
+ ol_tx_delete_flow_pool(pool, force);
+ } else {
+ qdf_spin_unlock_bh(&pool->flow_pool_lock);
+ qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ ol_txrx_dbg("pool %p, ref_cnt %x",
+ pool, qdf_atomic_read(&pool->ref_cnt));
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
* ol_tx_dump_flow_pool_info() - dump global_pool and flow_pool info
*
* Return: none
@@ -150,7 +282,7 @@ void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev)
void ol_tx_dump_flow_pool_info(void)
{
struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
- struct ol_tx_flow_pool_t *pool = NULL;
+ struct ol_tx_flow_pool_t *pool = NULL, *pool_prev = NULL;
struct ol_tx_flow_pool_t tmp_pool;
@@ -180,10 +312,15 @@ void ol_tx_dump_flow_pool_info(void)
qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list,
flow_pool_list_elem) {
+ ol_tx_inc_pool_ref(pool);
qdf_spin_lock_bh(&pool->flow_pool_lock);
qdf_mem_copy(&tmp_pool, pool, sizeof(tmp_pool));
qdf_spin_unlock_bh(&pool->flow_pool_lock);
qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+
+ if (pool_prev)
+ ol_tx_dec_pool_ref(pool_prev, false);
+
ol_txrx_info("\n");
ol_txrx_info(
"Flow_pool_id %d :: status %d",
@@ -201,10 +338,16 @@ void ol_tx_dump_flow_pool_info(void)
ol_txrx_info(
"Pkt dropped due to unavailablity of descriptors %d",
tmp_pool.pkt_drop_no_desc);
+
+ pool_prev = pool;
qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
}
qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+ /* decrement ref count for last pool in list */
+ if (pool_prev)
+ ol_tx_dec_pool_ref(pool_prev, false);
+
return;
}
@@ -373,6 +516,8 @@ struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id,
pool->start_th = (start_threshold * flow_pool_size)/100;
pool->stop_th = (stop_threshold * flow_pool_size)/100;
qdf_spinlock_create(&pool->flow_pool_lock);
+ qdf_atomic_init(&pool->ref_cnt);
+ ol_tx_inc_pool_ref(pool);
/* Take TX descriptor from global_pool and put it in temp_list*/
qdf_spin_lock_bh(&pdev->tx_mutex);
@@ -405,91 +550,6 @@ struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id,
}
/**
- * ol_tx_delete_flow_pool() - delete flow pool
- * @pool: flow pool pointer
- * @force: free pool forcefully
- *
- * Delete flow_pool if all tx descriptors are available.
- * Otherwise put it in FLOW_POOL_INVALID state.
- * If force is set then pull all available descriptors to
- * global pool.
- *
- * Return: 0 for success or error
- */
-int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force)
-{
- struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
- uint16_t i, size;
- union ol_tx_desc_list_elem_t *temp_list = NULL;
- struct ol_tx_desc_t *tx_desc = NULL;
-
- if (!pool) {
- ol_txrx_err(
- "%s: pool is NULL\n", __func__);
- QDF_ASSERT(0);
- return -ENOMEM;
- }
- if (!pdev) {
- ol_txrx_err(
- "%s: pdev is NULL\n", __func__);
- QDF_ASSERT(0);
- return -ENOMEM;
- }
-
- qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
- TAILQ_REMOVE(&pdev->tx_desc.flow_pool_list, pool, flow_pool_list_elem);
- qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
-
- qdf_spin_lock_bh(&pool->flow_pool_lock);
- if (pool->avail_desc == pool->flow_pool_size || force == true)
- pool->status = FLOW_POOL_INACTIVE;
- else
- pool->status = FLOW_POOL_INVALID;
-
- /* Take all free descriptors and put it in temp_list */
- temp_list = pool->freelist;
- size = pool->avail_desc;
- pool->freelist = NULL;
- pool->avail_desc = 0;
-
- if (pool->status == FLOW_POOL_INACTIVE) {
- qdf_spin_unlock_bh(&pool->flow_pool_lock);
- /* Free flow_pool */
- qdf_spinlock_destroy(&pool->flow_pool_lock);
- qdf_mem_free(pool);
- } else { /* FLOW_POOL_INVALID case*/
- pool->flow_pool_size -= size;
- pool->flow_pool_id = INVALID_FLOW_ID;
- qdf_spin_unlock_bh(&pool->flow_pool_lock);
-
- pdev->tx_desc.num_invalid_bin++;
- ol_txrx_info(
- "%s: invalid pool created %d\n",
- __func__, pdev->tx_desc.num_invalid_bin);
- if (pdev->tx_desc.num_invalid_bin > MAX_INVALID_BIN)
- ASSERT(0);
-
- qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
- TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool,
- flow_pool_list_elem);
- qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
- }
-
- /* put free descriptors to global pool */
- qdf_spin_lock_bh(&pdev->tx_mutex);
- for (i = 0; i < size; i++) {
- tx_desc = &temp_list->tx_desc;
- temp_list = temp_list->next;
-
- ol_tx_put_desc_global_pool(pdev, tx_desc);
- }
- qdf_spin_unlock_bh(&pdev->tx_mutex);
-
- return 0;
-}
-
-
-/**
* ol_tx_free_invalid_flow_pool() - free invalid pool
* @pool: pool
*
@@ -517,7 +577,7 @@ int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool)
"%s: invalid pool deleted %d\n",
__func__, pdev->tx_desc.num_invalid_bin);
- return ol_tx_delete_flow_pool(pool, false);
+ return ol_tx_dec_pool_ref(pool, false);
}
/**
@@ -670,7 +730,7 @@ void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type,
break;
default:
if (pool_create)
- ol_tx_delete_flow_pool(pool, false);
+ ol_tx_dec_pool_ref(pool, false);
ol_txrx_err(
"%s: flow type %d not supported !!!\n",
__func__, type);
@@ -729,8 +789,11 @@ void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type,
return;
}
- /* only delete if all descriptors are available */
- ol_tx_delete_flow_pool(pool, false);
+ /*
+ * only delete if all descriptors are available
+ * and pool ref count becomes 0
+ */
+ ol_tx_dec_pool_ref(pool, false);
return;
}
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 2668d898c4fa..c7c21073d00c 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -475,6 +475,7 @@ struct ol_txrx_pool_stats {
* @start_th: start threshold
* @freelist: tx descriptor freelist
* @pkt_drop_no_desc: drop due to no descriptors
+ * @ref_cnt: pool's ref count
*/
struct ol_tx_flow_pool_t {
TAILQ_ENTRY(ol_tx_flow_pool_t) flow_pool_list_elem;
@@ -490,6 +491,7 @@ struct ol_tx_flow_pool_t {
uint16_t start_th;
union ol_tx_desc_list_elem_t *freelist;
uint16_t pkt_drop_no_desc;
+ qdf_atomic_t ref_cnt;
};
#endif