mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
350 lines
9.9 KiB
Diff
350 lines
9.9 KiB
Diff
From b2b2aa897a88b4d9405068a3edfd68c92dfbf745 Mon Sep 17 00:00:00 2001
|
|
From: Wright Feng <wright.feng@cypress.com>
|
|
Date: Mon, 24 Aug 2020 02:51:00 -0500
|
|
Subject: [PATCH 060/179] 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 firwmare 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>
|
|
---
|
|
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 256 ++++++++++++++++++
|
|
.../broadcom/brcm80211/brcmfmac/feature.c | 3 +-
|
|
.../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
|
|
3 files changed, 261 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
index 19b941bf3b70..b1b875b2a935 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
@@ -90,9 +90,39 @@
|
|
|
|
#define BRCMF_PS_MAX_TIMEOUT_MS 2000
|
|
|
|
+/* Dump obss definitions */
|
|
+#define ACS_MSRMNT_DELAY 100
|
|
+#define CHAN_NOISE_DUMMY (-80)
|
|
+#define OBSS_TOKEN_IDX 15
|
|
+#define IBSS_TOKEN_IDX 15
|
|
+#define TX_TOKEN_IDX 14
|
|
+#define CTG_TOKEN_IDX 13
|
|
+#define PKT_TOKEN_IDX 15
|
|
+#define IDLE_TOKEN_IDX 12
|
|
+
|
|
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
|
|
(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
|
|
|
|
+struct brcmf_dump_survey {
|
|
+ u32 obss;
|
|
+ u32 ibss;
|
|
+ u32 no_ctg;
|
|
+ u32 no_pckt;
|
|
+ u32 tx;
|
|
+ u32 idle;
|
|
+};
|
|
+
|
|
+struct cca_stats_n_flags {
|
|
+ u32 msrmnt_time; /* Time for Measurement (msec) */
|
|
+ u32 msrmnt_done; /* flag set when measurement complete */
|
|
+ char buf[1];
|
|
+};
|
|
+
|
|
+struct cca_msrmnt_query {
|
|
+ u32 msrmnt_query;
|
|
+ u32 time_req;
|
|
+};
|
|
+
|
|
static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
|
|
{
|
|
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
|
|
@@ -7777,6 +7807,227 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+brcmf_parse_dump_obss(char *buf, struct brcmf_dump_survey *survey)
|
|
+{
|
|
+ int i;
|
|
+ char *token;
|
|
+ char delim[] = "\n ";
|
|
+ unsigned long val;
|
|
+ int err = 0;
|
|
+
|
|
+ token = strsep(&buf, delim);
|
|
+ while (token) {
|
|
+ if (!strcmp(token, "OBSS")) {
|
|
+ for (i = 0; i < OBSS_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->obss = val;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(token, "IBSS")) {
|
|
+ for (i = 0; i < IBSS_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->ibss = val;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(token, "TXDur")) {
|
|
+ for (i = 0; i < TX_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->tx = val;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(token, "Category")) {
|
|
+ for (i = 0; i < CTG_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->no_ctg = val;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(token, "Packet")) {
|
|
+ for (i = 0; i < PKT_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->no_pckt = val;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(token, "Opp(time):")) {
|
|
+ for (i = 0; i < IDLE_TOKEN_IDX; i++)
|
|
+ token = strsep(&buf, delim);
|
|
+ err = kstrtoul(token, 10, &val);
|
|
+ survey->idle = val;
|
|
+ }
|
|
+
|
|
+ token = strsep(&buf, delim);
|
|
+
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+brcmf_dump_obss(struct brcmf_if *ifp, struct cca_msrmnt_query req,
|
|
+ struct brcmf_dump_survey *survey)
|
|
+{
|
|
+ struct cca_stats_n_flags *results;
|
|
+ char *buf;
|
|
+ int err;
|
|
+
|
|
+ buf = kzalloc(sizeof(char) * BRCMF_DCMD_MEDLEN, GFP_KERNEL);
|
|
+ if (unlikely(!buf)) {
|
|
+ brcmf_err("%s: buf alloc failed\n", __func__);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ memcpy(buf, &req, sizeof(struct cca_msrmnt_query));
|
|
+ err = brcmf_fil_iovar_data_get(ifp, "dump_obss",
|
|
+ buf, BRCMF_DCMD_MEDLEN);
|
|
+ if (err < 0) {
|
|
+ brcmf_err("dump_obss error (%d)\n", err);
|
|
+ goto exit;
|
|
+ }
|
|
+ results = (struct cca_stats_n_flags *)(buf);
|
|
+
|
|
+ if (req.msrmnt_query)
|
|
+ brcmf_parse_dump_obss(results->buf, survey);
|
|
+
|
|
+ kfree(buf);
|
|
+ return 0;
|
|
+exit:
|
|
+ kfree(buf);
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static s32
|
|
+cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
|
+ struct ieee80211_channel *chan,
|
|
+ enum nl80211_channel_type channel_type)
|
|
+{
|
|
+ u16 chspec = 0;
|
|
+ int err = 0;
|
|
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
|
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
|
|
+
|
|
+ /* set_channel */
|
|
+ chspec = channel_to_chanspec(&cfg->d11inf, chan);
|
|
+ if (chspec != INVCHANSPEC) {
|
|
+ err = brcmf_fil_iovar_int_set(ifp, "chanspec", chspec);
|
|
+ if (err)
|
|
+ err = -EINVAL;
|
|
+ } else {
|
|
+ brcmf_err("failed to convert host chanspec to fw chanspec\n");
|
|
+ err = -EINVAL;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int
|
|
+brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
|
|
+ int idx, struct survey_info *info)
|
|
+{
|
|
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
|
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
|
|
+ struct brcmf_dump_survey *survey;
|
|
+ struct ieee80211_supported_band *band;
|
|
+ struct ieee80211_channel *chan;
|
|
+ struct cca_msrmnt_query req;
|
|
+ u32 val, noise;
|
|
+ int err;
|
|
+
|
|
+ brcmf_dbg(TRACE, "Enter: channel idx=%d\n", idx);
|
|
+
|
|
+ band = wiphy->bands[NL80211_BAND_2GHZ];
|
|
+ if (band && idx >= band->n_channels) {
|
|
+ idx -= band->n_channels;
|
|
+ band = NULL;
|
|
+ }
|
|
+
|
|
+ if (!band || idx >= band->n_channels) {
|
|
+ band = wiphy->bands[NL80211_BAND_5GHZ];
|
|
+ if (idx >= band->n_channels)
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ /* Setting current channel to the requested channel */
|
|
+ chan = &band->channels[idx];
|
|
+ err = cfg80211_set_channel(wiphy, ndev, chan, NL80211_CHAN_HT20);
|
|
+ if (err) {
|
|
+ info->channel = chan;
|
|
+ info->filled = 0;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!idx) {
|
|
+ /* Disable mpc */
|
|
+ val = 0;
|
|
+ brcmf_set_mpc(ifp, val);
|
|
+ /* Set interface up, explicitly. */
|
|
+ val = 1;
|
|
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, val);
|
|
+ if (err) {
|
|
+ brcmf_err("BRCMF_C_UP error (%d)\n", err);
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Get noise value */
|
|
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PHY_NOISE, &noise);
|
|
+ if (err) {
|
|
+ brcmf_err("Get Phy Noise failed, error = %d\n", err);
|
|
+ noise = CHAN_NOISE_DUMMY;
|
|
+ }
|
|
+
|
|
+ survey = kzalloc(sizeof(*survey), GFP_KERNEL);
|
|
+ if (unlikely(!survey)) {
|
|
+ brcmf_err("%s: alloc failed\n", __func__);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Start Measurement for obss stats on current channel */
|
|
+ req.msrmnt_query = 0;
|
|
+ req.time_req = ACS_MSRMNT_DELAY;
|
|
+ err = brcmf_dump_obss(ifp, req, survey);
|
|
+ if (err)
|
|
+ goto exit;
|
|
+
|
|
+ /* Add 10 ms for IOVAR completion */
|
|
+ msleep(ACS_MSRMNT_DELAY + 10);
|
|
+
|
|
+ /* Issue IOVAR to collect measurement results */
|
|
+ req.msrmnt_query = 1;
|
|
+ err = brcmf_dump_obss(ifp, req, survey);
|
|
+ if (err < 0)
|
|
+ goto exit;
|
|
+
|
|
+ info->channel = chan;
|
|
+ info->noise = noise;
|
|
+ info->time = ACS_MSRMNT_DELAY;
|
|
+ info->time_busy = ACS_MSRMNT_DELAY - survey->idle;
|
|
+ info->time_rx = survey->obss + survey->ibss + survey->no_ctg +
|
|
+ survey->no_pckt;
|
|
+ info->time_tx = survey->tx;
|
|
+ info->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
|
|
+ SURVEY_INFO_TIME_BUSY | SURVEY_INFO_TIME_RX |
|
|
+ SURVEY_INFO_TIME_TX;
|
|
+
|
|
+ brcmf_dbg(INFO, "OBSS dump: channel %d: survey duraion %d\n",
|
|
+ ieee80211_frequency_to_channel(chan->center_freq),
|
|
+ ACS_MSRMNT_DELAY);
|
|
+ brcmf_dbg(INFO, "noise(%d) busy(%llu) rx(%llu) tx(%llu)\n",
|
|
+ info->noise, info->time_busy, info->time_rx, info->time_tx);
|
|
+
|
|
+ kfree(survey);
|
|
+ return 0;
|
|
+exit:
|
|
+ kfree(survey);
|
|
+ return err;
|
|
+}
|
|
+
|
|
static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
|
|
struct regulatory_request *req)
|
|
{
|
|
@@ -7930,6 +8181,11 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
|
|
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
|
|
ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
|
|
#endif
|
|
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_DUMP_OBSS))
|
|
+ ops->dump_survey = brcmf_cfg80211_dump_survey;
|
|
+ else
|
|
+ ops->dump_survey = NULL;
|
|
+
|
|
err = wiphy_register(wiphy);
|
|
if (err < 0) {
|
|
bphy_err(drvr, "Could not register wiphy device (%d)\n", err);
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
index 2733977b07a8..f483f0a3f8dd 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
@@ -142,7 +142,7 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
|
|
ifp->fwil_fwerr = true;
|
|
|
|
err = brcmf_fil_iovar_int_get(ifp, name, &data);
|
|
- if (err == 0) {
|
|
+ if (err != -BRCMF_FW_UNSUPPORTED) {
|
|
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
|
|
ifp->drvr->feat_flags |= BIT(id);
|
|
} else {
|
|
@@ -278,6 +278,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
|
|
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
|
|
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
|
|
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
|
|
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_DUMP_OBSS, "dump_obss");
|
|
|
|
pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
|
|
err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
index d1f4257af696..f1b086a69d73 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
@@ -29,6 +29,7 @@
|
|
* DOT11H: firmware supports 802.11h
|
|
* SAE: simultaneous authentication of equals
|
|
* FWAUTH: Firmware authenticator
|
|
+ * DUMP_OBSS: Firmware has capable to dump obss info to support ACS
|
|
*/
|
|
#define BRCMF_FEAT_LIST \
|
|
BRCMF_FEAT_DEF(MBSS) \
|
|
@@ -51,7 +52,8 @@
|
|
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
|
|
BRCMF_FEAT_DEF(DOT11H) \
|
|
BRCMF_FEAT_DEF(SAE) \
|
|
- BRCMF_FEAT_DEF(FWAUTH)
|
|
+ BRCMF_FEAT_DEF(FWAUTH) \
|
|
+ BRCMF_FEAT_DEF(DUMP_OBSS)
|
|
|
|
/*
|
|
* Quirks:
|
|
--
|
|
2.17.1
|
|
|