Browse Source

qcacmn: scan all channels in A/G if 0 channels provided

When wide band scan is enabled, host configures all possible
channels with all possible phy modes. In his case if a scan
is invoked with 0 channels, target will end up scanning each
channel with all possible phy modes which increases scan time
exponentially.
If wide band scan is enabled and scan is issues with 0 channels,
configure target to scan all available channels only in 11A/11G mode.

Change-Id: I7c678ccf43c3238aacbfc59cc7e7bd19763453cc
CRs-Fixed: 2165025
Om Prakash Tripathi 7 years ago
parent
commit
7dd49fec17

+ 8 - 0
os_if/linux/scan/src/wlan_cfg80211_scan.c

@@ -1119,6 +1119,7 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
 	struct wlan_objmgr_psoc *psoc;
 	wlan_scan_id scan_id;
 	bool is_p2p_scan = false;
+	enum wlan_band band;
 	struct net_device *netdev = NULL;
 
 	/* Get the vdev object */
@@ -1277,6 +1278,13 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
 			len += snprintf(chl + len, 5, "%d ", channel);
 			req->scan_req.chan_list.chan[num_chan].freq =
 				wlan_chan_to_freq(channel);
+			band = util_scan_scm_chan_to_band(channel);
+			if (band == WLAN_BAND_2_4_GHZ)
+				req->scan_req.chan_list.chan[num_chan].phymode =
+					SCAN_PHY_MODE_11G;
+			else
+				req->scan_req.chan_list.chan[num_chan].phymode =
+					SCAN_PHY_MODE_11A;
 			num_chan++;
 		}
 		cfg80211_notice("Channel-List: %s", chl);

+ 58 - 0
umac/scan/dispatcher/inc/wlan_scan_public_structs.h

@@ -592,6 +592,64 @@ enum scan_type {
 	SCAN_TYPE_COUNT,
 };
 
+/**
+ * enum scan_phy_mode - phymode used for scan
+ * @SCAN_PHY_MODE_11A: 11a mode
+ * @SCAN_PHY_MODE_11G: 11g mode
+ * @SCAN_PHY_MODE_11B: 11b mode
+ * @SCAN_PHY_MODE_11GONLY: 11g only mode
+ * @SCAN_PHY_MODE_11NA_HT20: 11na ht20 mode
+ * @SCAN_PHY_MODE_11NG_HT20: 11ng ht20 mode
+ * @SCAN_PHY_MODE_11NA_HT40: 11na ht40 mode
+ * @SCAN_PHY_MODE_11NG_HT40: 11ng ht40 mode
+ * @SCAN_PHY_MODE_11AC_VHT20: 11ac vht20 mode
+ * @SCAN_PHY_MODE_11AC_VHT40: 11ac vht40 mode
+ * @SCAN_PHY_MODE_11AC_VHT80: 11ac vht80 mode
+ * @SCAN_PHY_MODE_11AC_VHT20_2G: 2GHz 11ac vht20 mode
+ * @SCAN_PHY_MODE_11AC_VHT40_2G: 2GHz 11ac vht40 mode
+ * @SCAN_PHY_MODE_11AC_VHT80_2G: 2GHz 11ac vht80 mode
+ * @SCAN_PHY_MODE_11AC_VHT80_80: 11ac vht 80+80 mode
+ * @SCAN_PHY_MODE_11AC_VHT160: 11ac vht160 mode
+ * @SCAN_PHY_MODE_11AX_HE20: 11ax he20 mode
+ * @SCAN_PHY_MODE_11AX_HE40: 11ax he40 mode
+ * @SCAN_PHY_MODE_11AX_HE80: 11ax he80 mode
+ * @SCAN_PHY_MODE_11AX_HE80_80: 11ax he80+80 mode
+ * @SCAN_PHY_MODE_11AX_HE160: 11ax he160 mode
+ * @SCAN_PHY_MODE_11AX_HE20_2G: 2GHz 11ax he20 mode
+ * @SCAN_PHY_MODE_11AX_HE40_2G: 2GHz 11ax he40 mode
+ * @SCAN_PHY_MODE_11AX_HE80_2G: 2GHz 11ax he80 mode
+ * @SCAN_PHY_MODE_UNKNOWN: unknown phy mode
+ * @SCAN_PHY_MODE_MAX: max valid phymode
+ */
+enum scan_phy_mode {
+	SCAN_PHY_MODE_11A = 0,
+	SCAN_PHY_MODE_11G = 1,
+	SCAN_PHY_MODE_11B = 2,
+	SCAN_PHY_MODE_11GONLY = 3,
+	SCAN_PHY_MODE_11NA_HT20 = 4,
+	SCAN_PHY_MODE_11NG_HT20 = 5,
+	SCAN_PHY_MODE_11NA_HT40 = 6,
+	SCAN_PHY_MODE_11NG_HT40 = 7,
+	SCAN_PHY_MODE_11AC_VHT20 = 8,
+	SCAN_PHY_MODE_11AC_VHT40 = 9,
+	SCAN_PHY_MODE_11AC_VHT80 = 10,
+	SCAN_PHY_MODE_11AC_VHT20_2G = 11,
+	SCAN_PHY_MODE_11AC_VHT40_2G = 12,
+	SCAN_PHY_MODE_11AC_VHT80_2G = 13,
+	SCAN_PHY_MODE_11AC_VHT80_80 = 14,
+	SCAN_PHY_MODE_11AC_VHT160 = 15,
+	SCAN_PHY_MODE_11AX_HE20 = 16,
+	SCAN_PHY_MODE_11AX_HE40 = 17,
+	SCAN_PHY_MODE_11AX_HE80 = 18,
+	SCAN_PHY_MODE_11AX_HE80_80 = 19,
+	SCAN_PHY_MODE_11AX_HE160 = 20,
+	SCAN_PHY_MODE_11AX_HE20_2G = 21,
+	SCAN_PHY_MODE_11AX_HE40_2G = 22,
+	SCAN_PHY_MODE_11AX_HE80_2G = 23,
+	SCAN_PHY_MODE_UNKNOWN = 24,
+	SCAN_PHY_MODE_MAX = 24
+};
+
 /**
  * struct scan_extra_params_legacy
  * extra parameters required for legacy DA scan module

+ 129 - 19
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -26,6 +26,8 @@
 #include <wlan_objmgr_cmn.h>
 #include <wlan_serialization_api.h>
 #include <wlan_scan_tgt_api.h>
+#include <wlan_scan_utils_api.h>
+#include <wlan_reg_ucfg_api.h>
 #include <wlan_reg_services_api.h>
 #include <wlan_utility.h>
 #include "../../core/src/wlan_scan_main.h"
@@ -480,6 +482,7 @@ ucfg_scan_start(struct scan_start_request *req)
 	QDF_STATUS status;
 	struct wlan_scan_obj *scan_obj;
 	struct wlan_objmgr_pdev *pdev;
+	uint8_t idx;
 
 	if (!req || !req->vdev) {
 		scm_err("req or vdev within req is NULL");
@@ -514,9 +517,13 @@ ucfg_scan_start(struct scan_start_request *req)
 
 	/* Overwrite scan parameters as required */
 	if (!ucfg_scan_get_wide_band_scan(pdev)) {
-		scm_debug("wide_band_scan not supported, Scan 20 MHz");
 		req->scan_req.scan_f_wide_band = false;
+	} else {
+		req->scan_req.scan_f_wide_band = true;
+		if (req->scan_req.chan_list.num_chan == 0)
+			ucfg_scan_init_chanlist_params(req, 0, NULL, NULL);
 	}
