1 From: Arend van Spriel <arend@broadcom.com>
2 Date: Tue, 14 Apr 2015 20:10:24 +0200
3 Subject: [PATCH] brcmfmac: use static superset of channels for wiphy
6 The driver was constructing a list of channels per wiphy band
7 by querying the device. This list is not what the hardware is
8 able to do as it is already filtered by the country setting in
9 the device. As user-space may change the country this would
10 require updating the channel list which is not recommended [1].
11 This patch introduces a superset of channels. The individual
12 channels are disabled appropriately by querying the device.
14 [1] http://mid.gmane.org/1426706320.3001.21.camel@sipsolutions.net
16 Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
17 Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
18 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
19 Signed-off-by: Arend van Spriel <arend@broadcom.com>
22 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
23 +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
24 @@ -129,13 +129,47 @@ static struct ieee80211_rate __wl_rates[
25 RATETAB_ENT(BRCM_RATE_54M, 0),
28 -#define wl_a_rates (__wl_rates + 4)
29 -#define wl_a_rates_size 8
30 #define wl_g_rates (__wl_rates + 0)
31 -#define wl_g_rates_size 12
32 +#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
33 +#define wl_a_rates (__wl_rates + 4)
34 +#define wl_a_rates_size (wl_g_rates_size - 4)
36 +#define CHAN2G(_channel, _freq) { \
37 + .band = IEEE80211_BAND_2GHZ, \
38 + .center_freq = (_freq), \
39 + .hw_value = (_channel), \
40 + .flags = IEEE80211_CHAN_DISABLED, \
41 + .max_antenna_gain = 0, \
45 +#define CHAN5G(_channel) { \
46 + .band = IEEE80211_BAND_5GHZ, \
47 + .center_freq = 5000 + (5 * (_channel)), \
48 + .hw_value = (_channel), \
49 + .flags = IEEE80211_CHAN_DISABLED, \
50 + .max_antenna_gain = 0, \
54 +static struct ieee80211_channel __wl_2ghz_channels[] = {
55 + CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
56 + CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
57 + CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
58 + CHAN2G(13, 2472), CHAN2G(14, 2484)
61 +static struct ieee80211_channel __wl_5ghz_channels[] = {
62 + CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
63 + CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
64 + CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
65 + CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
66 + CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
67 + CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
70 /* Band templates duplicated per wiphy. The channel info
71 - * is filled in after querying the device.
72 + * above is added to the band during setup.
74 static const struct ieee80211_supported_band __wl_band_2ghz = {
75 .band = IEEE80211_BAND_2GHZ,
76 @@ -143,7 +177,7 @@ static const struct ieee80211_supported_
77 .n_bitrates = wl_g_rates_size,
80 -static const struct ieee80211_supported_band __wl_band_5ghz_a = {
81 +static const struct ieee80211_supported_band __wl_band_5ghz = {
82 .band = IEEE80211_BAND_5GHZ,
83 .bitrates = wl_a_rates,
84 .n_bitrates = wl_a_rates_size,
85 @@ -5252,40 +5286,6 @@ dongle_scantime_out:
89 -/* Filter the list of channels received from firmware counting only
90 - * the 20MHz channels. The wiphy band data only needs those which get
91 - * flagged to indicate if they can take part in higher bandwidth.
93 -static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
94 - struct brcmf_chanspec_list *chlist,
97 - u32 total = le32_to_cpu(chlist->count);
98 - struct brcmu_chan ch;
101 - for (i = 0; i < total; i++) {
102 - ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
103 - cfg->d11inf.decchspec(&ch);
105 - /* Firmware gives a ordered list. We skip non-20MHz
106 - * channels is 2G. For 5G we can abort upon reaching
107 - * a non-20MHz channel in the list.
109 - if (ch.bw != BRCMU_CHAN_BW_20) {
110 - if (ch.band == BRCMU_CHAN_BAND_5G)
116 - if (ch.band == BRCMU_CHAN_BAND_2G)
118 - else if (ch.band == BRCMU_CHAN_BAND_5G)
123 static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
124 struct brcmu_chan *ch)
126 @@ -5321,7 +5321,6 @@ static int brcmf_construct_chaninfo(stru
130 - u32 chcnt[2] = { 0, 0 };
133 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
134 @@ -5338,42 +5337,15 @@ static int brcmf_construct_chaninfo(stru
138 - brcmf_count_20mhz_channels(cfg, list, chcnt);
139 wiphy = cfg_to_wiphy(cfg);
141 - band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
143 - if (band == NULL) {
147 - band->channels = kcalloc(chcnt[0], sizeof(*channel),
149 - if (band->channels == NULL) {
154 - band->n_channels = 0;
155 - wiphy->bands[IEEE80211_BAND_2GHZ] = band;
158 - band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
160 - if (band == NULL) {
164 - band->channels = kcalloc(chcnt[1], sizeof(*channel),
166 - if (band->channels == NULL) {
171 - band->n_channels = 0;
172 - wiphy->bands[IEEE80211_BAND_5GHZ] = band;
174 + band = wiphy->bands[IEEE80211_BAND_2GHZ];
176 + for (i = 0; i < band->n_channels; i++)
177 + band->channels[i].flags = IEEE80211_CHAN_DISABLED;
178 + band = wiphy->bands[IEEE80211_BAND_5GHZ];
180 + for (i = 0; i < band->n_channels; i++)
181 + band->channels[i].flags = IEEE80211_CHAN_DISABLED;
183 total = le32_to_cpu(list->count);
184 for (i = 0; i < total; i++) {
185 @@ -5388,6 +5360,8 @@ static int brcmf_construct_chaninfo(stru
186 brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
191 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
192 ch.bw == BRCMU_CHAN_BW_40)
194 @@ -5415,9 +5389,9 @@ static int brcmf_construct_chaninfo(stru
195 } else if (ch.bw == BRCMU_CHAN_BW_40) {
196 brcmf_update_bw40_channel_flag(&channel[index], &ch);
198 - /* disable other bandwidths for now as mentioned
199 - * order assure they are enabled for subsequent
201 + /* enable the channel and disable other bandwidths
202 + * for now as mentioned order assure they are enabled
203 + * for subsequent chanspecs.
205 channel[index].flags = IEEE80211_CHAN_NO_HT40 |
206 IEEE80211_CHAN_NO_80MHZ;
207 @@ -5436,16 +5410,8 @@ static int brcmf_construct_chaninfo(stru
208 IEEE80211_CHAN_NO_IR;
211 - if (index == band->n_channels)
212 - band->n_channels++;
218 - kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
219 - kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
220 - wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
224 @@ -5778,7 +5744,12 @@ static void brcmf_wiphy_wowl_params(stru
226 static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
228 + struct ieee80211_supported_band *band;
229 struct ieee80211_iface_combination ifc_combo;
230 + __le32 bandlist[3];
234 wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
235 wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
236 wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
237 @@ -5820,7 +5791,52 @@ static int brcmf_setup_wiphy(struct wiph
238 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
239 brcmf_wiphy_wowl_params(wiphy);
241 - return brcmf_setup_wiphybands(wiphy);
242 + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
245 + brcmf_err("could not obtain band info: err=%d\n", err);
248 + /* first entry in bandlist is number of bands */
249 + n_bands = le32_to_cpu(bandlist[0]);
250 + for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
251 + if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
252 + band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
257 + band->channels = kmemdup(&__wl_2ghz_channels,
258 + sizeof(__wl_2ghz_channels),
260 + if (!band->channels) {
265 + band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
266 + wiphy->bands[IEEE80211_BAND_2GHZ] = band;
268 + if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
269 + band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
274 + band->channels = kmemdup(&__wl_5ghz_channels,
275 + sizeof(__wl_5ghz_channels),
277 + if (!band->channels) {
282 + band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
283 + wiphy->bands[IEEE80211_BAND_5GHZ] = band;
286 + err = brcmf_setup_wiphybands(wiphy);
290 static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
291 @@ -6011,6 +6027,9 @@ static void brcmf_cfg80211_reg_notifier(
293 static void brcmf_free_wiphy(struct wiphy *wiphy)
298 kfree(wiphy->iface_combinations);
299 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
300 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);