Skip to content

Commit d7842ec

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 eeded05 commit d7842ec

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
@@ -3980,17 +3980,11 @@ brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
39803980
}
39813981

39823982
static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
3983-
u8 *ssid, u8 ssid_len, u8 channel)
3983+
u8 *ssid, u8 ssid_len, u8 channel, enum nl80211_band band)
39843984
{
39853985
struct ieee80211_channel *chan;
3986-
enum nl80211_band band;
39873986
int freq, i;
39883987

3989-
if (channel <= CH_MAX_2G_CHANNEL)
3990-
band = NL80211_BAND_2GHZ;
3991-
else
3992-
band = NL80211_BAND_5GHZ;
3993-
39943988
freq = ieee80211_channel_to_frequency(channel, band);
39953989
if (!freq)
39963990
return -EINVAL;
@@ -4046,53 +4040,30 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
40464040
return 0;
40474041
}
40484042

4049-
static struct brcmf_pno_net_info_le *
4050-
brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
4051-
{
4052-
struct brcmf_pno_scanresults_v2_le *pfn_v2;
4053-
struct brcmf_pno_net_info_le *netinfo;
4054-
4055-
switch (pfn_v1->version) {
4056-
default:
4057-
WARN_ON(1);
4058-
fallthrough;
4059-
case cpu_to_le32(1):
4060-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
4061-
break;
4062-
case cpu_to_le32(2):
4063-
pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
4064-
netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
4065-
break;
4066-
}
4067-
4068-
return netinfo;
4069-
}
4070-
40714043
/* PFN result doesn't have all the info which are required by the supplicant
40724044
* (For e.g IEs) Do a target Escan so that sched scan results are reported
40734045
* via wl_inform_single_bss in the required format. Escan does require the
40744046
* scan request in the form of cfg80211_scan_request. For timebeing, create
40754047
* cfg80211_scan_request one out of the received PNO event.
40764048
*/
4077-
static s32
4078-
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4079-
const struct brcmf_event_msg *e, void *data)
4049+
static s32 brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
4050+
const struct brcmf_event_msg *e,
4051+
void *data)
40804052
{
40814053
struct brcmf_pub *drvr = ifp->drvr;
40824054
struct brcmf_cfg80211_info *cfg = drvr->config;
4083-
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
40844055
struct cfg80211_scan_request *request = NULL;
40854056
struct wiphy *wiphy = cfg_to_wiphy(cfg);
40864057
int i, err = 0;
4087-
struct brcmf_pno_scanresults_le *pfn_result;
40884058
u32 bucket_map;
40894059
u32 result_count;
40904060
u32 status;
4091-
u32 datalen;
4061+
u32 min_data_len;
40924062

40934063
brcmf_dbg(SCAN, "Enter\n");
4064+
min_data_len = drvr->pno_handler.get_min_data_len();
40944065

4095-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4066+
if (e->datalen < min_data_len) {
40964067
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
40974068
return 0;
40984069
}
@@ -4102,9 +4073,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41024073
return 0;
41034074
}
41044075

4105-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
4106-
result_count = le32_to_cpu(pfn_result->count);
4107-
status = le32_to_cpu(pfn_result->status);
4076+
result_count = drvr->pno_handler.get_result_count(data);
4077+
status = drvr->pno_handler.get_result_status(data);
41084078