+	scm_debug("scan_f_wide_band: %d", req->scan_req.scan_f_wide_band);
 
 	if (scan_obj->scan_def.usr_cfg_probe_rpt_time) {
 		req->scan_req.repeat_probe_time =
@@ -545,6 +552,13 @@ ucfg_scan_start(struct scan_start_request *req)
 		return status;
 	}
 
+	scm_info("request to scan %d channels",
+		req->scan_req.chan_list.num_chan);
+	for (idx = 0; idx < req->scan_req.chan_list.num_chan; idx++)
+		scm_info("chan[%d]: freq:%d, phymode:%d", idx,
+				req->scan_req.chan_list.chan[idx].freq,
+				req->scan_req.chan_list.chan[idx].phymode);
+
 	msg.bodyptr = req;
 	msg.callback = scm_scan_start_req;
 	msg.flush_callback = scm_scan_start_flush_callback;
@@ -1216,54 +1230,150 @@ ucfg_scan_init_bssid_params(struct scan_start_request *req,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * is_chan_enabled_for_scan() - helper API to check if a frequency
+ * is allowed to scan.
+ * @reg_chan: regulatory_channel object
+ * @low_2g: lower 2.4 GHz frequency thresold
+ * @high_2g: upper 2.4 GHz frequency thresold
+ * @low_5g: lower 5 GHz frequency thresold
+ * @high_5g: upper 5 GHz frequency thresold
+ *
+ * Return: true if scan is allowed. false otherwise.
+ */
+static bool
+is_chan_enabled_for_scan(struct regulatory_channel *reg_chan,
+		uint32_t low_2g, uint32_t high_2g, uint32_t low_5g,
+		uint32_t high_5g)
+{
+	if (reg_chan->state == CHANNEL_STATE_DISABLE)
+		return false;
+	if (reg_chan->nol_chan)
+		return false;
+	/* 2 GHz channel */
+	if ((util_scan_scm_chan_to_band(reg_chan->chan_num) ==
+			WLAN_BAND_2_4_GHZ) &&
+			((reg_chan->center_freq < low_2g) ||
+			(reg_chan->center_freq > high_2g)))
+		return false;
+	else if ((reg_chan->center_freq < low_5g) ||
+			(reg_chan->center_freq > high_5g))
+		return false;
+
+	return true;
+}
+
 QDF_STATUS
 ucfg_scan_init_chanlist_params(struct scan_start_request *req,
 		uint32_t num_chans, uint32_t *chan_list, uint32_t *phymode)
 {
 	uint32_t idx;
+	QDF_STATUS status;
+	struct regulatory_channel *reg_chan_list = NULL;
+	uint32_t low_2g, high_2g, low_5g, high_5g;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	uint32_t *scan_freqs = NULL;
 	uint32_t max_chans = sizeof(req->scan_req.chan_list.chan) /
 				sizeof(req->scan_req.chan_list.chan[0]);
 	if (!req) {
 		scm_err("null request");
 		return QDF_STATUS_E_NULL_VALUE;
 	}
+
+	if (req->vdev)
+		pdev = wlan_vdev_get_pdev(req->vdev);
+	/*
+	 * If 0 channels are provided for scan and
+	 * wide band scan is enabled, scan all 20 mhz
+	 * available channels. This is required as FW
+	 * scans all channel/phy mode combinations
+	 * provided in scan channel list if 0 chans are
+	 * provided in scan request causing scan to take
+	 * too much time to complete.
+	 */
+	if (pdev && !num_chans && ucfg_scan_get_wide_band_scan(pdev)) {
+		reg_chan_list = qdf_mem_malloc(NUM_CHANNELS *
+				sizeof(struct regulatory_channel));
+		if (!reg_chan_list) {
+			scm_err("Couldn't allocate reg_chan_list memory");
+			status = QDF_STATUS_E_NOMEM;
+			goto end;
+		}
+		scan_freqs = qdf_mem_malloc(sizeof(uint32_t) * max_chans);
+		if (!scan_freqs) {
+			scm_err("Couldn't allocate scan_freqs memory");
+			status = QDF_STATUS_E_NOMEM;
+			goto end;
+		}
+		status = ucfg_reg_get_current_chan_list(pdev, reg_chan_list);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			scm_err("Couldn't get current chan list");
+			goto end;
+		}
+		status = wlan_reg_get_freq_range(pdev, &low_2g,
+				&high_2g, &low_5g, &high_5g);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			scm_err("Couldn't get frequency range");
+			goto end;
+		}
+
+		for (idx = 0, num_chans = 0;
+			(idx < NUM_CHANNELS && num_chans < max_chans); idx++)
+			if (is_chan_enabled_for_scan(&reg_chan_list[idx],
+					low_2g, high_2g, low_5g, high_5g))
+				scan_freqs[num_chans++] =
+				reg_chan_list[idx].center_freq;
+
+		chan_list = scan_freqs;
+	}
+
 	if (!num_chans) {
 		/* empty channel list provided */
 		qdf_mem_zero(&req->scan_req.chan_list,
 			sizeof(req->scan_req.chan_list));
 		req->scan_req.chan_list.num_chan = 0;
-		return QDF_STATUS_SUCCESS;
+		status = QDF_STATUS_SUCCESS;
+		goto end;
 	}
 	if (!chan_list) {
 		scm_err("null chan_list while num_chans: %d", num_chans);
-		return QDF_STATUS_E_NULL_VALUE;
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto end;
 	}
 
 	if (num_chans > max_chans) {
-		/* got a big list. alert and continue */
+		/* got a big list. alert and fail */
 		scm_warn("overflow: received %d, max supported : %d",
 			num_chans, max_chans);
-		return QDF_STATUS_E_E2BIG;
+		status = QDF_STATUS_E_E2BIG;
+		goto end;
 	}
 
