Browse Source

qcacld-3.0: Handle vendor LTE unsafe channel ranges

In 3rd party platform, CNSS driver will provide
LTE avoidance channel frequency ranges by API
cnss_utils_get_wlan_unsafe_channel_sap.
Based on requirement, in single SAP case or SAP+SAP
case, ACS channel list should be filtered out based
on vendor unsafe channel frequency ranges.

Change-Id: I583c1bb2583c783858c54e8643fbe1af69d492b1
CRs-Fixed: 3061043
Liangwei Dong 3 years ago
parent
commit
6e61b6bb8c

+ 90 - 44
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,54 +3423,26 @@ 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_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 list count 0");
+			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 list count 0");
+			hdd_err("channel count 0 after vendor unsafe filter");
 			ret = -EINVAL;
 			goto out;
 		}

+ 52 - 0
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)

+ 33 - 0
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

+ 15 - 0
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

+ 64 - 0
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,