linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V4 1/3] brcmfmac: add support multi-scheduled scan
@ 2017-05-19  7:57 Arend van Spriel
  2017-05-19  7:57 ` [PATCH V4 2/3] brcmfmac: add mutex to protect pno requests Arend van Spriel
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Arend van Spriel @ 2017-05-19  7:57 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Arend Van Spriel

From: Arend Van Spriel <arend.vanspriel@broadcom.com>

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: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c         |  67 +++-
 .../broadcom/brcm80211/brcmfmac/cfg80211.h         |   6 +-
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |   1 +
 .../wireless/broadcom/brcm80211/brcmfmac/debug.h   |   2 +
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       |  32 +-
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 398 ++++++++++++++++++---
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.h |  47 ++-
 7 files changed, 464 insertions(+), 89 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 2bf76bd..0bc2c04 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -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 @@ static void brcmf_escan_timeout(unsigned long data)
 		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 @@ static void brcmf_escan_timeout(unsigned long data)
 		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 @@ static int brcmf_start_internal_escan(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 @@ static int brcmf_start_internal_escan(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 @@ static int brcmf_start_internal_escan(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 @@ static int brcmf_start_internal_escan(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 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp,
 	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;
 }
@@ -6944,6 +6966,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);
@@ -6976,6 +7005,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:
@@ -6995,6 +7025,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);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index a1c2e0a..12ff154 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -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;
 };
 
 /**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index a3d8236..a88da5a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -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"
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
index fe264a5..35919d9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
@@ -78,6 +78,7 @@
 #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 @@
 #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) */
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 8c18fad..45aaae8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -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];
 };
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index a473445..5ae0680 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -14,6 +14,7 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/netdevice.h>
+#include <linux/gcd.h>
 #include <net/cfg80211.h>
 
 #include "core.h"
@@ -35,6 +36,59 @@
 #define BRCMF_PNO_HIDDEN_BIT		2
 #define BRCMF_PNO_SCHED_SCAN_PERIOD	30
 
+#define BRCMF_PNO_MAX_BUCKETS		16
+#define GSCAN_BATCH_NO_THR_SET			101
+#define GSCAN_RETRY_THRESHOLD			3
+
+struct brcmf_pno_info {
+	int n_reqs;
+	struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS];
+};
+
+#define ifp_to_pno(_ifp)	((_ifp)->drvr->config->pno)
+
+static int brcmf_pno_store_request(struct brcmf_pno_info *pi,
+				   struct cfg80211_sched_scan_request *req)
+{
+	if (WARN_ON(pi->n_reqs == BRCMF_PNO_MAX_BUCKETS)) {
+		brcmf_err("pno request storage full\n");
+		return -ENOSPC;
+	}
+	brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid);
+	pi->reqs[pi->n_reqs++] = req;
+	return 0;
+}
+
+static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid)
+{
+	int i;
+
+	/* find request */
+	for (i = 0; i < pi->n_reqs; i++) {
+		if (pi->reqs[i]->reqid == reqid)
+			break;
+	}
+	/* request not found */
+	if (WARN_ON(i == pi->n_reqs)) {
+		brcmf_err("reqid not found\n");
+		return -ENOENT;
+	}
+
+	brcmf_dbg(SCAN, "reqid=%llu\n", reqid);
+	pi->n_reqs--;
+
+	/* if last we are done */
+	if (!pi->n_reqs || i == pi->n_reqs)
+		return 0;
+
+	/* fill the gap with remaining requests */
+	while (i <= pi->n_reqs - 1) {
+		pi->reqs[i] = pi->reqs[i + 1];
+		i++;
+	}
+	return 0;
+}
+
 static int brcmf_pno_channel_config(struct brcmf_if *ifp,
 				    struct brcmf_pno_config_le *cfg)
 {
@@ -63,10 +117,6 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq,
 	pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
 
 	/* set up pno scan fr */
-	if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) {
-		brcmf_dbg(SCAN, "scan period too small, using minimum\n");
-		scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD;
-	}
 	pfn_param.scan_freq = cpu_to_le32(scan_freq);
 
 	if (mscan) {
@@ -101,12 +151,24 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq,
 	return err;
 }
 
-static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr,
-				u8 *mac_mask)
+static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi)
 {
 	struct brcmf_pno_macaddr_le pfn_mac;
+	u8 *mac_addr;
+	u8 *mac_mask;
 	int err, i;
 
+	for (i = 0; i < pi->n_reqs; i++)
+		if (pi->reqs[i]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+			mac_addr = pi->reqs[i]->mac_addr;
+			mac_mask = pi->reqs[i]->mac_addr_mask;
+			break;
+		}
+
+	/* no random mac requested */
+	if (i == pi->n_reqs)
+		return 0;
+
 	pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
 	pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
 
@@ -120,6 +182,8 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr,
 	/* Set locally administered */
 	pfn_mac.mac[0] |= 0x02;
 
+	brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n",
+		  pi->reqs[i]->reqid, pfn_mac.mac);
 	err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
 				       sizeof(pfn_mac));
 	if (err)
@@ -163,7 +227,7 @@ static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid,
 	return false;
 }
 
-int brcmf_pno_clean(struct brcmf_if *ifp)
+static int brcmf_pno_clean(struct brcmf_if *ifp)
 {
 	int ret;
 
@@ -179,73 +243,307 @@ int brcmf_pno_clean(struct brcmf_if *ifp)
 	return ret;
 }
 
-int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
-			       struct cfg80211_sched_scan_request *req)
+static int brcmf_pno_get_bucket_channels(struct cfg80211_sched_scan_request *r,
+					 struct brcmf_pno_config_le *pno_cfg)
 {
-	struct brcmf_pno_config_le pno_cfg;
-	struct cfg80211_ssid *ssid;
+	u32 n_chan = le32_to_cpu(pno_cfg->channel_num);
 	u16 chan;
-	int i, ret;
+	int i, err = 0;
 
-	/* clean up everything */
-	ret = brcmf_pno_clean(ifp);
-	if  (ret < 0) {
-		brcmf_err("failed error=%d\n", ret);
-		return ret;
+	for (i = 0; i < r->n_channels; i++) {
+		if (n_chan >= BRCMF_NUMCHANNELS) {
+			err = -ENOSPC;
+			goto done;
+		}
+		chan = r->channels[i]->hw_value;
+		brcmf_dbg(SCAN, "[%d] Chan : %u\n", n_chan, chan);
+		pno_cfg->channel_list[n_chan++] = cpu_to_le16(chan);
 	}
+	/* return number of channels */
+	err = n_chan;
+done:
+	pno_cfg->channel_num = cpu_to_le32(n_chan);
+	return err;
+}
 
-	/* configure pno */
-	ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0);
-	if (ret < 0)
-		return ret;
-
-	/* configure random mac */
-	if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
-		ret = brcmf_pno_set_random(ifp, req->mac_addr,
-					   req->mac_addr_mask);
-		if (ret < 0)
-			return ret;
+static int brcmf_pno_prep_fwconfig(struct brcmf_pno_info *pi,
+				   struct brcmf_pno_config_le *pno_cfg,
+				   struct brcmf_gscan_bucket_config **buckets,
+				   u32 *scan_freq)
+{
+	struct cfg80211_sched_scan_request *sr;
+	struct brcmf_gscan_bucket_config *fw_buckets;
+	int i, err, chidx;
+
+	brcmf_dbg(SCAN, "n_reqs=%d\n", pi->n_reqs);
+	if (WARN_ON(!pi->n_reqs))
+		return -ENODATA;
+
+	/*
+	 * actual scan period is determined using gcd() for each
+	 * scheduled scan period.
+	 */
+	*scan_freq = pi->reqs[0]->scan_plans[0].interval;
+	for (i = 1; i < pi->n_reqs; i++) {
+		sr = pi->reqs[i];
+		*scan_freq = gcd(sr->scan_plans[0].interval, *scan_freq);
+	}
+	if (*scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) {
+		brcmf_dbg(SCAN, "scan period too small, using minimum\n");
+		*scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD;
 	}
 
-	/* configure channels to use */
-	for (i = 0; i < req->n_channels; i++) {
-		chan = req->channels[i]->hw_value;
-		pno_cfg.channel_list[i] = cpu_to_le16(chan);
+	*buckets = NULL;
+	fw_buckets = kcalloc(pi->n_reqs, sizeof(*fw_buckets), GFP_KERNEL);
+	if (!fw_buckets)
+		return -ENOMEM;
+
+	memset(pno_cfg, 0, sizeof(*pno_cfg));
+	for (i = 0; i < pi->n_reqs; i++) {
+		sr = pi->reqs[i];
+		chidx = brcmf_pno_get_bucket_channels(sr, pno_cfg);
+		if (chidx < 0) {
+			err = chidx;
+			goto fail;
+		}
+		fw_buckets[i].bucket_end_index = chidx - 1;
+		fw_buckets[i].bucket_freq_multiple =
+			sr->scan_plans[0].interval / *scan_freq;
+		/* assure period is non-zero */
+		if (!fw_buckets[i].bucket_freq_multiple)
+			fw_buckets[i].bucket_freq_multiple = 1;
+		fw_buckets[i].flag = BRCMF_PNO_REPORT_NO_BATCH;
 	}
-	if (req->n_channels) {
-		pno_cfg.channel_num = cpu_to_le32(req->n_channels);
-		brcmf_pno_channel_config(ifp, &pno_cfg);
+
+	if (BRCMF_SCAN_ON()) {
+		brcmf_err("base period=%u\n", *scan_freq);
+		for (i = 0; i < pi->n_reqs; i++) {
+			brcmf_err("[%d] period %u max %u repeat %u flag %x idx %u\n",
+				  i, fw_buckets[i].bucket_freq_multiple,
+				  le16_to_cpu(fw_buckets[i].max_freq_multiple),
+				  fw_buckets[i].repeat, fw_buckets[i].flag,
+				  fw_buckets[i].bucket_end_index);
+		}
 	}
+	*buckets = fw_buckets;
+	return pi->n_reqs;
 
-	/* configure each match set */
-	for (i = 0; i < req->n_match_sets; i++) {
-		ssid = &req->match_sets[i].ssid;
-		if (!ssid->ssid_len) {
-			brcmf_err("skip broadcast ssid\n");
-			continue;
+fail:
+	kfree(fw_buckets);
+	return err;
+}
+
+static int brcmf_pno_config_ssids(struct brcmf_if *ifp,
+				  struct brcmf_pno_info *pi)
+{
+	struct cfg80211_sched_scan_request *r;
+	struct cfg80211_match_set *ms;
+	bool active;
+	int i, j, err;
+
+	for (i = 0; i < pi->n_reqs; i++) {
+		r = pi->reqs[i];
+
+		for (j = 0; j < r->n_match_sets; j++) {
+			ms = &r->match_sets[j];
+			if (!ms->ssid.ssid_len)
+				continue;
+			active = brcmf_is_ssid_active(&ms->ssid, r);
+			brcmf_dbg(SCAN, "adding %.32s (active=%d)\n",
+				  ms->ssid.ssid, active);
+			err = brcmf_pno_add_ssid(ifp, &ms->ssid, active);
+			if (err < 0) {
+				brcmf_err("adding failed: err=%d\n", err);
+				return err;
+			}
 		}
+	}
+	return 0;
+}
+
+static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp)
+{
+	struct brcmf_pno_info *pi;
+	struct brcmf_gscan_config *gscan_cfg;
+	struct brcmf_gscan_bucket_config *buckets;
+	struct brcmf_pno_config_le pno_cfg;
+	size_t gsz;
+	u32 scan_freq;
+	int err, n_buckets;
+
+	pi = ifp_to_pno(ifp);
+	n_buckets = brcmf_pno_prep_fwconfig(pi, &pno_cfg, &buckets,
+					    &scan_freq);
+	if (n_buckets < 0)
+		return n_buckets;
+
+	gsz = sizeof(*gscan_cfg) + (n_buckets - 1) * sizeof(*buckets);
+	gscan_cfg = kzalloc(gsz, GFP_KERNEL);
+	if (!gscan_cfg) {
+		err = -ENOMEM;
+		goto free_buckets;
+	}
 
-		ret = brcmf_pno_add_ssid(ifp, ssid,
-					 brcmf_is_ssid_active(ssid, req));
-		if (ret < 0)
-			brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
-				  ret == 0 ? "set" : "failed", ssid->ssid);
+	/* clean up everything */
+	err = brcmf_pno_clean(ifp);
+	if  (err < 0) {
+		brcmf_err("failed error=%d\n", err);
+		goto free_gscan;
 	}
+
+	/* configure pno */
+	err = brcmf_pno_config(ifp, scan_freq, 0, 0);
+	if (err < 0)
+		goto free_gscan;
+
+	err = brcmf_pno_channel_config(ifp, &pno_cfg);
+	if (err < 0)
+		goto clean;
+
+	gscan_cfg->version = cpu_to_le16(BRCMF_GSCAN_CFG_VERSION);
+	gscan_cfg->retry_threshold = GSCAN_RETRY_THRESHOLD;
+	gscan_cfg->buffer_threshold = GSCAN_BATCH_NO_THR_SET;
+	gscan_cfg->flags = BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN;
+
+	gscan_cfg->count_of_channel_buckets = n_buckets;
+	memcpy(&gscan_cfg->bucket[0], buckets,
+	       n_buckets * sizeof(*buckets));
+
+	err = brcmf_fil_iovar_data_set(ifp, "pfn_gscan_cfg", gscan_cfg, gsz);
+
+	if (err < 0)
+		goto clean;
+
+	/* configure random mac */
+	err = brcmf_pno_set_random(ifp, pi);
+	if (err < 0)
+		goto clean;
+
+	err = brcmf_pno_config_ssids(ifp, pi);
+	if (err < 0)
+		goto clean;
+
 	/* Enable the PNO */
-	ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1);
+	err = brcmf_fil_iovar_int_set(ifp, "pfn", 1);
+
+clean:
+	if (err < 0)
+		brcmf_pno_clean(ifp);
+free_gscan:
+	kfree(gscan_cfg);
+free_buckets:
+	kfree(buckets);
+	return err;
+}
+
+int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
+			       struct cfg80211_sched_scan_request *req)
+{
+	struct brcmf_pno_info *pi;
+	int ret;
+
+	brcmf_dbg(TRACE, "reqid=%llu\n", req->reqid);
+
+	pi = ifp_to_pno(ifp);
+	ret = brcmf_pno_store_request(pi, req);
 	if (ret < 0)
-		brcmf_err("PNO enable failed!! ret=%d\n", ret);
+		return ret;
 
-	return ret;
+	ret = brcmf_pno_config_sched_scans(ifp);
+	if (ret < 0) {
+		brcmf_pno_remove_request(pi, req->reqid);
+		if (pi->n_reqs)
+			(void)brcmf_pno_config_sched_scans(ifp);
+		return ret;
+	}
+	return 0;
+}
+
+int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid)
+{
+	struct brcmf_pno_info *pi;
+	int err;
+
+	brcmf_dbg(TRACE, "reqid=%llu\n", reqid);
+
+	pi = ifp_to_pno(ifp);
+	err = brcmf_pno_remove_request(pi, reqid);
+	if (err)
+		return err;
+
+	brcmf_pno_clean(ifp);
+
+	if (pi->n_reqs)
+		(void)brcmf_pno_config_sched_scans(ifp);
+
+	return 0;
+}
+
+int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_pno_info *pi;
+
+	brcmf_err("enter\n");
+	pi = kzalloc(sizeof(*pi), GFP_KERNEL);
+	if (!pi)
+		return -ENOMEM;
+
+	cfg->pno = pi;
+	return 0;
+}
+
+void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_pno_info *pi;
+
+	brcmf_err("enter\n");
+	pi = cfg->pno;
+	cfg->pno = NULL;
+
+	WARN_ON(pi->n_reqs);
+	kfree(pi);
 }
 
 void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan)
 {
 	/* scheduled scan settings */
-	wiphy->max_sched_scan_reqs = gscan ? 2 : 1;
+	wiphy->max_sched_scan_reqs = gscan ? BRCMF_PNO_MAX_BUCKETS : 1;
 	wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
 	wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
 	wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
 	wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
 }
 
+u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket)
+{
+	/* bucket appears to be gone */
+	if (bucket >= pi->n_reqs)
+		return 0;
+
+	return pi->reqs[bucket]->reqid;
+}
+
+u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
+			     struct brcmf_pno_net_info_le *ni)
+{
+	struct cfg80211_sched_scan_request *req;
+	struct cfg80211_match_set *ms;
+	u32 bucket_map = 0;
+	int i, j;
+
+	for (i = 0; i < pi->n_reqs; i++) {
+		req = pi->reqs[i];
+
+		if (!req->n_match_sets)
+			continue;
+		for (j = 0; j < req->n_match_sets; j++) {
+			ms = &req->match_sets[j];
+			if (ms->ssid.ssid_len == ni->SSID_len &&
+			    !strncmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) {
+				bucket_map |= BIT(i);
+				break;
+			}
+		}
+	}
+	return bucket_map;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
index 07ec51f..cd9e35a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
@@ -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.
@@ -38,6 +34,14 @@ 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.
  *
  * @wiphy: wiphy instance to be used.
@@ -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 */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH V4 2/3] brcmfmac: add mutex to protect pno requests
  2017-05-19  7:57 [PATCH V4 1/3] brcmfmac: add support multi-scheduled scan Arend van Spriel
@ 2017-05-19  7:57 ` Arend van Spriel
  2017-05-19  7:57 ` [PATCH V4 3/3] brcmfmac: add scheduled scan support for specified BSSIDs Arend van Spriel
  2017-05-22 15:16 ` [V4,1/3] brcmfmac: add support multi-scheduled scan Kalle Valo
  2 siblings, 0 replies; 7+ messages in thread
From: Arend van Spriel @ 2017-05-19  7:57 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Arend Van Spriel

From: Arend Van Spriel <arend.vanspriel@broadcom.com>

The request references kept in pno are accessed in user-space context
and in firmware event handler context. As such we need to protect it
with a lock. As both context allow sleep a mutex seems appropriate.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 33 ++++++++++++++++------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index 5ae0680..81e8549 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -43,6 +43,7 @@
 struct brcmf_pno_info {
 	int n_reqs;
 	struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS];
+	struct mutex req_lock;
 };
 
 #define ifp_to_pno(_ifp)	((_ifp)->drvr->config->pno)
@@ -55,13 +56,17 @@ static int brcmf_pno_store_request(struct brcmf_pno_info *pi,
 		return -ENOSPC;
 	}
 	brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid);
+	mutex_lock(&pi->req_lock);
 	pi->reqs[pi->n_reqs++] = req;
+	mutex_unlock(&pi->req_lock);
 	return 0;
 }
 
 static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid)
 {
-	int i;
+	int i, err = 0;
+
+	mutex_lock(&pi->req_lock);
 
 	/* find request */
 	for (i = 0; i < pi->n_reqs; i++) {
@@ -71,7 +76,8 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid)
 	/* request not found */
 	if (WARN_ON(i == pi->n_reqs)) {
 		brcmf_err("reqid not found\n");
-		return -ENOENT;
+		err = -ENOENT;
+		goto done;
 	}
 
 	brcmf_dbg(SCAN, "reqid=%llu\n", reqid);
@@ -79,14 +85,17 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid)
 
 	/* if last we are done */
 	if (!pi->n_reqs || i == pi->n_reqs)
-		return 0;
+		goto done;
 
 	/* fill the gap with remaining requests */
 	while (i <= pi->n_reqs - 1) {
 		pi->reqs[i] = pi->reqs[i + 1];
 		i++;
 	}
-	return 0;
+
+done:
+	mutex_unlock(&pi->req_lock);
+	return err;
 }
 
 static int brcmf_pno_channel_config(struct brcmf_if *ifp,
@@ -489,6 +498,7 @@ int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg)
 		return -ENOMEM;
 
 	cfg->pno = pi;
+	mutex_init(&pi->req_lock);
 	return 0;
 }
 
@@ -501,6 +511,7 @@ void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg)
 	cfg->pno = NULL;
 
 	WARN_ON(pi->n_reqs);
+	mutex_destroy(&pi->req_lock);
 	kfree(pi);
 }
 
@@ -516,11 +527,15 @@ void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan)
 
 u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket)
 {
-	/* bucket appears to be gone */
-	if (bucket >= pi->n_reqs)
-		return 0;
+	u64 reqid = 0;
+
+	mutex_lock(&pi->req_lock);
+
+	if (bucket < pi->n_reqs)
+		reqid = pi->reqs[bucket]->reqid;
 
-	return pi->reqs[bucket]->reqid;
+	mutex_unlock(&pi->req_lock);
+	return reqid;
 }
 
 u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
