Skip to content

Commit b5f3cfd

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 dd70985 commit b5f3cfd

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
@@ -4002,17 +4002,11 @@ brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
40024002
}
40034003

40044004
static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
4005-
u8 *ssid, u8 ssid_len, u8 channel)
4005+
u8 *ssid, u8 ssid_len, u8 channel, enum nl80211_band band)
40064006
{
40074007
struct ieee80211_channel *chan;
4008-
enum nl80211_band band;
40094008
int freq, i;
40104009

4011-
if (channel <= CH_MAX_2G_CHANNEL)
4012-
band = NL80211_BAND_2GHZ;
4013-
else
4014-
band = NL80211_BAND_5GHZ;
4015-
40164010
freq = ieee80211_channel_to_frequency(channel, band);
40174011
if (!freq)
40184012
return -EINVAL;
@@ -4068,53 +4062,30 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
40684062
return 0;
40694063
}
40704064

4071-
static struct brcmf_pno_net_info_le *
4072-
brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
4073-
{
4074-
struct brcmf_pno_scanresults_v2_le *pfn_v2;
4075-
struct brcmf_pno_net_info_le *netinfo;
4076-
4077-
switch (pfn_v1->version) {
4078-
default:
4079-
WARN_ON(1);
4080-
fallthrough;
4081-
case cpu_to_le32(1):
4082-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
4083-
break;
4084-
case cpu_to_le32(2):
4085-
pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
4086-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
4087-
break;
4088-
}
4089-
4090-
return netinfo;
4091-
}
4092-
40934065
/* PFN result doesn't have all the info which are required by the supplicant
40944066
* (For e.g IEs) Do a target Escan so that sched scan results are reported
40954067
* via wl_inform_single_bss in the required format. Escan does require the
40964068
* scan request in the form of cfg80211_scan_request. For timebeing, create
40974069
* cfg80211_scan_request one out of the received PNO event.
40984070
*/
4099-
static s32
4100-
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4101-
const struct brcmf_event_msg *e, void *data)
4071+
static s32 brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4072+
const struct brcmf_event_msg *e,
4073+
void *data)
41024074
{
41034075
struct brcmf_pub *drvr = ifp->drvr;
41044076
struct brcmf_cfg80211_info *cfg = drvr->config;
4105-
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
41064077
struct cfg80211_scan_request *request = NULL;
41074078
struct wiphy *wiphy = cfg_to_wiphy(cfg);
41084079
int i, err = 0;
4109-
struct brcmf_pno_scanresults_le *pfn_result;
41104080
u32 bucket_map;
41114081
u32 result_count;
41124082
u32 status;
4113-
u32 datalen;
4083+
u32 min_data_len;
41144084

41154085
brcmf_dbg(SCAN, "Enter\n");
4086+
min_data_len = drvr->pno_handler.get_min_data_len();
41164087

4117-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4088+
if (e->datalen < min_data_len) {
41184089
brcmf_dbg(SCAN, "Event data too small. Ignore\n");
41194090
return 0;
41204091
}
@@ -4124,9 +4095,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41244095
return 0;
41254096
}
41264097

4127-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
4128-
result_count = le32_to_cpu(pfn_result->count);
4129-
status = le32_to_cpu(pfn_result->status);
4098+
result_count = drvr->pno_handler.get_result_count(data);
4099+
status = drvr->pno_handler.get_result_status(data);
41304100

