Explorar o código

qcacmn: Fix TDLS set state cmd sequence for roaming

Firmware expects TDLS set state cmd before vdev stop, but
the cmd is going out of sequence during roaming and induce
crash in the system.
Send the TDLS set state cmd with correct sequence.

Change-Id: Ie106b8a8cebaa7f107c9eff67dda924b231162da
CRs-Fixed: 2048036
Kabilan Kannan %!s(int64=8) %!d(string=hai) anos
pai
achega
ac7731fc62

+ 3 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h

@@ -199,6 +199,9 @@
   /* CAPABILITY: bg scanning */
 #define WLAN_VDEV_C_BGSCAN               0x00000100
 
+/* Invalid VDEV identifier */
+#define WLAN_INVALID_VDEV_ID 255
+
 /**
  * enum wlan_vdev_state - VDEV state
  * @WLAN_VDEV_S_INIT:    Default state, IDLE state

+ 13 - 0
umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -1331,6 +1331,19 @@ void policy_mgr_checkn_update_hw_mode_single_mac_mode(
  */
 void policy_mgr_dump_connection_status_info(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * policy_mgr_mode_specific_vdev_id() - provides the
+ * vdev id of the pecific mode
+ * @psoc: PSOC object information
+ * @mode: type of connection
+ *
+ * This function provides vdev id for the given mode
+ *
+ * Return: vdev id
+ */
+uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc,
+					  enum policy_mgr_con_mode mode);
+
 /**
  * policy_mgr_mode_specific_connection_count() - provides the
  * count of connections of specific mode

+ 30 - 0
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -788,6 +788,36 @@ uint32_t policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc)
 	return count;
 }
 
+uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc,
+					  enum policy_mgr_con_mode mode)
+{
+	uint32_t conn_index = 0;
+	uint32_t vdev_id = WLAN_INVALID_VDEV_ID;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return vdev_id;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	/*
+	 * Note: This gives you the first vdev id of the mode type in a
+	 * sta+sta or sap+sap or p2p + p2p case
+	 */
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			vdev_id = pm_conc_connection_list[conn_index].vdev_id;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return vdev_id;
+}
+
 uint32_t policy_mgr_mode_specific_connection_count(
 		struct wlan_objmgr_psoc *psoc,
 		enum policy_mgr_con_mode mode,

+ 71 - 35
umac/tdls/core/src/wlan_tdls_main.c

@@ -623,20 +623,25 @@ tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc)
 struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc,
 					  wlan_objmgr_ref_dbgid dbg_id)
 {
+	uint32_t vdev_id;
+
 	if (policy_mgr_get_connection_count(psoc) > 1)
 		return NULL;
-	if (policy_mgr_mode_specific_connection_count(psoc,
-						      PM_STA_MODE,
-						      NULL) == 1)
-		return wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc,
-							QDF_STA_MODE,
-							dbg_id);
-	if (policy_mgr_mode_specific_connection_count(psoc,
-						      PM_P2P_CLIENT_MODE,
-						      NULL) == 1)
-		return wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc,
-							QDF_P2P_CLIENT_MODE,
-							dbg_id);
+
+	vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_STA_MODE);
+
+	if (WLAN_INVALID_VDEV_ID != vdev_id)
+		return wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							    vdev_id,
+							    dbg_id);
+
+	vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_P2P_CLIENT_MODE);
+
+	if (WLAN_INVALID_VDEV_ID != vdev_id)
+		return wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							    vdev_id,
+							    dbg_id);
+
 	return NULL;
 }
 
@@ -705,10 +710,9 @@ static void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj,
 	uint32_t tdls_feature_flags;
 	QDF_STATUS status;
 
-
-	/* If TDLS support is disabled then no need to update target */
-	if (tdls_soc_obj->tdls_current_mode <= TDLS_SUPPORT_SUSPENDED) {
-		tdls_err("TDLS not enabled or suspended");
+	tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_ENABLED(tdls_feature_flags)) {
+		tdls_debug("TDLS mode is not enabled");
 		return;
 	}
 
@@ -717,23 +721,28 @@ static void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj,
 		return;
 	}
 
-	tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags;
-
 	/* If AP or caller indicated TDLS Prohibited then disable tdls mode */
-	if (tdls_prohibited) {
-		tdls_soc_obj->tdls_current_mode = TDLS_SUPPORT_DISABLED;
-	} else {
-		tdls_debug("TDLS feature flags from ini %d ",
-				tdls_feature_flags);
-		if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags))
-			tdls_soc_obj->tdls_current_mode =
-				TDLS_SUPPORT_EXP_TRIG_ONLY;
-		else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags))
-			tdls_soc_obj->tdls_current_mode =
-				TDLS_SUPPORT_EXT_CONTROL;
-		else
+	if (sta_connect_event) {
+		if (tdls_prohibited) {
 			tdls_soc_obj->tdls_current_mode =
-				TDLS_SUPPORT_IMP_MODE;
+					TDLS_SUPPORT_DISABLED;
+		} else {
+			tdls_debug("TDLS feature flags from ini %d ",
+				tdls_feature_flags);
+			if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags))
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_EXP_TRIG_ONLY;
+			else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
+				tdls_feature_flags))
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_EXT_CONTROL;
+			else
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_IMP_MODE;
+		}
+	} else {
+		tdls_soc_obj->tdls_current_mode =
+				TDLS_SUPPORT_DISABLED;
 	}
 
 	tdls_info_to_fw = qdf_mem_malloc(sizeof(struct tdls_info));