@@ -531,6 +546,7 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 	u32 bucket_map = 0;
 	int i, j;
 
+	mutex_lock(&pi->req_lock);
 	for (i = 0; i < pi->n_reqs; i++) {
 		req = pi->reqs[i];
 
@@ -545,5 +561,6 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 			}
 		}
 	}
+	mutex_unlock(&pi->req_lock);
 	return bucket_map;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH V4 3/3] brcmfmac: add scheduled scan support for specified BSSIDs
  2017-05-19  7:57 [PATCH V4 1/3] brcmfmac: add support multi-scheduled scan Arend van Spriel
  2017-05-19  7:57 ` [PATCH V4 2/3] brcmfmac: add mutex to protect pno requests Arend van Spriel
@ 2017-05-19  7:57 ` Arend van Spriel
  2017-05-22 15:16 ` [V4,1/3] brcmfmac: add support multi-scheduled scan Kalle Valo
  2 siblings, 0 replies; 7+ messages in thread
From: Arend van Spriel @ 2017-05-19  7:57 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Arend Van Spriel

From: Arend Van Spriel <arend.vanspriel@broadcom.com>

Add support to handle scheduled scan request containing BSSID in
the matchsets. The firmware can send event upon finding BSSIDs and
SSIDs. To get these in one event the bit REPORT_SEPARATELY needed
to be removed from the flags in brcmf_pno_config().

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       | 11 ++++
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 58 ++++++++++++++++------
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 45aaae8..b857d53 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -806,6 +806,17 @@ struct brcmf_pno_macaddr_le {
 };
 
 /**
+ * struct brcmf_pno_bssid_le - bssid configuration for PNO scan.
+ *
+ * @bssid: BSS network identifier.
+ * @flags: flags for this BSSID.
+ */
+struct brcmf_pno_bssid_le {
+	u8 bssid[ETH_ALEN];
+	__le16 flags;
+};
+
+/**
  * struct brcmf_pktcnt_le - packet counters.
  *
  * @rx_good_pkt: packets (MSDUs & MMPDUs) received from this station
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index 81e8549..9623157 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -120,7 +120,6 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq,
 
 	/* set extra pno params */
 	flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) |
-		BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) |
 		BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
 	pfn_param.repeat = BRCMF_PNO_REPEAT;
 	pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
@@ -205,6 +204,7 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
 			      bool active)
 {
 	struct brcmf_pno_net_param_le pfn;
+	int err;
 
 	pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
 	pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
@@ -215,7 +215,28 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
 		pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
 	pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len);
 	memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len);
-	return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn));
+
+	brcmf_dbg(SCAN, "adding ssid=%.32s (active=%d)\n", ssid->ssid, active);
+	err = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn));
+	if (err < 0)
+		brcmf_err("adding failed: err=%d\n", err);
+	return err;
+}
+
+static int brcmf_pno_add_bssid(struct brcmf_if *ifp, const u8 *bssid)
+{
+	struct brcmf_pno_bssid_le bssid_cfg;
+	int err;
+
+	memcpy(bssid_cfg.bssid, bssid, ETH_ALEN);
+	bssid_cfg.flags = 0;
+
+	brcmf_dbg(SCAN, "adding bssid=%pM\n", bssid);
+	err = brcmf_fil_iovar_data_set(ifp, "pfn_add_bssid", &bssid_cfg,
+				       sizeof(bssid_cfg));
+	if (err < 0)
+		brcmf_err("adding failed: err=%d\n", err);
+	return err;
 }
 
 static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid,
@@ -342,29 +363,29 @@ static int brcmf_pno_prep_fwconfig(struct brcmf_pno_info *pi,
 	return err;
 }
 
-static int brcmf_pno_config_ssids(struct brcmf_if *ifp,
-				  struct brcmf_pno_info *pi)
+static int brcmf_pno_config_networks(struct brcmf_if *ifp,
+				     struct brcmf_pno_info *pi)
 {
 	struct cfg80211_sched_scan_request *r;
 	struct cfg80211_match_set *ms;
 	bool active;
-	int i, j, err;
+	int i, j, err = 0;
 
 	for (i = 0; i < pi->n_reqs; i++) {
 		r = pi->reqs[i];
 
 		for (j = 0; j < r->n_match_sets; j++) {
 			ms = &r->match_sets[j];
-			if (!ms->ssid.ssid_len)
-				continue;
-			active = brcmf_is_ssid_active(&ms->ssid, r);
-			brcmf_dbg(SCAN, "adding %.32s (active=%d)\n",
-				  ms->ssid.ssid, active);
-			err = brcmf_pno_add_ssid(ifp, &ms->ssid, active);
-			if (err < 0) {
-				brcmf_err("adding failed: err=%d\n", err);
-				return err;
+			if (ms->ssid.ssid_len) {
+				active = brcmf_is_ssid_active(&ms->ssid, r);
+				err = brcmf_pno_add_ssid(ifp, &ms->ssid,
+							 active);
 			}
+			if (!err && is_valid_ether_addr(ms->bssid))
+				err = brcmf_pno_add_bssid(ifp, ms->bssid);
+
+			if (err < 0)
+				return err;
 		}
 	}
 	return 0;
@@ -428,7 +449,7 @@ static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp)
 	if (err < 0)
 		goto clean;
 
-	err = brcmf_pno_config_ssids(ifp, pi);
+	err = brcmf_pno_config_networks(ifp, pi);
 	if (err < 0)
 		goto clean;
 
@@ -555,7 +576,12 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 		for (j = 0; j < req->n_match_sets; j++) {
 			ms = &req->match_sets[j];
 			if (ms->ssid.ssid_len == ni->SSID_len &&
-			    !strncmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) {
+			    !memcmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) {
+				bucket_map |= BIT(i);
+				break;
+			}
+			if (is_valid_ether_addr(ms->bssid) &&
+			    !memcmp(ms->bssid, ni->bssid, ETH_ALEN)) {
 				bucket_map |= BIT(i);
 				break;
 			}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [V4,1/3] brcmfmac: add support multi-scheduled scan
  2017-05-19  7:57 [PATCH V4 1/3] brcmfmac: add support multi-scheduled scan Arend van Spriel
  2017-05-19  7:57 ` [PATCH V4 2/3] brcmfmac: add mutex to protect pno requests Arend van Spriel
  2017-05-19  7:57 ` [PATCH V4 3/3] brcmfmac: add scheduled scan support for specified BSSIDs Arend van Spriel
@ 2017-05-22 15:16 ` Kalle Valo
  2017-06-07  8:15   ` Arend van Spriel
  2 siblings, 1 reply; 7+ messages in thread
From: Kalle Valo @ 2017-05-22 15:16 UTC (permalink / raw)
  To: Arend Van Spriel; +Cc: linux-wireless, Arend Van Spriel

Arend Van Spriel <arend.vanspriel@broadcom.com> wrote:
> From: Arend Van Spriel <arend.vanspriel@broadcom.com>
> 
> 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: Hante Meuleman <hante.meuleman@broadcom.com>
> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>

I see new warnings:

drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c: In function ‘brcmf_pno_config_sched_scans’:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:166:6: warning: ‘mac_mask’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  u8 *mac_mask;
      ^
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:183:2: warning: ‘mac_addr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  memcpy(pfn_mac.mac, mac_addr, ETH_ALEN);
  ^
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:165:6: note: ‘mac_addr’ was declared here
  u8 *mac_addr;
      ^

3 patches set to Changes Requested.

9736151 [V4,1/3] brcmfmac: add support multi-scheduled scan
9736147 [V4,2/3] brcmfmac: add mutex to protect pno requests
9736149 [V4,3/3] brcmfmac: add scheduled scan support for specified BSSIDs

-- 
https://patchwork.kernel.org/patch/9736151/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [V4,1/3] brcmfmac: add support multi-scheduled scan
  2017-05-22 15:16 ` [V4,1/3] brcmfmac: add support multi-scheduled scan Kalle Valo