-	if (max_chans > num_chans)
-		max_chans = num_chans;
-
-	req->scan_req.chan_list.num_chan = max_chans;
-	for (idx = 0; idx < max_chans; idx++) {
+	req->scan_req.chan_list.num_chan = num_chans;
+	for (idx = 0; idx < num_chans; idx++) {
 		req->scan_req.chan_list.chan[idx].freq =
 			(chan_list[idx] > WLAN_24_GHZ_BASE_FREQ) ?
-			chan_list[idx] : wlan_chan_to_freq(chan_list[idx]);
-		req->scan_req.chan_list.chan[idx].phymode =
-			(phymode ? phymode[idx] : 0);
+			chan_list[idx] :
+			wlan_reg_chan_to_freq(pdev, chan_list[idx]);
+		if (phymode)
+			req->scan_req.chan_list.chan[idx].phymode =
+				phymode[idx];
+		else if (req->scan_req.chan_list.chan[idx].freq <=
+			WLAN_CHAN_15_FREQ)
+			req->scan_req.chan_list.chan[idx].phymode =
+				SCAN_PHY_MODE_11G;
+		else
+			req->scan_req.chan_list.chan[idx].phymode =
+				SCAN_PHY_MODE_11A;
+
+		scm_debug("chan[%d]: freq:%d, phymode:%d", idx,
+			req->scan_req.chan_list.chan[idx].freq,
+			req->scan_req.chan_list.chan[idx].phymode);
 	}
 
-	/* Enable wide band scan by default if phymode list is provided.
-	 * This flag will be cleared in @ucfg_scan_start() if underlying
-	 * phy doesn't support wide band scan.
-	 */
-	if (phymode)
-		req->scan_req.scan_f_wide_band = true;
+end:
+	if (scan_freqs)
+		qdf_mem_free(scan_freqs);
 
 	return QDF_STATUS_SUCCESS;
 }