@@ -827,8 +836,6 @@ static void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj,
 
 done:
 	qdf_mem_free(tdls_info_to_fw);
-	tdls_process_session_update(tdls_soc_obj->soc,
-					TDLS_CMD_SESSION_INCREMENT);
 	return;
 }
 
@@ -846,6 +853,11 @@ tdls_process_sta_connect(struct tdls_sta_notify_params *notify)
 
 	tdls_debug("Check and update TDLS state");
 
+	if (policy_mgr_get_connection_count(tdls_soc_obj->soc) > 1) {
+		tdls_debug("Concurrent sessions exist, TDLS can't be enabled");
+		return QDF_STATUS_SUCCESS;
+	}
+
 	/* Association event */
 	if (!tdls_soc_obj->tdls_disable_in_progress) {
 		tdls_send_update_to_fw(tdls_vdev_obj,
@@ -872,8 +884,10 @@ QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify)
 		return QDF_STATUS_E_INVAL;
 
 	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev,
-							WLAN_TDLS_NB_ID))
+							WLAN_TDLS_NB_ID)) {
+		qdf_mem_free(notify);
 		return QDF_STATUS_E_INVAL;
+	}
 
 	status = tdls_process_sta_connect(notify);
 
@@ -956,8 +970,10 @@ QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify)
 		return QDF_STATUS_E_INVAL;
 
 	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev,
-							       WLAN_TDLS_NB_ID))
+							WLAN_TDLS_NB_ID)) {
+		qdf_mem_free(notify);
 		return QDF_STATUS_E_INVAL;
+	}
 
 	status = tdls_process_sta_disconnect(notify);
 
@@ -968,6 +984,26 @@ QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify)
 	return status;
 }
 
+void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
+					 uint32_t session_id)
+{
+	struct tdls_sta_notify_params *notify;
+
+	notify = qdf_mem_malloc(sizeof(*notify));
+	if (!notify) {
+		tdls_err("memory allocation failed !!!");
+		return;
+	}
+
+	notify->lfr_roam = true;
+	notify->tdls_chan_swit_prohibited = false;
+	notify->tdls_prohibited = false;
+	notify->session_id = session_id;
+	notify->vdev = vdev;
+
+	tdls_notify_sta_disconnect(notify);
+}
+
 /**
  * tdls_set_mode_in_vdev() - set TDLS mode
  * @tdls_vdev: tdls vdev object

+ 14 - 0
umac/tdls/core/src/wlan_tdls_main.h

@@ -583,6 +583,20 @@ QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify);
  */
 QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify);
 
+/**
+ * tdls_peers_deleted_notification() - peer delete notification
+ * @vdev: vdev object
+ * @session_id: session id
+ *
+ * Legacy lim layer will delete tdls peers for roaming and heart beat failures
+ * and notify the component about the delete event to update the tdls.
+ * state.
+ *
+ * Return: None
+ */
+void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
+					 uint32_t session_id);
+
 /**
  * tdls_notify_decrement_session() - Notify the session decrement
  * @psoc: psoc  object manager

+ 12 - 0
umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h

@@ -146,4 +146,16 @@ QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
 	struct mgmt_rx_event_params *mgmt_rx_params,
 	enum mgmt_frame_type frm_type);
 
+/**
+ * tgt_tdls_peers_deleted_notification()- notification from legacy lim
+ * @psoc: soc object
+ * @session_id: session id
+ *
+ * This function called from legacy lim to notify tdls peer deletion
+ *
+ * Return: None
+ */
+void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+					 uint32_t session_id);
+
 #endif

+ 21 - 0
umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c

@@ -334,3 +334,24 @@ release_nbuf:
 	return status;
 }
 
+void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+						uint32_t session_id)
+{
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    session_id,
+						    WLAN_TDLS_SB_ID);
+
+	if (!vdev) {
+		tdls_err("vdev not exist for the session id %d",
+			 session_id);
+		return;
+	}
+
+	tdls_peers_deleted_notification(vdev, session_id);
+
+	wlan_objmgr_vdev_release_ref(vdev,
+				     WLAN_TDLS_SB_ID);
+}
+

+ 1 - 0
umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c

@@ -623,6 +623,7 @@ QDF_STATUS ucfg_tdls_notify_sta_disconnect(
 	notify->tdls_chan_swit_prohibited = false;
 	notify->tdls_prohibited = false;
 	notify->vdev = notify_info->vdev;
+	notify->lfr_roam = notify_info->lfr_roam;
 
 	msg.bodyptr = notify;
 	msg.callback = tdls_process_cmd;