Jelajahi Sumber

qcacld-3.0: Hold lock while temporary deleting the connection entry

If two thread are trying to access the connection entry and one of them
Is modifying it by temporarily deleting an entry, the other thread may
get the invalid connection entry and decision made using that connection
table will be invalid.

Thus acquire the lock before the entry is temporarily deleted and release
only after its added back.

Change-Id: I83b9d7a77045d8bddd6cf3e4b1af80bded116e2f
CRs-Fixed: 2422611
Abhishek Singh 6 tahun lalu
induk
melakukan
424ca57742

+ 114 - 37
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -777,26 +777,33 @@ policy_mgr_get_third_conn_action_table(
 	}
 }
 
-QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
-		uint32_t session_id,
-		uint8_t channel,
-		enum policy_mgr_conn_update_reason reason)
+static QDF_STATUS
+policy_mgr_get_next_action(struct wlan_objmgr_psoc *psoc,
+			   uint32_t session_id,
+			   uint8_t channel,
+			   enum policy_mgr_conn_update_reason reason,
+			   enum policy_mgr_conc_next_action *next_action)
 {
-	enum policy_mgr_conc_next_action next_action = PM_NOP;
 	uint32_t num_connections = 0;
 	enum policy_mgr_one_connection_mode second_index = 0;
 	enum policy_mgr_two_connection_mode third_index = 0;
 	policy_mgr_next_action_two_connection_table_type *second_conn_table;
 	policy_mgr_next_action_three_connection_table_type *third_conn_table;
 	enum policy_mgr_band band;
-	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
 	enum QDF_OPMODE new_conn_mode = QDF_MAX_NO_OF_MODE;
 
-	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
-		policy_mgr_err("driver isn't dbs capable, no further action needed");
-		return QDF_STATUS_E_NOSUPPORT;
+	if (!next_action) {
+		policy_mgr_err("next_action is NULL");
+		return QDF_STATUS_E_FAILURE;
 	}
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	if (WLAN_REG_IS_24GHZ_CH(channel))
 		band = POLICY_MGR_BAND_24;
 	else
@@ -811,11 +818,11 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 	case 0:
 		if (band == POLICY_MGR_BAND_24)
 			if (policy_mgr_is_hw_dbs_2x2_capable(psoc))
-				next_action = PM_DBS;
+				*next_action = PM_DBS;
 			else
-				next_action = PM_NOP;
+				*next_action = PM_NOP;
 		else
-			next_action = PM_NOP;
+			*next_action = PM_NOP;
 		break;
 	case 1:
 		second_index =
@@ -823,11 +830,11 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 		if (PM_MAX_ONE_CONNECTION_MODE == second_index) {
 			policy_mgr_err(
 			"couldn't find index for 2nd connection next action table");
-			goto done;
+			return QDF_STATUS_E_FAILURE;
 		}
 		second_conn_table = policy_mgr_get_second_conn_action_table(
 			psoc, session_id, channel, reason);
-		next_action = (*second_conn_table)[second_index][band];
+		*next_action = (*second_conn_table)[second_index][band];
 		break;
 	case 2:
 		third_index =
@@ -835,11 +842,11 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 		if (PM_MAX_TWO_CONNECTION_MODE == third_index) {
 			policy_mgr_err(
 			"couldn't find index for 3rd connection next action table");
-			goto done;
+			return QDF_STATUS_E_FAILURE;
 		}
 		third_conn_table = policy_mgr_get_third_conn_action_table(
 			psoc, session_id, channel, reason);
-		next_action = (*third_conn_table)[third_index][band];
+		*next_action = (*third_conn_table)[third_index][band];
 		break;
 	default:
 		policy_mgr_err("unexpected num_connections value %d",
@@ -847,12 +854,6 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 		break;
 	}
 
-	pm_ctx = policy_mgr_get_context(psoc);
-	if (!pm_ctx) {
-		policy_mgr_err("Invalid context");
-		goto done;
-	}
-
 	/*
 	 * There is no adapter associated with NAN Discovery, hence skip the
 	 * HDD callback and fill separately.
@@ -874,10 +875,36 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 	 */
 	if (policy_mgr_is_current_hwmode_dbs(psoc) &&
 		!policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode))
-		next_action = PM_SINGLE_MAC;
+		*next_action = PM_SINGLE_MAC;
 	else if (!policy_mgr_is_current_hwmode_dbs(psoc) &&
 		!policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode))
