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

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
......@@ -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");
......@@ -749,7 +751,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le, sizeof(params_le));
if (err)
brcmf_err("Scan abort failed\n");
brcmf_err("Scan abort failed\n");
}
brcmf_scan_config_mpc(ifp, 1);
......@@ -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);
......
......@@ -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;
};
/**
......
......@@ -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"
......
......@@ -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) */
......
......@@ -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),
};
......@@ -884,12 +890,12 @@ enum brcmf_gscan_cfg_flags {
*/
struct brcmf_gscan_config {
__le16 version;
u8 flags;
u8 buffer_threshold;
u8 swc_nbssid_threshold;
u8 swc_rssi_window_size;
u8 count_of_channel_buckets;
u8 retry_threshold;
u8 flags;
u8 buffer_threshold;
u8 swc_nbssid_threshold;
u8 swc_rssi_window_size;
u8 count_of_channel_buckets;
u8 retry_threshold;
__le16 lost_ap_window;
struct brcmf_gscan_bucket_config bucket[1];
};
......
......@@ -21,12 +21,8 @@
#define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10
#define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508
/**
* brcmf_pno_clean - disable and clear pno in firmware.
*
* @ifp: interface object used.
*/
int brcmf_pno_clean(struct brcmf_if *ifp);
/* forward declaration */
struct brcmf_pno_info;
/**
* brcmf_pno_start_sched_scan - initiate scheduled scan on device.
......@@ -37,6 +33,14 @@ int brcmf_pno_clean(struct brcmf_if *ifp);
int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
struct cfg80211_sched_scan_request *req);
/**
* brcmf_pno_stop_sched_scan - terminate scheduled scan on device.
*
* @ifp: interface object used.
* @reqid: unique identifier of scan to be stopped.
*/
int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid);
/**
* brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance.
*
......@@ -45,4 +49,35 @@ int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
*/
void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan);
/**
* brcmf_pno_attach - allocate and attach module information.
*
* @cfg: cfg80211 context used.
*/
int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg);
/**
* brcmf_pno_detach - detach and free module information.
*
* @cfg: cfg80211 context used.
*/
void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg);
/**
* brcmf_pno_find_reqid_by_bucket - find request id for given bucket index.
*
* @pi: pno instance used.
* @bucket: index of firmware bucket.
*/
u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket);
/**
* brcmf_pno_get_bucket_map - determine bucket map for given netinfo.
*
* @pi: pno instance used.
* @netinfo: netinfo to compare with bucket configuration.
*/
u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
struct brcmf_pno_net_info_le *netinfo);
#endif /* _BRCMF_PNO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment