block: fix warning with calling smp_processor_id() in preemptible section
[pandora-kernel.git] / drivers / staging / brcm80211 / brcmsmac / wlc_channel.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 #include <linux/module.h>
20 #include <linux/pci.h>
21
22 #include <bcmdefs.h>
23 #include <bcmutils.h>
24 #include <bcmnvram.h>
25 #include <aiutils.h>
26 #include <sbhnddma.h>
27 #include <wlioctl.h>
28
29 #include "wlc_types.h"
30 #include "d11.h"
31 #include "wlc_cfg.h"
32 #include "wlc_scb.h"
33 #include "wlc_pub.h"
34 #include "wlc_key.h"
35 #include "phy/wlc_phy_hal.h"
36 #include "wlc_bmac.h"
37 #include "wlc_rate.h"
38 #include "wlc_channel.h"
39 #include "wlc_main.h"
40 #include "wlc_stf.h"
41 #include "wl_dbg.h"
42
43 #define VALID_CHANNEL20_DB(wlc, val) wlc_valid_channel20_db((wlc)->cmi, val)
44 #define VALID_CHANNEL20_IN_BAND(wlc, bandunit, val) \
45         wlc_valid_channel20_in_band((wlc)->cmi, bandunit, val)
46 #define VALID_CHANNEL20(wlc, val) wlc_valid_channel20((wlc)->cmi, val)
47
48 typedef struct wlc_cm_band {
49         u8 locale_flags;        /* locale_info_t flags */
50         chanvec_t valid_channels;       /* List of valid channels in the country */
51         const chanvec_t *restricted_channels;   /* List of restricted use channels */
52         const chanvec_t *radar_channels;        /* List of radar sensitive channels */
53         u8 PAD[8];
54 } wlc_cm_band_t;
55
56 struct wlc_cm_info {
57         struct wlc_pub *pub;
58         struct wlc_info *wlc;
59         char srom_ccode[WLC_CNTRY_BUF_SZ];      /* Country Code in SROM */
60         uint srom_regrev;       /* Regulatory Rev for the SROM ccode */
61         const country_info_t *country;  /* current country def */
62         char ccode[WLC_CNTRY_BUF_SZ];   /* current internal Country Code */
63         uint regrev;            /* current Regulatory Revision */
64         char country_abbrev[WLC_CNTRY_BUF_SZ];  /* current advertised ccode */
65         wlc_cm_band_t bandstate[MAXBANDS];      /* per-band state (one per phy/radio) */
66         /* quiet channels currently for radar sensitivity or 11h support */
67         chanvec_t quiet_channels;       /* channels on which we cannot transmit */
68 };
69
70 static int wlc_channels_init(wlc_cm_info_t *wlc_cm,
71                              const country_info_t *country);
72 static void wlc_set_country_common(wlc_cm_info_t *wlc_cm,
73                                    const char *country_abbrev,
74                                    const char *ccode, uint regrev,
75                                    const country_info_t *country);
76 static int wlc_set_countrycode(wlc_cm_info_t *wlc_cm, const char *ccode);
77 static int wlc_set_countrycode_rev(wlc_cm_info_t *wlc_cm,
78                                    const char *country_abbrev,
79                                    const char *ccode, int regrev);
80 static int wlc_country_aggregate_map(wlc_cm_info_t *wlc_cm, const char *ccode,
81                                      char *mapped_ccode, uint *mapped_regrev);
82 static const country_info_t *wlc_country_lookup_direct(const char *ccode,
83                                                        uint regrev);
84 static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm,
85                                                  const char *ccode,
86                                                  char *mapped_ccode,
87                                                  uint *mapped_regrev);
88 static void wlc_channels_commit(wlc_cm_info_t *wlc_cm);
89 static void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm);
90 static bool wlc_quiet_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chspec);
91 static bool wlc_valid_channel20_db(wlc_cm_info_t *wlc_cm, uint val);
92 static bool wlc_valid_channel20_in_band(wlc_cm_info_t *wlc_cm, uint bandunit,
93                                         uint val);
94 static bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val);
95 static const country_info_t *wlc_country_lookup(struct wlc_info *wlc,
96                                                 const char *ccode);
97 static void wlc_locale_get_channels(const locale_info_t *locale,
98                                     chanvec_t *valid_channels);
99 static const locale_info_t *wlc_get_locale_2g(u8 locale_idx);
100 static const locale_info_t *wlc_get_locale_5g(u8 locale_idx);
101 static bool wlc_japan(struct wlc_info *wlc);
102 static bool wlc_japan_ccode(const char *ccode);
103 static void wlc_channel_min_txpower_limits_with_local_constraint(wlc_cm_info_t *
104                                                                  wlc_cm,
105                                                                  struct
106                                                                  txpwr_limits
107                                                                  *txpwr,
108                                                                  u8
109                                                                  local_constraint_qdbm);
110 static void wlc_locale_add_channels(chanvec_t *target,
111                                     const chanvec_t *channels);
112 static const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx);
113 static const locale_mimo_info_t *wlc_get_mimo_5g(u8 locale_idx);
114
115 /* QDB() macro takes a dB value and converts to a quarter dB value */
116 #ifdef QDB
117 #undef QDB
118 #endif
119 #define QDB(n) ((n) * WLC_TXPWR_DB_FACTOR)
120
121 /* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
122
123 /*
124  * Some common channel sets
125  */
126
127 /* No channels */
128 static const chanvec_t chanvec_none = {
129         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132          0x00, 0x00, 0x00, 0x00}
133 };
134
135 /* All 2.4 GHz HW channels */
136 const chanvec_t chanvec_all_2G = {
137         {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140          0x00, 0x00, 0x00, 0x00}
141 };
142
143 /* All 5 GHz HW channels */
144 const chanvec_t chanvec_all_5G = {
145         {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
146          0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
147          0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
148          0x11, 0x11, 0x11, 0x01}
149 };
150
151 /*
152  * Radar channel sets
153  */
154
155 /* No radar */
156 #define radar_set_none chanvec_none
157
158 static const chanvec_t radar_set1 = {   /* Channels 52 - 64, 100 - 140 */
159         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,        /* 52 - 60 */
160          0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,        /* 64, 100 - 124 */
161          0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,        /* 128 - 140 */
162          0x00, 0x00, 0x00, 0x00}
163 };
164
165 /*
166  * Restricted channel sets
167  */
168
169 #define restricted_set_none chanvec_none
170
171 /* Channels 34, 38, 42, 46 */
172 static const chanvec_t restricted_set_japan_legacy = {
173         {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
174          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176          0x00, 0x00, 0x00, 0x00}
177 };
178
179 /* Channels 12, 13 */
180 static const chanvec_t restricted_set_2g_short = {
181         {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184          0x00, 0x00, 0x00, 0x00}
185 };
186
187 /* Channel 165 */
188 static const chanvec_t restricted_chan_165 = {
189         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191          0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
192          0x00, 0x00, 0x00, 0x00}
193 };
194
195 /* Channels 36 - 48 & 149 - 165 */
196 static const chanvec_t restricted_low_hi = {
197         {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
198          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199          0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
200          0x00, 0x00, 0x00, 0x00}
201 };
202
203 /* Channels 12 - 14 */
204 static const chanvec_t restricted_set_12_13_14 = {
205         {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208          0x00, 0x00, 0x00, 0x00}
209 };
210
211 #define  LOCALE_CHAN_01_11       (1<<0)
212 #define  LOCALE_CHAN_12_13       (1<<1)
213 #define  LOCALE_CHAN_14          (1<<2)
214 #define  LOCALE_SET_5G_LOW_JP1   (1<<3) /* 34-48, step 2 */
215 #define  LOCALE_SET_5G_LOW_JP2   (1<<4) /* 34-46, step 4 */
216 #define  LOCALE_SET_5G_LOW1      (1<<5) /* 36-48, step 4 */
217 #define  LOCALE_SET_5G_LOW2      (1<<6) /* 52 */
218 #define  LOCALE_SET_5G_LOW3      (1<<7) /* 56-64, step 4 */
219 #define  LOCALE_SET_5G_MID1      (1<<8) /* 100-116, step 4 */
220 #define  LOCALE_SET_5G_MID2      (1<<9) /* 120-124, step 4 */
221 #define  LOCALE_SET_5G_MID3      (1<<10)        /* 128 */
222 #define  LOCALE_SET_5G_HIGH1     (1<<11)        /* 132-140, step 4 */
223 #define  LOCALE_SET_5G_HIGH2     (1<<12)        /* 149-161, step 4 */
224 #define  LOCALE_SET_5G_HIGH3     (1<<13)        /* 165 */
225 #define  LOCALE_CHAN_52_140_ALL  (1<<14)
226 #define  LOCALE_SET_5G_HIGH4     (1<<15)        /* 184-216 */
227
228 #define  LOCALE_CHAN_36_64       (LOCALE_SET_5G_LOW1 | LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
229 #define  LOCALE_CHAN_52_64       (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
230 #define  LOCALE_CHAN_100_124     (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
231 #define  LOCALE_CHAN_100_140     \
232         (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
233 #define  LOCALE_CHAN_149_165     (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
234 #define  LOCALE_CHAN_184_216     LOCALE_SET_5G_HIGH4
235
236 #define  LOCALE_CHAN_01_14      (LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13 | LOCALE_CHAN_14)
237
238 #define  LOCALE_RADAR_SET_NONE            0
239 #define  LOCALE_RADAR_SET_1               1
240
241 #define  LOCALE_RESTRICTED_NONE           0
242 #define  LOCALE_RESTRICTED_SET_2G_SHORT   1
243 #define  LOCALE_RESTRICTED_CHAN_165       2
244 #define  LOCALE_CHAN_ALL_5G               3
245 #define  LOCALE_RESTRICTED_JAPAN_LEGACY   4
246 #define  LOCALE_RESTRICTED_11D_2G         5
247 #define  LOCALE_RESTRICTED_11D_5G         6
248 #define  LOCALE_RESTRICTED_LOW_HI         7
249 #define  LOCALE_RESTRICTED_12_13_14       8
250
251 /* global memory to provide working buffer for expanded locale */
252
253 static const chanvec_t *g_table_radar_set[] = {
254         &chanvec_none,
255         &radar_set1
256 };
257
258 static const chanvec_t *g_table_restricted_chan[] = {
259         &chanvec_none,          /* restricted_set_none */
260         &restricted_set_2g_short,
261         &restricted_chan_165,
262         &chanvec_all_5G,
263         &restricted_set_japan_legacy,
264         &chanvec_all_2G,        /* restricted_set_11d_2G */
265         &chanvec_all_5G,        /* restricted_set_11d_5G */
266         &restricted_low_hi,
267         &restricted_set_12_13_14
268 };
269
270 static const chanvec_t locale_2g_01_11 = {
271         {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274          0x00, 0x00, 0x00, 0x00}
275 };
276
277 static const chanvec_t locale_2g_12_13 = {
278         {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281          0x00, 0x00, 0x00, 0x00}
282 };
283
284 static const chanvec_t locale_2g_14 = {
285         {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288          0x00, 0x00, 0x00, 0x00}
289 };
290
291 static const chanvec_t locale_5g_LOW_JP1 = {
292         {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
293          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295          0x00, 0x00, 0x00, 0x00}
296 };
297
298 static const chanvec_t locale_5g_LOW_JP2 = {
299         {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
300          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302          0x00, 0x00, 0x00, 0x00}
303 };
304
305 static const chanvec_t locale_5g_LOW1 = {
306         {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
307          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309          0x00, 0x00, 0x00, 0x00}
310 };
311
312 static const chanvec_t locale_5g_LOW2 = {
313         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
314          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316          0x00, 0x00, 0x00, 0x00}
317 };
318
319 static const chanvec_t locale_5g_LOW3 = {
320         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
321          0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323          0x00, 0x00, 0x00, 0x00}
324 };
325
326 static const chanvec_t locale_5g_MID1 = {
327         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328          0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
329          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330          0x00, 0x00, 0x00, 0x00}
331 };
332
333 static const chanvec_t locale_5g_MID2 = {
334         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
336          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337          0x00, 0x00, 0x00, 0x00}
338 };
339
340 static const chanvec_t locale_5g_MID3 = {
341         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343          0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344          0x00, 0x00, 0x00, 0x00}
345 };
346
347 static const chanvec_t locale_5g_HIGH1 = {
348         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350          0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351          0x00, 0x00, 0x00, 0x00}
352 };
353
354 static const chanvec_t locale_5g_HIGH2 = {
355         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357          0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
358          0x00, 0x00, 0x00, 0x00}
359 };
360
361 static const chanvec_t locale_5g_HIGH3 = {
362         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364          0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
365          0x00, 0x00, 0x00, 0x00}
366 };
367
368 static const chanvec_t locale_5g_52_140_ALL = {
369         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
370          0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
371          0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
372          0x00, 0x00, 0x00, 0x00}
373 };
374
375 static const chanvec_t locale_5g_HIGH4 = {
376         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
379          0x11, 0x11, 0x11, 0x11}
380 };
381
382 static const chanvec_t *g_table_locale_base[] = {
383         &locale_2g_01_11,
384         &locale_2g_12_13,
385         &locale_2g_14,
386         &locale_5g_LOW_JP1,
387         &locale_5g_LOW_JP2,
388         &locale_5g_LOW1,
389         &locale_5g_LOW2,
390         &locale_5g_LOW3,
391         &locale_5g_MID1,
392         &locale_5g_MID2,
393         &locale_5g_MID3,
394         &locale_5g_HIGH1,
395         &locale_5g_HIGH2,
396         &locale_5g_HIGH3,
397         &locale_5g_52_140_ALL,
398         &locale_5g_HIGH4
399 };
400
401 static void wlc_locale_add_channels(chanvec_t *target,
402                                     const chanvec_t *channels)
403 {
404         u8 i;
405         for (i = 0; i < sizeof(chanvec_t); i++) {
406                 target->vec[i] |= channels->vec[i];
407         }
408 }
409
410 static void wlc_locale_get_channels(const locale_info_t *locale,
411                                     chanvec_t *channels)
412 {
413         u8 i;
414
415         memset(channels, 0, sizeof(chanvec_t));
416
417         for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
418                 if (locale->valid_channels & (1 << i)) {
419                         wlc_locale_add_channels(channels,
420                                                 g_table_locale_base[i]);
421                 }
422         }
423 }
424
425 /*
426  * Locale Definitions - 2.4 GHz
427  */
428 static const locale_info_t locale_i = { /* locale i. channel 1 - 13 */
429         LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
430         LOCALE_RADAR_SET_NONE,
431         LOCALE_RESTRICTED_SET_2G_SHORT,
432         {QDB(19), QDB(19), QDB(19),
433          QDB(19), QDB(19), QDB(19)},
434         {20, 20, 20, 0},
435         WLC_EIRP
436 };
437
438 /*
439  * Locale Definitions - 5 GHz
440  */
441 static const locale_info_t locale_11 = {
442         /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
443         LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
444         LOCALE_RADAR_SET_1,
445         LOCALE_RESTRICTED_NONE,
446         {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
447         {23, 23, 23, 30, 30},
448         WLC_EIRP | WLC_DFS_EU
449 };
450
451 #define LOCALE_2G_IDX_i                 0
452 static const locale_info_t *g_locale_2g_table[] = {
453         &locale_i
454 };
455
456 #define LOCALE_5G_IDX_11        0
457 static const locale_info_t *g_locale_5g_table[] = {
458         &locale_11
459 };
460
461 /*
462  * MIMO Locale Definitions - 2.4 GHz
463  */
464 static const locale_mimo_info_t locale_bn = {
465         {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
466          QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
467          QDB(13), QDB(13), QDB(13)},
468         {0, 0, QDB(13), QDB(13), QDB(13),
469          QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
470          QDB(13), 0, 0},
471         0
472 };
473
474 /* locale mimo 2g indexes */
475 #define LOCALE_MIMO_IDX_bn                      0
476
477 static const locale_mimo_info_t *g_mimo_2g_table[] = {
478         &locale_bn
479 };
480
481 /*
482  * MIMO Locale Definitions - 5 GHz
483  */
484 static const locale_mimo_info_t locale_11n = {
485         { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
486         {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
487         0
488 };
489
490 #define LOCALE_MIMO_IDX_11n                     0
491 static const locale_mimo_info_t *g_mimo_5g_table[] = {
492         &locale_11n
493 };
494
495 #ifdef LC
496 #undef LC
497 #endif
498 #define LC(id)  LOCALE_MIMO_IDX_ ## id
499
500 #ifdef LC_2G
501 #undef LC_2G
502 #endif
503 #define LC_2G(id)       LOCALE_2G_IDX_ ## id
504
505 #ifdef LC_5G
506 #undef LC_5G
507 #endif
508 #define LC_5G(id)       LOCALE_5G_IDX_ ## id
509
510 #define LOCALES(band2, band5, mimo2, mimo5)     {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
511
512 static const struct {
513         char abbrev[WLC_CNTRY_BUF_SZ];  /* country abbreviation */
514         country_info_t country;
515 } cntry_locales[] = {
516         {
517         "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
518 };
519
520 #ifdef SUPPORT_40MHZ
521 /* 20MHz channel info for 40MHz pairing support */
522 struct chan20_info {
523         u8 sb;
524         u8 adj_sbs;
525 };
526
527 /* indicates adjacent channels that are allowed for a 40 Mhz channel and
528  * those that permitted by the HT
529  */
530 struct chan20_info chan20_info[] = {
531         /* 11b/11g */
532 /* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
533 /* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
534 /* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
535 /* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
536 /* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
537 /* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
538 /* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
539 /* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
540 /* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
541 /* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
542 /* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
543 /* 11 */ {12, (CH_LOWER_SB)},
544 /* 12 */ {13, (CH_LOWER_SB)},
545 /* 13 */ {14, (CH_LOWER_SB)},
546
547 /* 11a japan high */
548 /* 14 */ {34, (CH_UPPER_SB)},
549 /* 15 */ {38, (CH_LOWER_SB)},
550 /* 16 */ {42, (CH_LOWER_SB)},
551 /* 17 */ {46, (CH_LOWER_SB)},
552
553 /* 11a usa low */
554 /* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
555 /* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
556 /* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
557 /* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
558 /* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
559 /* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
560 /* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
561 /* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
562
563 /* 11a Europe */
564 /* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
565 /* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
566 /* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
567 /* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
568 /* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
569 /* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
570 /* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
571 /* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
572 /* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
573 /* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
574 /* 36 */ {140, (CH_LOWER_SB)},
575
576 /* 11a usa high, ref5 only */
577 /* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
578 /* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
579 /* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
580 /* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
581 /* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
582 /* 41 */ {165, (CH_LOWER_SB)},
583
584 /* 11a japan */
585 /* 42 */ {184, (CH_UPPER_SB)},
586 /* 43 */ {188, (CH_LOWER_SB)},
587 /* 44 */ {192, (CH_UPPER_SB)},
588 /* 45 */ {196, (CH_LOWER_SB)},
589 /* 46 */ {200, (CH_UPPER_SB)},
590 /* 47 */ {204, (CH_LOWER_SB)},
591 /* 48 */ {208, (CH_UPPER_SB)},
592 /* 49 */ {212, (CH_LOWER_SB)},
593 /* 50 */ {216, (CH_LOWER_SB)}
594 };
595 #endif                          /* SUPPORT_40MHZ */
596
597 static const locale_info_t *wlc_get_locale_2g(u8 locale_idx)
598 {
599         if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) {
600                 return NULL; /* error condition */
601         }
602         return g_locale_2g_table[locale_idx];
603 }
604
605 static const locale_info_t *wlc_get_locale_5g(u8 locale_idx)
606 {
607         if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) {
608                 return NULL; /* error condition */
609         }
610         return g_locale_5g_table[locale_idx];
611 }
612
613 static const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx)
614 {
615         if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) {
616                 return NULL;
617         }
618         return g_mimo_2g_table[locale_idx];
619 }
620
621 static const locale_mimo_info_t *wlc_get_mimo_5g(u8 locale_idx)
622 {
623         if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) {
624                 return NULL;
625         }
626         return g_mimo_5g_table[locale_idx];
627 }
628
629 wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc)
630 {
631         wlc_cm_info_t *wlc_cm;
632         char country_abbrev[WLC_CNTRY_BUF_SZ];
633         const country_info_t *country;
634         struct wlc_pub *pub = wlc->pub;
635         char *ccode;
636
637         BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
638
639         wlc_cm = kzalloc(sizeof(wlc_cm_info_t), GFP_ATOMIC);
640         if (wlc_cm == NULL) {
641                 wiphy_err(wlc->wiphy, "wl%d: %s: out of memory", pub->unit,
642                           __func__);
643                 return NULL;
644         }
645         wlc_cm->pub = pub;
646         wlc_cm->wlc = wlc;
647         wlc->cmi = wlc_cm;
648
649         /* store the country code for passing up as a regulatory hint */
650         ccode = getvar(wlc->pub->vars, "ccode");
651         if (ccode) {
652                 strncpy(wlc->pub->srom_ccode, ccode, WLC_CNTRY_BUF_SZ - 1);
653         }
654
655         /* internal country information which must match regulatory constraints in firmware */
656         memset(country_abbrev, 0, WLC_CNTRY_BUF_SZ);
657         strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
658         country = wlc_country_lookup(wlc, country_abbrev);
659
660         /* save default country for exiting 11d regulatory mode */
661         strncpy(wlc->country_default, country_abbrev, WLC_CNTRY_BUF_SZ - 1);
662
663         /* initialize autocountry_default to driver default */
664         strncpy(wlc->autocountry_default, "X2", WLC_CNTRY_BUF_SZ - 1);
665
666         wlc_set_countrycode(wlc_cm, country_abbrev);
667
668         return wlc_cm;
669 }
670
671 void wlc_channel_mgr_detach(wlc_cm_info_t *wlc_cm)
672 {
673         kfree(wlc_cm);
674 }
675
676 u8 wlc_channel_locale_flags_in_band(wlc_cm_info_t *wlc_cm, uint bandunit)
677 {
678         return wlc_cm->bandstate[bandunit].locale_flags;
679 }
680
681 /* set the driver's current country and regulatory information using a country code
682  * as the source. Lookup built in country information found with the country code.
683  */
684 static int wlc_set_countrycode(wlc_cm_info_t *wlc_cm, const char *ccode)
685 {
686         char country_abbrev[WLC_CNTRY_BUF_SZ];
687         strncpy(country_abbrev, ccode, WLC_CNTRY_BUF_SZ);
688         return wlc_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
689 }
690
691 static int
692 wlc_set_countrycode_rev(wlc_cm_info_t *wlc_cm,
693                         const char *country_abbrev,
694                         const char *ccode, int regrev)
695 {
696         const country_info_t *country;
697         char mapped_ccode[WLC_CNTRY_BUF_SZ];
698         uint mapped_regrev;
699
700         /* if regrev is -1, lookup the mapped country code,
701          * otherwise use the ccode and regrev directly
702          */
703         if (regrev == -1) {
704                 /* map the country code to a built-in country code, regrev, and country_info */
705                 country =
706                     wlc_countrycode_map(wlc_cm, ccode, mapped_ccode,
707                                         &mapped_regrev);
708         } else {
709                 /* find the matching built-in country definition */
710                 country = wlc_country_lookup_direct(ccode, regrev);
711                 strncpy(mapped_ccode, ccode, WLC_CNTRY_BUF_SZ);
712                 mapped_regrev = regrev;
713         }
714
715         if (country == NULL)
716                 return -EINVAL;
717
718         /* set the driver state for the country */
719         wlc_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
720                                mapped_regrev, country);
721
722         return 0;
723 }
724
725 /* set the driver's current country and regulatory information using a country code
726  * as the source. Look up built in country information found with the country code.
727  */
728 static void
729 wlc_set_country_common(wlc_cm_info_t *wlc_cm,
730                        const char *country_abbrev,
731                        const char *ccode, uint regrev,
732                        const country_info_t *country)
733 {
734         const locale_mimo_info_t *li_mimo;
735         const locale_info_t *locale;
736         struct wlc_info *wlc = wlc_cm->wlc;
737         char prev_country_abbrev[WLC_CNTRY_BUF_SZ];
738
739         /* save current country state */
740         wlc_cm->country = country;
741
742         memset(&prev_country_abbrev, 0, WLC_CNTRY_BUF_SZ);
743         strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
744                 WLC_CNTRY_BUF_SZ - 1);
745
746         strncpy(wlc_cm->country_abbrev, country_abbrev, WLC_CNTRY_BUF_SZ - 1);
747         strncpy(wlc_cm->ccode, ccode, WLC_CNTRY_BUF_SZ - 1);
748         wlc_cm->regrev = regrev;
749
750         /* disable/restore nmode based on country regulations */
751         li_mimo = wlc_get_mimo_2g(country->locale_mimo_2G);
752         if (li_mimo && (li_mimo->flags & WLC_NO_MIMO)) {
753                 wlc_set_nmode(wlc, OFF);
754                 wlc->stf->no_cddstbc = true;
755         } else {
756                 wlc->stf->no_cddstbc = false;
757                 if (N_ENAB(wlc->pub) != wlc->protection->nmode_user)
758                         wlc_set_nmode(wlc, wlc->protection->nmode_user);
759         }
760
761         wlc_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
762         wlc_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
763         /* set or restore gmode as required by regulatory */
764         locale = wlc_get_locale_2g(country->locale_2G);
765         if (locale && (locale->flags & WLC_NO_OFDM)) {
766                 wlc_set_gmode(wlc, GMODE_LEGACY_B, false);
767         } else {
768                 wlc_set_gmode(wlc, wlc->protection->gmode_user, false);
769         }
770
771         wlc_channels_init(wlc_cm, country);
772
773         return;
774 }
775
776 /* Lookup a country info structure from a null terminated country code
777  * The lookup is case sensitive.
778  */
779 static const country_info_t *wlc_country_lookup(struct wlc_info *wlc,
780                                          const char *ccode)
781 {
782         const country_info_t *country;
783         char mapped_ccode[WLC_CNTRY_BUF_SZ];
784         uint mapped_regrev;
785
786         /* map the country code to a built-in country code, regrev, and country_info struct */
787         country =
788             wlc_countrycode_map(wlc->cmi, ccode, mapped_ccode, &mapped_regrev);
789
790         return country;
791 }
792
793 static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm,
794                                                  const char *ccode,
795                                                  char *mapped_ccode,
796                                                  uint *mapped_regrev)
797 {
798         struct wlc_info *wlc = wlc_cm->wlc;
799         const country_info_t *country;
800         uint srom_regrev = wlc_cm->srom_regrev;
801         const char *srom_ccode = wlc_cm->srom_ccode;
802         int mapped;
803
804         /* check for currently supported ccode size */
805         if (strlen(ccode) > (WLC_CNTRY_BUF_SZ - 1)) {
806                 wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
807                           "match\n", wlc->pub->unit, __func__, ccode);
808                 return NULL;
809         }
810
811         /* default mapping is the given ccode and regrev 0 */
812         strncpy(mapped_ccode, ccode, WLC_CNTRY_BUF_SZ);
813         *mapped_regrev = 0;
814
815         /* If the desired country code matches the srom country code,
816          * then the mapped country is the srom regulatory rev.
817          * Otherwise look for an aggregate mapping.
818          */
819         if (!strcmp(srom_ccode, ccode)) {
820                 *mapped_regrev = srom_regrev;
821                 mapped = 0;
822                 wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
823         } else {
824                 mapped =
825                     wlc_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
826                                               mapped_regrev);
827         }
828
829         /* find the matching built-in country definition */
830         country = wlc_country_lookup_direct(mapped_ccode, *mapped_regrev);
831
832         /* if there is not an exact rev match, default to rev zero */
833         if (country == NULL && *mapped_regrev != 0) {
834                 *mapped_regrev = 0;
835                 country =
836                     wlc_country_lookup_direct(mapped_ccode, *mapped_regrev);
837         }
838
839         return country;
840 }
841
842 static int
843 wlc_country_aggregate_map(wlc_cm_info_t *wlc_cm, const char *ccode,
844                           char *mapped_ccode, uint *mapped_regrev)
845 {
846         return false;
847 }
848
849 /* Lookup a country info structure from a null terminated country
850  * abbreviation and regrev directly with no translation.
851  */
852 static const country_info_t *wlc_country_lookup_direct(const char *ccode,
853                                                        uint regrev)
854 {
855         uint size, i;
856
857         /* Should just return 0 for single locale driver. */
858         /* Keep it this way in case we add more locales. (for now anyway) */
859
860         /* all other country def arrays are for regrev == 0, so if regrev is non-zero, fail */
861         if (regrev > 0)
862                 return NULL;
863
864         /* find matched table entry from country code */
865         size = ARRAY_SIZE(cntry_locales);
866         for (i = 0; i < size; i++) {
867                 if (strcmp(ccode, cntry_locales[i].abbrev) == 0) {
868                         return &cntry_locales[i].country;
869                 }
870         }
871         return NULL;
872 }
873
874 static int
875 wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country)
876 {
877         struct wlc_info *wlc = wlc_cm->wlc;
878         uint i, j;
879         struct wlcband *band;
880         const locale_info_t *li;
881         chanvec_t sup_chan;
882         const locale_mimo_info_t *li_mimo;
883
884         band = wlc->band;
885         for (i = 0; i < NBANDS(wlc);
886              i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
887
888                 li = BAND_5G(band->bandtype) ?
889                     wlc_get_locale_5g(country->locale_5G) :
890                     wlc_get_locale_2g(country->locale_2G);
891                 wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
892                 li_mimo = BAND_5G(band->bandtype) ?
893                     wlc_get_mimo_5g(country->locale_mimo_5G) :
894                     wlc_get_mimo_2g(country->locale_mimo_2G);
895
896                 /* merge the mimo non-mimo locale flags */
897                 wlc_cm->bandstate[band->bandunit].locale_flags |=
898                     li_mimo->flags;
899
900                 wlc_cm->bandstate[band->bandunit].restricted_channels =
901                     g_table_restricted_chan[li->restricted_channels];
902                 wlc_cm->bandstate[band->bandunit].radar_channels =
903                     g_table_radar_set[li->radar_channels];
904
905                 /* set the channel availability,
906                  * masking out the channels that may not be supported on this phy
907                  */
908                 wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
909                                               &sup_chan);
910                 wlc_locale_get_channels(li,
911                                         &wlc_cm->bandstate[band->bandunit].
912                                         valid_channels);
913                 for (j = 0; j < sizeof(chanvec_t); j++)
914                         wlc_cm->bandstate[band->bandunit].valid_channels.
915                             vec[j] &= sup_chan.vec[j];
916         }
917
918         wlc_quiet_channels_reset(wlc_cm);
919         wlc_channels_commit(wlc_cm);
920
921         return 0;
922 }
923
924 /* Update the radio state (enable/disable) and tx power targets
925  * based on a new set of channel/regulatory information
926  */
927 static void wlc_channels_commit(wlc_cm_info_t *wlc_cm)
928 {
929         struct wlc_info *wlc = wlc_cm->wlc;
930         uint chan;
931         struct txpwr_limits txpwr;
932
933         /* search for the existence of any valid channel */
934         for (chan = 0; chan < MAXCHANNEL; chan++) {
935                 if (VALID_CHANNEL20_DB(wlc, chan)) {
936                         break;
937                 }
938         }
939         if (chan == MAXCHANNEL)
940                 chan = INVCHANNEL;
941
942         /* based on the channel search above, set or clear WL_RADIO_COUNTRY_DISABLE */
943         if (chan == INVCHANNEL) {
944                 /* country/locale with no valid channels, set the radio disable bit */
945                 mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
946                 wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
947                           "nbands %d bandlocked %d\n", wlc->pub->unit,
948                           __func__, wlc_cm->country_abbrev, NBANDS(wlc),
949                           wlc->bandlocked);
950         } else
951             if (mboolisset(wlc->pub->radio_disabled,
952                 WL_RADIO_COUNTRY_DISABLE)) {
953                 /* country/locale with valid channel, clear the radio disable bit */
954                 mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
955         }
956
957         /* Now that the country abbreviation is set, if the radio supports 2G, then
958          * set channel 14 restrictions based on the new locale.
959          */
960         if (NBANDS(wlc) > 1 || BAND_2G(wlc->band->bandtype)) {
961                 wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
962                                                      wlc_japan(wlc) ? true :
963                                                      false);
964         }
965
966         if (wlc->pub->up && chan != INVCHANNEL) {
967                 wlc_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
968                 wlc_channel_min_txpower_limits_with_local_constraint(wlc_cm,
969                                                                      &txpwr,
970                                                                      WLC_TXPWR_MAX);
971                 wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
972         }
973 }
974
975 /* reset the quiet channels vector to the union of the restricted and radar channel sets */
976 static void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm)
977 {
978         struct wlc_info *wlc = wlc_cm->wlc;
979         uint i, j;
980         struct wlcband *band;
981         const chanvec_t *chanvec;
982
983         memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t));
984
985         band = wlc->band;
986         for (i = 0; i < NBANDS(wlc);
987              i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
988
989                 /* initialize quiet channels for restricted channels */
990                 chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
991                 for (j = 0; j < sizeof(chanvec_t); j++)
992                         wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
993
994         }
995 }
996
997 static bool wlc_quiet_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chspec)
998 {
999         return N_ENAB(wlc_cm->wlc->pub) && CHSPEC_IS40(chspec) ?
1000                 (isset
1001                  (wlc_cm->quiet_channels.vec,
1002                   LOWER_20_SB(CHSPEC_CHANNEL(chspec)))
1003                  || isset(wlc_cm->quiet_channels.vec,
1004                           UPPER_20_SB(CHSPEC_CHANNEL(chspec)))) : isset(wlc_cm->
1005                                                                         quiet_channels.
1006                                                                         vec,
1007                                                                         CHSPEC_CHANNEL
1008                                                                         (chspec));
1009 }
1010
1011 /* Is the channel valid for the current locale? (but don't consider channels not
1012  *   available due to bandlocking)
1013  */
1014 static bool wlc_valid_channel20_db(wlc_cm_info_t *wlc_cm, uint val)
1015 {
1016         struct wlc_info *wlc = wlc_cm->wlc;
1017
1018         return VALID_CHANNEL20(wlc, val) ||
1019                 (!wlc->bandlocked
1020                  && VALID_CHANNEL20_IN_BAND(wlc, OTHERBANDUNIT(wlc), val));
1021 }
1022
1023 /* Is the channel valid for the current locale and specified band? */
1024 static bool
1025 wlc_valid_channel20_in_band(wlc_cm_info_t *wlc_cm, uint bandunit, uint val)
1026 {
1027         return ((val < MAXCHANNEL)
1028                 && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
1029 }
1030
1031 /* Is the channel valid for the current locale and current band? */
1032 static bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val)
1033 {
1034         struct wlc_info *wlc = wlc_cm->wlc;
1035
1036         return ((val < MAXCHANNEL) &&
1037                 isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
1038                       val));
1039 }
1040
1041 static void
1042 wlc_channel_min_txpower_limits_with_local_constraint(wlc_cm_info_t *wlc_cm,
1043                                                      struct txpwr_limits *txpwr,
1044                                                      u8
1045                                                      local_constraint_qdbm)
1046 {
1047         int j;
1048
1049         /* CCK Rates */
1050         for (j = 0; j < WL_TX_POWER_CCK_NUM; j++) {
1051                 txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
1052         }
1053
1054         /* 20 MHz Legacy OFDM SISO */
1055         for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++) {
1056                 txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
1057         }
1058
1059         /* 20 MHz Legacy OFDM CDD */
1060         for (j = 0; j < WLC_NUM_RATES_OFDM; j++) {
1061                 txpwr->ofdm_cdd[j] =
1062                     min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
1063         }
1064
1065         /* 40 MHz Legacy OFDM SISO */
1066         for (j = 0; j < WLC_NUM_RATES_OFDM; j++) {
1067                 txpwr->ofdm_40_siso[j] =
1068                     min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
1069         }
1070
1071         /* 40 MHz Legacy OFDM CDD */
1072         for (j = 0; j < WLC_NUM_RATES_OFDM; j++) {
1073                 txpwr->ofdm_40_cdd[j] =
1074                     min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
1075         }
1076
1077         /* 20MHz MCS 0-7 SISO */
1078         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1079                 txpwr->mcs_20_siso[j] =
1080                     min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
1081         }
1082
1083         /* 20MHz MCS 0-7 CDD */
1084         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1085                 txpwr->mcs_20_cdd[j] =
1086                     min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
1087         }
1088
1089         /* 20MHz MCS 0-7 STBC */
1090         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1091                 txpwr->mcs_20_stbc[j] =
1092                     min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
1093         }
1094
1095         /* 20MHz MCS 8-15 MIMO */
1096         for (j = 0; j < WLC_NUM_RATES_MCS_2_STREAM; j++)
1097                 txpwr->mcs_20_mimo[j] =
1098                     min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
1099
1100         /* 40MHz MCS 0-7 SISO */
1101         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1102                 txpwr->mcs_40_siso[j] =
1103                     min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
1104         }
1105
1106         /* 40MHz MCS 0-7 CDD */
1107         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1108                 txpwr->mcs_40_cdd[j] =
1109                     min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
1110         }
1111
1112         /* 40MHz MCS 0-7 STBC */
1113         for (j = 0; j < WLC_NUM_RATES_MCS_1_STREAM; j++) {
1114                 txpwr->mcs_40_stbc[j] =
1115                     min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
1116         }
1117
1118         /* 40MHz MCS 8-15 MIMO */
1119         for (j = 0; j < WLC_NUM_RATES_MCS_2_STREAM; j++)
1120                 txpwr->mcs_40_mimo[j] =
1121                     min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
1122
1123         /* 40MHz MCS 32 */
1124         txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
1125
1126 }
1127
1128 void
1129 wlc_channel_set_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chanspec,
1130                          u8 local_constraint_qdbm)
1131 {
1132         struct wlc_info *wlc = wlc_cm->wlc;
1133         struct txpwr_limits txpwr;
1134
1135         wlc_channel_reg_limits(wlc_cm, chanspec, &txpwr);
1136
1137         wlc_channel_min_txpower_limits_with_local_constraint(wlc_cm, &txpwr,
1138                                                              local_constraint_qdbm);
1139
1140         wlc_bmac_set_chanspec(wlc->hw, chanspec,
1141                               (wlc_quiet_chanspec(wlc_cm, chanspec) != 0),
1142                               &txpwr);
1143 }
1144
1145 #ifdef POWER_DBG
1146 static void wlc_phy_txpower_limits_dump(txpwr_limits_t *txpwr)
1147 {
1148         int i;
1149         char buf[80];
1150         char fraction[4][4] = { "   ", ".25", ".5 ", ".75" };
1151
1152         sprintf(buf, "CCK                ");
1153         for (i = 0; i < WLC_NUM_RATES_CCK; i++) {
1154                 sprintf(buf[strlen(buf)], " %2d%s",
1155                         txpwr->cck[i] / WLC_TXPWR_DB_FACTOR,
1156                         fraction[txpwr->cck[i] % WLC_TXPWR_DB_FACTOR]);
1157         }
1158         printk(KERN_DEBUG "%s\n", buf);
1159
1160         sprintf(buf, "20 MHz OFDM SISO   ");
1161         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1162                 sprintf(buf[strlen(buf)], " %2d%s",
1163                         txpwr->ofdm[i] / WLC_TXPWR_DB_FACTOR,
1164                         fraction[txpwr->ofdm[i] % WLC_TXPWR_DB_FACTOR]);
1165         }
1166         printk(KERN_DEBUG "%s\n", buf);
1167
1168         sprintf(buf, "20 MHz OFDM CDD    ");
1169         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1170                 sprintf(buf[strlen(buf)], " %2d%s",
1171                         txpwr->ofdm_cdd[i] / WLC_TXPWR_DB_FACTOR,
1172                         fraction[txpwr->ofdm_cdd[i] % WLC_TXPWR_DB_FACTOR]);
1173         }
1174         printk(KERN_DEBUG "%s\n", buf);
1175
1176         sprintf(buf, "40 MHz OFDM SISO   ");
1177         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1178                 sprintf(buf[strlen(buf)], " %2d%s",
1179                         txpwr->ofdm_40_siso[i] / WLC_TXPWR_DB_FACTOR,
1180                         fraction[txpwr->ofdm_40_siso[i] % WLC_TXPWR_DB_FACTOR]);
1181         }
1182         printk(KERN_DEBUG "%s\n", buf);
1183
1184         sprintf(buf, "40 MHz OFDM CDD    ");
1185         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1186                 sprintf(buf[strlen(buf)], " %2d%s",
1187                         txpwr->ofdm_40_cdd[i] / WLC_TXPWR_DB_FACTOR,
1188                         fraction[txpwr->ofdm_40_cdd[i] % WLC_TXPWR_DB_FACTOR]);
1189         }
1190         printk(KERN_DEBUG "%s\n", buf);
1191
1192         sprintf(buf, "20 MHz MCS0-7 SISO ");
1193         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1194                 sprintf(buf[strlen(buf)], " %2d%s",
1195                         txpwr->mcs_20_siso[i] / WLC_TXPWR_DB_FACTOR,
1196                         fraction[txpwr->mcs_20_siso[i] % WLC_TXPWR_DB_FACTOR]);
1197         }
1198         printk(KERN_DEBUG "%s\n", buf);
1199
1200         sprintf(buf, "20 MHz MCS0-7 CDD  ");
1201         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1202                 sprintf(buf[strlen(buf)], " %2d%s",
1203                         txpwr->mcs_20_cdd[i] / WLC_TXPWR_DB_FACTOR,
1204                         fraction[txpwr->mcs_20_cdd[i] % WLC_TXPWR_DB_FACTOR]);
1205         }
1206         printk(KERN_DEBUG "%s\n", buf);
1207
1208         sprintf(buf, "20 MHz MCS0-7 STBC ");
1209         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1210                 sprintf(buf[strlen(buf)], " %2d%s",
1211                         txpwr->mcs_20_stbc[i] / WLC_TXPWR_DB_FACTOR,
1212                         fraction[txpwr->mcs_20_stbc[i] % WLC_TXPWR_DB_FACTOR]);
1213         }
1214         printk(KERN_DEBUG "%s\n", buf);
1215
1216         sprintf(buf, "20 MHz MCS8-15 SDM ");
1217         for (i = 0; i < WLC_NUM_RATES_MCS_2_STREAM; i++) {
1218                 sprintf(buf[strlen(buf)], " %2d%s",
1219                         txpwr->mcs_20_mimo[i] / WLC_TXPWR_DB_FACTOR,
1220                         fraction[txpwr->mcs_20_mimo[i] % WLC_TXPWR_DB_FACTOR]);
1221         }
1222         printk(KERN_DEBUG "%s\n", buf);
1223
1224         sprintf(buf, "40 MHz MCS0-7 SISO ");
1225         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1226                 sprintf(buf[strlen(buf)], " %2d%s",
1227                         txpwr->mcs_40_siso[i] / WLC_TXPWR_DB_FACTOR,
1228                         fraction[txpwr->mcs_40_siso[i] % WLC_TXPWR_DB_FACTOR]);
1229         }
1230         printk(KERN_DEBUG "%s\n", buf);
1231
1232         sprintf(buf, "40 MHz MCS0-7 CDD  ");
1233         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1234                 sprintf(buf[strlen(buf)], " %2d%s",
1235                         txpwr->mcs_40_cdd[i] / WLC_TXPWR_DB_FACTOR,
1236                         fraction[txpwr->mcs_40_cdd[i] % WLC_TXPWR_DB_FACTOR]);
1237         }
1238         printk(KERN_DEBUG "%s\n", buf);
1239
1240         sprintf(buf, "40 MHz MCS0-7 STBC ");
1241         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1242                 sprintf(buf[strlen(buf)], " %2d%s",
1243                         txpwr->mcs_40_stbc[i] / WLC_TXPWR_DB_FACTOR,
1244                         fraction[txpwr->mcs_40_stbc[i] % WLC_TXPWR_DB_FACTOR]);
1245         }
1246         printk(KERN_DEBUG "%s\n", buf);
1247
1248         sprintf(buf, "40 MHz MCS8-15 SDM ");
1249         for (i = 0; i < WLC_NUM_RATES_MCS_2_STREAM; i++) {
1250                 sprintf(buf[strlen(buf)], " %2d%s",
1251                         txpwr->mcs_40_mimo[i] / WLC_TXPWR_DB_FACTOR,
1252                         fraction[txpwr->mcs_40_mimo[i] % WLC_TXPWR_DB_FACTOR]);
1253         }
1254         printk(KERN_DEBUG "%s\n", buf);
1255
1256         printk(KERN_DEBUG "MCS32               %2d%s\n",
1257                txpwr->mcs32 / WLC_TXPWR_DB_FACTOR,
1258                fraction[txpwr->mcs32 % WLC_TXPWR_DB_FACTOR]);
1259 }
1260 #endif                          /* POWER_DBG */
1261
1262 void
1263 wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec,
1264                        txpwr_limits_t *txpwr)
1265 {
1266         struct wlc_info *wlc = wlc_cm->wlc;
1267         uint i;
1268         uint chan;
1269         int maxpwr;
1270         int delta;
1271         const country_info_t *country;
1272         struct wlcband *band;
1273         const locale_info_t *li;
1274         int conducted_max;
1275         int conducted_ofdm_max;
1276         const locale_mimo_info_t *li_mimo;
1277         int maxpwr20, maxpwr40;
1278         int maxpwr_idx;
1279         uint j;
1280
1281         memset(txpwr, 0, sizeof(txpwr_limits_t));
1282
1283         if (!wlc_valid_chanspec_db(wlc_cm, chanspec)) {
1284                 country = wlc_country_lookup(wlc, wlc->autocountry_default);
1285                 if (country == NULL)
1286                         return;
1287         } else {
1288                 country = wlc_cm->country;
1289         }
1290
1291         chan = CHSPEC_CHANNEL(chanspec);
1292         band = wlc->bandstate[CHSPEC_WLCBANDUNIT(chanspec)];
1293         li = BAND_5G(band->bandtype) ?
1294             wlc_get_locale_5g(country->locale_5G) :
1295             wlc_get_locale_2g(country->locale_2G);
1296
1297         li_mimo = BAND_5G(band->bandtype) ?
1298             wlc_get_mimo_5g(country->locale_mimo_5G) :
1299             wlc_get_mimo_2g(country->locale_mimo_2G);
1300
1301         if (li->flags & WLC_EIRP) {
1302                 delta = band->antgain;
1303         } else {
1304                 delta = 0;
1305                 if (band->antgain > QDB(6))
1306                         delta = band->antgain - QDB(6); /* Excess over 6 dB */
1307         }
1308
1309         if (li == &locale_i) {
1310                 conducted_max = QDB(22);
1311                 conducted_ofdm_max = QDB(22);
1312         }
1313
1314         /* CCK txpwr limits for 2.4G band */
1315         if (BAND_2G(band->bandtype)) {
1316                 maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
1317
1318                 maxpwr = maxpwr - delta;
1319                 maxpwr = max(maxpwr, 0);
1320                 maxpwr = min(maxpwr, conducted_max);
1321
1322                 for (i = 0; i < WLC_NUM_RATES_CCK; i++)
1323                         txpwr->cck[i] = (u8) maxpwr;
1324         }
1325
1326         /* OFDM txpwr limits for 2.4G or 5G bands */
1327         if (BAND_2G(band->bandtype)) {
1328                 maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
1329
1330         } else {
1331                 maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
1332         }
1333
1334         maxpwr = maxpwr - delta;
1335         maxpwr = max(maxpwr, 0);
1336         maxpwr = min(maxpwr, conducted_ofdm_max);
1337
1338         /* Keep OFDM lmit below CCK limit */
1339         if (BAND_2G(band->bandtype))
1340                 maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
1341
1342         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1343                 txpwr->ofdm[i] = (u8) maxpwr;
1344         }
1345
1346         for (i = 0; i < WLC_NUM_RATES_OFDM; i++) {
1347                 /* OFDM 40 MHz SISO has the same power as the corresponding MCS0-7 rate unless
1348                  * overriden by the locale specific code. We set this value to 0 as a
1349                  * flag (presumably 0 dBm isn't a possibility) and then copy the MCS0-7 value
1350                  * to the 40 MHz value if it wasn't explicitly set.
1351                  */
1352                 txpwr->ofdm_40_siso[i] = 0;
1353
1354                 txpwr->ofdm_cdd[i] = (u8) maxpwr;
1355
1356                 txpwr->ofdm_40_cdd[i] = 0;
1357         }
1358
1359         /* MIMO/HT specific limits */
1360         if (li_mimo->flags & WLC_EIRP) {
1361                 delta = band->antgain;
1362         } else {
1363                 delta = 0;
1364                 if (band->antgain > QDB(6))
1365                         delta = band->antgain - QDB(6); /* Excess over 6 dB */
1366         }
1367
1368         if (BAND_2G(band->bandtype))
1369                 maxpwr_idx = (chan - 1);
1370         else
1371                 maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
1372
1373         maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
1374         maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
1375
1376         maxpwr20 = maxpwr20 - delta;
1377         maxpwr20 = max(maxpwr20, 0);
1378         maxpwr40 = maxpwr40 - delta;
1379         maxpwr40 = max(maxpwr40, 0);
1380
1381         /* Fill in the MCS 0-7 (SISO) rates */
1382         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1383
1384                 /* 20 MHz has the same power as the corresponding OFDM rate unless
1385                  * overriden by the locale specific code.
1386                  */
1387                 txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
1388                 txpwr->mcs_40_siso[i] = 0;
1389         }
1390
1391         /* Fill in the MCS 0-7 CDD rates */
1392         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1393                 txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
1394                 txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
1395         }
1396
1397         /* These locales have SISO expressed in the table and override CDD later */
1398         if (li_mimo == &locale_bn) {
1399                 if (li_mimo == &locale_bn) {
1400                         maxpwr20 = QDB(16);
1401                         maxpwr40 = 0;
1402
1403                         if (chan >= 3 && chan <= 11) {
1404                                 maxpwr40 = QDB(16);
1405                         }
1406                 }
1407
1408                 for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1409                         txpwr->mcs_20_siso[i] = (u8) maxpwr20;
1410                         txpwr->mcs_40_siso[i] = (u8) maxpwr40;
1411                 }
1412         }
1413
1414         /* Fill in the MCS 0-7 STBC rates */
1415         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1416                 txpwr->mcs_20_stbc[i] = 0;
1417                 txpwr->mcs_40_stbc[i] = 0;
1418         }
1419
1420         /* Fill in the MCS 8-15 SDM rates */
1421         for (i = 0; i < WLC_NUM_RATES_MCS_2_STREAM; i++) {
1422                 txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
1423                 txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
1424         }
1425
1426         /* Fill in MCS32 */
1427         txpwr->mcs32 = (u8) maxpwr40;
1428
1429         for (i = 0, j = 0; i < WLC_NUM_RATES_OFDM; i++, j++) {
1430                 if (txpwr->ofdm_40_cdd[i] == 0)
1431                         txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
1432                 if (i == 0) {
1433                         i = i + 1;
1434                         if (txpwr->ofdm_40_cdd[i] == 0)
1435                                 txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
1436                 }
1437         }
1438
1439         /* Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO value if it wasn't
1440          * provided explicitly.
1441          */
1442
1443         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1444                 if (txpwr->mcs_40_siso[i] == 0)
1445                         txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
1446         }
1447
1448         for (i = 0, j = 0; i < WLC_NUM_RATES_OFDM; i++, j++) {
1449                 if (txpwr->ofdm_40_siso[i] == 0)
1450                         txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
1451                 if (i == 0) {
1452                         i = i + 1;
1453                         if (txpwr->ofdm_40_siso[i] == 0)
1454                                 txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
1455                 }
1456         }
1457
1458         /* Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding STBC values if they weren't
1459          * provided explicitly.
1460          */
1461         for (i = 0; i < WLC_NUM_RATES_MCS_1_STREAM; i++) {
1462                 if (txpwr->mcs_20_stbc[i] == 0)
1463                         txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
1464
1465                 if (txpwr->mcs_40_stbc[i] == 0)
1466                         txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
1467         }
1468
1469 #ifdef POWER_DBG
1470         wlc_phy_txpower_limits_dump(txpwr);
1471 #endif
1472         return;
1473 }
1474
1475 /* Returns true if currently set country is Japan or variant */
1476 static bool wlc_japan(struct wlc_info *wlc)
1477 {
1478         return wlc_japan_ccode(wlc->cmi->country_abbrev);
1479 }
1480
1481 /* JP, J1 - J10 are Japan ccodes */
1482 static bool wlc_japan_ccode(const char *ccode)
1483 {
1484         return (ccode[0] == 'J' &&
1485                 (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
1486 }
1487
1488 /*
1489  * Validate the chanspec for this locale, for 40MHZ we need to also check that the sidebands
1490  * are valid 20MZH channels in this locale and they are also a legal HT combination
1491  */
1492 static bool
1493 wlc_valid_chanspec_ext(wlc_cm_info_t *wlc_cm, chanspec_t chspec, bool dualband)
1494 {
1495         struct wlc_info *wlc = wlc_cm->wlc;
1496         u8 channel = CHSPEC_CHANNEL(chspec);
1497
1498         /* check the chanspec */
1499         if (bcm_chspec_malformed(chspec)) {
1500                 wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
1501                         wlc->pub->unit, chspec);
1502                 return false;
1503         }
1504
1505         if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
1506             CHSPEC_WLCBANDUNIT(chspec))
1507                 return false;
1508
1509         /* Check a 20Mhz channel */
1510         if (CHSPEC_IS20(chspec)) {
1511                 if (dualband)
1512                         return VALID_CHANNEL20_DB(wlc_cm->wlc, channel);
1513                 else
1514                         return VALID_CHANNEL20(wlc_cm->wlc, channel);
1515         }
1516 #ifdef SUPPORT_40MHZ
1517         /* We know we are now checking a 40MHZ channel, so we should only be here
1518          * for NPHYS
1519          */
1520         if (WLCISNPHY(wlc->band) || WLCISSSLPNPHY(wlc->band)) {
1521                 u8 upper_sideband = 0, idx;
1522                 u8 num_ch20_entries =
1523                     sizeof(chan20_info) / sizeof(struct chan20_info);
1524
1525                 if (!VALID_40CHANSPEC_IN_BAND(wlc, CHSPEC_WLCBANDUNIT(chspec)))
1526                         return false;
1527
1528                 if (dualband) {
1529                         if (!VALID_CHANNEL20_DB(wlc, LOWER_20_SB(channel)) ||
1530                             !VALID_CHANNEL20_DB(wlc, UPPER_20_SB(channel)))
1531                                 return false;
1532                 } else {
1533                         if (!VALID_CHANNEL20(wlc, LOWER_20_SB(channel)) ||
1534                             !VALID_CHANNEL20(wlc, UPPER_20_SB(channel)))
1535                                 return false;
1536                 }
1537
1538                 /* find the lower sideband info in the sideband array */
1539                 for (idx = 0; idx < num_ch20_entries; idx++) {
1540                         if (chan20_info[idx].sb == LOWER_20_SB(channel))
1541                                 upper_sideband = chan20_info[idx].adj_sbs;
1542                 }
1543                 /* check that the lower sideband allows an upper sideband */
1544                 if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
1545                     (CH_UPPER_SB | CH_EWA_VALID))
1546                         return true;
1547                 return false;
1548         }
1549 #endif                          /* 40 MHZ */
1550
1551         return false;
1552 }
1553
1554 bool wlc_valid_chanspec_db(wlc_cm_info_t *wlc_cm, chanspec_t chspec)
1555 {
1556         return wlc_valid_chanspec_ext(wlc_cm, chspec, true);
1557 }