Parcourir la source

qcacld-3.0: Free all TX descriptors in error scenario

Forcefully free all TX descriptors during driver unload
which is not freed because of unmap event missing from
firmware to avoid memory leak.

Change-Id: I47ff7e6a8f2aa130c77ac68a92eee9373d152e87
CRs-Fixed: 1001994
Nirav Shah il y a 9 ans
Parent
commit
7a0a90597b

+ 3 - 2
core/dp/ol/inc/ol_txrx_ctrl_api.h

@@ -517,7 +517,7 @@ 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);
+int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force);
 #else
 
 static inline void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev)
@@ -551,7 +551,8 @@ 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)
+static inline int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool,
+		bool force)
 {
 	return 0;
 }

+ 1 - 1
core/dp/txrx/ol_txrx.c

@@ -1025,7 +1025,6 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force)
 #endif
 #endif
 	ol_tso_seg_list_deinit(pdev);
-	ol_tx_deregister_flow_control(pdev);
 
 	if (force) {
 		/*
@@ -1045,6 +1044,7 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force)
 		ol_txrx_peer_find_hash_erase(pdev);
 	}
 
+	ol_tx_deregister_flow_control(pdev);
 	/* Stop the communication between HTT and target at first */
 	htt_detach_target(pdev->htt_pdev);
 

+ 25 - 9
core/dp/txrx/ol_txrx_flow_control.c

@@ -82,7 +82,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);
+	ol_tx_delete_flow_pool(pdev->mgmt_pool, false);
 	return;
 }
 #else
@@ -121,14 +121,27 @@ void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev)
  */
 void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev)
 {
+	int i = 0;
+	struct ol_tx_flow_pool_t *pool = NULL;
+
 	if (!ol_tx_get_is_mgmt_over_wmi_enabled())
 		ol_tx_deregister_global_mgmt_pool(pdev);
 
-	qdf_spinlock_destroy(&pdev->tx_desc.flow_pool_list_lock);
-	if (!TAILQ_EMPTY(&pdev->tx_desc.flow_pool_list)) {
+	qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
+	while (!TAILQ_EMPTY(&pdev->tx_desc.flow_pool_list)) {
+		pool = TAILQ_FIRST(&pdev->tx_desc.flow_pool_list);
+		if (!pool)
+			break;
+		qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
 		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
-			"flow pool list is not empty!!!\n");
+			"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);
+		qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
 	}
+	qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
+	qdf_spinlock_destroy(&pdev->tx_desc.flow_pool_list_lock);
 }
 
 /**
@@ -381,13 +394,16 @@ 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)
+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;
@@ -405,7 +421,7 @@ int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool)
 	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)
+	if (pool->avail_desc == pool->flow_pool_size || force == true)
 		pool->status = FLOW_POOL_INACTIVE;
 	else
 		pool->status = FLOW_POOL_INVALID;
@@ -481,7 +497,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);
+	return ol_tx_delete_flow_pool(pool, false);
 }
 
 /**
@@ -624,7 +640,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);
+			ol_tx_delete_flow_pool(pool, false);
 		TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
 		   "%s: flow type %d not supported !!!\n",
 		   __func__, type);
@@ -684,7 +700,7 @@ void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type,
 	}
 
 	/* only delete if all descriptors are available */
-	ol_tx_delete_flow_pool(pool);
+	ol_tx_delete_flow_pool(pool, false);
 
 	return;
 }