Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efc2c1fa authored by Arend Van Spriel's avatar Arend Van Spriel Committed by Kalle Valo
Browse files

brcmfmac: add support multi-scheduled scan



This change adds support for multi-scheduled scan in the driver. It
currently relies on g-scan support in firmware and will set struct
wiphy::max_sched_scan_reqs accordingly. This is limited to 16 concurrent
requests.

The firmware currently has a limit of 64 channels that can be configured
for all requests in total regardless whether there are duplicates. So if
a request uses 35 channels there are 29 channels left for another request.
When user-space does not specify any channels cfg80211 will add all
channels defined by the wiphy instance to the request, which makes
reaching the limit rather easy for dual-band devices.

Reviewed-by: default avatarHante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: default avatarFranky Lin <franky.lin@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 83368904
Loading
Loading
Loading
Loading
+49 −18
Original line number Diff line number Diff line
@@ -719,6 +719,8 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
{
	struct brcmf_scan_params_le params_le;
	struct cfg80211_scan_request *scan_request;
	u64 reqid;
	u32 bucket;
	s32 err = 0;

	brcmf_dbg(SCAN, "Enter\n");
@@ -758,11 +760,21 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
	 * e-scan can be initiated internally
	 * which takes precedence.
	 */
	if (cfg->internal_escan) {
		brcmf_dbg(SCAN, "scheduled scan completed\n");
		cfg->internal_escan = false;
		if (!aborted)
			cfg80211_sched_scan_results(cfg_to_wiphy(cfg), 0);
	if (cfg->int_escan_map) {
		brcmf_dbg(SCAN, "scheduled scan completed (%x)\n",
			  cfg->int_escan_map);
		while (cfg->int_escan_map) {
			bucket = __ffs(cfg->int_escan_map);
			cfg->int_escan_map &= ~BIT(bucket);
			reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno,
							       bucket);
			if (!aborted) {
				brcmf_dbg(SCAN, "report results: reqid=%llu\n",
					  reqid);
				cfg80211_sched_scan_results(cfg_to_wiphy(cfg),
							    reqid);
			}
		}
	} else if (scan_request) {
		struct cfg80211_scan_info info = {
			.aborted = aborted,
@@ -1011,7 +1023,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
			if (!ssid_le.SSID_len)
				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
			else
				brcmf_dbg(SCAN, "%d: scan for  %s size =%d\n",
				brcmf_dbg(SCAN, "%d: scan for  %.32s size=%d\n",
					  i, ssid_le.SSID, ssid_le.SSID_len);
			memcpy(ptr, &ssid_le, sizeof(ssid_le));
			ptr += sizeof(ssid_le);
@@ -3011,7 +3023,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
	struct escan_info *escan = &cfg->escan_info;

	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
	if (cfg->internal_escan || cfg->scan_request) {
	if (cfg->int_escan_map || cfg->scan_request) {
		escan->escan_state = WL_ESCAN_STATE_IDLE;
		brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
	}
@@ -3034,7 +3046,7 @@ static void brcmf_escan_timeout(unsigned long data)
	struct brcmf_cfg80211_info *cfg =
			(struct brcmf_cfg80211_info *)data;

	if (cfg->internal_escan || cfg->scan_request) {
	if (cfg->int_escan_map || cfg->scan_request) {
		brcmf_err("timer expired\n");
		schedule_work(&cfg->escan_timeout_work);
	}
@@ -3120,7 +3132,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
		if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
			goto exit;

		if (!cfg->internal_escan && !cfg->scan_request) {
		if (!cfg->int_escan_map && !cfg->scan_request) {
			brcmf_dbg(SCAN, "result without cfg80211 request\n");
			goto exit;
		}
@@ -3166,7 +3178,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
			goto exit;
		if (cfg->internal_escan || cfg->scan_request) {
		if (cfg->int_escan_map || cfg->scan_request) {
			brcmf_inform_bss(cfg);
			aborted = status != BRCMF_E_STATUS_SUCCESS;
			brcmf_notify_escan_complete(cfg, ifp, aborted, false);
@@ -3248,17 +3260,21 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
	return 0;
}

static int brcmf_start_internal_escan(struct brcmf_if *ifp,
static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
				      struct cfg80211_scan_request *request)
{
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	int err;

	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
		if (cfg->int_escan_map)
			brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
				  cfg->int_escan_map);
		/* Abort any on-going scan */
		brcmf_abort_scanning(cfg);
	}

	brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	cfg->escan_info.run = brcmf_run_escan;
	err = brcmf_do_escan(ifp, request);
@@ -3266,7 +3282,7 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp,
		clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
		return err;
	}
	cfg->internal_escan = true;
	cfg->int_escan_map = fwmap;
	return 0;
}

@@ -3308,6 +3324,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
	int i, err = 0;
	struct brcmf_pno_scanresults_le *pfn_result;
	u32 bucket_map;
	u32 result_count;
	u32 status;
	u32 datalen;
@@ -3352,6 +3369,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
		goto out_err;
	}

	bucket_map = 0;
	for (i = 0; i < result_count; i++) {
		netinfo = &netinfo_start[i];

@@ -3359,6 +3377,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
			netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
		brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
			  netinfo->SSID, netinfo->channel);
		bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
		err = brcmf_internal_escan_add_info(request,
						    netinfo->SSID,
						    netinfo->SSID_len,
@@ -3367,7 +3386,10 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
			goto out_err;
	}

	err = brcmf_start_internal_escan(ifp, request);
	if (!bucket_map)
		goto free_req;

	err = brcmf_start_internal_escan(ifp, bucket_map, request);
	if (!err)
		goto free_req;

@@ -3386,11 +3408,11 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);

	brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
	brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
		  req->n_match_sets, req->n_ssids);

	if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
		brcmf_err("Scanning suppressed: status (%lu)\n",
		brcmf_err("Scanning suppressed: status=%lu\n",
			  cfg->scan_status);
		return -EAGAIN;
	}
@@ -3411,8 +3433,8 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
	struct brcmf_if *ifp = netdev_priv(ndev);

	brcmf_dbg(SCAN, "enter\n");
	brcmf_pno_clean(ifp);
	if (cfg->internal_escan)
	brcmf_pno_stop_sched_scan(ifp, reqid);
	if (cfg->int_escan_map)
		brcmf_notify_escan_complete(cfg, ifp, true, true);
	return 0;
}
@@ -6941,6 +6963,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
		brcmf_p2p_detach(&cfg->p2p);
		goto wiphy_unreg_out;
	}
	err = brcmf_pno_attach(cfg);
	if (err) {
		brcmf_err("PNO initialisation failed (%d)\n", err);
		brcmf_btcoex_detach(cfg);
		brcmf_p2p_detach(&cfg->p2p);
		goto wiphy_unreg_out;
	}

	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
		err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