@ 2017-06-07  8:15   ` Arend van Spriel
  2017-06-07 14:53     ` Kalle Valo
  0 siblings, 1 reply; 7+ messages in thread
From: Arend van Spriel @ 2017-06-07  8:15 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless

On 5/22/2017 5:16 PM, Kalle Valo wrote:
> Arend Van Spriel <arend.vanspriel@broadcom.com> wrote:
>> From: Arend Van Spriel <arend.vanspriel@broadcom.com>
>>
>> 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: Hante Meuleman <hante.meuleman@broadcom.com>
>> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
>> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
>> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
> 
> I see new warnings:
> 
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c: In function ‘brcmf_pno_config_sched_scans’:
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:166:6: warning: ‘mac_mask’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>    u8 *mac_mask;
>        ^
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:183:2: warning: ‘mac_addr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>    memcpy(pfn_mac.mac, mac_addr, ETH_ALEN);
>    ^
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:165:6: note: ‘mac_addr’ was declared here
>    u8 *mac_addr;
>        ^
> 
> 3 patches set to Changes Requested.
> 
> 9736151 [V4,1/3] brcmfmac: add support multi-scheduled scan
> 9736147 [V4,2/3] brcmfmac: add mutex to protect pno requests
> 9736149 [V4,3/3] brcmfmac: add scheduled scan support for specified BSSIDs

