diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 042e0bd90b..38d9c44dfd 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -3041,6 +3041,73 @@ static void wlan_hdd_handle_zero_acs_list(struct hdd_context *hdd_ctx, hdd_debug("retore acs chan list to single freq %d", acs_chan_default); } +/** + * wlan_hdd_handle_single_ch_in_acs_list() - Handle acs list with single channel + * @hdd_ctx: hdd context + * @adapter: adapter + * @sap_config: sap acs config context + * + * If only one acs channel is left after filter, driver will return the channel + * to hostapd without ACS scan. + * + * Return: None + */ +static void +wlan_hdd_handle_single_ch_in_acs_list(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct sap_config *sap_config) +{ + uint32_t channel_bonding_mode_2g; + + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode_2g); + sap_config->acs_cfg.start_ch_freq = + sap_config->acs_cfg.freq_list[0]; + sap_config->acs_cfg.end_ch_freq = + sap_config->acs_cfg.freq_list[0]; + sap_config->acs_cfg.pri_ch_freq = + sap_config->acs_cfg.freq_list[0]; + if (sap_config->acs_cfg.pri_ch_freq <= + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484) && + sap_config->acs_cfg.ch_width >= + CH_WIDTH_40MHZ && + !channel_bonding_mode_2g) { + sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; + hdd_debug("2.4ghz channel resetting BW to %d 2.4 cbmode %d", + sap_config->acs_cfg.ch_width, + channel_bonding_mode_2g); + } + + wlan_sap_set_sap_ctx_acs_cfg( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), sap_config); + sap_config_acs_result(hdd_ctx->mac_handle, + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config->acs_cfg.ht_sec_ch_freq); + sap_config->ch_params.ch_width = + sap_config->acs_cfg.ch_width; + sap_config->ch_params.sec_ch_offset = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.ht_sec_ch_freq); + sap_config->ch_params.center_freq_seg0 = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.vht_seg0_center_ch_freq); + sap_config->ch_params.center_freq_seg1 = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.vht_seg1_center_ch_freq); + sap_config->ch_params.mhz_freq_seg0 = + sap_config->acs_cfg.vht_seg0_center_ch_freq; + sap_config->ch_params.mhz_freq_seg1 = + sap_config->acs_cfg.vht_seg1_center_ch_freq; + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config); +} + #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) static void wlan_hdd_set_sap_acs_ch_width_320(struct sap_config *sap_config) { @@ -3110,6 +3177,7 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, QDF_STATUS qdf_status; bool is_vendor_acs_support = false; bool is_external_acs_policy = false; + bool is_vendor_unsafe_ch_present = false; bool sap_force_11n_for_11ac = 0; bool go_force_11n_for_11ac = 0; bool go_11ac_override = 0; @@ -3334,13 +3402,19 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, if (is_external_acs_policy && policy_mgr_is_force_scc(hdd_ctx->psoc) && policy_mgr_get_connection_count(hdd_ctx->psoc)) { + if (adapter->device_mode == QDF_SAP_MODE) + is_vendor_unsafe_ch_present = + wlansap_filter_vendor_unsafe_ch_freq( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config); wlan_hdd_trim_acs_channel_list( sap_config->acs_cfg.pcl_chan_freq, sap_config->acs_cfg.pcl_ch_count, sap_config->acs_cfg.freq_list, &sap_config->acs_cfg.ch_list_count); if (!sap_config->acs_cfg.ch_list_count && - sap_config->acs_cfg.master_ch_list_count) + sap_config->acs_cfg.master_ch_list_count && + !is_vendor_unsafe_ch_present) wlan_hdd_handle_zero_acs_list( hdd_ctx, sap_config->acs_cfg.freq_list, @@ -3349,50 +3423,8 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, sap_config->acs_cfg.master_ch_list_count); /* if it is only one channel, send ACS event to upper layer */ if (sap_config->acs_cfg.ch_list_count == 1) { - sap_config->acs_cfg.start_ch_freq = - sap_config->acs_cfg.freq_list[0]; - sap_config->acs_cfg.end_ch_freq = - sap_config->acs_cfg.freq_list[0]; - sap_config->acs_cfg.pri_ch_freq = - sap_config->acs_cfg.freq_list[0]; - if (sap_config->acs_cfg.pri_ch_freq <= - WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484) && - sap_config->acs_cfg.ch_width >= - CH_WIDTH_40MHZ && - !channel_bonding_mode_2g) { - sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; - hdd_debug("2.4ghz channel resetting BW to %d 2.4 cbmode %d", - sap_config->acs_cfg.ch_width, - channel_bonding_mode_2g); - } - - wlan_sap_set_sap_ctx_acs_cfg( - WLAN_HDD_GET_SAP_CTX_PTR(adapter), sap_config); - sap_config_acs_result(hdd_ctx->mac_handle, - WLAN_HDD_GET_SAP_CTX_PTR(adapter), - sap_config->acs_cfg.ht_sec_ch_freq); - sap_config->ch_params.ch_width = - sap_config->acs_cfg.ch_width; - sap_config->ch_params.sec_ch_offset = - wlan_reg_freq_to_chan(hdd_ctx->pdev, - sap_config->acs_cfg.ht_sec_ch_freq); - sap_config->ch_params.center_freq_seg0 = - wlan_reg_freq_to_chan( - hdd_ctx->pdev, - sap_config->acs_cfg.vht_seg0_center_ch_freq); - sap_config->ch_params.center_freq_seg1 = - wlan_reg_freq_to_chan( - hdd_ctx->pdev, - sap_config->acs_cfg.vht_seg1_center_ch_freq); - sap_config->ch_params.mhz_freq_seg0 = - sap_config->acs_cfg.vht_seg0_center_ch_freq; - sap_config->ch_params.mhz_freq_seg1 = - sap_config->acs_cfg.vht_seg1_center_ch_freq; - /*notify hostapd about channel override */ - wlan_hdd_cfg80211_acs_ch_select_evt(adapter); - wlansap_dcs_set_wlan_interference_mitigation_on_band( - WLAN_HDD_GET_SAP_CTX_PTR(adapter), - sap_config); + wlan_hdd_handle_single_ch_in_acs_list( + hdd_ctx, adapter, sap_config); ret = 0; goto out; } else if (!sap_config->acs_cfg.ch_list_count) { @@ -3400,6 +3432,20 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, ret = -EINVAL; goto out; } + } else if (adapter->device_mode == QDF_SAP_MODE) { + wlansap_filter_vendor_unsafe_ch_freq( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config); + if (sap_config->acs_cfg.ch_list_count == 1) { + wlan_hdd_handle_single_ch_in_acs_list( + hdd_ctx, adapter, sap_config); + ret = 0; + goto out; + } else if (!sap_config->acs_cfg.ch_list_count) { + hdd_err("channel count 0 after vendor unsafe filter"); + ret = -EINVAL; + goto out; + } } ret = wlan_hdd_set_acs_ch_range(sap_config, hw_mode, diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h index 04fd666542..11f8f06252 100644 --- a/core/pld/inc/pld_common.h +++ b/core/pld/inc/pld_common.h @@ -417,6 +417,30 @@ enum pld_wlan_time_sync_trigger_type { }; #endif /* FEATURE_WLAN_TIME_SYNC_FTM */ +/* MAX channel avoid ranges supported in PLD */ +#define PLD_CH_AVOID_MAX_RANGE 4 + +/** + * struct pld_ch_avoid_freq_type + * @start_freq: start freq (MHz) + * @end_freq: end freq (Mhz) + */ +struct pld_ch_avoid_freq_type { + uint32_t start_freq; + uint32_t end_freq; +}; + +/** + * struct pld_ch_avoid_ind_type + * @ch_avoid_range_cnt: count + * @avoid_freq_range: avoid freq range array + */ +struct pld_ch_avoid_ind_type { + uint32_t ch_avoid_range_cnt; + struct pld_ch_avoid_freq_type + avoid_freq_range[PLD_CH_AVOID_MAX_RANGE]; +}; + /** * struct pld_driver_ops - driver callback functions * @probe: required operation, will be called when device is detected @@ -569,6 +593,28 @@ int pld_get_audio_wlan_timestamp(struct device *dev, #endif /* FEATURE_WLAN_TIME_SYNC_FTM */ #if IS_ENABLED(CONFIG_CNSS_UTILS) +#ifdef CNSS_UTILS_VENDOR_UNSAFE_CHAN_API_SUPPORT +/** + * pld_get_wlan_unsafe_channel_sap() - Get vendor unsafe ch freq ranges + * @dev: device + * @ch_avoid_ranges: unsafe freq channel ranges + * + * Get vendor specific unsafe channel frequency ranges + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges); +#else +static inline +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + return 0; +} +#endif + /** * pld_set_wlan_unsafe_channel() - Set unsafe channel * @dev: device @@ -694,6 +740,12 @@ static inline int pld_get_driver_load_cnt(struct device *dev) return cnss_utils_get_driver_load_cnt(dev); } #else +static inline int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + return 0; +} + static inline int pld_set_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list, u16 ch_count) diff --git a/core/pld/src/pld_common.c b/core/pld/src/pld_common.c index 6493b1952c..82e8051789 100644 --- a/core/pld/src/pld_common.c +++ b/core/pld/src/pld_common.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -3240,6 +3241,38 @@ int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state, return errno; } +#ifdef CNSS_UTILS_VENDOR_UNSAFE_CHAN_API_SUPPORT +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + struct cnss_ch_avoid_ind_type cnss_ch_avoid; + int ret; + int i; + + if (!ch_avoid_ranges) + return -EINVAL; + cnss_ch_avoid.ch_avoid_range_cnt = 0; + ret = cnss_utils_get_wlan_unsafe_channel_sap(dev, &cnss_ch_avoid); + if (ret) + return ret; + + for (i = 0; + i < PLD_CH_AVOID_MAX_RANGE && + i < cnss_ch_avoid.ch_avoid_range_cnt; i++) { + ch_avoid_ranges->avoid_freq_range[i].start_freq = + cnss_ch_avoid.avoid_freq_range[i].start_freq; + ch_avoid_ranges->avoid_freq_range[i].end_freq = + cnss_ch_avoid.avoid_freq_range[i].end_freq; + } + ch_avoid_ranges->ch_avoid_range_cnt = i; + if (i < cnss_ch_avoid.ch_avoid_range_cnt) + pr_err("unexpected cnss ch_avoid_range_cnt %d", + cnss_ch_avoid.ch_avoid_range_cnt); + + return 0; +} +#endif + #ifdef FEATURE_WLAN_TIME_SYNC_FTM /** * pld_get_audio_wlan_timestamp() - Get audio timestamp diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index 28cfc9737e..d1d11763b3 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1699,6 +1700,20 @@ static inline qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context) } #endif +/** + * wlansap_filter_vendor_unsafe_ch_freq() - filter sap acs ch list by + * vendor unsafe ch freq ranges + * @sap_context: sap context + * @sap_config: sap conifg + * + * This function is used to filter out unsafe channel frequency from acs + * channel frequency list based on vendor unsafe channel frequency ranges. + * + * Return: true if vendor unsafe ch range is present, otherwise false + */ +bool wlansap_filter_vendor_unsafe_ch_freq( + struct sap_context *sap_context, struct sap_config *sap_config); + /** * wlansap_dump_acs_ch_freq() - print acs channel frequency * @sap_ctx: sap context diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index f9a4426e17..4c79d9abd0 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -56,6 +56,7 @@ #include "cfg_ucfg_api.h" #include "wlan_mlme_ucfg_api.h" #include "wlan_mlme_vdev_mgr_interface.h" +#include "pld_common.h" #define SAP_DEBUG static struct sap_context *gp_sap_ctx[SAP_MAX_NUM_SESSION]; @@ -3266,6 +3267,69 @@ qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx, return restart_freq; } +static inline bool +wlansap_ch_in_avoid_ranges(uint32_t ch_freq, + struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + uint32_t i; + + for (i = 0; i < ch_avoid_ranges->ch_avoid_range_cnt; i++) { + if (ch_freq >= + ch_avoid_ranges->avoid_freq_range[i].start_freq && + ch_freq <= + ch_avoid_ranges->avoid_freq_range[i].end_freq) + return true; + } + + return false; +} + +bool wlansap_filter_vendor_unsafe_ch_freq( + struct sap_context *sap_context, struct sap_config *sap_config) +{ + struct pld_ch_avoid_ind_type ch_avoid_ranges; + uint32_t i, j; + int ret; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct mac_context *mac; + uint32_t count; + + if (!qdf_ctx) + return false; + mac = sap_get_mac_context(); + if (!mac) + return false; + + count = policy_mgr_mode_specific_connection_count(mac->psoc, + PM_SAP_MODE, NULL); + if (count != policy_mgr_get_connection_count(mac->psoc)) + return false; + + ch_avoid_ranges.ch_avoid_range_cnt = 0; + ret = pld_get_wlan_unsafe_channel_sap(qdf_ctx->dev, &ch_avoid_ranges); + if (ret) { + sap_debug("failed to get vendor unsafe ch range, ret %d", ret); + return false; + } + if (!ch_avoid_ranges.ch_avoid_range_cnt) + return false; + for (i = 0; i < ch_avoid_ranges.ch_avoid_range_cnt; i++) { + sap_debug("vendor unsafe range[%d] %d %d", i, + ch_avoid_ranges.avoid_freq_range[i].start_freq, + ch_avoid_ranges.avoid_freq_range[i].end_freq); + } + for (i = 0, j = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + if (!wlansap_ch_in_avoid_ranges( + sap_config->acs_cfg.freq_list[i], + &ch_avoid_ranges)) + sap_config->acs_cfg.freq_list[j++] = + sap_config->acs_cfg.freq_list[i]; + } + sap_config->acs_cfg.ch_list_count = j; + + return true; +} + #ifdef DCS_INTERFERENCE_DETECTION QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( struct sap_context *sap_context,