Sfoglia il codice sorgente

qcacld-3.0: Use new event infrastructure for session open/close events

With current implementation, if sme_open_session sends down a command
to the Firmware and an SSR/PDR occurs, the thread is stuck on waiting
on an event. The thread also holds the rtnl lock and will keep
blocking any other thread from acquiring it till timeout occurs. This
can result in deadlock situation with IPA driver trying to execute
driver ops during the SSR/PDR notification callback.

Use the wait_for_event_completion API for waiting on event. With this
the event will be purged when driver receives FW_DOWN indication.

Change-Id: I2920fd36c0eb5bb5994e66e584d12a2a9d8f409a
CRs-Fixed: 2120226
Nachiket Kukade 7 anni fa
parent
commit
08b9f2903b

+ 4 - 4
core/hdd/inc/wlan_hdd_main.h

@@ -1035,11 +1035,11 @@ struct hdd_adapter {
 
 	uint8_t session_id;
 
-	/* Completion variable for session close */
-	struct completion session_close_comp_var;
+	/* QDF event for session close */
+	qdf_event_t qdf_session_close_event;
 
-	/* Completion variable for session open */
-	struct completion session_open_comp_var;
+	/* QDF event for session open */
+	qdf_event_t qdf_session_open_event;
 
 	/* TODO: move these to sta ctx. These may not be used in AP */
 	/** completion variable for disconnect callback */

+ 5 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -13932,6 +13932,11 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
 	if (0 != status)
 		return status;
 
+	if (cds_is_fw_down()) {
+		hdd_err("Ignore if FW is already down");
+		return -EINVAL;
+	}
+
 	MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
 			 TRACE_CODE_HDD_CFG80211_CHANGE_IFACE,
 			 adapter->session_id, type));

+ 18 - 2
core/hdd/src/wlan_hdd_hostapd.c

@@ -6298,6 +6298,7 @@ struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx,
 {
 	struct net_device *dev;
 	struct hdd_adapter *adapter;
+	QDF_STATUS qdf_status;
 
 	hdd_debug("iface_name = %s", iface_name);
 
@@ -6350,8 +6351,23 @@ struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx,
 	adapter->wdev.wiphy = hdd_ctx->wiphy;
 	adapter->wdev.netdev = dev;
 	hdd_set_tso_flags(hdd_ctx, dev);
-	init_completion(&adapter->session_close_comp_var);
-	init_completion(&adapter->session_open_comp_var);
+
+	qdf_status = qdf_event_create(
+			&adapter->qdf_session_open_event);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		hdd_err("failed to create session open QDF event!");
+		free_netdev(adapter->dev);
+		return NULL;
+	}
+
+	qdf_status = qdf_event_create(
+			&adapter->qdf_session_close_event);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		hdd_err("failed to create session close QDF event!");
+		free_netdev(adapter->dev);
+		return NULL;
+	}
+
 	init_completion(&adapter->tx_action_cnf_event);
 	init_completion(&adapter->cancel_rem_on_chan_var);
 	init_completion(&adapter->rem_on_chan_ready_event);

+ 61 - 22
core/hdd/src/wlan_hdd_main.c

@@ -3145,6 +3145,7 @@ static struct hdd_adapter *hdd_alloc_station_adapter(struct hdd_context *hdd_ctx
 	struct net_device *dev = NULL;
 	struct hdd_adapter *adapter = NULL;
 	struct hdd_station_ctx *sta_ctx;
+	QDF_STATUS qdf_status;
 	/*
 	 * cfg80211 initialization and registration....
 	 */
@@ -3171,8 +3172,22 @@ static struct hdd_adapter *hdd_alloc_station_adapter(struct hdd_context *hdd_ctx
 		adapter->magic = WLAN_HDD_ADAPTER_MAGIC;
 		adapter->session_id = HDD_SESSION_ID_INVALID;
 
-		init_completion(&adapter->session_open_comp_var);
-		init_completion(&adapter->session_close_comp_var);
+		qdf_status = qdf_event_create(
+				&adapter->qdf_session_open_event);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+			hdd_err("Session open QDF event init failed!");
+			free_netdev(adapter->dev);
+			return NULL;
+		}
+
+		qdf_status = qdf_event_create(
+				&adapter->qdf_session_close_event);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+			hdd_err("Session close QDF event init failed!");
+			free_netdev(adapter->dev);
+			return NULL;
+		}
+
 		init_completion(&adapter->disconnect_comp_var);
 		init_completion(&adapter->roaming_comp_var);
 		init_completion(&adapter->linkup_event_var);
@@ -3278,7 +3293,7 @@ QDF_STATUS hdd_sme_open_session_callback(uint8_t session_id)
 		return QDF_STATUS_E_INVAL;
 	}
 	set_bit(SME_SESSION_OPENED, &adapter->event_flags);
