Browse Source

qcacld-3.0: Set hw mode during channel switch in SAP/P2P-GO case

Set the hw mode, if needed, during channel switch in SAP and
P2P-GO scenario.

Change-Id: Icef31277465b3a298695ccefb856d9cad8a16108
CRs-Fixed: 969307
Chandrasekaran, Manishekar 9 năm trước cách đây
mục cha
commit
e716c40025

+ 2 - 0
core/cds/inc/cds_concurrency.h

@@ -463,6 +463,8 @@ struct cds_conc_connection_info {
 	bool          in_use;
 };
 
+enum cds_conc_next_action cds_get_pref_hw_mode_for_chan(uint32_t vdev_id,
+		uint32_t target_channel);
 bool cds_is_connection_in_progress(void);
 void cds_dump_concurrency_info(void);
 void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode);

+ 128 - 1
core/cds/src/cds_concurrency.c

@@ -3593,6 +3593,12 @@ enum cds_conc_next_action cds_need_opportunistic_upgrade(void)
 	/* Are both mac's still in use*/
 	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
 		conn_index++) {
+		cds_debug("index:%d mac:%d in_use:%d chan:%d org_nss:%d",
+			conn_index,
+			conc_connection_list[conn_index].mac,
+			conc_connection_list[conn_index].in_use,
+			conc_connection_list[conn_index].chan,
+			conc_connection_list[conn_index].original_nss);
 		if ((conc_connection_list[conn_index].mac == 0) &&
 			conc_connection_list[conn_index].in_use) {
 			mac |= 1;
@@ -3608,8 +3614,10 @@ enum cds_conc_next_action cds_need_opportunistic_upgrade(void)
 #ifdef QCA_WIFI_3_0_EMU
 	/* For M2M emulation only: if we have a connection on 2.4, stay in DBS */
 	if (hdd_ctx->config->enable_m2m_limitation &&
-		CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan))
+		CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) {
+		cds_debug("For emulation only: connection on 2.4, stay in DBS");
 		goto done;
+	}
 #endif
 	/* Let's request for single MAC mode */
 	upgrade = CDS_MCC;
@@ -3803,6 +3811,7 @@ void cds_dbs_opportunistic_timer_handler(void *data)
 	qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock);
 	/* if we still need it */
 	action = cds_need_opportunistic_upgrade();
