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