Message ID | 20230214092423.15175-3-marcan@marcan.st (mailing list archive) |
---|---|
State | Awaiting Upstream |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | BCM4387 / Apple M1 platform support | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Not a local patch |
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(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le, > + sizeof(params_le->ssid_le)); > + memcpy(¶ms_le->bssid, ¶ms_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(¶ms_le->channel_list[0], > + ¶ms_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(¶ms_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(¶ms_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, ¶ms_v2_le, NULL); > + > /* E-Scan (or anyother type) can be aborted by SCAN */ > - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, > - ¶ms_le, sizeof(params_le)); > + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { > + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, > + ¶ms_v2_le, > + sizeof(params_v2_le)); > + } else { > + struct brcmf_scan_params_le params_le; > + > + brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le); > + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, > + ¶ms_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(¶ms_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, ¶ms->params_le, request); > - params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); > + brcmf_escan_prep(cfg, ¶ms->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(¶ms->params_v2_le, ¶ms_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 {
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(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le, + sizeof(params_le->ssid_le)); + memcpy(¶ms_le->bssid, ¶ms_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(¶ms_le->channel_list[0], + ¶ms_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(¶ms_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(¶ms_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, ¶ms_v2_le, NULL); + /* E-Scan (or anyother type) can be aborted by SCAN */ - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, - ¶ms_le, sizeof(params_le)); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, + ¶ms_v2_le, + sizeof(params_v2_le)); + } else { + struct brcmf_scan_params_le params_le; + + brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, + ¶ms_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(¶ms_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, ¶ms->params_le, request); - params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); + brcmf_escan_prep(cfg, ¶ms->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(¶ms->params_v2_le, ¶ms_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 {