Not seeing it here using gcc version 4.8.4 (Ubuntu 
4.8.4-2ubuntu1~14.04.3). Also tried using W=1 on the make command line. 
Getting a bunck of other warnings, but not the ones above. Do you want 
me to fix it?

Regards,
Arend

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [V4,1/3] brcmfmac: add support multi-scheduled scan
  2017-06-07  8:15   ` Arend van Spriel
@ 2017-06-07 14:53     ` Kalle Valo
  2017-06-07 16:46       ` Arend van Spriel
  0 siblings, 1 reply; 7+ messages in thread
From: Kalle Valo @ 2017-06-07 14:53 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: linux-wireless

Arend van Spriel <arend.vanspriel@broadcom.com> writes:

> On 5/22/2017 5:16 PM, Kalle Valo wrote:
>> Arend Van Spriel <arend.vanspriel@broadcom.com> wrote:
>>> From: Arend Van Spriel <arend.vanspriel@broadcom.com>
>>>
>>> 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 reque=
st.
>>> 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: Hante Meuleman <hante.meuleman@broadcom.com>
>>> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
>>> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
>>> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
>>
>> I see new warnings:
>>
>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c: In function =E2=
=80=98brcmf_pno_config_sched_scans=E2=80=99:
>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:166:6: warning: =
=E2=80=98mac_mask=E2=80=99 may be used uninitialized in this function [-Wma=
ybe-uninitialized]
>>    u8 *mac_mask;
>>        ^
>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:183:2: warning: =
=E2=80=98mac_addr=E2=80=99 may be used uninitialized in this function [-Wma=
ybe-uninitialized]
>>    memcpy(pfn_mac.mac, mac_addr, ETH_ALEN);
>>    ^
>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:165:6: note: =E2=
=80=98mac_addr=E2=80=99 was declared here
>>    u8 *mac_addr;
>>        ^
>>
>> 3 patches set to Changes Requested.
>>
>> 9736151 [V4,1/3] brcmfmac: add support multi-scheduled scan
>> 9736147 [V4,2/3] brcmfmac: add mutex to protect pno requests
>> 9736149 [V4,3/3] brcmfmac: add scheduled scan support for specified BSSI=
Ds
>
> Not seeing it here using gcc version 4.8.4 (Ubuntu
> 4.8.4-2ubuntu1~14.04.3).

My version is:

gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

I don't think that's really exocit version of the compiler, or is it?

> Also tried using W=3D1 on the make command
> line. Getting a bunck of other warnings, but not the ones above.

This was without W=3D1, just a default compilation with all wireless
drivers enabled.

> Do you want me to fix it?

Yes, please. I try to keep the patches warning free, even if they are
false warnings.

--=20
Kalle Valo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [V4,1/3] brcmfmac: add support multi-scheduled scan
  2017-06-07 14:53     ` Kalle Valo