+	cds_info("action:%d", action);
 	if (action) {
 		/* lets call for action */
 		/* session id is being used only
@@ -7854,3 +7863,121 @@ QDF_STATUS qdf_init_connection_update(void)
 
 	return QDF_STATUS_SUCCESS;
 }
+
+/**
+ * cds_get_pref_hw_mode_for_chan() - Get preferred hw mode for new channel
+ * @vdev_id: vdev id whose target channel needs to change
+ * @target_channel: Target channel
+ *
+ * Get the preferred hw mode based on the vdev whose channel is going to change
+ *
+ * Return: No change (CDS_NOP), MCC (CDS_MCC_UPGRADE), DBS (CDS_DBS_DOWNGRADE)
+ */
+enum cds_conc_next_action cds_get_pref_hw_mode_for_chan(uint32_t vdev_id,
+		uint32_t target_channel)
+{
+	uint32_t num_connections;
+	uint32_t conn_index = 0;
+	bool found = false;
+	uint8_t old_band, new_band;
+
+	while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if ((vdev_id == conc_connection_list[conn_index].vdev_id) &&
+			(conc_connection_list[conn_index].in_use == true)) {
+			found = true;
+			break;
+		}
+		conn_index++;
+	}
+
+	if (!found) {
+		cds_err("vdev_id:%d not available in the conn info", vdev_id);
+		return CDS_NOP;
+	}
+
+	old_band = cds_chan_to_band(conc_connection_list[conn_index].chan);
+	new_band = cds_chan_to_band(target_channel);
+
+	num_connections = cds_get_connection_count();
+
+	cds_debug("vdev_id:%d conn_index:%d target_channel:%d chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d",
+		vdev_id, conn_index, target_channel,
+		conc_connection_list[0].chan, conc_connection_list[1].chan,
+		conc_connection_list[2].chan,
+		num_connections);
+
+	/* If the band of the new channel to which the switching is done is same
+	 * as the band of the old channel, then there is no need for a hw mode
+	 * change. The driver would already be in the required hw mode.
+	 */
+	if (old_band == new_band)
+		return CDS_NOP;
+
+	switch (num_connections) {
+	case 1:
+		/* The driver would already be in the required hw mode */
+		return CDS_NOP;
+	case 2:
+		/* If the band of the new channel, is same as that of the band
+		 * of the channel on the other interface, the driver needs to
+		 * move to single MAC.
+		 *
+		 * If the band of the new channel, is different than that of the
+		 * band of the channel on the other interface, the driver needs
+		 * to move to DBS.
+		 */
+		if (conn_index == 0) {
+			if (new_band == cds_chan_to_band(
+					conc_connection_list[1].chan))
+				return CDS_MCC_UPGRADE;
+			else if (new_band != cds_chan_to_band(
+					conc_connection_list[1].chan))
+				return CDS_DBS_DOWNGRADE;
+		} else {
+			if (new_band == cds_chan_to_band(
+					conc_connection_list[0].chan))
+				return CDS_MCC_UPGRADE;
+			else if (new_band != cds_chan_to_band(
+					conc_connection_list[0].chan))
+				return CDS_DBS_DOWNGRADE;
+		}
+	case 3:
+		/* If the band of the new channel, is same as that of the band
+		 * of the channel on the other two interfaces, the driver needs
+		 * to move to single MAC.
+		 *
+		 * If the band of the new channel, is different than that of the
+		 * band of the channel on the other two interfaces, the driver
+		 * needs to move to DBS.
+		 */
+		if (conn_index == 0) {
+			if ((new_band == cds_chan_to_band(
+					conc_connection_list[1].chan)) &&
+				(new_band == cds_chan_to_band(
+					conc_connection_list[2].chan)))
+				return CDS_MCC_UPGRADE;
+			else
+				return CDS_DBS_DOWNGRADE;
+		} else if (conn_index == 1) {
+			if ((new_band == cds_chan_to_band(
+					conc_connection_list[0].chan)) &&
+				(new_band == cds_chan_to_band(
+					conc_connection_list[2].chan)))
+				return CDS_MCC_UPGRADE;
+			else
+				return CDS_DBS_DOWNGRADE;
+		} else {
+			if ((new_band == cds_chan_to_band(
+					conc_connection_list[0].chan)) &&
+				(new_band == cds_chan_to_band(
+					conc_connection_list[1].chan)))
+				return CDS_MCC_UPGRADE;
+			else
+				return CDS_DBS_DOWNGRADE;
+		}
+	default:
+		cds_err("unexpected num_connections value %d",
+				num_connections);
+		return CDS_NOP;
+	}
+}

+ 2 - 0
core/mac/inc/sir_api.h

@@ -104,6 +104,7 @@ typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN];
  * @CDS_UPDATE_REASON_HIDDEN_STA: Connection to Hidden STA
  * @CDS_UPDATE_REASON_OPPORTUNISTIC: Opportunistic HW mode update
  * @CDS_UPDATE_REASON_NSS_UPDATE: NSS update
