Browse Source

qcacld-3.0: Involve VDEV SM when STA switch channel width

When found AP channel width change from beacon:
    1. Set channel switch in progress with reason
	LIM_SWITCH_CHANNEL_HT_WIDTH, Send
	WLAN_VDEV_SM_EV_FW_VDEV_RESTART.
    2. Call lim_ht_switch_chnl_params in
        mlme_vdev_restart_send if reason is
	LIM_SWITCH_CHANNEL_HT_WIDTH, set ht width switch
	callback.
    3. Send WLAN_VDEV_SM_EV_RESTART_RESP in
        wma_vdev_start_resp_handler and clear channel switch in
	progress.
    4. Send WMA_SWITCH_CHANNEL_RSP in mlme_vdev_start_continue.
    5. Send WLAN_VDEV_SM_EV_START_SUCCESS in ht width switch
	callback to up vdev.

Change-Id: I46651e9aa17ebe049e44179d3a8fcc5a214762be
CRs-Fixed: 2372486
Jianmin Zhu 6 năm trước cách đây
mục cha
commit
f2de84f371

+ 1 - 0
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -3242,6 +3242,7 @@ void lim_process_switch_channel_rsp(struct mac_context *mac, void *body)
 		break;
 
 	case LIM_SWITCH_CHANNEL_OPERATION:
+	case LIM_SWITCH_CHANNEL_HT_WIDTH:
 		/*
 		 * The above code should also use the callback.
 		 * mechanism below, there is scope for cleanup here.

+ 1 - 0
core/mac/src/pe/lim/lim_types.h

@@ -160,6 +160,7 @@ enum eChannelChangeReasonCodes {
 	LIM_SWITCH_CHANNEL_JOIN,
 	LIM_SWITCH_CHANNEL_OPERATION,   /* Generic change channel */
 	LIM_SWITCH_CHANNEL_SAP_DFS,     /* DFS channel change */
