mac80211: backport brcmfmac to support multiple devices NVRAM
[openwrt/staging/chunkeey.git] / package / kernel / mac80211 / patches / 354-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch
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
4 bands
5
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.
13
14 [1] http://mid.gmane.org/1426706320.3001.21.camel@sipsolutions.net
15
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>
20 ---
21
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),
26 };
27
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)
35 +
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, \
42 + .max_power = 30, \
43 +}
44 +
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, \
51 + .max_power = 30, \
52 +}
53 +
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)
59 +};
60 +
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)
68 +};
69
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.
73 */
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,
78 };
79
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:
86 return err;
87 }
88
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.
92 - */
93 -static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
94 - struct brcmf_chanspec_list *chlist,
95 - u32 chcnt[])
96 -{
97 - u32 total = le32_to_cpu(chlist->count);
98 - struct brcmu_chan ch;
99 - int i;
100 -
101 - for (i = 0; i < total; i++) {
102 - ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
103 - cfg->d11inf.decchspec(&ch);
104 -
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.
108 - */
109 - if (ch.bw != BRCMU_CHAN_BW_20) {
110 - if (ch.band == BRCMU_CHAN_BAND_5G)
111 - break;
112 - else
113 - continue;
114 - }
115 -
116 - if (ch.band == BRCMU_CHAN_BAND_2G)
117 - chcnt[0] += 1;
118 - else if (ch.band == BRCMU_CHAN_BAND_5G)
119 - chcnt[1] += 1;
120 - }
121 -}
122 -
123 static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
124 struct brcmu_chan *ch)
125 {
126 @@ -5321,7 +5321,6 @@ static int brcmf_construct_chaninfo(stru
127 u32 i, j;
128 u32 total;
129 u32 chaninfo;
130 - u32 chcnt[2] = { 0, 0 };
131 u32 index;
132
133 pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
134 @@ -5338,42 +5337,15 @@ static int brcmf_construct_chaninfo(stru
135 goto fail_pbuf;
136 }
137
138 - brcmf_count_20mhz_channels(cfg, list, chcnt);
139 wiphy = cfg_to_wiphy(cfg);
140 - if (chcnt[0]) {
141 - band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
142 - GFP_KERNEL);
143 - if (band == NULL) {
144 - err = -ENOMEM;
145 - goto fail_pbuf;
146 - }
147 - band->channels = kcalloc(chcnt[0], sizeof(*channel),
148 - GFP_KERNEL);
149 - if (band->channels == NULL) {
150 - kfree(band);
151 - err = -ENOMEM;
152 - goto fail_pbuf;
153 - }
154 - band->n_channels = 0;
155 - wiphy->bands[IEEE80211_BAND_2GHZ] = band;
156 - }
157 - if (chcnt[1]) {
158 - band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
159 - GFP_KERNEL);
160 - if (band == NULL) {
161 - err = -ENOMEM;
162 - goto fail_band2g;
163 - }
164 - band->channels = kcalloc(chcnt[1], sizeof(*channel),
165 - GFP_KERNEL);
166 - if (band->channels == NULL) {
167 - kfree(band);
168 - err = -ENOMEM;
169 - goto fail_band2g;
170 - }
171 - band->n_channels = 0;
172 - wiphy->bands[IEEE80211_BAND_5GHZ] = band;
173 - }
174 + band = wiphy->bands[IEEE80211_BAND_2GHZ];
175 + if (band)
176 + for (i = 0; i < band->n_channels; i++)
177 + band->channels[i].flags = IEEE80211_CHAN_DISABLED;
178 + band = wiphy->bands[IEEE80211_BAND_5GHZ];
179 + if (band)
180 + for (i = 0; i < band->n_channels; i++)
181 + band->channels[i].flags = IEEE80211_CHAN_DISABLED;
182
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);
187 continue;
188 }
189 + if (!band)
190 + continue;
191 if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
192 ch.bw == BRCMU_CHAN_BW_40)
193 continue;
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);
197 } else {
198 - /* disable other bandwidths for now as mentioned
199 - * order assure they are enabled for subsequent
200 - * chanspecs.
201 + /* enable the channel and disable other bandwidths
202 + * for now as mentioned order assure they are enabled
203 + * for subsequent chanspecs.
204 */
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;
209 }
210 }
211 - if (index == band->n_channels)
212 - band->n_channels++;
213 }
214 - kfree(pbuf);
215 - return 0;
216
217 -fail_band2g:
218 - kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
219 - kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
220 - wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
221 fail_pbuf:
222 kfree(pbuf);
223 return err;
224 @@ -5778,7 +5744,12 @@ static void brcmf_wiphy_wowl_params(stru
225
226 static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
227 {
228 + struct ieee80211_supported_band *band;
229 struct ieee80211_iface_combination ifc_combo;
230 + __le32 bandlist[3];
231 + u32 n_bands;
232 + int err, i;
233 +
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);
240
241 - return brcmf_setup_wiphybands(wiphy);
242 + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
243 + sizeof(bandlist));
244 + if (err) {
245 + brcmf_err("could not obtain band info: err=%d\n", err);
246 + return err;
247 + }
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),
253 + GFP_KERNEL);
254 + if (!band)
255 + return -ENOMEM;
256 +
257 + band->channels = kmemdup(&__wl_2ghz_channels,
258 + sizeof(__wl_2ghz_channels),
259 + GFP_KERNEL);
260 + if (!band->channels) {
261 + kfree(band);
262 + return -ENOMEM;
263 + }
264 +
265 + band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
266 + wiphy->bands[IEEE80211_BAND_2GHZ] = band;
267 + }
268 + if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
269 + band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
270 + GFP_KERNEL);
271 + if (!band)
272 + return -ENOMEM;
273 +
274 + band->channels = kmemdup(&__wl_5ghz_channels,
275 + sizeof(__wl_5ghz_channels),
276 + GFP_KERNEL);
277 + if (!band->channels) {
278 + kfree(band);
279 + return -ENOMEM;
280 + }
281 +
282 + band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
283 + wiphy->bands[IEEE80211_BAND_5GHZ] = band;
284 + }
285 + }
286 + err = brcmf_setup_wiphybands(wiphy);
287 + return err;
288 }
289
290 static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
291 @@ -6011,6 +6027,9 @@ static void brcmf_cfg80211_reg_notifier(
292
293 static void brcmf_free_wiphy(struct wiphy *wiphy)
294 {
295 + if (!wiphy)
296 + return;
297 +
298 kfree(wiphy->iface_combinations);
299 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
300 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);