Skip to content

Commit 6c04dea

Browse files
WenChieh-FengKalle Valo
authored andcommitted
brcmfmac: Add dump_survey cfg80211 ops for HostApd AutoChannelSelection
To enable ACS feature in Hostap daemon, dump_survey cfg80211 ops and dump obss survey command in firmware side are needed. This patch is for adding dump_survey feature and adding DUMP_OBSS feature flag to check if firmware supports dump_obss iovar. Signed-off-by: Wright Feng <wright.feng@cypress.com> Signed-off-by: Chi-hsien Lin <chi-hsien.lin@cypress.com> Signed-off-by: Ian Lin <ian.lin@infineon.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/20220929012527.4152-2-ian.lin@infineon.com
1 parent 791082e commit 6c04dea

File tree

3 files changed

+261
-2
lines changed

3 files changed

+261
-2
lines changed

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

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,39 @@
8888

8989
#define BRCMF_PS_MAX_TIMEOUT_MS 2000
9090

91+
/* Dump obss definitions */
92+
#define ACS_MSRMNT_DELAY 100
93+
#define CHAN_NOISE_DUMMY (-80)
94+
#define OBSS_TOKEN_IDX 15
95+
#define IBSS_TOKEN_IDX 15
96+
#define TX_TOKEN_IDX 14
97+
#define CTG_TOKEN_IDX 13
98+
#define PKT_TOKEN_IDX 15
99+
#define IDLE_TOKEN_IDX 12
100+
91101
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
92102
(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
93103

104+
struct brcmf_dump_survey {
105+
u32 obss;
106+
u32 ibss;
107+
u32 no_ctg;
108+
u32 no_pckt;
109+
u32 tx;
110+
u32 idle;
111+
};
112+
113+
struct cca_stats_n_flags {
114+
u32 msrmnt_time; /* Time for Measurement (msec) */
115+
u32 msrmnt_done; /* flag set when measurement complete */
116+
char buf[1];
117+
};
118+
119+
struct cca_msrmnt_query {
120+
u32 msrmnt_query;
121+
u32 time_req;
122+
};
123+
94124
static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
95125
{
96126
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
@@ -7525,6 +7555,229 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
75257555
return 0;
75267556
}
75277557

7558+
static int
7559+
brcmf_parse_dump_obss(char *buf, struct brcmf_dump_survey *survey)
7560+
{
7561+
int i;
7562+
char *token;
7563+
char delim[] = "\n ";
7564+
unsigned long val;
7565+
int err = 0;
7566+
7567+
token = strsep(&buf, delim);
7568+
while (token) {
7569+
if (!strcmp(token, "OBSS")) {
7570+
for (i = 0; i < OBSS_TOKEN_IDX; i++)
7571+
token = strsep(&buf, delim);
7572+
err = kstrtoul(token, 10, &val);
7573+
if (err)
7574+
break;
7575+
survey->obss = val;
7576+
}
7577+
7578+
if (!strcmp(token, "IBSS")) {
7579+
for (i = 0; i < IBSS_TOKEN_IDX; i++)
7580+
token = strsep(&buf, delim);
7581+
err = kstrtoul(token, 10, &val);
7582+
if (err)
7583+
break;
7584+
survey->ibss = val;
7585+
}
7586+
7587+
if (!strcmp(token, "TXDur")) {
7588+
for (i = 0; i < TX_TOKEN_IDX; i++)
7589+
token = strsep(&buf, delim);
7590+
err = kstrtoul(token, 10, &val);
7591+
if (err)
7592+
break;
7593+
survey->tx = val;
7594+
}
7595+
7596+
if (!strcmp(token, "Category")) {
7597+
for (i = 0; i < CTG_TOKEN_IDX; i++)
7598+
token = strsep(&buf, delim);
7599+
err = kstrtoul(token, 10, &val);
7600+
if (err)
7601+
break;
7602+
survey->no_ctg = val;
7603+
}
7604+
7605+
if (!strcmp(token, "Packet")) {
7606+
for (i = 0; i < PKT_TOKEN_IDX; i++)
7607+
token = strsep(&buf, delim);
7608+
err = kstrtoul(token, 10, &val);
7609+
if (err)
7610+
break;
7611+
survey->no_pckt = val;
7612+
}
7613+
7614+
if (!strcmp(token, "Opp(time):")) {
7615+
for (i = 0; i < IDLE_TOKEN_IDX; i++)
7616+
token = strsep(&buf, delim);
7617+
err = kstrtoul(token, 10, &val);
7618+
if (err)
7619+
break;
7620+
survey->idle = val;
7621+
}
7622+
7623+
token = strsep(&buf, delim);
7624+
}
7625+
7626+
return err;
7627+
}
7628+
7629+
static int
7630+
brcmf_dump_obss(struct brcmf_if *ifp, struct cca_msrmnt_query req,
7631+
struct brcmf_dump_survey *survey)
7632+
{
7633+
struct cca_stats_n_flags *results;
7634+
char *buf;
7635+
int err;
7636+
7637+
buf = kzalloc(sizeof(char) * BRCMF_DCMD_MEDLEN, GFP_KERNEL);
7638+
if (unlikely(!buf)) {
7639+
brcmf_err("%s: buf alloc failed\n", __func__);
7640+
return -ENOMEM;
7641+
}
7642+
7643+
memcpy(buf, &req, sizeof(struct cca_msrmnt_query));
7644+
err = brcmf_fil_iovar_data_get(ifp, "dump_obss",
7645+
buf, BRCMF_DCMD_MEDLEN);
7646+
if (err < 0) {
7647+
brcmf_err("dump_obss error (%d)\n", err);
7648+
goto exit;
7649+
}
7650+
results = (struct cca_stats_n_flags *)(buf);
7651+
7652+
if (req.msrmnt_query)
7653+
brcmf_parse_dump_obss(results->buf, survey);
7654+
7655+
kfree(buf);
7656+
return 0;
7657+
exit:
7658+
kfree(buf);
7659+
return -EINVAL;
7660+
}
7661+
7662+
static s32
7663+
cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
7664+
struct ieee80211_channel *chan,
7665+
enum nl80211_channel_type channel_type)
7666+
{
7667+
u16 chspec = 0;
7668+
int err = 0;
7669+
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
7670+
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
7671+
7672+
/* set_channel */
7673+
chspec = channel_to_chanspec(&cfg->d11inf, chan);
7674+
if (chspec != INVCHANSPEC) {
7675+
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chspec);
7676+
if (err) {
7677+
brcmf_err("set chanspec 0x%04x fail, reason %d\n", chspec, err);
7678+
err = -EINVAL;
7679+
}
7680+
} else {
7681+
brcmf_err("failed to convert host chanspec to fw chanspec\n");
7682+
err = -EINVAL;
7683+
}
7684+
7685+
return err;
7686+
}
7687+
7688+
static int
7689+
brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
7690+
int idx, struct survey_info *info)
7691+
{
7692+
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
7693+
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
7694+
struct brcmf_dump_survey survey = {};
7695+
struct ieee80211_supported_band *band;
7696+
struct ieee80211_channel *chan;
7697+
struct cca_msrmnt_query req;
7698+
u32 val, noise;
7699+
int err;
7700+
7701+
brcmf_dbg(TRACE, "Enter: channel idx=%d\n", idx);
7702+
7703+
band = wiphy->bands[NL80211_BAND_2GHZ];
7704+
if (band && idx >= band->n_channels) {
7705+
idx -= band->n_channels;
7706+
band = NULL;
7707+
}
7708+
7709+
if (!band || idx >= band->n_channels) {
7710+
band = wiphy->bands[NL80211_BAND_5GHZ];
7711+
if (idx >= band->n_channels)
7712+
return -ENOENT;
7713+
}
7714+
7715+
/* Setting current channel to the requested channel */
7716+
chan = &band->channels[idx];
7717+
err = cfg80211_set_channel(wiphy, ndev, chan, NL80211_CHAN_HT20);
7718+
if (err) {
7719+
info->channel = chan;
7720+
info->filled = 0;
7721+
return 0;
7722+
}
7723+
7724+
if (!idx) {
7725+
/* Disable mpc */
7726+
val = 0;
7727+
brcmf_set_mpc(ifp, val);
7728+
/* Set interface up, explicitly. */
7729+
val = 1;
7730+
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, val);
7731+
if (err) {
7732+
brcmf_err("BRCMF_C_UP error (%d)\n", err);
7733+
return -EIO;
7734+
}
7735+
}
7736+
7737+
/* Get noise value */
7738+
err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PHY_NOISE, &noise);
7739+
if (err) {
7740+
brcmf_err("Get Phy Noise failed, error = %d\n", err);
7741+
noise = CHAN_NOISE_DUMMY;
7742+
}
7743+
7744+
/* Start Measurement for obss stats on current channel */
7745+
req.msrmnt_query = 0;
7746+
req.time_req = ACS_MSRMNT_DELAY;
7747+
err = brcmf_dump_obss(ifp, req, &survey);
7748+
if (err)
7749+
goto exit;
7750+
7751+
/* Add 10 ms for IOVAR completion */
7752+
msleep(ACS_MSRMNT_DELAY + 10);
7753+
7754+
/* Issue IOVAR to collect measurement results */
7755+
req.msrmnt_query = 1;
7756+
err = brcmf_dump_obss(ifp, req, &survey);
7757+
if (err < 0)
7758+
goto exit;
7759+
7760+
info->channel = chan;
7761+
info->noise = noise;
7762+
info->time = ACS_MSRMNT_DELAY;
7763+
info->time_busy = ACS_MSRMNT_DELAY - survey.idle;
7764+
info->time_rx = survey.obss + survey.ibss + survey.no_ctg +
7765+
survey.no_pckt;
7766+
info->time_tx = survey.tx;
7767+
info->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
7768+
SURVEY_INFO_TIME_BUSY | SURVEY_INFO_TIME_RX |
7769+
SURVEY_INFO_TIME_TX;
7770+
7771+
brcmf_dbg(INFO, "OBSS dump: channel %d: survey duration %d\n",
7772+
ieee80211_frequency_to_channel(chan->center_freq),
7773+
ACS_MSRMNT_DELAY);
7774+
brcmf_dbg(INFO, "noise(%d) busy(%llu) rx(%llu) tx(%llu)\n",
7775+
info->noise, info->time_busy, info->time_rx, info->time_tx);
7776+
7777+
exit:
7778+
return err;
7779+
}
7780+
75287781
static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
75297782
struct regulatory_request *req)
75307783
{
@@ -7676,6 +7929,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
76767929
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
76777930
ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
76787931
#endif
7932+
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_DUMP_OBSS))
7933+
ops->dump_survey = brcmf_cfg80211_dump_survey;
7934+
76797935
err = wiphy_register(wiphy);
76807936
if (err < 0) {
76817937
bphy_err(drvr, "Could not register wiphy device (%d)\n", err);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
143143
ifp->fwil_fwerr = true;
144144

145145
err = brcmf_fil_iovar_int_get(ifp, name, &data);
146-
if (err == 0) {
146+
if (err != -BRCMF_FW_UNSUPPORTED) {
147147
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
148148
ifp->drvr->feat_flags |= BIT(id);
149149
} else {
@@ -281,6 +281,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
281281
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
282282
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
283283
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
284+
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_DUMP_OBSS, "dump_obss");
284285

285286
pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
286287
err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* DOT11H: firmware supports 802.11h
3030
* SAE: simultaneous authentication of equals
3131
* FWAUTH: Firmware authenticator
32+
* DUMP_OBSS: Firmware has capable to dump obss info to support ACS
3233
*/
3334
#define BRCMF_FEAT_LIST \
3435
BRCMF_FEAT_DEF(MBSS) \
@@ -51,7 +52,8 @@
5152
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
5253
BRCMF_FEAT_DEF(DOT11H) \
5354
BRCMF_FEAT_DEF(SAE) \
54-
BRCMF_FEAT_DEF(FWAUTH)
55+
BRCMF_FEAT_DEF(FWAUTH) \
56+
BRCMF_FEAT_DEF(DUMP_OBSS)
5557

5658
/*
5759
* Quirks:

0 commit comments

Comments
 (0)