41314101
/* PFN event is limited to fit 512 bytes so we may get
41324102
* multiple NET_FOUND events. For now place a warning here.
@@ -4137,38 +4107,33 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41374107
bphy_err(drvr, "FALSE PNO Event. (pfn_count == 0)\n");
41384108
goto out_err;
41394109
}
4140-
4141-
netinfo_start = brcmf_get_netinfo_array(pfn_result);
4142-
datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
4143-
if (datalen < result_count * sizeof(*netinfo)) {
4144-
bphy_err(drvr, "insufficient event data\n");
4110+
err = drvr->pno_handler.validate_pfn_results(data, e->datalen);
4111+
if (err) {
4112+
bphy_err(drvr, "Invalid escan results (%d)", err);
41454113
goto out_err;
41464114
}
4147-
4148-
request = brcmf_alloc_internal_escan_request(wiphy,
4149-
result_count);
4115+
request = brcmf_alloc_internal_escan_request(wiphy, result_count);
41504116
if (!request) {
41514117
err = -ENOMEM;
41524118
goto out_err;
41534119
}
4154-
41554120
bucket_map = 0;
41564121
for (i = 0; i < result_count; i++) {
4157-
netinfo = &netinfo_start[i];
4158-
4159-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4160-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4161-
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
4162-
netinfo->SSID, netinfo->channel);
4163-
bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
4164-
err = brcmf_internal_escan_add_info(request,
4165-
netinfo->SSID,
4166-
netinfo->SSID_len,
4167-
netinfo->channel);
4122+
u8 channel;
4123+
enum nl80211_band band;
4124+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4125+
u8 ssid_len;
4126+
4127+
drvr->pno_handler.get_result_info(data, i, &ssid, &ssid_len,
4128+
&channel, &band);
4129+
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d Band:%d\n", ssid,
4130+
channel, band);
4131+
bucket_map |= drvr->pno_handler.get_bucket_map(data, i, cfg->pno);
4132+
err = brcmf_internal_escan_add_info(request, ssid, ssid_len,
4133+
channel, band);
41684134
if (err)
41694135
goto out_err;
41704136
}
4171-
41724137
if (!bucket_map)
41734138
goto free_req;
41744139

@@ -4271,48 +4236,50 @@ static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
42714236
return ret;
42724237
}
42734238

4274-
static s32
4275-
brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
4276-
void *data)
4239+
static s32 brcmf_wowl_nd_results(struct brcmf_if *ifp,
4240+
const struct brcmf_event_msg *e, void *data)
42774241
{
42784242
struct brcmf_pub *drvr = ifp->drvr;
42794243
struct brcmf_cfg80211_info *cfg = drvr->config;
4280-
struct brcmf_pno_scanresults_le *pfn_result;
4281-
struct brcmf_pno_net_info_le *netinfo;
4244+
u32 min_data_len;
4245+
u8 channel;
4246+
enum nl80211_band band;
4247+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4248+
u8 ssid_len;
4249+
u32 result_count;
42824250

42834251
brcmf_dbg(SCAN, "Enter\n");
42844252

4285-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4253+
min_data_len = drvr->pno_handler.get_min_data_len();
4254+
4255+
if (e->datalen < min_data_len) {
42864256
brcmf_dbg(SCAN, "Event data too small. Ignore\n");
42874257
return 0;
42884258
}
42894259

4290-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
42914260

42924261
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
42934262
brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
42944263
return 0;
42954264
}
42964265

4297-
if (le32_to_cpu(pfn_result->count) < 1) {
4266+
result_count = drvr->pno_handler.get_result_count(data);
4267+
if (result_count < 1) {
42984268
bphy_err(drvr, "Invalid result count, expected 1 (%d)\n",
4299-
le32_to_cpu(pfn_result->count));
4269+
result_count);
43004270
return -EINVAL;
43014271
}
43024272

4303-
netinfo = brcmf_get_netinfo_array(pfn_result);
4304-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4305-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4306-
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
4307-
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
4273+
drvr->pno_handler.get_result_info(data, 0, &ssid, &ssid_len, &channel,
4274+
&band);
4275+
memcpy(cfg->wowl.nd->ssid.ssid, ssid, ssid_len);
4276+
cfg->wowl.nd->ssid.ssid_len = ssid_len;
43084277
cfg->wowl.nd->n_channels = 1;
43094278
cfg->wowl.nd->channels[0] =
4310-
ieee80211_channel_to_frequency(netinfo->channel,
4311-
netinfo->channel <= CH_MAX_2G_CHANNEL ?
4312-
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
4279+
ieee80211_channel_to_frequency(channel, band);
4280+
43134281
cfg->wowl.nd_info->n_matches = 1;
43144282
cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
4315-
43164283
/* Inform (the resume task) that the net detect information was recvd */
43174284
cfg->wowl.nd_data_completed = true;
43184285
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)