lkml.org 
[lkml]   [2023]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH 03/10] brcmfmac: cfg80211: Add support for scan params v2
From
On 2/14/2023 10:24 AM, Hector Martin wrote:
> This new API version is required for at least the BCM4387 firmware. Add
> support for it, with a fallback to the v1 API.

This one is on my TODO list because both WCC and BCA chips have a
scanv2, but they are different. Anyway, I will have to sort that out
afterwards ;-)

Thanks,
Arend

> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
> Signed-off-by: Hector Martin <marcan@marcan.st>
> ---
> .../broadcom/brcm80211/brcmfmac/cfg80211.c | 245 +++++++++++-------
> .../broadcom/brcm80211/brcmfmac/feature.c | 1 +
> .../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
> .../broadcom/brcm80211/brcmfmac/fwil_types.h | 49 +++-
> 4 files changed, 209 insertions(+), 90 deletions(-)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> index a9690ec4c850..3e006b783f3f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> @@ -1039,12 +1039,134 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
> }
> }
>
> +static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
> + struct brcmf_scan_params_le *params_le)
> +{
> + size_t params_size;
> + u32 ch;
> + int n_channels, n_ssids;
> +
> + memcpy(&params_le->ssid_le, &params_v2_le->ssid_le,
> + sizeof(params_le->ssid_le));
> + memcpy(&params_le->bssid, &params_v2_le->bssid,
> + sizeof(params_le->bssid));
> +
> + params_le->bss_type = params_v2_le->bss_type;
> + params_le->scan_type = le32_to_cpu(params_v2_le->scan_type);
> + params_le->nprobes = params_v2_le->nprobes;
> + params_le->active_time = params_v2_le->active_time;
> + params_le->passive_time = params_v2_le->passive_time;
> + params_le->home_time = params_v2_le->home_time;
> + params_le->channel_num = params_v2_le->channel_num;
> +
> + ch = le32_to_cpu(params_v2_le->channel_num);
> + n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
> + n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
> +
> + params_size = sizeof(u16) * n_channels;
> + if (n_ssids > 0) {
> + params_size = roundup(params_size, sizeof(u32));
> + params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
> + }
> +
> + memcpy(&params_le->channel_list[0],
> + &params_v2_le->channel_list[0], params_size);
> +}
> +
> +static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
> + struct brcmf_scan_params_v2_le *params_le,
> + struct cfg80211_scan_request *request)
> +{
> + u32 n_ssids;
> + u32 n_channels;
> + s32 i;
> + s32 offset;
> + u16 chanspec;
> + char *ptr;
> + int length;
> + struct brcmf_ssid_le ssid_le;
> +
> + eth_broadcast_addr(params_le->bssid);
> +
> + length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
> +
> + params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2);
> + params_le->bss_type = DOT11_BSSTYPE_ANY;
> + params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE);
> + params_le->channel_num = 0;
> + params_le->nprobes = cpu_to_le32(-1);
> + params_le->active_time = cpu_to_le32(-1);
> + params_le->passive_time = cpu_to_le32(-1);
> + params_le->home_time = cpu_to_le32(-1);
> + memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
> +
> + /* Scan abort */
> + if (!request) {
> + length += sizeof(u16);
> + params_le->channel_num = cpu_to_le32(1);
> + params_le->channel_list[0] = cpu_to_le16(-1);
> + params_le->length = cpu_to_le16(length);
> + return;
> + }
> +
> + n_ssids = request->n_ssids;
> + n_channels = request->n_channels;
> +
> + /* Copy channel array if applicable */
> + brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
> + n_channels);
> + if (n_channels > 0) {
> + length += roundup(sizeof(u16) * n_channels, sizeof(u32));
> + for (i = 0; i < n_channels; i++) {
> + chanspec = channel_to_chanspec(&cfg->d11inf,
> + request->channels[i]);
> + brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
> + request->channels[i]->hw_value, chanspec);
> + params_le->channel_list[i] = cpu_to_le16(chanspec);
> + }
> + } else {
> + brcmf_dbg(SCAN, "Scanning all channels\n");
> + }
> +
> + /* Copy ssid array if applicable */
> + brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
> + if (n_ssids > 0) {
> + offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
> + n_channels * sizeof(u16);
> + offset = roundup(offset, sizeof(u32));
> + length += sizeof(ssid_le) * n_ssids,
> + ptr = (char *)params_le + offset;
> + for (i = 0; i < n_ssids; i++) {
> + memset(&ssid_le, 0, sizeof(ssid_le));
> + ssid_le.SSID_len =
> + cpu_to_le32(request->ssids[i].ssid_len);
> + memcpy(ssid_le.SSID, request->ssids[i].ssid,
> + request->ssids[i].ssid_len);
> + if (!ssid_le.SSID_len)
> + brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
> + else
> + 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);
> + }
> + } else {
> + brcmf_dbg(SCAN, "Performing passive scan\n");
> + params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE);
> + }
> + params_le->length = cpu_to_le16(length);
> + /* Adding mask to channel numbers */
> + params_le->channel_num =
> + cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
> + (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
> +}
> +
> s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
> struct brcmf_if *ifp, bool aborted,
> bool fw_abort)
> {
> struct brcmf_pub *drvr = cfg->pub;
> - struct brcmf_scan_params_le params_le;
> + struct brcmf_scan_params_v2_le params_v2_le;
> struct cfg80211_scan_request *scan_request;
> u64 reqid;
> u32 bucket;
> @@ -1063,20 +1185,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
> if (fw_abort) {
> /* Do a scan abort to stop the driver's scan engine */
> brcmf_dbg(SCAN, "ABORT scan in firmware\n");
> - memset(&params_le, 0, sizeof(params_le));
> - eth_broadcast_addr(params_le.bssid);
> - params_le.bss_type = DOT11_BSSTYPE_ANY;
> - params_le.scan_type = 0;
> - params_le.channel_num = cpu_to_le32(1);
> - params_le.nprobes = cpu_to_le32(1);
> - params_le.active_time = cpu_to_le32(-1);
> - params_le.passive_time = cpu_to_le32(-1);
> - params_le.home_time = cpu_to_le32(-1);
> - /* Scan is aborted by setting channel_list[0] to -1 */
> - params_le.channel_list[0] = cpu_to_le16(-1);
> +
> + brcmf_escan_prep(cfg, &params_v2_le, NULL);
> +
> /* E-Scan (or anyother type) can be aborted by SCAN */
> - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> - &params_le, sizeof(params_le));
> + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
> + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> + &params_v2_le,
> + sizeof(params_v2_le));
> + } else {
> + struct brcmf_scan_params_le params_le;
> +
> + brcmf_scan_params_v2_to_v1(&params_v2_le, &params_le);
> + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> + &params_le,
> + sizeof(params_le));
> + }
> +
> if (err)
> bphy_err(drvr, "Scan abort failed\n");
> }
> @@ -1295,83 +1420,13 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
> return err;
> }
>
> -static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
> - struct brcmf_scan_params_le *params_le,
> - struct cfg80211_scan_request *request)
> -{
> - u32 n_ssids;
> - u32 n_channels;
> - s32 i;
> - s32 offset;
> - u16 chanspec;
> - char *ptr;
> - struct brcmf_ssid_le ssid_le;
> -
> - eth_broadcast_addr(params_le->bssid);
> - params_le->bss_type = DOT11_BSSTYPE_ANY;
> - params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
> - params_le->channel_num = 0;
> - params_le->nprobes = cpu_to_le32(-1);
> - params_le->active_time = cpu_to_le32(-1);
> - params_le->passive_time = cpu_to_le32(-1);
> - params_le->home_time = cpu_to_le32(-1);
> - memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
> -
> - n_ssids = request->n_ssids;
> - n_channels = request->n_channels;
> -
> - /* Copy channel array if applicable */
> - brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
> - n_channels);
> - if (n_channels > 0) {
> - for (i = 0; i < n_channels; i++) {
> - chanspec = channel_to_chanspec(&cfg->d11inf,
> - request->channels[i]);
> - brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
> - request->channels[i]->hw_value, chanspec);
> - params_le->channel_list[i] = cpu_to_le16(chanspec);
> - }
> - } else {
> - brcmf_dbg(SCAN, "Scanning all channels\n");
> - }
> - /* Copy ssid array if applicable */
> - brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
> - if (n_ssids > 0) {
> - offset = offsetof(struct brcmf_scan_params_le, channel_list) +
> - n_channels * sizeof(u16);
> - offset = roundup(offset, sizeof(u32));
> - ptr = (char *)params_le + offset;
> - for (i = 0; i < n_ssids; i++) {
> - memset(&ssid_le, 0, sizeof(ssid_le));
> - ssid_le.SSID_len =
> - cpu_to_le32(request->ssids[i].ssid_len);
> - memcpy(ssid_le.SSID, request->ssids[i].ssid,
> - request->ssids[i].ssid_len);
> - if (!ssid_le.SSID_len)
> - brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
> - else
> - 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);
> - }
> - } else {
> - brcmf_dbg(SCAN, "Performing passive scan\n");
> - params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
> - }
> - /* Adding mask to channel numbers */
> - params_le->channel_num =
> - cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
> - (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
> -}
> -
> static s32
> brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
> struct cfg80211_scan_request *request)
> {
> struct brcmf_pub *drvr = cfg->pub;
> - s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
> - offsetof(struct brcmf_escan_params_le, params_le);
> + s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
> + offsetof(struct brcmf_escan_params_le, params_v2_le);
> struct brcmf_escan_params_le *params;
> s32 err = 0;
>
> @@ -1391,8 +1446,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
> goto exit;
> }
> BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
> - brcmf_escan_prep(cfg, &params->params_le, request);
> - params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
> + brcmf_escan_prep(cfg, &params->params_v2_le, request);
> +
> + params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
> +
> + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
> + struct brcmf_escan_params_le *params_v1;
> +
> + params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
> + params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
> + params_v1 = kzalloc(params_size, GFP_KERNEL);
> + params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
> + brcmf_scan_params_v2_to_v1(&params->params_v2_le, &params_v1->params_le);
> + kfree(params);
> + params = params_v1;
> + }
> +
> params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
> params->sync_id = cpu_to_le16(0x1234);
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> index 10bac865d724..b6797f800e55 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> @@ -290,6 +290,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
> ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
>
> brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
> + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver");
>
> if (drvr->settings->feature_disable) {
> brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> index f1b086a69d73..549298c55b55 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> @@ -30,6 +30,7 @@
> * SAE: simultaneous authentication of equals
> * FWAUTH: Firmware authenticator
> * DUMP_OBSS: Firmware has capable to dump obss info to support ACS
> + * SCAN_V2: Version 2 scan params
> */
> #define BRCMF_FEAT_LIST \
> BRCMF_FEAT_DEF(MBSS) \
> @@ -53,7 +54,8 @@
> BRCMF_FEAT_DEF(DOT11H) \
> BRCMF_FEAT_DEF(SAE) \
> BRCMF_FEAT_DEF(FWAUTH) \
> - BRCMF_FEAT_DEF(DUMP_OBSS)
> + BRCMF_FEAT_DEF(DUMP_OBSS) \
> + BRCMF_FEAT_DEF(SCAN_V2)
>
> /*
> * Quirks:
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> index 04e1beedfd81..b3844d0d1adb 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> @@ -48,6 +48,10 @@
>
> /* size of brcmf_scan_params not including variable length array */
> #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
> +#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72
> +
> +/* version of brcmf_scan_params structure */
> +#define BRCMF_SCAN_PARAMS_VERSION_V2 2
>
> /* masks for channel and ssid count */
> #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
> @@ -67,6 +71,7 @@
> #define BRCMF_PRIMARY_KEY (1 << 1)
> #define DOT11_BSSTYPE_ANY 2
> #define BRCMF_ESCAN_REQ_VERSION 1
> +#define BRCMF_ESCAN_REQ_VERSION_V2 2
>
> #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
>
> @@ -386,6 +391,45 @@ struct brcmf_scan_params_le {
> __le16 channel_list[1]; /* list of chanspecs */
> };
>
> +struct brcmf_scan_params_v2_le {
> + __le16 version; /* structure version */
> + __le16 length; /* structure length */
> + struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
> + u8 bssid[ETH_ALEN]; /* default: bcast */
> + s8 bss_type; /* default: any,
> + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
> + */
> + u8 pad;
> + __le32 scan_type; /* flags, 0 use default */
> + __le32 nprobes; /* -1 use default, number of probes per channel */
> + __le32 active_time; /* -1 use default, dwell time per channel for
> + * active scanning
> + */
> + __le32 passive_time; /* -1 use default, dwell time per channel
> + * for passive scanning
> + */
> + __le32 home_time; /* -1 use default, dwell time for the
> + * home channel between channel scans
> + */
> + __le32 channel_num; /* count of channels and ssids that follow
> + *
> + * low half is count of channels in
> + * channel_list, 0 means default (use all
> + * available channels)
> + *
> + * high half is entries in struct brcmf_ssid
> + * array that follows channel_list, aligned for
> + * s32 (4 bytes) meaning an odd channel count
> + * implies a 2-byte pad between end of
> + * channel_list and first ssid
> + *
> + * if ssid count is zero, single ssid in the
> + * fixed parameter portion is assumed, otherwise
> + * ssid in the fixed portion is ignored
> + */
> + __le16 channel_list[1]; /* list of chanspecs */
> +};
> +
> struct brcmf_scan_results {
> u32 buflen;
> u32 version;
> @@ -397,7 +441,10 @@ struct brcmf_escan_params_le {
> __le32 version;
> __le16 action;
> __le16 sync_id;
> - struct brcmf_scan_params_le params_le;
> + union {
> + struct brcmf_scan_params_le params_le;
> + struct brcmf_scan_params_v2_le params_v2_le;
> + };
> };
>
> struct brcmf_escan_result_le {
[unhandled content-type:application/pkcs7-signature]
\
 
 \ /
  Last update: 2023-03-27 00:21    [W:1.454 / U:0.096 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site