diff --git a/core/cds/inc/cds_concurrency.h b/core/cds/inc/cds_concurrency.h index 68622922ce47..87706bb09b3d 100644 --- a/core/cds/inc/cds_concurrency.h +++ b/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 */ diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h index f76ae48aeada..43a3b727d3fa 100644 --- a/core/cds/inc/cds_sched.h +++ b/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; /*--------------------------------------------------------------------------- diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c index 1d8d1efd7023..aba4e5288001 100644 --- a/core/cds/src/cds_concurrency.c +++ b/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; +} diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 220e6e6b457a..9eb174eb3139 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/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; } diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 8eac2daa650f..40a948f3d83b 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/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); diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 0775c69f04f0..9483a1e66d56 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/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; } diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 9133a7fb0930..7fe6ab1aa6f3 100644 --- a/core/wma/inc/wma_api.h +++ b/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, diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 8350bf699e9b..75c11a949728 100644 --- a/core/wma/src/wma_utils.c +++ b/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