Quellcode durchsuchen

qcacld-3.0: Avoid new connection while HW mode change is issued

In the case of concurrency, when the session decrements, the
opportunistic timer is started. After a while, when the
opportunistic time is expired, and the hw mode change for SMM
is issued, and the same time new interface comes up, then the
new forms MCC with the existing connection instead of forming
DBS.

The change is to avoid the race condition to form MCC instead of
DBS.

Change-Id: I977039138509676b964ba089e3cb479cd16968bb
CRs-Fixed: 2006350
Nitesh Shah vor 8 Jahren
Ursprung
Commit
a3dfea3ebb

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

@@ -675,6 +675,24 @@ enum cds_band {
 	CDS_MAX_BAND
 };
 
+/**
+ * enum cds_hw_mode_change - identify the HW mode switching to.
+ *
+ * @CDS_HW_MODE_NOT_IN_PROGRESS: HW mode change not in progress
+ * @CDS_SMM_IN_PROGRESS: switching to SMM mode
+ * @CDS_DBS_IN_PROGRESS: switching to DBS mode
+ * @CDS_SBS_IN_PROGRESS: switching to SBS mode
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum cds_hw_mode_change {
+	CDS_HW_MODE_NOT_IN_PROGRESS = 0,
+	CDS_SMM_IN_PROGRESS,
+	CDS_DBS_IN_PROGRESS,
+	CDS_SBS_IN_PROGRESS
+};
+
 /**
  * struct cds_conc_connection_info - information of all existing
  * connections in the wlan system
@@ -968,4 +986,6 @@ void cds_hw_mode_transition_cb(uint32_t old_hw_mode_index,
 			uint32_t new_hw_mode_index,
 			uint32_t num_vdev_mac_entries,
 			 struct sir_vdev_mac_map *vdev_mac_map);
+void cds_set_hw_mode_change_in_progress(enum cds_hw_mode_change value);
+enum cds_hw_mode_change cds_is_hw_mode_change_in_progress(void);
 #endif /* __CDS_CONCURRENCY_H */

+ 3 - 0
core/cds/inc/cds_sched.h

@@ -242,6 +242,9 @@ typedef struct _cds_context_type {
 	bool do_hw_mode_change;
 	bool enable_fatal_event;
 	struct cds_config_info *cds_cfg;
+
+	/* This is to track if HW mode change is in progress */
+	uint32_t hw_mode_change_in_progress;
 } cds_context_type, *p_cds_contextType;
 
 /*---------------------------------------------------------------------------

+ 58 - 0
core/cds/src/cds_concurrency.c

@@ -654,6 +654,8 @@ static void cds_pdev_set_hw_mode_cb(uint32_t status,
 	struct sir_hw_mode_params hw_mode;
 	uint32_t i;
 
+	cds_set_hw_mode_change_in_progress(CDS_HW_MODE_NOT_IN_PROGRESS);
+
 	if (status != SET_HW_MODE_STATUS_OK) {
 		cds_err("Set HW mode failed with status %d", status);
 		return;
@@ -2308,6 +2310,7 @@ QDF_STATUS cds_init_policy_mgr(struct cds_sme_cbacks *sme_cbacks)
 	}
 
 	cds_ctx->do_hw_mode_change = false;
+	cds_ctx->hw_mode_change_in_progress = CDS_HW_MODE_NOT_IN_PROGRESS;
 	cds_ctx->sme_get_valid_channels = sme_cbacks->sme_get_valid_channels;
 	cds_ctx->sme_get_nss_for_vdev = sme_cbacks->sme_get_nss_for_vdev;
 
@@ -8308,3 +8311,58 @@ bool cds_is_hw_mode_change_after_vdev_up(void)
 
 	return flag;
 }
+
+/**
+ * cds_set_hw_mode_change_in_progress() - Set value corresponding to
+ * cds_hw_mode_change that indicate if HW mode change is in progress
+ * @value: Indicate if hw mode change is in progress
+ *
+ * Set the value corresponding to cds_hw_mode_change that
+ * indicated if hw mode change is in progress.
+ *
+ * Return: None
+ */
+void cds_set_hw_mode_change_in_progress(enum cds_hw_mode_change value)
+{
+	cds_context_type *cds_ctx;
+	cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
+
+	if (!cds_ctx) {
+		cds_err("Invalid CDS Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock);
+	cds_ctx->hw_mode_change_in_progress = value;
+	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
+
+	cds_debug("hw_mode_change_in_progress:%d", value);
+}
+
+/**
+ * cds_is_hw_mode_change_in_progress() - Check if HW mode change is in
+ * progress.
+ *
+ * Returns the corresponding cds_hw_mode_change value.
+ *
+ * Return: cds_hw_mode_change value.
+ */
+enum cds_hw_mode_change cds_is_hw_mode_change_in_progress(void)
+{
+	cds_context_type *cds_ctx;
+	enum cds_hw_mode_change value;
+	value = CDS_HW_MODE_NOT_IN_PROGRESS;
+
+	cds_ctx = cds_get_context(QDF_MODULE_ID_QDF);
+
+	if (!cds_ctx) {
+		cds_err("Invalid CDS Context");
+		return value;
+	}
+
+	qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock);
+	value = cds_ctx->hw_mode_change_in_progress;
+	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
+
+	return value;
+}

+ 50 - 13
core/hdd/src/wlan_hdd_cfg80211.c

@@ -12819,11 +12819,18 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 
 	status = wlan_hdd_validate_context(pHddCtx);
 	if (status)
-		return status;
+		goto ret_status;
 
 	if (SIR_MAC_MAX_SSID_LENGTH < ssid_len) {
 		hdd_err("wrong SSID len");
-		return -EINVAL;
+		status = -EINVAL;
+		goto ret_status;
+	}
+
+	if (true == cds_is_connection_in_progress()) {
+		hdd_err("Connection refused: conn in progress");
+		status = -EINVAL;
+		goto ret_status;
 	}
 
 	pRoamProfile = &pWextState->roamProfile;
@@ -12834,6 +12841,24 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 		hdd_station_ctx_t *pHddStaCtx;
 		pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
 
+		/* Restart the opportunistic timer
+		 *
+		 * If hw_mode_change_in_progress is true, then wait
+		 * till firmware sends the callback for hw_mode change.
+		 *
+		 * Else set connect_in_progress as true and proceed.
+		 */
+		cds_restart_opportunistic_timer(false);
+		if (cds_is_hw_mode_change_in_progress()) {
+			status = qdf_wait_for_connection_update();
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				hdd_err("qdf wait for event failed!!");
+				status = -EINVAL;
+				goto ret_status;
+			}
+		}
+		cds_set_connection_in_progress(true);
+
 		if (HDD_WMM_USER_MODE_NO_QOS ==
 		    (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) {
 			/*QoS not enabled in cfg file */
@@ -12965,7 +12990,8 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 
 			if (QDF_STATUS_SUCCESS != status) {
 				hdd_err("Set IBSS Power Save Params Failed");
-				return -EINVAL;
+				status = -EINVAL;
+				goto conn_failure;
 			}
 			pRoamProfile->ch_params.ch_width =
 				hdd_map_nl_chan_width(ch_width);
@@ -12991,12 +13017,9 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 					pWextState->roamProfile.MFPEnabled,
 					pWextState->roamProfile.MFPRequired,
 					pWextState->roamProfile.MFPCapable);
-			return -EINVAL;
-		}
 