@ 2017-06-07 16:46       ` Arend van Spriel
  0 siblings, 0 replies; 7+ messages in thread
From: Arend van Spriel @ 2017-06-07 16:46 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless

On 07-06-17 16:53, Kalle Valo wrote:
> Arend van Spriel <arend.vanspriel@broadcom.com> writes:
> 
>> On 5/22/2017 5:16 PM, Kalle Valo wrote:
>>> Arend Van Spriel <arend.vanspriel@broadcom.com> wrote:
>>>> From: Arend Van Spriel <arend.vanspriel@broadcom.com>
>>>>
>>>> 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: Hante Meuleman <hante.meuleman@broadcom.com>
>>>> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
>>>> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
>>>> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
>>>
>>> I see new warnings:
>>>
>>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c: In function ‘brcmf_pno_config_sched_scans’:
>>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:166:6: warning: ‘mac_mask’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>>>    u8 *mac_mask;
>>>        ^
>>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:183:2: warning: ‘mac_addr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>>>    memcpy(pfn_mac.mac, mac_addr, ETH_ALEN);
>>>    ^
>>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c:165:6: note: ‘mac_addr’ was declared here
>>>    u8 *mac_addr;
>>>        ^
>>>
>>> 3 patches set to Changes Requested.
>>>
>>> 9736151 [V4,1/3] brcmfmac: add support multi-scheduled scan
>>> 9736147 [V4,2/3] brcmfmac: add mutex to protect pno requests
>>> 9736149 [V4,3/3] brcmfmac: add scheduled scan support for specified BSSIDs
>>
>> Not seeing it here using gcc version 4.8.4 (Ubuntu
>> 4.8.4-2ubuntu1~14.04.3).
> 
> My version is:
> 
> gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
> 
> I don't think that's really exocit version of the compiler, or is it?

Nope.

>> Also tried using W=1 on the make command
>> line. Getting a bunck of other warnings, but not the ones above.
> 
> This was without W=1, just a default compilation with all wireless
> drivers enabled.
> 
>> Do you want me to fix it?
> 
> Yes, please. I try to keep the patches warning free, even if they are
> false warnings.

Will do. And thanks again for the reminder ;-)

Regards,
Arend

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-06-07 16:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-19  7:57 [PATCH V4 1/3] brcmfmac: add support multi-scheduled scan Arend van Spriel
2017-05-19  7:57 ` [PATCH V4 2/3] brcmfmac: add mutex to protect pno requests Arend van Spriel
2017-05-19  7:57 ` [PATCH V4 3/3] brcmfmac: add scheduled scan support for specified BSSIDs Arend van Spriel
2017-05-22 15:16 ` [V4,1/3] brcmfmac: add support multi-scheduled scan Kalle Valo
2017-06-07  8:15   ` Arend van Spriel
2017-06-07 14:53     ` Kalle Valo
2017-06-07 16:46       ` Arend van Spriel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).