diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 2f4be4dfd64a..4632a21a2cd4 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -2700,6 +2700,37 @@ enum dot11p_mode { #define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX (0x7fffffff) #define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT (60000) +/* + * Early stop scan is a feature for roaming to stop the scans at + * an early stage as soon as we find a better AP to roam. This + * would make the roaming happen quickly. + */ +#define CFG_EARLY_STOP_SCAN_ENABLE "gEnableEarlyStopScan" +#define CFG_EARLY_STOP_SCAN_ENABLE_MIN (0) +#define CFG_EARLY_STOP_SCAN_ENABLE_MAX (1) +#define CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT (0) +/* + * Early stop scan minimum threshold is the minimum threshold + * at which the candidate AP should be to be qualified as a + * potential roam candidate and good enough to stop the roaming scan + */ +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD "gEarlyStopScanMinThreshold" +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN (-60) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX (-40) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT (-45) +/* + * Early stop scan maximum threshold is the maximum threshold + * to be considered for stopping the scan. The algorithm starts + * with a scan on the greedy channel list with the minimum threshold + * and steps up the threshold by 20% for each further channel. + * It can step up on each channel but cannot exceed the maximum + * threshold. + */ +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD "gEarlyStopScanMaxThreshold" +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN (-80) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX (-70) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT (-78) + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -3264,6 +3295,9 @@ struct hdd_config { uint8_t stationary_thresh; uint32_t channel_prediction_full_scan; #endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; }; #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index bf57226f1c2c..4b13ed73b7f3 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -3517,6 +3517,29 @@ REG_TABLE_ENTRY g_registry_table[] = { CFG_SELF_GEN_FRM_PWR_MIN, CFG_SELF_GEN_FRM_PWR_MAX), + REG_VARIABLE(CFG_EARLY_STOP_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, early_stop_scan_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_MIN, + CFG_EARLY_STOP_SCAN_ENABLE_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_min_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_max_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX), + }; @@ -5050,6 +5073,16 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, pHddCtx->config->channel_prediction_full_scan); #endif + hddLog(LOGE, "Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_ENABLE, + pHddCtx->config->early_stop_scan_enable); + hddLog(LOGE, "Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + pHddCtx->config->early_stop_scan_min_threshold); + hddLog(LOGE, "Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + pHddCtx->config->early_stop_scan_max_threshold); + } @@ -6462,6 +6495,12 @@ CDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) (pHddCtx->config->dot11p_mode != WLAN_HDD_11P_DISABLED); hdd_set_pno_channel_prediction_config(smeConfig, pHddCtx); + smeConfig->early_stop_scan_enable = + pHddCtx->config->early_stop_scan_enable; + smeConfig->early_stop_scan_min_threshold = + pHddCtx->config->early_stop_scan_min_threshold; + smeConfig->early_stop_scan_max_threshold = + pHddCtx->config->early_stop_scan_max_threshold; status = sme_update_config(pHddCtx->hHal, smeConfig); if (!CDF_IS_STATUS_SUCCESS(status)) { hddLog(LOGE, "sme_update_config() return failure %d", diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 28b2e8a7b965..887901bc8bb0 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -2900,6 +2900,9 @@ typedef struct sSirRoamOffloadScanReq { uint32_t hi_rssi_scan_rssi_delta; uint32_t hi_rssi_scan_delay; int32_t hi_rssi_scan_rssi_ub; + uint8_t early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; } tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; typedef struct sSirRoamOffloadScanRsp { diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index caa878751c4f..365401784c6f 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -1269,6 +1269,9 @@ typedef struct tagCsrConfigParam { uint8_t stationary_thresh; uint32_t channel_prediction_full_scan; #endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; } tCsrConfigParam; /* Tush */ diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index d06b9e23103a..f4def8f0e579 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -651,6 +651,9 @@ typedef struct tagCsrConfig { uint8_t stationary_thresh; uint32_t channel_prediction_full_scan; #endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; } tCsrConfig; typedef struct tagCsrChannelPowerInfo { diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 7c20e05f5c92..863ea995f3a9 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -130,6 +130,9 @@ typedef struct _smeConfigParams { uint8_t stationary_thresh; uint32_t channel_prediction_full_scan; #endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; } tSmeConfigParams, *tpSmeConfigParams; #ifdef FEATURE_WLAN_TDLS diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 111433369f9b..c436ce546bab 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -1349,6 +1349,12 @@ CDF_STATUS sme_update_config(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams pSmeConfigParams->dual_mac_feature_disable; sme_update_roam_pno_channel_prediction_config(pMac, pSmeConfigParams, SME_CONFIG_TO_ROAM_CONFIG); + pMac->roam.configParam.early_stop_scan_enable = + pSmeConfigParams->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pSmeConfigParams->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pSmeConfigParams->early_stop_scan_max_threshold; return status; } @@ -4192,6 +4198,12 @@ CDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam) pMac->f_sta_miracast_mcc_rest_time_val; sme_update_roam_pno_channel_prediction_config(pMac, pParam, ROAM_CONFIG_TO_SME_CONFIG); + pParam->early_stop_scan_enable = + pMac->roam.configParam.early_stop_scan_enable; + pParam->early_stop_scan_min_threshold = + pMac->roam.configParam.early_stop_scan_min_threshold; + pParam->early_stop_scan_max_threshold = + pMac->roam.configParam.early_stop_scan_max_threshold; sme_release_global_lock(&pMac->sme); } diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 9074f37cae7c..f4dfbbe4a956 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -474,6 +474,121 @@ static tPowerdBm csr_find_channel_pwr(tChannelListWithPower * CDF_ASSERT(0); return 0; } +/** + * csr_roam_sort_channel_for_early_stop() - Sort the channels + * @chan_list: Original channel list from the upper layers + * @num_channel: Number of original channels + * + * For Early stop scan feature, the channel list should be in an order, + * where-in there is a maximum chance to detect an AP in the initial + * channels in the list so that the scanning can be stopped early as the + * feature demands. + * Below fixed greedy channel list has been provided + * based on most of the enterprise wifi installations across the globe. + * + * Identify all the greedy channels within the channel list from user space. + * Identify all the non-greedy channels in the user space channel list. + * Merge greedy channels followed by non-greedy channels back into the + * chan_list. + * + * Return: None + */ +void csr_roam_sort_channel_for_early_stop(tSirUpdateChanList *chan_list, + uint8_t num_channel) +{ + tSirUpdateChanList *chan_list_greedy, *chan_list_non_greedy; + uint8_t i, j; + static const uint8_t fixed_greedy_chan_list[] = {1, 6, 11, 36, 48, 40, + 44, 10, 2, 9, 149, 157, 161, 3, 4, 8, 153, 165, 7, 5, 136, 140, + 52, 116, 56, 104, 64, 60, 100, 120, 13, 14, 112, 132, 151, 155}; + uint8_t num_fixed_greedy_chan; + uint8_t num_greedy_chan = 0; + uint8_t num_non_greedy_chan = 0; + uint8_t match_found = false; + uint32_t buf_size; + + buf_size = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * num_channel); + chan_list_greedy = cdf_mem_malloc(buf_size); + chan_list_non_greedy = cdf_mem_malloc(buf_size); + if (!chan_list_greedy || !chan_list_non_greedy) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + return; + } + cdf_mem_zero(chan_list_greedy, buf_size); + cdf_mem_zero(chan_list_non_greedy, buf_size); + /* + * fixed_greedy_chan_list is an evaluated channel list based on most of + * the enterprise wifi deployments and the order of the channels + * determines the highest possibility of finding an AP. + * chan_list is the channel list provided by upper layers based on the + * regulatory domain. + */ + num_fixed_greedy_chan = sizeof(fixed_greedy_chan_list)/sizeof(uint8_t); + /* + * Browse through the chan_list and put all the non-greedy channels + * into a seperate list by name chan_list_non_greedy + */ + for (i = 0; i < num_channel; i++) { + for (j = 0; j < num_fixed_greedy_chan; j++) { + if (chan_list->chanParam[i].chanId == + fixed_greedy_chan_list[j]) { + match_found = true; + break; + } + } + if (!match_found) { + cdf_mem_copy( + &chan_list_non_greedy->chanParam[num_non_greedy_chan], + &chan_list->chanParam[i], + sizeof(tSirUpdateChanParam)); + num_non_greedy_chan++; + } else { + match_found = false; + } + } + /* + * Browse through the fixed_greedy_chan_list and put all the greedy + * channels in the chan_list into a seperate list by name + * chan_list_greedy + */ + for (i = 0; i < num_fixed_greedy_chan; i++) { + for (j = 0; j < num_channel; j++) { + if (fixed_greedy_chan_list[i] == + chan_list->chanParam[j].chanId) { + cdf_mem_copy( + &chan_list_greedy->chanParam[num_greedy_chan], + &chan_list->chanParam[j], + sizeof(tSirUpdateChanParam)); + num_greedy_chan++; + break; + } + } + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_DEBUG, + "greedy=%d, non-greedy=%d, tot=%d", + num_greedy_chan, num_non_greedy_chan, num_channel); + if ((num_greedy_chan + num_non_greedy_chan) != num_channel) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "incorrect sorting of channels"); + goto scan_list_sort_error; + } + /* Copy the Greedy channels first */ + i = 0; + cdf_mem_copy(&chan_list->chanParam[i], + &chan_list_greedy->chanParam[i], + num_greedy_chan * sizeof(tSirUpdateChanParam)); + /* Copy the remaining Non Greedy channels */ + i = num_greedy_chan; + j = 0; + cdf_mem_copy(&chan_list->chanParam[i], + &chan_list_non_greedy->chanParam[j], + num_non_greedy_chan * sizeof(tSirUpdateChanParam)); +scan_list_sort_error: + cdf_mem_free(chan_list_greedy); + cdf_mem_free(chan_list_non_greedy); +} CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) { @@ -532,6 +647,11 @@ CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) else pChanList->chanParam[num_channel].dfsSet = true; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "channel:%d, pwr=%d, DFS=%d\n", + pChanList->chanParam[num_channel].chanId, + pChanList->chanParam[num_channel].pwr, + pChanList->chanParam[num_channel].dfsSet); num_channel++; } } @@ -550,6 +670,11 @@ CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) } } } + if (pMac->roam.configParam.early_stop_scan_enable) + csr_roam_sort_channel_for_early_stop(pChanList, num_channel); + else + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Early Stop Scan Feature not supported")); msg.type = WMA_UPDATE_CHAN_LIST_REQ; msg.reserved = 0; @@ -1869,6 +1994,13 @@ CDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, pParam->sendDeauthBeforeCon; pMac->enable_dot11p = pParam->enable_dot11p; + pMac->roam.configParam.early_stop_scan_enable = + pParam->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pParam->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pParam->early_stop_scan_max_threshold; + } return status; @@ -16773,6 +16905,17 @@ csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, session); req_buf->allowDFSChannelRoam = mac_ctx->roam.configParam.allowDFSChannelRoam; + req_buf->early_stop_scan_enable = + mac_ctx->roam.configParam.early_stop_scan_enable; + req_buf->early_stop_scan_min_threshold = + mac_ctx->roam.configParam.early_stop_scan_min_threshold; + req_buf->early_stop_scan_max_threshold = + mac_ctx->roam.configParam.early_stop_scan_max_threshold; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("EarlyStopFeature Enable=%d, MinThresh=%d, MaxThresh=%d"), + req_buf->early_stop_scan_enable, + req_buf->early_stop_scan_min_threshold, + req_buf->early_stop_scan_max_threshold); #ifdef WLAN_FEATURE_ROAM_OFFLOAD req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx); req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled; diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 82627bc0757b..5716c52584ad 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -1122,6 +1122,7 @@ CDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, uint8_t *buf_ptr; wmi_roam_scan_rssi_threshold_fixed_param *rssi_threshold_fp; wmi_roam_scan_extended_threshold_param *ext_thresholds = NULL; + wmi_roam_earlystop_rssi_thres_param *early_stop_thresholds = NULL; struct roam_ext_params *roam_params; int32_t good_rssi_threshold; uint32_t hirssi_scan_max_count; @@ -1139,6 +1140,8 @@ CDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, len = sizeof(wmi_roam_scan_rssi_threshold_fixed_param); len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/ len += sizeof(wmi_roam_scan_extended_threshold_param); + len += WMI_TLV_HDR_SIZE; + len += sizeof(wmi_roam_earlystop_rssi_thres_param); buf = wmi_buf_alloc(wma_handle->wmi_handle, len); if (!buf) { WMA_LOGE("%s : wmi_buf_alloc failed", __func__); @@ -1209,6 +1212,27 @@ CDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, WMITLV_GET_STRUCT_TLVLEN (wmi_roam_scan_extended_threshold_param)); + buf_ptr += sizeof(wmi_roam_scan_extended_threshold_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_earlystop_rssi_thres_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + early_stop_thresholds = (wmi_roam_earlystop_rssi_thres_param *) buf_ptr; + early_stop_thresholds->roam_earlystop_thres_min = + roam_req->early_stop_scan_min_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + early_stop_thresholds->roam_earlystop_thres_max = + roam_req->early_stop_scan_max_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + WMITLV_SET_HDR(&early_stop_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_earlystop_rssi_thres_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_earlystop_rssi_thres_param)); + WMA_LOGD("early_stop_thresholds en=%d, min=%d, max=%d", + roam_req->early_stop_scan_enable, + early_stop_thresholds->roam_earlystop_thres_min, + early_stop_thresholds->roam_earlystop_thres_max); + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, WMI_ROAM_SCAN_RSSI_THRESHOLD); if (status != EOK) {