diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index c078f75f18..2836204c0f 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1460,6 +1460,9 @@ struct hdd_context_s { #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE qdf_mc_timer_t skip_acs_scan_timer; uint8_t skip_acs_scan_status; + uint8_t *last_acs_channel_list; + uint8_t num_of_channels; + qdf_spinlock_t acs_skip_lock; #endif qdf_wake_lock_t sap_dfs_wakelock; diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index ed07c2b2b9..804b5e4732 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -961,6 +961,78 @@ static void wlan_hdd_sap_pre_cac_success(void *data) } } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_event: tpSap_Event + * @adapter: hdd_adapter_t for SAP + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * It will update scan result to cfg80211 and start a timer to flush the + * cached acs scan result. + * + * Return: QDF_STATUS_SUCCESS on success, + * other value on failure + */ +static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event, + hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx; + struct sap_acs_scan_complete_event *comp_evt; + QDF_STATUS qdf_status; + int chan_list_size; + + hdd_ctx = (hdd_context_t *)(adapter->pHddCtx); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + comp_evt = &sap_event->sapevt.sap_acs_scan_comp; + hdd_ctx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + /* cache the previous ACS scan channel list . + * If the following OBSS scan chan list is covered by ACS chan list, + * we can skip OBSS Scan to save SAP starting total time. + */ + if (comp_evt->num_of_channels && comp_evt->channellist) { + chan_list_size = comp_evt->num_of_channels * + sizeof(comp_evt->channellist[0]); + hdd_ctx->last_acs_channel_list = qdf_mem_malloc( + chan_list_size); + if (hdd_ctx->last_acs_channel_list) { + qdf_mem_copy(hdd_ctx->last_acs_channel_list, + comp_evt->channellist, + chan_list_size); + hdd_ctx->num_of_channels = comp_evt->num_of_channels; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + /* Update ACS scan result to cfg80211. Then OBSS scan can reuse the + * scan result. + */ + if (wlan_hdd_cfg80211_update_bss(hdd_ctx->wiphy, adapter, 0)) + hdd_info("NO SCAN result"); + + hdd_info("Reusing Last ACS scan result for %d sec", + ACS_SCAN_EXPIRY_TIMEOUT_S); + qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + qdf_status = qdf_mc_timer_start(&hdd_ctx->skip_acs_scan_timer, + ACS_SCAN_EXPIRY_TIMEOUT_S * 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to start ACS scan expiry timer"); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event, + hdd_adapter_t *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, void *usrDataForCallback) { @@ -1880,21 +1952,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, return hdd_chan_change_notify(pHostapdAdapter, dev, chan_change); } - -#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE case eSAP_ACS_SCAN_SUCCESS_EVENT: - pHddCtx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN; - hdd_notice("Reusing Last ACS scan result for %d sec", - ACS_SCAN_EXPIRY_TIMEOUT_S); - qdf_mc_timer_stop(&pHddCtx->skip_acs_scan_timer); - qdf_status = qdf_mc_timer_start(&pHddCtx->skip_acs_scan_timer, - ACS_SCAN_EXPIRY_TIMEOUT_S * - 1000); - if (!QDF_IS_STATUS_SUCCESS(qdf_status)) - hdd_err("Failed to start ACS scan expiry timer"); - return QDF_STATUS_SUCCESS; -#endif - + return hdd_handle_acs_scan_event(pSapEvent, pHostapdAdapter); case eSAP_DFS_NOL_GET: hdd_notice("Received eSAP_DFS_NOL_GET event"); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 06684bd596..7cd0c0a44c 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4839,6 +4839,11 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx) (qdf_mc_timer_destroy(&hdd_ctx->skip_acs_scan_timer))) { hdd_err("Cannot deallocate ACS Skip timer"); } + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); #endif mutex_lock(&hdd_ctx->iface_change_lock); @@ -4945,12 +4950,27 @@ void __hdd_wlan_exit(void) } #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_skip_acs_scan_timer_handler() - skip ACS scan timer timeout handler + * @data: pointer to hdd_context_t + * + * This function will reset acs_scan_status to eSAP_DO_NEW_ACS_SCAN. + * Then new ACS request will do a fresh scan without reusing the cached + * scan information. + * + * Return: void + */ void hdd_skip_acs_scan_timer_handler(void *data) { hdd_context_t *hdd_ctx = (hdd_context_t *) data; hdd_notice("ACS Scan result expired. Reset ACS scan skip"); hdd_ctx->skip_acs_scan_status = eSAP_DO_NEW_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); if (!hdd_ctx->hHal) return; @@ -8098,6 +8118,7 @@ int hdd_wlan_startup(struct device *dev) (void *)hdd_ctx); if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("Failed to init ACS Skip timer"); + qdf_spinlock_create(&hdd_ctx->acs_skip_lock); #endif hdd_bus_bandwidth_init(hdd_ctx); diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index facbc2f508..83f1601a87 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -1294,6 +1294,65 @@ allow_suspend: return 0; } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * wlan_hdd_sap_skip_scan_check() - The function will check OBSS + * scan skip or not for SAP. + * @hdd_ctx: pointer to hdd context. + * @request: pointer to scan request. + * + * This function will check the scan request's chan list against the + * previous ACS scan chan list. If all the chan are covered by + * previous ACS scan, we can skip the scan and return scan complete + * to save the SAP starting time. + * + * Return: true to skip the scan, + * false to continue the scan + */ +static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx, + struct cfg80211_scan_request *request) +{ + int i, j; + bool skip; + + hdd_info("HDD_ACS_SKIP_STATUS = %d", + hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN) + return false; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + if (hdd_ctx->last_acs_channel_list == NULL || + hdd_ctx->num_of_channels == 0 || + request->n_channels == 0) { + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return false; + } + skip = true; + for (i = 0; i < request->n_channels ; i++) { + bool find = false; + for (j = 0; j < hdd_ctx->num_of_channels; j++) { + if (hdd_ctx->last_acs_channel_list[j] == + request->channels[i]->hw_value) { + find = true; + break; + } + } + if (!find) { + skip = false; + hdd_info("Chan %d isn't in ACS chan list", + request->channels[i]->hw_value); + break; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return skip; +} +#else +static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx, + struct cfg80211_scan_request *request) +{ + return false; +} +#endif /** * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler @@ -1483,6 +1542,7 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, * If we return scan failure hostapd fails secondary AP * startup. */ + hdd_err("##In DFS Master mode. Scan aborted"); pAdapter->request = request; INIT_WORK(&pAdapter->scan_block_work, @@ -1536,6 +1596,16 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, hdd_err("Scan not allowed"); return -EBUSY; } + /* Check whether SAP scan can be skipped or not */ + if (pAdapter->device_mode == QDF_SAP_MODE && + wlan_hdd_sap_skip_scan_check(pHddCtx, request)) { + hdd_err("sap scan skipped"); + pAdapter->request = request; + INIT_WORK(&pAdapter->scan_block_work, + wlan_hdd_cfg80211_scan_block_cb); + schedule_work(&pAdapter->scan_block_work); + return 0; + } qdf_mem_zero(&scan_req, sizeof(scan_req)); diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index 2f73ae9b89..3add3a0f1b 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -179,9 +179,7 @@ typedef enum { eSAP_DFS_NOL_SET, /* No ch available after DFS RADAR detect */ eSAP_DFS_NO_AVAILABLE_CHANNEL, -#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE eSAP_ACS_SCAN_SUCCESS_EVENT, -#endif eSAP_ACS_CHANNEL_SELECTED, eSAP_ECSA_CHANGE_CHAN_IND, } eSapHddEvent; @@ -405,6 +403,18 @@ struct sap_roc_ready_ind_s { uint32_t scan_id; }; +/** + * struct sap_acs_scan_complete_event - acs scan complete event + * @status: status of acs scan + * @channellist: acs scan channels + * @num_of_channels: number of channels + */ +struct sap_acs_scan_complete_event{ + uint8_t status; + uint8_t *channellist; + uint8_t num_of_channels; +}; + /** * struct sap_ch_change_ind - channel change indication * @new_chan: channel to change @@ -454,6 +464,7 @@ typedef struct sap_Event_s { struct sap_ch_selected_s sap_ch_selected; struct sap_roc_ready_ind_s sap_roc_ind; struct sap_ch_change_ind sap_chan_cng_ind; + struct sap_acs_scan_complete_event sap_acs_scan_comp; } sapevt; } tSap_Event, *tpSap_Event; diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c index 7b249cb746..9a62d3413c 100644 --- a/core/sap/src/sap_api_link_cntl.c +++ b/core/sap/src/sap_api_link_cntl.c @@ -207,6 +207,7 @@ QDF_STATUS wlansap_scan_callback(tHalHandle hal_handle, * the result */ qdf_mem_free(sap_ctx->channelList); sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; } #endif @@ -412,6 +413,7 @@ wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext, */ qdf_mem_free(sap_ctx->channelList); sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; } #endif QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index 452f9cc65a..9493d91a9c 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -2328,7 +2328,7 @@ QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context, eCSR_SCAN_SOFTAP_CHANNEL_RANGE; sap_context->channelList = channel_list; - + sap_context->num_of_channel = num_of_channels; #endif /* Set requestType to Full scan */ @@ -2382,6 +2382,7 @@ QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context, qdf_mem_free(sap_context-> channelList); sap_context->channelList = NULL; + sap_context->num_of_channel = 0; } #endif if (true == sap_do_acs_pre_start_bss) { @@ -2705,6 +2706,34 @@ static QDF_STATUS sap_goto_disconnected(ptSapContext sapContext) return qdf_status; } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * sap_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_context: ptSapContext + * @sap_event: tSap_Event + * @status: status of acs scan + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * + * Return: void + */ +static void sap_handle_acs_scan_event(ptSapContext sap_context, + tSap_Event *sap_event, eSapStatus status) +{ + sap_event->sapHddEventCode = eSAP_ACS_SCAN_SUCCESS_EVENT; + sap_event->sapevt.sap_acs_scan_comp.status = status; + sap_event->sapevt.sap_acs_scan_comp.num_of_channels = + sap_context->num_of_channel; + sap_event->sapevt.sap_acs_scan_comp.channellist = + sap_context->channelList; +} +#else +static void sap_handle_acs_scan_event(ptSapContext sap_context, + tSap_Event *sap_event, eSapStatus status) +{ +} +#endif + /** * sap_signal_hdd_event() - send event notification * @sap_ctx: Sap Context @@ -2808,14 +2837,14 @@ QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx, case eSAP_DFS_RADAR_DETECT: case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC: case eSAP_DFS_NO_AVAILABLE_CHANNEL: -#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE - case eSAP_ACS_SCAN_SUCCESS_EVENT: -#endif sap_ap_event.sapHddEventCode = sap_hddevent; sap_ap_event.sapevt.sapStopBssCompleteEvent.status = (eSapStatus) context; break; - + case eSAP_ACS_SCAN_SUCCESS_EVENT: + sap_handle_acs_scan_event(sap_ctx, &sap_ap_event, + (eSapStatus)context); + break; case eSAP_ACS_CHANNEL_SELECTED: sap_ap_event.sapHddEventCode = sap_hddevent; acs_selected = &sap_ap_event.sapevt.sap_ch_selected; diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h index 22608eff91..1259ebbc78 100644 --- a/core/sap/src/sap_internal.h +++ b/core/sap/src/sap_internal.h @@ -210,6 +210,7 @@ typedef struct sSapContext { uint32_t nStaAddIeLength; uint8_t pStaAddIE[MAX_ASSOC_IND_IE_LEN]; uint8_t *channelList; + uint8_t num_of_channel; tSapChannelListInfo SapChnlList; uint16_t ch_width_orig; struct ch_params_s ch_params;