301 lines
9.1 KiB
Diff
301 lines
9.1 KiB
Diff
|
From: Arend van Spriel <arend@broadcom.com>
|
||
|
Date: Tue, 14 Apr 2015 20:10:24 +0200
|
||
|
Subject: [PATCH] brcmfmac: use static superset of channels for wiphy
|
||
|
bands
|
||
|
|
||
|
The driver was constructing a list of channels per wiphy band
|
||
|
by querying the device. This list is not what the hardware is
|
||
|
able to do as it is already filtered by the country setting in
|
||
|
the device. As user-space may change the country this would
|
||
|
require updating the channel list which is not recommended [1].
|
||
|
This patch introduces a superset of channels. The individual
|
||
|
channels are disabled appropriately by querying the device.
|
||
|
|
||
|
[1] http://mid.gmane.org/1426706320.3001.21.camel@sipsolutions.net
|
||
|
|
||
|
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||
|
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||
|
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||
|
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||
|
---
|
||
|
|
||
|
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||
|
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||
|
@@ -129,13 +129,47 @@ static struct ieee80211_rate __wl_rates[
|
||
|
RATETAB_ENT(BRCM_RATE_54M, 0),
|
||
|
};
|
||
|
|
||
|
-#define wl_a_rates (__wl_rates + 4)
|
||
|
-#define wl_a_rates_size 8
|
||
|
#define wl_g_rates (__wl_rates + 0)
|
||
|
-#define wl_g_rates_size 12
|
||
|
+#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
|
||
|
+#define wl_a_rates (__wl_rates + 4)
|
||
|
+#define wl_a_rates_size (wl_g_rates_size - 4)
|
||
|
+
|
||
|
+#define CHAN2G(_channel, _freq) { \
|
||
|
+ .band = IEEE80211_BAND_2GHZ, \
|
||
|
+ .center_freq = (_freq), \
|
||
|
+ .hw_value = (_channel), \
|
||
|
+ .flags = IEEE80211_CHAN_DISABLED, \
|
||
|
+ .max_antenna_gain = 0, \
|
||
|
+ .max_power = 30, \
|
||
|
+}
|
||
|
+
|
||
|
+#define CHAN5G(_channel) { \
|
||
|
+ .band = IEEE80211_BAND_5GHZ, \
|
||
|
+ .center_freq = 5000 + (5 * (_channel)), \
|
||
|
+ .hw_value = (_channel), \
|
||
|
+ .flags = IEEE80211_CHAN_DISABLED, \
|
||
|
+ .max_antenna_gain = 0, \
|
||
|
+ .max_power = 30, \
|
||
|
+}
|
||
|
+
|
||
|
+static struct ieee80211_channel __wl_2ghz_channels[] = {
|
||
|
+ CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
|
||
|
+ CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
|
||
|
+ CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
|
||
|
+ CHAN2G(13, 2472), CHAN2G(14, 2484)
|
||
|
+};
|
||
|
+
|
||
|
+static struct ieee80211_channel __wl_5ghz_channels[] = {
|
||
|
+ CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
|
||
|
+ CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
|
||
|
+ CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
|
||
|
+ CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
|
||
|
+ CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
|
||
|
+ CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
|
||
|
+};
|
||
|
|
||
|
/* Band templates duplicated per wiphy. The channel info
|
||
|
- * is filled in after querying the device.
|
||
|
+ * above is added to the band during setup.
|
||
|
*/
|
||
|
static const struct ieee80211_supported_band __wl_band_2ghz = {
|
||
|
.band = IEEE80211_BAND_2GHZ,
|
||
|
@@ -143,7 +177,7 @@ static const struct ieee80211_supported_
|
||
|
.n_bitrates = wl_g_rates_size,
|
||
|
};
|
||
|
|
||
|
-static const struct ieee80211_supported_band __wl_band_5ghz_a = {
|
||
|
+static const struct ieee80211_supported_band __wl_band_5ghz = {
|
||
|
.band = IEEE80211_BAND_5GHZ,
|
||
|
.bitrates = wl_a_rates,
|
||
|
.n_bitrates = wl_a_rates_size,
|
||
|
@@ -5252,40 +5286,6 @@ dongle_scantime_out:
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-/* Filter the list of channels received from firmware counting only
|
||
|
- * the 20MHz channels. The wiphy band data only needs those which get
|
||
|
- * flagged to indicate if they can take part in higher bandwidth.
|
||
|
- */
|
||
|
-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
|
||
|
- struct brcmf_chanspec_list *chlist,
|
||
|
- u32 chcnt[])
|
||
|
-{
|
||
|
- u32 total = le32_to_cpu(chlist->count);
|
||
|
- struct brcmu_chan ch;
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; i < total; i++) {
|
||
|
- ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
|
||
|
- cfg->d11inf.decchspec(&ch);
|
||
|
-
|
||
|
- /* Firmware gives a ordered list. We skip non-20MHz
|
||
|
- * channels is 2G. For 5G we can abort upon reaching
|
||
|
- * a non-20MHz channel in the list.
|
||
|
- */
|
||
|
- if (ch.bw != BRCMU_CHAN_BW_20) {
|
||
|
- if (ch.band == BRCMU_CHAN_BAND_5G)
|
||
|
- break;
|
||
|
- else
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- if (ch.band == BRCMU_CHAN_BAND_2G)
|
||
|
- chcnt[0] += 1;
|
||
|
- else if (ch.band == BRCMU_CHAN_BAND_5G)
|
||
|
- chcnt[1] += 1;
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
|
||
|
struct brcmu_chan *ch)
|
||
|
{
|
||
|
@@ -5321,7 +5321,6 @@ static int brcmf_construct_chaninfo(stru
|
||
|
u32 i, j;
|
||
|
u32 total;
|
||
|
u32 chaninfo;
|
||
|
- u32 chcnt[2] = { 0, 0 };
|
||
|
u32 index;
|
||
|
|
||
|
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
|
||
|
@@ -5338,42 +5337,15 @@ static int brcmf_construct_chaninfo(stru
|
||
|
goto fail_pbuf;
|
||
|
}
|
||
|
|
||
|
- brcmf_count_20mhz_channels(cfg, list, chcnt);
|
||
|
wiphy = cfg_to_wiphy(cfg);
|
||
|
- if (chcnt[0]) {
|
||
|
- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
|
||
|
- GFP_KERNEL);
|
||
|
- if (band == NULL) {
|
||
|
- err = -ENOMEM;
|
||
|
- goto fail_pbuf;
|
||
|
- }
|
||
|
- band->channels = kcalloc(chcnt[0], sizeof(*channel),
|
||
|
- GFP_KERNEL);
|
||
|
- if (band->channels == NULL) {
|
||
|
- kfree(band);
|
||
|
- err = -ENOMEM;
|
||
|
- goto fail_pbuf;
|
||
|
- }
|
||
|
- band->n_channels = 0;
|
||
|
- wiphy->bands[IEEE80211_BAND_2GHZ] = band;
|
||
|
- }
|
||
|
- if (chcnt[1]) {
|
||
|
- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
|
||
|
- GFP_KERNEL);
|
||
|
- if (band == NULL) {
|
||
|
- err = -ENOMEM;
|
||
|
- goto fail_band2g;
|
||
|
- }
|
||
|
- band->channels = kcalloc(chcnt[1], sizeof(*channel),
|
||
|
- GFP_KERNEL);
|
||
|
- if (band->channels == NULL) {
|
||
|
- kfree(band);
|
||
|
- err = -ENOMEM;
|
||
|
- goto fail_band2g;
|
||
|
- }
|
||
|
- band->n_channels = 0;
|
||
|
- wiphy->bands[IEEE80211_BAND_5GHZ] = band;
|
||
|
- }
|
||
|
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
|
||
|
+ if (band)
|
||
|
+ for (i = 0; i < band->n_channels; i++)
|
||
|
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
|
||
|
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
|
||
|
+ if (band)
|
||
|
+ for (i = 0; i < band->n_channels; i++)
|
||
|
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
|
||
|
|
||
|
total = le32_to_cpu(list->count);
|
||
|
for (i = 0; i < total; i++) {
|
||
|
@@ -5388,6 +5360,8 @@ static int brcmf_construct_chaninfo(stru
|
||
|
brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
|
||
|
continue;
|
||
|
}
|
||
|
+ if (!band)
|
||
|
+ continue;
|
||
|
if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
|
||
|
ch.bw == BRCMU_CHAN_BW_40)
|
||
|
continue;
|
||
|
@@ -5415,9 +5389,9 @@ static int brcmf_construct_chaninfo(stru
|
||
|
} else if (ch.bw == BRCMU_CHAN_BW_40) {
|
||
|
brcmf_update_bw40_channel_flag(&channel[index], &ch);
|
||
|
} else {
|
||
|
- /* disable other bandwidths for now as mentioned
|
||
|
- * order assure they are enabled for subsequent
|
||
|
- * chanspecs.
|
||
|
+ /* enable the channel and disable other bandwidths
|
||
|
+ * for now as mentioned order assure they are enabled
|
||
|
+ * for subsequent chanspecs.
|
||
|
*/
|
||
|
channel[index].flags = IEEE80211_CHAN_NO_HT40 |
|
||
|
IEEE80211_CHAN_NO_80MHZ;
|
||
|
@@ -5436,16 +5410,8 @@ static int brcmf_construct_chaninfo(stru
|
||
|
IEEE80211_CHAN_NO_IR;
|
||
|
}
|
||
|
}
|
||
|
- if (index == band->n_channels)
|
||
|
- band->n_channels++;
|
||
|
}
|
||
|
- kfree(pbuf);
|
||
|
- return 0;
|
||
|
|
||
|
-fail_band2g:
|
||
|
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
|
||
|
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
|
||
|
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
|
||
|
fail_pbuf:
|
||
|
kfree(pbuf);
|
||
|
return err;
|
||
|
@@ -5778,7 +5744,12 @@ static void brcmf_wiphy_wowl_params(stru
|
||
|
|
||
|
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||
|
{
|
||
|
+ struct ieee80211_supported_band *band;
|
||
|
struct ieee80211_iface_combination ifc_combo;
|
||
|
+ __le32 bandlist[3];
|
||
|
+ u32 n_bands;
|
||
|
+ int err, i;
|
||
|
+
|
||
|
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
|
||
|
wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
||
|
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
|
||
|
@@ -5820,7 +5791,52 @@ static int brcmf_setup_wiphy(struct wiph
|
||
|
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
|
||
|
brcmf_wiphy_wowl_params(wiphy);
|
||
|
|
||
|
- return brcmf_setup_wiphybands(wiphy);
|
||
|
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
|
||
|
+ sizeof(bandlist));
|
||
|
+ if (err) {
|
||
|
+ brcmf_err("could not obtain band info: err=%d\n", err);
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ /* first entry in bandlist is number of bands */
|
||
|
+ n_bands = le32_to_cpu(bandlist[0]);
|
||
|
+ for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
|
||
|
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
|
||
|
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!band)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ band->channels = kmemdup(&__wl_2ghz_channels,
|
||
|
+ sizeof(__wl_2ghz_channels),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!band->channels) {
|
||
|
+ kfree(band);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
|
||
|
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
|
||
|
+ }
|
||
|
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
|
||
|
+ band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!band)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ band->channels = kmemdup(&__wl_5ghz_channels,
|
||
|
+ sizeof(__wl_5ghz_channels),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!band->channels) {
|
||
|
+ kfree(band);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
|
||
|
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ err = brcmf_setup_wiphybands(wiphy);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
||
|
@@ -6011,6 +6027,9 @@ static void brcmf_cfg80211_reg_notifier(
|
||
|
|
||
|
static void brcmf_free_wiphy(struct wiphy *wiphy)
|
||
|
{
|
||
|
+ if (!wiphy)
|
||
|
+ return;
|
||
|
+
|
||
|
kfree(wiphy->iface_combinations);
|
||
|
if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
|
||
|
kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
|