Skip to content

Commit fe78d01

Browse files
dberlinjannau
authored andcommitted
[brcmfmac] Structurize PNF scan and add support for latest version
This patch structurizes PNF scan handling, adding support for netinfo v3 and PNO v3 structures. This in turn, enables the chip to tell us about 6G scan results, as the results contain chanspecs and not just channels. Signed-off-by: Daniel Berlin <dberlin@dberlin.org>
1 parent ea01c83 commit fe78d01

7 files changed

Lines changed: 456 additions & 90 deletions

File tree

drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c

Lines changed: 45 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3985,17 +3985,11 @@ brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
39853985
}
39863986

39873987
static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3988-
u8 *ssid, u8 ssid_len, u8 channel)
3988+
u8 *ssid, u8 ssid_len, u8 channel, enum nl80211_band band)
39893989
{
39903990
struct ieee80211_channel *chan;
3991-
enum nl80211_band band;
39923991
int freq, i;
39933992

3994-
if (channel <= CH_MAX_2G_CHANNEL)
3995-
band = NL80211_BAND_2GHZ;
3996-
else
3997-
band = NL80211_BAND_5GHZ;
3998-
39993993
freq = ieee80211_channel_to_frequency(channel, band);
40003994
if (!freq)
40013995
return -EINVAL;
@@ -4051,53 +4045,30 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
40514045
return 0;
40524046
}
40534047

4054-
static struct brcmf_pno_net_info_le *
4055-
brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
4056-
{
4057-
struct brcmf_pno_scanresults_v2_le *pfn_v2;
4058-
struct brcmf_pno_net_info_le *netinfo;
4059-
4060-
switch (pfn_v1->version) {
4061-
default:
4062-
WARN_ON(1);
4063-
fallthrough;
4064-
case cpu_to_le32(1):
4065-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
4066-
break;
4067-
case cpu_to_le32(2):
4068-
pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
4069-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
4070-
break;
4071-
}
4072-
4073-
return netinfo;
4074-
}
4075-
40764048
/* PFN result doesn't have all the info which are required by the supplicant
40774049
* (For e.g IEs) Do a target Escan so that sched scan results are reported
40784050
* via wl_inform_single_bss in the required format. Escan does require the
40794051
* scan request in the form of cfg80211_scan_request. For timebeing, create
40804052
* cfg80211_scan_request one out of the received PNO event.
40814053
*/
4082-
static s32
4083-
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4084-
const struct brcmf_event_msg *e, void *data)
4054+
static s32 brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4055+
const struct brcmf_event_msg *e,
4056+
void *data)
40854057
{
40864058
struct brcmf_pub *drvr = ifp->drvr;
40874059
struct brcmf_cfg80211_info *cfg = drvr->config;
4088-
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
40894060
struct cfg80211_scan_request *request = NULL;
40904061
struct wiphy *wiphy = cfg_to_wiphy(cfg);
40914062
int i, err = 0;
4092-
struct brcmf_pno_scanresults_le *pfn_result;
40934063
u32 bucket_map;
40944064
u32 result_count;
40954065
u32 status;
4096-
u32 datalen;
4066+
u32 min_data_len;
40974067

40984068
brcmf_dbg(SCAN, "Enter\n");
4069+
min_data_len = drvr->pno_handler.get_min_data_len();
40994070

4100-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4071+
if (e->datalen < min_data_len) {
41014072
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
41024073
return 0;
41034074
}
@@ -4107,9 +4078,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41074078
return 0;
41084079
}
41094080

4110-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
4111-
result_count = le32_to_cpu(pfn_result->count);
4112-
status = le32_to_cpu(pfn_result->status);
4081+
result_count = drvr->pno_handler.get_result_count(data);
4082+
status = drvr->pno_handler.get_result_status(data);
41134083