-		if (true == cds_is_connection_in_progress()) {
-			hdd_err("Connection refused: conn in progress");
-			return -EINVAL;
+			status = -EINVAL;
+			goto conn_failure;
 		}
 
 		/*
@@ -13023,8 +13046,10 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 		if (wma_is_hw_dbs_capable() == false) {
 			cds_handle_conc_rule1(pAdapter, pRoamProfile);
 			if (true != cds_handle_conc_rule2(
-					pAdapter, pRoamProfile, &roamId))
-				return 0;
+					pAdapter, pRoamProfile, &roamId)) {
+				status = 0;
+				goto conn_failure;
+			}
 		}
 
 		if ((wma_is_hw_dbs_capable() == true) &&
@@ -13033,7 +13058,8 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 			hdd_err("sap-sta conc will fail, can't allow sta");
 			hdd_conn_set_connection_state(pAdapter,
 					eConnectionState_NotConnected);
-			return -ENOMEM;
+			status = -ENOMEM;
+			goto conn_failure;
 		}
 
 		sme_config = qdf_mem_malloc(sizeof(*sme_config));
@@ -13041,7 +13067,8 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 			hdd_err("unable to allocate sme_config");
 			hdd_conn_set_connection_state(pAdapter,
 					eConnectionState_NotConnected);
-			return -ENOMEM;
+			status = -ENOMEM;
+			goto conn_failure;
 		}
 		sme_get_config_param(pHddCtx->hHal, sme_config);
 		/* These values are not sessionized. So, any change in these SME
@@ -13100,6 +13127,9 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 						     connect);
 		}
 
+		/* Reset connect_in_progress */
+		cds_set_connection_in_progress(false);
+
 		pRoamProfile->ChannelInfo.ChannelList = NULL;
 		pRoamProfile->ChannelInfo.numOfChannels = 0;
 
@@ -13114,8 +13144,15 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
 
 	} else {
 		hdd_err("No valid Roam profile");
-		return -EINVAL;
+		status = -EINVAL;
 	}
+	goto ret_status;
+
+conn_failure:
+	/* Reset connect_in_progress */
+	cds_set_connection_in_progress(false);
+
+ret_status:
 	EXIT();
 	return status;
 }

+ 16 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -7218,6 +7218,14 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
 		return -EINVAL;
 	}
 