+ * @CDS_UPDATE_REASON_CHANNEL_SWITCH: Channel switch
  */
 enum cds_conn_update_reason {
 	CDS_UPDATE_REASON_SET_OPER_CHAN,
@@ -114,6 +115,7 @@ enum cds_conn_update_reason {
 	CDS_UPDATE_REASON_HIDDEN_STA,
 	CDS_UPDATE_REASON_OPPORTUNISTIC,
 	CDS_UPDATE_REASON_NSS_UPDATE,
+	CDS_UPDATE_REASON_CHANNEL_SWITCH,
 };
 
 typedef enum {

+ 153 - 7
core/sap/src/sap_api_link_cntl.c

@@ -48,9 +48,13 @@
 #include "qdf_trace.h"
 /* Pick up the CSR callback definition */
 #include "csr_api.h"
+#include "ani_global.h"
+#include "csr_inside_api.h"
 #include "sme_api.h"
 /* SAP Internal API header file */
 #include "sap_internal.h"
+#include "cds_concurrency.h"
+#include "wma.h"
 
 /*----------------------------------------------------------------------------
  * Preprocessor Definitions and Constants
@@ -495,8 +499,130 @@ wlansap_roam_process_ch_change_success(tpAniSirGlobal mac_ctx,
 }
 
 /**
- * wlansap_roam_process_dfs_chansw_update_fail() - handles the case for
- * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE in wlansap_roam_callback()
+ * wlansap_set_hw_mode_on_channel_switch() - Set hw mode before channel switch
+ * @sap_ctx: Global SAP context
+ * @target_channel: Target channel
+ *
+ * Sets hw mode, if needed, before doing a channel switch
+ *
+ * Return: None
+ */
+static QDF_STATUS wlansap_set_hw_mode_on_channel_switch(tpAniSirGlobal mac_ctx,
+		ptSapContext sap_ctx,
+		uint32_t target_channel)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE, qdf_status;
+	cds_context_type *cds_ctx;
+	enum cds_conc_next_action action;
+
+	cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
+	if (!cds_ctx) {
+		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+			FL("Invalid CDS Context"));
+		return status;
+	}
+
+	qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock);
+
+	action = cds_get_pref_hw_mode_for_chan(sap_ctx->sessionId,
+					target_channel);
+
+	if ((action != CDS_DBS_DOWNGRADE) && (action != CDS_MCC_UPGRADE)) {
+		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+			FL("Invalid action: %d"), action);
+		goto done;
+	}
+
+	QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
+			FL("action:%d session id:%d"),
+			action, sap_ctx->sessionId);
+
+	/* For MCC, opportunistic timer will be trigerred. We do not
+	 * want to do hw mode change here to avoid the ping pong effect.
+	 * e.g., If a new connection is immediately coming up, we could be
+	 * moving in and out of MCC. The timer after DBS_OPPORTUNISTIC_TIME
+	 * seconds will check if the driver can move to MCC or not.
+	 *
+	 * 1. Start opportunistic timer
+	 * 2. Do vdev restart on the new channel
+	 * 3. PM will check if MCC upgrade can be done after timer expiry
+	 */
+	if (action == CDS_MCC_UPGRADE) {
+		qdf_mc_timer_stop(&cds_ctx->dbs_opportunistic_timer);
+		qdf_status = qdf_mc_timer_start(
+				&cds_ctx->dbs_opportunistic_timer,
+				DBS_OPPORTUNISTIC_TIME *
+				1000);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+			QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+				FL("Failed to start dbs opportunistic timer"));
+		else
+			QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+				FL("opportunistic timer for MCC upgrade"));
+		goto done;
+	}
+
+	/* For DBS, we want to move right away to DBS mode. Else, we could
+	 * be doing MCC momentarily.
+	 *
+	 * 1. PM will initiate HW mode change to DBS rightaway
+	 * 2. Do vdev restart on the new channel
+	 */
+	status = cds_next_actions(sap_ctx->sessionId, action,
+				CDS_UPDATE_REASON_CHANNEL_SWITCH);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+			FL("no set hw mode command was issued"));
+		goto done;
+	}
+done:
+	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
+	/* success must be returned only when a set hw mode was done */
+	return status;
+}
+
+/**
+ * wlansap_update_hw_mode() - Set the hw mode for the new channel switch
+ * @hal: HAL pointer
+ * @sap_ctx: SAP context
+ *
+ * Sets the hw mode, if needed, for the driver based on the new channel
+ * to which the vdev is going to switch to
+ *
+ * Return: None
+ */
+void wlansap_update_hw_mode(tHalHandle hal, ptSapContext sap_ctx)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+	tCsrRoamInfo roam_info = {0};
+
+	if (mac_ctx->policy_manager_enabled &&
+				wma_is_hw_dbs_capable() == true) {
+		status = wlansap_set_hw_mode_on_channel_switch(mac_ctx, sap_ctx,
+				mac_ctx->sap.SapDfsInfo.target_channel);
+	}
+
+	QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
+			FL("status:%d"), status);
+
+	/*
+	 * If no set hw mode was done, proceed as before by doing set channel.
+	 * If set hw mode was done, perform the following in the callback so
+	 * that the set channel operations are done after the driver moves to
+	 * the required hw mode.
+	 */
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		csr_roam_call_callback(mac_ctx, sap_ctx->sessionId,
+			&roam_info, 0,
+			eCSR_ROAM_STATUS_UPDATE_HW_MODE,
+			eCSR_ROAM_RESULT_UPDATE_HW_MODE);
+	}
+}
+
+/**
+ * wlansap_roam_process_dfs_chansw_update() - handles the case for
+ * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS in wlansap_roam_callback()
  *
  * @hal:           hal global context
  * @sap_ctx:       sap context
@@ -505,7 +631,7 @@ wlansap_roam_process_ch_change_success(tpAniSirGlobal mac_ctx,
  * Return: void
  */
 static void