41094079
/* PFN event is limited to fit 512 bytes so we may get
41104080
* multiple NET_FOUND events. For now place a warning here.
@@ -4115,38 +4085,33 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
41154085
bphy_err(drvr, "FALSE PNO Event. (pfn_count == 0)\n");
41164086
goto out_err;
41174087
}
4118-
4119-
netinfo_start = brcmf_get_netinfo_array(pfn_result);
4120-
datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
4121-
if (datalen < result_count * sizeof(*netinfo)) {
4122-
bphy_err(drvr, "insufficient event data\n");
4088+
err = drvr->pno_handler.validate_pfn_results(data, e->datalen);
4089+
if (err) {
4090+
bphy_err(drvr, "Invalid escan results (%d)", err);
41234091
goto out_err;
41244092
}
4125-
4126-
request = brcmf_alloc_internal_escan_request(wiphy,
4127-
result_count);
4093+
request = brcmf_alloc_internal_escan_request(wiphy, result_count);
41284094
if (!request) {
41294095
err = -ENOMEM;
41304096
goto out_err;
41314097
}
4132-
41334098
bucket_map = 0;
41344099
for (i = 0; i < result_count; i++) {
4135-
netinfo = &netinfo_start[i];
4136-
4137-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4138-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4139-
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
4140-
netinfo->SSID, netinfo->channel);
4141-
bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
4142-
err = brcmf_internal_escan_add_info(request,
4143-
netinfo->SSID,
4144-
netinfo->SSID_len,
4145-
netinfo->channel);
4100+
u8 channel;
4101+
enum nl80211_band band;
4102+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4103+
u8 ssid_len;
4104+
4105+
drvr->pno_handler.get_result_info(data, i, &ssid, &ssid_len,
4106+
&channel, &band);
4107+
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d Band:%d\n", ssid,
4108+
channel, band);
4109+
bucket_map |= drvr->pno_handler.get_bucket_map(data, i, cfg->pno);
4110+
err = brcmf_internal_escan_add_info(request, ssid, ssid_len,
4111+
channel, band);
41464112
if (err)
41474113
goto out_err;
41484114
}
4149-
41504115
if (!bucket_map)
41514116
goto free_req;
41524117

@@ -4249,48 +4214,50 @@ static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
42494214
return ret;
42504215
}
42514216

4252-
static s32
4253-
brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
4254-
void *data)
4217+
static s32 brcmf_wowl_nd_results(struct brcmf_if *ifp,
4218+
const struct brcmf_event_msg *e, void *data)
42554219
{
42564220
struct brcmf_pub *drvr = ifp->drvr;
42574221
struct brcmf_cfg80211_info *cfg = drvr->config;
4258-
struct brcmf_pno_scanresults_le *pfn_result;
4259-
struct brcmf_pno_net_info_le *netinfo;
4222+
u32 min_data_len;
4223+
u8 channel;
4224+
enum nl80211_band band;
4225+
u8 ssid[IEEE80211_MAX_SSID_LEN];
4226+
u8 ssid_len;
4227+
u32 result_count;
42604228

42614229
brcmf_dbg(SCAN, "Enter\n");
42624230

4263-
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
4231+
min_data_len = drvr->pno_handler.get_min_data_len();
4232+
4233+
if (e->datalen < min_data_len) {
42644234
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
42654235
return 0;
42664236
}
42674237

4268-
pfn_result = (struct brcmf_pno_scanresults_le *)data;
42694238

42704239
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
42714240
brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
42724241
return 0;
42734242
}
42744243

4275-
if (le32_to_cpu(pfn_result->count) < 1) {
4244+
result_count = drvr->pno_handler.get_result_count(data);
4245+
if (result_count < 1) {
42764246
bphy_err(drvr, "Invalid result count, expected 1 (%d)\n",
4277-
le32_to_cpu(pfn_result->count));
4247+
result_count);
42784248
return -EINVAL;
42794249
}
42804250

4281-
netinfo = brcmf_get_netinfo_array(pfn_result);
4282-
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
4283-
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
4284-
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
4285-
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
4251+
drvr->pno_handler.get_result_info(data, 0, &ssid, &ssid_len, &channel,
4252+
&band);
4253+
memcpy(cfg->wowl.nd->ssid.ssid, ssid, ssid_len);
4254+
cfg->wowl.nd->ssid.ssid_len = ssid_len;
42864255
cfg->wowl.nd->n_channels = 1;
42874256
cfg->wowl.nd->channels[0] =
4288-
ieee80211_channel_to_frequency(netinfo->channel,
4289-
netinfo->channel <= CH_MAX_2G_CHANNEL ?
4290-
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
4257+
ieee80211_channel_to_frequency(channel, band);
4258+
42914259
cfg->wowl.nd_info->n_matches = 1;
42924260
cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
4293-
42944261
/* Inform (the resume task) that the net detect information was recvd */
42954262
cfg->wowl.nd_data_completed = true;
42964263
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"
@@ -388,6 +389,22 @@ struct brcmf_tlv {
388389
u8 data[];
389390
};
390391

392+
static inline enum nl80211_band fwil_band_to_nl80211(u16 band)
393+
{
394+
switch (band) {
395+
case WLC_BAND_2G:
396+
return NL80211_BAND_2GHZ;
397+
case WLC_BAND_5G:
398+
return NL80211_BAND_5GHZ;
399+
case WLC_BAND_6G:
400+
return NL80211_BAND_6GHZ;
401+
default:
402+
WARN_ON(1);
403+
break;
404+
}
405+
return 0;
406+
}
407+
391408
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
392409
{
393410
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

@@ -290,6 +291,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
290291
{
291292
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
292293
struct brcmf_wl_scan_version_le scan_ver;
294+
struct brcmf_pno_param_v3_le pno_params;
293295
struct brcmf_pno_macaddr_le pfn_mac;
294296
struct brcmf_gscan_config gscan_cfg;
295297
u32 wowl_cap;
@@ -356,6 +358,16 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
356358
}
357359
}
358360

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

0 commit comments

Comments
 (0)