+	if (cds_is_hw_mode_change_in_progress()) {
+		status = qdf_wait_for_connection_update();
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			hdd_err("qdf wait for event failed!!");
+			return -EINVAL;
+		}
+	}
+
 	iniConfig = pHddCtx->config;
 	pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter);
 
@@ -8082,6 +8090,14 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 		return -EBUSY;
 	}
 
+	if (cds_is_hw_mode_change_in_progress()) {
+		status = qdf_wait_for_connection_update();
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			hdd_err("qdf wait for event failed!!");
+			return -EINVAL;
+		}
+	}
+
 	channel_width = wlan_hdd_get_channel_bw(params->chandef.width);
 	channel = ieee80211_frequency_to_channel(
 				params->chandef.chan->center_freq);

+ 18 - 0
core/sme/src/csr/csr_api_roam.c

@@ -19342,6 +19342,7 @@ void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command)
 	QDF_STATUS status;
 	struct scheduler_msg msg;
 	struct sir_set_hw_mode_resp *param;
+	enum cds_hw_mode_change cds_hw_mode;
 
 	/* Setting HW mode is for the entire system.
 	 * So, no need to check session
@@ -19375,6 +19376,22 @@ void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command)
 		}
 	}
 
+	if ((SIR_UPDATE_REASON_OPPORTUNISTIC ==
+	     command->u.set_hw_mode_cmd.reason) &&
+	    (true == cds_is_connection_in_progress())) {
+		sms_log(mac, LOGE, FL("Set HW mode refused: conn in progress"));
+		cds_restart_opportunistic_timer(false);
+		goto fail;
+	}
+
+	cds_hw_mode = wma_get_cds_hw_mode_change_from_hw_mode_index(
+				command->u.set_hw_mode_cmd.hw_mode_index);
+
+	if (CDS_HW_MODE_NOT_IN_PROGRESS == cds_hw_mode)
+		goto fail;
+
+	cds_set_hw_mode_change_in_progress(cds_hw_mode);
+
 	cmd->messageType = eWNI_SME_SET_HW_MODE_REQ;
 	cmd->length = len;
 	cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index;
@@ -19392,6 +19409,7 @@ void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command)
 
 	status = umac_send_mb_message_to_mac(cmd);
 	if (QDF_STATUS_SUCCESS != status) {
+		cds_set_hw_mode_change_in_progress(CDS_HW_MODE_NOT_IN_PROGRESS);
 		sms_log(mac, LOGE, FL("Posting to PE failed"));
 		return;
 	}

+ 3 - 0
core/wma/inc/wma_api.h

@@ -200,6 +200,9 @@ void wma_set_dbs_capability_ut(uint32_t dbs);
 QDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs);
 QDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode);
 bool wma_is_dbs_enable(void);
+enum cds_hw_mode_change
+wma_get_cds_hw_mode_change_from_hw_mode_index(uint32_t hw_mode_index);
+
 QDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config,
 		bool dbs_scan,
 		bool dbs_plus_agile_scan,

+ 45 - 0
core/wma/src/wma_utils.c

@@ -3108,6 +3108,51 @@ bool wma_is_hw_sbs_capable(void)
 	return true;
 }
 
+/*
+ * wma_get_cds_hw_mode_change_from_hw_mode_index - Returns value in terms of
+ * cds_hw_mode_change enums derived from hw_mode_index.
+ *
+ * Returns cds_hw_mode_change value derived from hw_mode_index.
+ *
+ * Return: value in terms of cds_hw_mode_change enums.
+ */
+enum cds_hw_mode_change
+wma_get_cds_hw_mode_change_from_hw_mode_index(uint32_t hw_mode_index)
+{
+	tp_wma_handle wma;
+	uint32_t param = 0;
+	enum cds_hw_mode_change value = CDS_HW_MODE_NOT_IN_PROGRESS;
+
+	wma = cds_get_context(QDF_MODULE_ID_WMA);
+	if (!wma) {
+		WMA_LOGE("%s: Invalid WMA handle", __func__);
+		goto ret_value;
+	}
+
+	WMA_LOGI("%s: HW param: %x", __func__, param);
+
+	param = wma->hw_mode.hw_mode_list[hw_mode_index];
+	if (WMA_HW_MODE_DBS_MODE_GET(param)) {
+		WMA_LOGI("%s: DBS is requested with HW (%d)", __func__,
+			 hw_mode_index);
+		value = CDS_DBS_IN_PROGRESS;
+		goto ret_value;
+	}
+
+	if (WMA_HW_MODE_SBS_MODE_GET(param)) {
+		WMA_LOGI("%s: SBS is requested with HW (%d)", __func__,
+			 hw_mode_index);
+		value = CDS_SBS_IN_PROGRESS;
+		goto ret_value;
+	}
+
+	value = CDS_SMM_IN_PROGRESS;
+	WMA_LOGI("%s: SMM is requested with HW (%d)", __func__,
+		 hw_mode_index);
+ret_value:
+	return value;
+}
+
 /**
  * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev
  * @vdev_id: VDEV whose MAC ID is required