-	complete(&adapter->session_open_comp_var);
+	qdf_event_set(&adapter->qdf_session_open_event);
 	hdd_debug("session %d opened", adapter->session_id);
 
 	return QDF_STATUS_SUCCESS;
@@ -3323,7 +3338,7 @@ QDF_STATUS hdd_sme_close_session_callback(uint8_t session_id)
 	 * valid, before signaling completion
 	 */
 	if (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)
-		complete(&adapter->session_close_comp_var);
+		qdf_event_set(&adapter->qdf_session_close_event);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -3353,7 +3368,6 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
 	QDF_STATUS status;
 	int errno;
 	struct hdd_context *hdd_ctx;
-	unsigned long rc;
 	uint8_t vdev_id;
 
 	vdev_id = adapter->session_id;
@@ -3377,7 +3391,7 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
 	}
 
 	/* close sme session (destroy vdev in firmware via legacy API) */
-	INIT_COMPLETION(adapter->session_close_comp_var);
+	qdf_event_reset(&adapter->qdf_session_close_event);
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	status = sme_close_session(hdd_ctx->hHal, adapter->session_id);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -3386,15 +3400,24 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
 	}
 
 	/* block on a completion variable until sme session is closed */
-	rc = wait_for_completion_timeout(
-		&adapter->session_close_comp_var,
-		msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
-	if (!rc) {
-		hdd_err("timed out waiting for close sme session: %ld", rc);
+	status = qdf_wait_for_event_completion(
+			&adapter->qdf_session_close_event,
+			WLAN_WAIT_TIME_SESSIONOPENCLOSE);
+	if (QDF_STATUS_SUCCESS != status) {
 		if (adapter->device_mode == QDF_NDI_MODE)
 			hdd_ndp_session_end_handler(adapter);
 		clear_bit(SME_SESSION_OPENED, &adapter->event_flags);
-		return -ETIMEDOUT;
+		adapter->session_id = HDD_SESSION_ID_INVALID;
+		if (QDF_STATUS_E_TIMEOUT != status) {
+			hdd_err("timed out waiting for close sme session: %u", status);
+			return -ETIMEDOUT;
+		} else if (adapter->qdf_session_close_event.force_set) {
+			hdd_err("Session close evt focefully set, SSR/PDR has occurred");
+			return -EINVAL;
+		} else {
+			hdd_err("Failed to close sme session (%u)", status);
+			return -EINVAL;
+		}
 	}
 release_vdev:
 	/* do vdev logical destroy via objmgr */
@@ -3449,7 +3472,6 @@ int hdd_vdev_create(struct hdd_adapter *adapter,
 	int errno;
 	struct hdd_context *hdd_ctx;
 	struct sme_session_params sme_session_params = {0};
-	unsigned long rc;
 
 	hdd_info("creating new vdev");
 
@@ -3462,7 +3484,11 @@ int hdd_vdev_create(struct hdd_adapter *adapter,
 	}
 
 	/* Open a SME session (prepare vdev in firmware via legacy API) */
-	INIT_COMPLETION(adapter->session_open_comp_var);
+	status = qdf_event_reset(&adapter->qdf_session_open_event);
+	if (QDF_STATUS_SUCCESS != status) {
+		hdd_err("failed to reinit session open event");
+		return -EINVAL;
+	}
 	errno = hdd_set_sme_session_param(adapter, &sme_session_params,
 					  callback, ctx);
 	if (errno) {
@@ -3478,14 +3504,27 @@ int hdd_vdev_create(struct hdd_adapter *adapter,
 	}
 
 	/* block on a completion variable until sme session is opened */
-	rc = wait_for_completion_timeout(
-		&adapter->session_open_comp_var,
-		msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
-	if (!rc) {
-		hdd_err("timed out waiting for open sme session: %ld", rc);
-		errno = -ETIMEDOUT;
-		set_bit(SME_SESSION_OPENED, &adapter->event_flags);
-		goto hdd_vdev_destroy_procedure;
+	status = qdf_wait_for_event_completion(&adapter->qdf_session_open_event,
+			WLAN_WAIT_TIME_SESSIONOPENCLOSE);
+	if (QDF_STATUS_SUCCESS != status) {
+		if (adapter->qdf_session_open_event.force_set) {
+			/*
+			 * SSR/PDR has caused shutdown, which has forcefully
+			 * set the event. Return without the closing session.
+			 */
+			adapter->session_id = HDD_SESSION_ID_INVALID;
+			hdd_err("Session open event forcefully set");
+			return -EINVAL;
+		} else {
+			if (QDF_STATUS_E_TIMEOUT == status)
+				hdd_err("Session failed to open within timeout period");
+			else
+				hdd_err("Failed to wait for session open event(status-%d)",
+					status);
+			errno = -ETIMEDOUT;
+			set_bit(SME_SESSION_OPENED, &adapter->event_flags);
+			goto hdd_vdev_destroy_procedure;
+		}
 	}
 
 	/* firmware ready for component communication, raise vdev_ready event */