aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch')
-rw-r--r--package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch300
1 files changed, 300 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch b/package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch
new file mode 100644
index 0000000000..6e461f617f
--- /dev/null
+++ b/package/kernel/mac80211/patches/339-0001-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch
@@ -0,0 +1,300 @@
+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);