41144084
/* PFN event is limited to fit 512 bytes so we may get
41154085
* multiple NET_FOUND events. For now place a warning here.
@@ -4120,38 +4090,33 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41204090
bphy_err(drvr, "FALSE PNO Event. (pfn_count == 0)\n");
41214091
goto out_err;
41224092
}
4123-
4124-
netinfo_start = brcmf_get_netinfo_array(pfn_result);
4125-
datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
4126-
if (datalen < result_count * sizeof(*netinfo)) {
4127-
bphy_err(drvr, "insufficient event data\n");
4093+
err = drvr->pno_handler.validate_pfn_results(data, e->datalen);
4094+
if (err) {
4095+
bphy_err(drvr, "Invalid escan results (%d)", err);
41284096
goto out_err;
41294097
}
4130-
4131-
request = brcmf_alloc_internal_escan_request(wiphy,
4132-
result_count);
4098+
request = brcmf_alloc_internal_escan_request(wiphy, result_count);
41334099
if (!request) {
41344100
err = -ENOMEM;
41354101
goto out_err;
41364102
}
4137-
41384103
bucket_map = 0;
41394104
for (i = 0; i < result_count; i++) {
4140-
netinfo = &netinfo_start[i];
4141-
4142-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4143-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4144-
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
4145-
netinfo->SSID, netinfo->channel);
4146-
bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
4147-
err = brcmf_internal_escan_add_info(request,
4148-
netinfo->SSID,
4149-
netinfo->SSID_len,
4150-
netinfo->channel);
4105+
u8 channel;
4106+
enum nl80211_band band;
4107+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4108+
u8 ssid_len;
4109+
4110+
drvr->pno_handler.get_result_info(data, i, &ssid, &ssid_len,
4111+
&channel, &band);
4112+
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d Band:%d\n", ssid,
4113+
channel, band);
4114+
bucket_map |= drvr->pno_handler.get_bucket_map(data, i, cfg->pno);
4115+
err = brcmf_internal_escan_add_info(request, ssid, ssid_len,
4116+
channel, band);
41514117
if (err)
41524118
goto out_err;
41534119
}
4154-
41554120
if (!bucket_map)
41564121
goto free_req;
41574122

@@ -4254,48 +4219,50 @@ static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
42544219
return ret;
42554220
}
42564221

4257-
static s32
4258-
brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
4259-
void *data)
4222+
static s32 brcmf_wowl_nd_results(struct brcmf_if *ifp,
4223+
const struct brcmf_event_msg *e, void *data)
42604224
{
42614225
struct brcmf_pub *drvr = ifp->drvr;
42624226
struct brcmf_cfg80211_info *cfg = drvr->config;
4263-
struct brcmf_pno_scanresults_le *pfn_result;
4264-
struct brcmf_pno_net_info_le *netinfo;
4227+
u32 min_data_len;
4228+
u8 channel;
4229+
enum nl80211_band band;
4230+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4231+
u8 ssid_len;
4232+
u32 result_count;
42654233

42664234
brcmf_dbg(SCAN, "Enter\n");
42674235

4268-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4236+
min_data_len = drvr->pno_handler.get_min_data_len();
4237+
4238+
if (e->datalen < min_data_len) {
42694239
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
42704240
return 0;
42714241
}
42724242

4273-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
42744243

42754244
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
42764245
brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
42774246
return 0;
42784247
}
42794248

4280-
if (le32_to_cpu(pfn_result->count) < 1) {
4249+
result_count = drvr->pno_handler.get_result_count(data);
4250+
if (result_count < 1) {
42814251
bphy_err(drvr, "Invalid result count, expected 1 (%d)\n",
4282-
le32_to_cpu(pfn_result->count));
4252+
result_count);
42834253
return -EINVAL;
42844254
}
42854255

4286-
netinfo = brcmf_get_netinfo_array(pfn_result);
4287-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4288-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4289-
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
4290-
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
4256+
drvr->pno_handler.get_result_info(data, 0, &ssid, &ssid_len, &channel,
4257+
&band);
4258+
memcpy(cfg->wowl.nd->ssid.ssid, ssid, ssid_len);
4259+
cfg->wowl.nd->ssid.ssid_len = ssid_len;
42914260
cfg->wowl.nd->n_channels = 1;
42924261
cfg->wowl.nd->channels[0] =
4293-
ieee80211_channel_to_frequency(netinfo->channel,
4294-
netinfo->channel <= CH_MAX_2G_CHANNEL ?
4295-
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
4262+
ieee80211_channel_to_frequency(channel, band);
4263+
42964264
cfg->wowl.nd_info->n_matches = 1;
42974265
cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
4298-
42994266
/* Inform (the resume task) that the net detect information was recvd */
43004267
cfg->wowl.nd_data_completed = true;
43014268
wake_up(&cfg->wowl.nd_data_wait);

drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* for brcmu_d11inf */
1010
#include <brcmu_d11.h>
11+
#include <brcmu_wifi.h>
1112

1213
#include "core.h"
1314
#include "fwil_types.h"
@@ -411,6 +412,22 @@ struct brcmf_tlv {
411412
u8 data[];
412413
};
413414

415+
static inline enum nl80211_band fwil_band_to_nl80211(u16 band)
416+
{
417+
switch (band) {
418+
case WLC_BAND_2G:
419+
return NL80211_BAND_2GHZ;
420+
case WLC_BAND_5G:
421+
return NL80211_BAND_5GHZ;
422+
case WLC_BAND_6G:
423+
return NL80211_BAND_6GHZ;
424+
default:
425+
WARN_ON(1);
426+
break;
427+
}
428+
return 0;
429+
}
430+
414431
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
415432
{
416433
return cfg->wiphy;

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ struct brcmf_rev_info {
9797
u32 nvramrev;
9898
};
9999

100+
struct brcmf_pno_info;
101+
/**
102+
* struct pno_struct_handler
103+
*/
104+
struct pno_struct_handler {
105+
u8 version;
106+
int (*pno_config)(struct brcmf_if *ifp, u32 scan_freq, u32 mscan,
107+
u32 bestn);
108+
u32 (*get_min_data_len)(void);
109+
u32 (*get_result_count)(void *data);
110+
u32 (*get_result_status)(void *data);
111+
int (*validate_pfn_results)(void *data, u32 event_datalen);
112+
u32 (*get_bucket_map)(void *data, int idx, struct brcmf_pno_info *pi);
113+
int (*get_result_info)(void *data, int result_idx,
114+
u8 (*ssid)[IEEE80211_MAX_SSID_LEN], u8 *ssid_len,
115+
u8 *channel, enum nl80211_band *band);
116+
};
117+
100118
/* Common structure for module and instance linkage */
101119
struct brcmf_pub {
102120
/* Linkage ponters */
@@ -145,6 +163,8 @@ struct brcmf_pub {
145163
u8 sta_mac_idx;
146164
const struct brcmf_fwvid_ops *vops;
147165
void *vdata;
166+
u16 cnt_ver;
167+
struct pno_struct_handler pno_handler;
148168
};
149169

150170
/* forward declarations */

drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "fwvid.h"
1717
#include "feature.h"
1818
#include "common.h"
19+
#include "pno.h"
1920

2021
#define BRCMF_FW_UNSUPPORTED 23
2122

@@ -291,6 +292,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
291292
{
292293
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
293294
struct brcmf_wl_scan_version_le scan_ver;
295+
struct brcmf_pno_param_v3_le pno_params;
294296
struct brcmf_pno_macaddr_le pfn_mac;
295297
struct brcmf_gscan_config gscan_cfg;
296298
u32 wowl_cap;
@@ -357,6 +359,16 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
357359
}
358360
}
359361

362+
/* See what version of PFN scan is supported*/
363+
err = brcmf_fil_iovar_data_get(ifp, "pno_set", &pno_params,
364+
sizeof(pno_params));
365+
if (!err) {
366+
brcmf_pno_setup_for_version(drvr, le16_to_cpu(pno_params.version));
367+
} else {
368+
/* Default to version 2, supported by all chips we support. */
369+
brcmf_pno_setup_for_version(drvr, 2);
370+
}
371+
360372
brcmf_feat_wlc_version_overrides(drvr);
361373
brcmf_feat_firmware_overrides(drvr);
362374

0 commit comments

Comments
 (0)