+	LIM_SWITCH_CHANNEL_HT_WIDTH     /* HT channel width change */
 };
 
 typedef struct sLimAuthRspTimeout {

+ 158 - 51
core/mac/src/pe/lim/lim_utils.c

@@ -1953,18 +1953,21 @@ lim_decide_sta_protection(struct mac_context *mac_ctx,
  *
  *
  ***NOTE:
- * @param  mac           - Pointer to Global MAC structure
+ * @param  pe_session           - Pointer to pe session
  * @return None
  */
-static void __lim_process_channel_switch_timeout(struct mac_context *mac)
+static void __lim_process_channel_switch_timeout(struct pe_session *pe_session)
 {
-	struct pe_session *pe_session = NULL;
+	struct mac_context *mac;
 	uint8_t channel; /* This is received and stored from channelSwitch Action frame */
 
-	pe_session = pe_find_session_by_session_id(mac,
-			mac->lim.limTimers.gLimChannelSwitchTimer.sessionId);
-	if (pe_session == NULL) {
-		pe_err("Session Does not exist for given sessionID");
+	if (!pe_session) {
+		pe_err("Invalid pe session");
+		return;
+	}
+	mac = pe_session->mac_ctx;
+	if (!mac) {
+		pe_err("Invalid mac context");
 		return;
 	}
 
@@ -2072,18 +2075,24 @@ void lim_disconnect_complete(struct pe_session *session, bool del_bss)
 
 void lim_process_channel_switch_timeout(struct mac_context *mac_ctx)
 {
-	struct pe_session *session_entry = NULL;
+	struct pe_session *session_entry;
 	QDF_STATUS status;
 
 	session_entry = pe_find_session_by_session_id(
 		mac_ctx,
 		mac_ctx->lim.limTimers.gLimChannelSwitchTimer.sessionId);
+	if (!session_entry) {
+		pe_err("Session does not exist for given sessionID");
+		return;
+	}
+
+	session_entry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION;
 	mlme_set_chan_switch_in_progress(session_entry->vdev, true);
 	status = wlan_vdev_mlme_sm_deliver_evt(
 					session_entry->vdev,
 					WLAN_VDEV_SM_EV_FW_VDEV_RESTART,
-					sizeof(*mac_ctx),
-					mac_ctx);
+					sizeof(*session_entry),
+					session_entry);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		pe_err("Failed to post WLAN_VDEV_SM_EV_FW_VDEV_RESTART for vdevid %d",
 		       session_entry->smeSessionId);
@@ -2103,9 +2112,19 @@ void lim_disconnect_complete(struct pe_session *session, bool del_bss)
  *
  * Return: none
  */
-void lim_process_channel_switch_timeout(struct mac_context *mac)
+void lim_process_channel_switch_timeout(struct mac_context *mac_ctx)
 {
-	__lim_process_channel_switch_timeout(mac);
+	struct pe_session *session_entry;
+
+	session_entry = pe_find_session_by_session_id(
+		mac_ctx,
+		mac_ctx->lim.limTimers.gLimChannelSwitchTimer.sessionId);
+	if (!session_entry) {
+		pe_err("Session does not exist for given sessionID");
+		return;
+	}
+
+	__lim_process_channel_switch_timeout(session_entry);
 }
 #endif
 
@@ -3993,6 +4012,103 @@ QDF_STATUS lim_tx_complete(void *context, qdf_nbuf_t buf, bool free)
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef CONFIG_VDEV_SM
+static void lim_ht_width_switch_cback(struct mac_context *mac,
+				QDF_STATUS status, uint32_t *data,
+				struct pe_session *pe_session)
+{
+	pe_debug("status %d for ht width switch for vdev %d", status,
+		 pe_session->smeSessionId);
+	if (QDF_IS_STATUS_SUCCESS(status))
+		lim_switch_channel_vdev_started(pe_session);
+}
+#else
+static void lim_ht_width_switch_cback(struct mac_context *mac,
+				QDF_STATUS status, uint32_t *data,
+				struct pe_session *pe_session)
+{
+	pe_debug("status %d for ht width switch for vdev %d", status,
+		 pe_session->smeSessionId);
+}
+#endif
+
+static void lim_ht_switch_chnl_params(struct pe_session *pe_session)
+{
+	uint8_t center_freq = 0;
+	enum phy_ch_width ch_width = CH_WIDTH_20MHZ;
+	struct mac_context *mac;
+	uint8_t primary_channel;
+
+	mac = pe_session->mac_ctx;
+	if (!mac) {
+		pe_err("Invalid mac_ctx");
+		return;
+	}
+
+	primary_channel = pe_session->gLimChannelSwitch.primaryChannel;
+	if (eHT_CHANNEL_WIDTH_40MHZ ==
+	    pe_session->htRecommendedTxWidthSet) {
+		ch_width = CH_WIDTH_40MHZ;
+		if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY ==
+		    pe_session->htSecondaryChannelOffset)
+			center_freq = primary_channel + 2;
+		else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY ==
+			 pe_session->htSecondaryChannelOffset)
+			center_freq = primary_channel - 2;
+		else
+			ch_width = CH_WIDTH_20MHZ;
+	}
+
+	/* notify HAL */
+	pe_debug("HT IE changed: Primary Channel: %d Secondary Channel Offset: %d Channel Width: %d",
+		 primary_channel, center_freq,
+		 pe_session->htRecommendedTxWidthSet);
+	pe_session->channelChangeReasonCode =
+			LIM_SWITCH_CHANNEL_HT_WIDTH;
+	mac->lim.gpchangeChannelCallback = lim_ht_width_switch_cback;
+	mac->lim.gpchangeChannelData = NULL;
+
+	lim_send_switch_chnl_params(mac, primary_channel,
+				    center_freq, 0, ch_width,
+				    pe_session->maxTxPower,
+				    pe_session->peSessionId,
+				    true, 0, 0);
+}
+
+#ifdef CONFIG_VDEV_SM
+static void lim_ht_switch_chnl_req(struct pe_session *session)
+{
+	struct mac_context *mac;
+	QDF_STATUS status;
+
+	mac = session->mac_ctx;
+	if (!mac) {
+		pe_err("Invalid mac context");
+		return;
+	}
+
+	session->channelChangeReasonCode =
+			LIM_SWITCH_CHANNEL_HT_WIDTH;
+	mlme_set_chan_switch_in_progress(session->vdev, true);
+	status = wlan_vdev_mlme_sm_deliver_evt(
+					session->vdev,
+					WLAN_VDEV_SM_EV_FW_VDEV_RESTART,
+					sizeof(*session),
+					session);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to post WLAN_VDEV_SM_EV_FW_VDEV_RESTART for vdevid %d",
+		       session->smeSessionId);
+		mlme_set_chan_switch_in_progress(session->vdev, false);
+	}
+}
+#else
+static void lim_ht_switch_chnl_req(struct pe_session *session)
+{
+	lim_ht_switch_chnl_params(session);
+}
+#endif
+
+
 /**
  * \brief This function updates lim global structure, if CB parameters in the BSS
  *  have changed, and sends an indication to HAL also with the
@@ -4018,9 +4134,6 @@ void lim_update_sta_run_time_ht_switch_chnl_params(struct mac_context *mac,
 						   uint8_t bssIdx,
 						   struct pe_session *pe_session)
 {
-	uint8_t center_freq = 0;
-	enum phy_ch_width ch_width = CH_WIDTH_20MHZ;
-
 	/* If self capability is set to '20Mhz only', then do not change the CB mode. */
 	if (!lim_get_ht_capability
 		    (mac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, pe_session))