@@ -6973,6 +7002,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
	return cfg;

detach:
	brcmf_pno_detach(cfg);
	brcmf_btcoex_detach(cfg);
	brcmf_p2p_detach(&cfg->p2p);
wiphy_unreg_out:
@@ -6992,6 +7022,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
	if (!cfg)
		return;

	brcmf_pno_detach(cfg);
	brcmf_btcoex_detach(cfg);
	wiphy_unregister(cfg->wiphy);
	kfree(cfg->ops);
+4 −2
Original line number Diff line number Diff line
@@ -273,7 +273,7 @@ struct brcmf_cfg80211_wowl {
 * @pub: common driver information.
 * @channel: current channel.
 * @active_scan: current scan mode.
 * @internal_escan: indicates internally initiated e-scan is running.
 * @int_escan_map: bucket map for which internal e-scan is done.
 * @ibss_starter: indicates this sta is ibss starter.
 * @pwr_save: indicate whether dongle to support power save mode.
 * @dongle_up: indicate whether dongle up or not.
@@ -289,6 +289,7 @@ struct brcmf_cfg80211_wowl {
 * @vif_cnt: number of vif instances.
 * @vif_event: vif event signalling.
 * @wowl: wowl related information.
 * @pno: information of pno module.
 */
struct brcmf_cfg80211_info {
	struct wiphy *wiphy;
@@ -305,7 +306,7 @@ struct brcmf_cfg80211_info {
	struct brcmf_pub *pub;
	u32 channel;
	bool active_scan;
	bool internal_escan;
	u32 int_escan_map;
	bool ibss_starter;
	bool pwr_save;
	bool dongle_up;
@@ -322,6 +323,7 @@ struct brcmf_cfg80211_info {
	struct brcmu_d11inf d11inf;
	struct brcmf_assoclist_le assoclist;
	struct brcmf_cfg80211_wowl wowl;
	struct brcmf_pno_info *pno;
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "debug.h"
#include "fwil_types.h"
#include "p2p.h"
#include "pno.h"
#include "cfg80211.h"
#include "fwil.h"
#include "feature.h"
+2 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ do { \
#define BRCMF_EVENT_ON()	(brcmf_msg_level & BRCMF_EVENT_VAL)
#define BRCMF_FIL_ON()		(brcmf_msg_level & BRCMF_FIL_VAL)
#define BRCMF_FWCON_ON()	(brcmf_msg_level & BRCMF_FWCON_VAL)
#define BRCMF_SCAN_ON()		(brcmf_msg_level & BRCMF_SCAN_VAL)

#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */

@@ -96,6 +97,7 @@ do { \
#define BRCMF_EVENT_ON()	0
#define BRCMF_FIL_ON()		0
#define BRCMF_FWCON_ON()	0
#define BRCMF_SCAN_ON()		0

#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */

+19 −13
Original line number Diff line number Diff line
@@ -835,15 +835,18 @@ struct brcmf_gtk_keyinfo_le {
	u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
};

#define BRCMF_PNO_REPORT_NO_BATCH	BIT(2)

/**
 * struct brcmf_gscan_bucket_config - configuration data for channel bucket.
 *
 * @bucket_end_index: !unknown!
 * @bucket_freq_multiple: !unknown!
 * @flag: !unknown!
 * @reserved: !unknown!
 * @repeat: !unknown!
 * @max_freq_multiple: !unknown!
 * @bucket_end_index: last channel index in @channel_list in
 *	@struct brcmf_pno_config_le.
 * @bucket_freq_multiple: scan interval expressed in N * @scan_freq.
 * @flag: channel bucket report flags.
 * @reserved: for future use.
 * @repeat: number of scan at interval for exponential scan.
 * @max_freq_multiple: maximum scan interval for exponential scan.
 */
struct brcmf_gscan_bucket_config {
	u8 bucket_end_index;
@@ -855,16 +858,19 @@ struct brcmf_gscan_bucket_config {
};

/* version supported which must match firmware */
#define BRCMF_GSCAN_CFG_VERSION                     1
#define BRCMF_GSCAN_CFG_VERSION                     2

/**
 * enum brcmf_gscan_cfg_flags - bit values for gscan flags.
 *
 * @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host.
 * @BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN: all buckets will be included in
 *	first scan cycle.
 * @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed.
 */
enum brcmf_gscan_cfg_flags {
	BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0),
	BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN = BIT(3),
	BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7),
};

Loading