-wlansap_roam_process_dfs_chansw_update_fail(tHalHandle hHal,
+wlansap_roam_process_dfs_chansw_update(tHalHandle hHal,
 					    ptSapContext sap_ctx,
 					    QDF_STATUS *ret_status)
 {
@@ -531,8 +657,7 @@ wlansap_roam_process_dfs_chansw_update_fail(tHalHandle hHal,
 		return;
 	}
 	/*
-	 * Both success and failure cases are handled intentionally handled
-	 * together. Irrespective of whether the channel switch IE was sent out
+	 * Irrespective of whether the channel switch IE was sent out
 	 * successfully or not, SAP should still vacate the channel immediately
 	 */
 	if (eSAP_STARTED != sap_ctx->sapsMachine) {
@@ -965,6 +1090,10 @@ wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId,
 		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
 			  FL("Received Chan Sw Update Notification"));
 		break;
+	case eCSR_ROAM_STATUS_UPDATE_HW_MODE:
+		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
+			  FL("Received HW mode update notification"));
+		break;
 	case eCSR_ROAM_SET_CHANNEL_RSP:
 		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
 			  FL("Received set channel response"));
@@ -1180,8 +1309,25 @@ wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId,
 						&qdf_ret_status);
 		break;
 	case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS:
-	case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE:
-		wlansap_roam_process_dfs_chansw_update_fail(hal, sap_ctx,
+		/* eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS indicates the
+		 * completion of sending (E)CSA IEs. After these IEs are sent,
+		 * in eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS state, check
+		 * for DBS downgrade/MCC upgrade is done.
+		 * (1) From this state
+		 * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS, on MCC upgrade,
+		 * transition immediately happens to the state
+		 * eCSR_ROAM_RESULT_UPDATE_HW_MODE, where the vdev restart
+		 * happens internally.
+		 * (2) From this state,
+		 * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS, on DBS downgrade,
+		 * transition happens to the state
+		 * eCSR_ROAM_RESULT_UPDATE_HW_MODE to do vdev restart only after
+		 * SME received the set HW mode response.
+		 */
+		wlansap_update_hw_mode(hal, sap_ctx);
+		break;
+	case eCSR_ROAM_RESULT_UPDATE_HW_MODE:
+		wlansap_roam_process_dfs_chansw_update(hal, sap_ctx,
 						&qdf_ret_status);
 		break;
 	case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS:

+ 2 - 1
core/sme/inc/csr_api.h

@@ -497,6 +497,7 @@ typedef enum {
 	/* Channel sw update notification */
 	eCSR_ROAM_DFS_CHAN_SW_NOTIFY,
 	eCSR_ROAM_EXT_CHG_CHNL_IND,
+	eCSR_ROAM_STATUS_UPDATE_HW_MODE,
 } eRoamCmdStatus;
 
 /* comment inside indicates what roaming callback gets */
@@ -590,8 +591,8 @@ typedef enum {
 	eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS,
 	eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE,
 	eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS,
-	eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE,
 	eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND,
+	eCSR_ROAM_RESULT_UPDATE_HW_MODE,
 } eCsrRoamResult;
 
 /*----------------------------------------------------------------------------

+ 7 - 0
core/sme/src/common/sme_api.c

@@ -155,6 +155,7 @@ static QDF_STATUS sme_process_set_hw_mode_resp(tpAniSirGlobal mac, uint8_t *msg)
 	struct sir_set_hw_mode_resp *param;
 	enum cds_conn_update_reason reason;
 	tSmeCmd *saved_cmd;
+	tCsrRoamInfo roam_info = {0};
 
 	sms_log(mac, LOG1, FL("%s"), __func__);
 	param = (struct sir_set_hw_mode_resp *)msg;
@@ -227,6 +228,12 @@ static QDF_STATUS sme_process_set_hw_mode_resp(tpAniSirGlobal mac, uint8_t *msg)
 				saved_cmd = NULL;
 				mac->sme.saved_scan_cmd = NULL;
 			}
+		} else if (reason == CDS_UPDATE_REASON_CHANNEL_SWITCH) {
+			csr_roam_call_callback(mac,
+					command->u.set_hw_mode_cmd.session_id,
+					&roam_info, 0,
+					eCSR_ROAM_STATUS_UPDATE_HW_MODE,
+					eCSR_ROAM_RESULT_UPDATE_HW_MODE);
 		} else {
 			sms_log(mac, LOGE,
 			      FL("Calling HDD callback for HW mode response"));