@@ -4047,51 +4160,29 @@ void lim_update_sta_run_time_ht_switch_chnl_params(struct mac_context *mac,
 		return;
 	}
 
+	/* If channel mismatch the CSA will take care of this change */
+	if (pHTInfo->primaryChannel != pe_session->currentOperChannel) {
+		pe_debug("Current channel doesnt match HT info ignore");
+		return;
+	}
+
 	if (pe_session->htSecondaryChannelOffset !=
 	    (uint8_t) pHTInfo->secondaryChannelOffset
 	    || pe_session->htRecommendedTxWidthSet !=
 	    (uint8_t) pHTInfo->recommendedTxWidthSet) {
+		pe_session->gLimChannelSwitch.primaryChannel =
+							pHTInfo->primaryChannel;
 		pe_session->htSecondaryChannelOffset =
 			(ePhyChanBondState) pHTInfo->secondaryChannelOffset;
 		pe_session->htRecommendedTxWidthSet =
 			(uint8_t) pHTInfo->recommendedTxWidthSet;
-		if (eHT_CHANNEL_WIDTH_40MHZ ==
-		    pe_session->htRecommendedTxWidthSet) {
-			ch_width = CH_WIDTH_40MHZ;
-			if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY ==
-					pHTInfo->secondaryChannelOffset)
-				center_freq = pHTInfo->primaryChannel + 2;
-			else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY ==
-					pHTInfo->secondaryChannelOffset)
-				center_freq = pHTInfo->primaryChannel - 2;
-			else
-				ch_width = CH_WIDTH_20MHZ;
-		}
-
-		/* notify HAL */
-		pe_debug("Channel Information in HT IE change"
-				       "d; sending notification to HAL.");
-		pe_debug("Primary Channel: %d Secondary Chan"
-				       "nel Offset: %d Channel Width: %d",
-			pHTInfo->primaryChannel, center_freq,
-			pe_session->htRecommendedTxWidthSet);
-		pe_session->channelChangeReasonCode =
-			LIM_SWITCH_CHANNEL_OPERATION;
-		mac->lim.gpchangeChannelCallback = NULL;
-		mac->lim.gpchangeChannelData = NULL;
-
-		lim_send_switch_chnl_params(mac, (uint8_t) pHTInfo->primaryChannel,
-					    center_freq, 0, ch_width,
-					    pe_session->maxTxPower,
-					    pe_session->peSessionId,
-					    true, 0, 0);
+		lim_ht_switch_chnl_req(pe_session);
 
 		/* In case of IBSS, if STA should update HT Info IE in its beacons. */
-		if (LIM_IS_IBSS_ROLE(pe_session)) {
+		if (LIM_IS_IBSS_ROLE(pe_session))
 			sch_set_fixed_beacon_fields(mac, pe_session);
-		}
-
 	}
+
 } /* End limUpdateStaRunTimeHTParams. */
 
 /**
@@ -7981,6 +8072,13 @@ QDF_STATUS lim_sta_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme,
 QDF_STATUS lim_sta_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme,
 					  uint16_t data_len, void *data)
 {
+	struct pe_session *session;
+
+	session = (struct pe_session *)data;
+	if (!session) {
+		pe_err("Invalid session");
+		return QDF_STATUS_E_INVAL;
+	}
 	if (!vdev_mlme) {
 		pe_err("vdev_mlme is NULL");
 		return QDF_STATUS_E_INVAL;
@@ -7989,9 +8087,18 @@ QDF_STATUS lim_sta_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme,
 		pe_err("event_data is NULL");
 		return QDF_STATUS_E_INVAL;
 	}
-	if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev))
-		__lim_process_channel_switch_timeout((struct mac_context *)data);
-
+	if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) {
+		switch (session->channelChangeReasonCode) {
+		case LIM_SWITCH_CHANNEL_OPERATION:
+			__lim_process_channel_switch_timeout(session);
+			break;
+		case LIM_SWITCH_CHANNEL_HT_WIDTH:
+			lim_ht_switch_chnl_params(session);
+			break;
+		default:
+			break;
+		}
+	}
 	return QDF_STATUS_SUCCESS;
 }