123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- From: Arend van Spriel <[email protected]>
- 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/[email protected]
- Reviewed-by: Hante Meuleman <[email protected]>
- Reviewed-by: Daniel (Deognyoun) Kim <[email protected]>
- Reviewed-by: Pieter-Paul Giesberts <[email protected]>
- Signed-off-by: Arend van Spriel <[email protected]>
- ---
- --- 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);
|