-		next_action = PM_NOP;
+		*next_action = PM_NOP;
+
+	policy_mgr_debug("idx2=%d idx3=%d next_action=%d, band=%d reason=%d session_id=%d",
+			 second_index, third_index, *next_action, band,
+			 reason, session_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+
+QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		uint8_t channel,
+		enum policy_mgr_conn_update_reason reason)
+{
+	enum policy_mgr_conc_next_action next_action = PM_NOP;
+	QDF_STATUS status;
+
+	if (!policy_mgr_is_hw_dbs_capable(psoc)) {
+		policy_mgr_err("driver isn't dbs capable, no further action needed");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	status = policy_mgr_get_next_action(psoc, session_id, channel, reason,
+					    &next_action);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
 
 	if (PM_NOP != next_action)
 		status = policy_mgr_next_actions(psoc, session_id,
@@ -885,12 +912,9 @@ QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 	else
 		status = QDF_STATUS_E_NOSUPPORT;
 
-	policy_mgr_debug(
-		"idx2=%d idx3=%d next_action=%d, band=%d status=%d reason=%d session_id=%d",
-		second_index, third_index, next_action, band, status,
-		reason, session_id);
+	policy_mgr_debug("next_action %d reason=%d session_id=%d",
+			 next_action, reason, session_id);
 
-done:
 	return status;
 }
 
@@ -1919,6 +1943,16 @@ QDF_STATUS policy_mgr_set_hw_mode_before_channel_switch(
 	QDF_STATUS status;
 	struct policy_mgr_conc_connection_info info;
 	uint8_t num_cxn_del = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum policy_mgr_conc_next_action next_action = PM_NOP;
+	enum policy_mgr_conn_update_reason reason =
+			POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
 
 	if (!policy_mgr_is_hw_dbs_capable(psoc)) {
 		policy_mgr_err("DBS is disabled");
@@ -1944,6 +1978,7 @@ QDF_STATUS policy_mgr_set_hw_mode_before_channel_switch(
 		return QDF_STATUS_E_ALREADY;
 	}
 
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	/*
 	 * Store the connection's parameter and temporarily delete it
 	 * from the concurrency table. This way the allow concurrency
@@ -1952,19 +1987,39 @@ QDF_STATUS policy_mgr_set_hw_mode_before_channel_switch(
 	 */
 	policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id,
 						      &info, &num_cxn_del);
-
-	status = policy_mgr_update_and_wait_for_connection_update(psoc,
-				vdev_id, chan,
-				POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH);
+	status = policy_mgr_get_next_action(psoc, vdev_id, chan, reason,
+					    &next_action);
 	/* Restore the connection entry */
 	if (num_cxn_del)
 		policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del);
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 
+	if (QDF_IS_STATUS_ERROR(status))
+		goto chk_opportunistic_timer;
+
+	status = policy_mgr_reset_connection_update(psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		policy_mgr_err("clearing event failed");
+
+	if (PM_NOP != next_action)
+		status = policy_mgr_next_actions(psoc, vdev_id,
+						 next_action, reason);
+	else
+		status = QDF_STATUS_E_NOSUPPORT;
+
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		status = policy_mgr_wait_for_connection_update(psoc);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			policy_mgr_err("qdf wait for event failed");
+		}
+	}
+
+chk_opportunistic_timer:
 	/*
 	 * If hw mode change failed restart the opportunistic timer to
 	 * Switch to single mac if required.
 	 */
-	if (QDF_IS_STATUS_ERROR(status)) {
+	if (status == QDF_STATUS_E_FAILURE) {
 		policy_mgr_err("Failed to update HW modeStatus %d", status);
 		policy_mgr_check_n_start_opportunistic_timer(psoc);
 	}
@@ -1978,6 +2033,16 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_sta_channel_switch(
 	QDF_STATUS status;
 	struct policy_mgr_conc_connection_info info;
 	uint8_t num_cxn_del = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum policy_mgr_conc_next_action next_action = PM_NOP;
+	enum policy_mgr_conn_update_reason reason =
+			POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
 
 	if (!policy_mgr_is_hw_dbs_capable(psoc) ||
 	    !policy_mgr_is_hw_dbs_2x2_capable(psoc)) {
@@ -2001,6 +2066,8 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_sta_channel_switch(
 		policy_mgr_err("DBS is not required for 5Ghz chan");
 		return QDF_STATUS_E_NOSUPPORT;
 	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	/*
 	 * Store the connection's parameter and temporarily delete it
 	 * from the concurrency table. This way the allow concurrency
@@ -2010,13 +2077,23 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_sta_channel_switch(
 	policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id,
 						      &info, &num_cxn_del);
 
-	status = policy_mgr_current_connections_update(psoc, vdev_id, chan,
-				POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA);
-
+	status = policy_mgr_get_next_action(psoc, vdev_id, chan,
+					    reason, &next_action);
 	/* Restore the connection entry */
 	if (num_cxn_del)
 		policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del);
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		goto chk_opportunistic_timer;
+
+	if (PM_NOP != next_action)
+		status = policy_mgr_next_actions(psoc, vdev_id,
+						next_action, reason);
+	else
+		status = QDF_STATUS_E_NOSUPPORT;
 
+chk_opportunistic_timer:
 	/*
 	 * If hw mode change failed restart the opportunistic timer to
 	 * Switch to single mac if required.

+ 8 - 9
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -1329,7 +1329,7 @@ QDF_STATUS policy_mgr_pdev_get_pcl(struct wlan_objmgr_psoc *psoc,
 void policy_mgr_set_pcl_for_existing_combo(
 		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode)
 {
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct policy_mgr_conc_connection_info
 			info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} };
 	enum QDF_OPMODE pcl_mode;
@@ -1348,7 +1348,6 @@ void policy_mgr_set_pcl_for_existing_combo(
 		return;
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	if (policy_mgr_mode_specific_connection_count(psoc, mode, NULL) > 0) {
-		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 		/* Check, store and temp delete the mode's parameter */
 		policy_mgr_store_and_del_conn_info(psoc, mode, false,
 						info, &num_cxn_del);
@@ -1357,14 +1356,14 @@ void policy_mgr_set_pcl_for_existing_combo(
 		policy_mgr_debug("Set PCL to FW for mode:%d", mode);
 		/* Restore the connection info */
 		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 
-		if (QDF_IS_STATUS_SUCCESS(status)) {
-			status = pm_ctx->sme_cbacks.sme_pdev_set_pcl(&pcl);
-			if (QDF_IS_STATUS_ERROR(status))
-				policy_mgr_err("Send set PCL to SME failed");
-		}
-	} else {
-		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	/* Send PCL only if policy_mgr_pdev_get_pcl returned success */
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		status = pm_ctx->sme_cbacks.sme_pdev_set_pcl(&pcl);
+		if (QDF_IS_STATUS_ERROR(status))
+			policy_mgr_err("Send set PCL to SME failed");
 	}
 }
 

+ 12 - 2
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -2137,6 +2137,13 @@ bool  policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc,
 	bool allow = false;
 	struct policy_mgr_conc_connection_info info;
 	uint8_t num_cxn_del = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return allow;
+	}
 
 	/*
 	 * Store the connection's parameter and temporarily delete it
@@ -2144,6 +2151,7 @@ bool  policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc,
 	 * check can be used as though a new connection is coming up,
 	 * after check, restore the connection to concurrency table.
 	 */
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id,
 						      &info, &num_cxn_del);
 	allow = policy_mgr_allow_concurrency(
@@ -2151,11 +2159,13 @@ bool  policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc,
 				mode,
 				channel,
 				HW_MODE_20_MHZ);
-	if (!allow)
-		policy_mgr_err("CSA concurrency check failed");
 	/* Restore the connection entry */
 	if (num_cxn_del > 0)
 		policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del);
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	if (!allow)
+		policy_mgr_err("CSA concurrency check failed");
 
 	return allow;
 }

+ 0 - 4
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -86,12 +86,10 @@ QDF_STATUS policy_mgr_get_pcl_for_existing_conn(struct wlan_objmgr_psoc *psoc,
 		/* Check, store and temp delete the mode's parameter */
 		policy_mgr_store_and_del_conn_info(psoc, mode,
 				all_matching_cxn_to_del, info, &num_cxn_del);
-		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 		/* Get the PCL */
 		status = policy_mgr_get_pcl(psoc, mode, pcl_ch, len,
 					pcl_weight, weight_len);
 		policy_mgr_debug("Get PCL to FW for mode:%d", mode);
-		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 		/* Restore the connection info */
 		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
 	}
@@ -1778,7 +1776,6 @@ QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
 		 */
 		policy_mgr_store_and_del_conn_info(psoc, PM_STA_MODE, false,
 						info, &num_cxn_del);
-		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 		/*
 		 * There is a small window between releasing the above lock
 		 * and acquiring the same in policy_mgr_allow_concurrency,
@@ -1792,7 +1789,6 @@ QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
 					WEIGHT_OF_NON_PCL_CHANNELS;
 			}
 		}
-		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 		/* Restore the connection info */
 		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
 	}