2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
17 #include <linux/types.h>
18 #include <net/cfg80211.h>
19 #include <net/mac80211.h>
20 #include <net/regulatory.h>
24 #include "phy/phy_hal.h"
28 #include "mac80211_if.h"
30 /* QDB() macro takes a dB value and converts to a quarter dB value */
31 #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
33 #define LOCALE_CHAN_01_11 (1<<0)
34 #define LOCALE_CHAN_12_13 (1<<1)
35 #define LOCALE_CHAN_14 (1<<2)
36 #define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
37 #define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
38 #define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
39 #define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
40 #define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
41 #define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
42 #define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
43 #define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
44 #define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
45 #define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
46 #define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
47 #define LOCALE_CHAN_52_140_ALL (1<<14)
48 #define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
50 #define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
51 LOCALE_SET_5G_LOW2 | \
53 #define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
54 #define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
55 #define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
56 LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
57 #define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
58 #define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
60 #define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
64 #define LOCALE_RESTRICTED_NONE 0
65 #define LOCALE_RESTRICTED_SET_2G_SHORT 1
67 #define LOCALE_2G_IDX_i 0
68 #define LOCALE_5G_IDX_11 0
69 #define LOCALE_MIMO_IDX_bn 0
70 #define LOCALE_MIMO_IDX_11n 0
72 /* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
73 #define BRCMS_MAXPWR_TBL_SIZE 6
74 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
75 #define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
77 /* power level in group of 2.4GHz band channels:
78 * maxpwr[0] - CCK channels [1]
79 * maxpwr[1] - CCK channels [2-10]
80 * maxpwr[2] - CCK channels [11-14]
81 * maxpwr[3] - OFDM channels [1]
82 * maxpwr[4] - OFDM channels [2-10]
83 * maxpwr[5] - OFDM channels [11-14]
86 /* maxpwr mapping to 5GHz band channels:
87 * maxpwr[0] - channels [34-48]
88 * maxpwr[1] - channels [52-60]
89 * maxpwr[2] - channels [62-64]
90 * maxpwr[3] - channels [100-140]
91 * maxpwr[4] - channels [149-165]
93 #define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
95 #define LC(id) LOCALE_MIMO_IDX_ ## id
97 #define LC_2G(id) LOCALE_2G_IDX_ ## id
99 #define LC_5G(id) LOCALE_5G_IDX_ ## id
101 #define LOCALES(band2, band5, mimo2, mimo5) \
102 {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
104 /* macro to get 2.4 GHz channel group index for tx power */
105 #define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
106 #define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
108 /* macro to get 5 GHz channel group index for tx power */
109 #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
112 (((c) < 149) ? 3 : 4))))
114 #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
115 #define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
116 NL80211_RRF_PASSIVE_SCAN | \
119 #define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
120 NL80211_RRF_PASSIVE_SCAN | \
122 #define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
123 NL80211_RRF_PASSIVE_SCAN | \
126 #define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
127 NL80211_RRF_PASSIVE_SCAN | \
130 #define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
131 NL80211_RRF_PASSIVE_SCAN | \
134 static const struct ieee80211_regdomain brcms_regdom_x2
= {
147 struct brcms_cm_band
{
148 /* struct locale_info flags */
150 /* List of valid channels in the country */
151 struct brcms_chanvec valid_channels
;
152 /* List of restricted use channels */
153 const struct brcms_chanvec
*restricted_channels
;
156 /* locale per-channel tx power limits for MIMO frames
157 * maxpwr arrays are index by channel for 2.4 GHz limits, and
158 * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
160 struct locale_mimo_info
{
161 /* tx 20 MHz power limits, qdBm units */
162 s8 maxpwr20
[BRCMS_MAXPWR_MIMO_TBL_SIZE
];
163 /* tx 40 MHz power limits, qdBm units */
164 s8 maxpwr40
[BRCMS_MAXPWR_MIMO_TBL_SIZE
];
168 /* Country names and abbreviations with locale defined from ISO 3166 */
169 struct country_info
{
170 const u8 locale_2G
; /* 2.4G band locale */
171 const u8 locale_5G
; /* 5G band locale */
172 const u8 locale_mimo_2G
; /* 2.4G mimo info */
173 const u8 locale_mimo_5G
; /* 5G mimo info */
177 struct country_info country
;
178 const struct ieee80211_regdomain
*regdomain
;
181 struct brcms_cm_info
{
182 struct brcms_pub
*pub
;
183 struct brcms_c_info
*wlc
;
184 const struct brcms_regd
*world_regd
;
185 /* per-band state (one per phy/radio) */
186 struct brcms_cm_band bandstate
[MAXBANDS
];
187 /* quiet channels currently for radar sensitivity or 11h support */
188 /* channels on which we cannot transmit */
189 struct brcms_chanvec quiet_channels
;
192 /* locale channel and power info. */
195 /* List of channels used only if APs are detected */
196 u8 restricted_channels
;
197 /* Max tx pwr in qdBm for each sub-band */
198 s8 maxpwr
[BRCMS_MAXPWR_TBL_SIZE
];
202 /* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
205 * Some common channel sets
209 static const struct brcms_chanvec chanvec_none
= {
210 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00}
217 * Restricted channel sets
220 /* Channels 12, 13 */
221 static const struct brcms_chanvec restricted_set_2g_short
= {
222 {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x00, 0x00, 0x00}
228 /* global memory to provide working buffer for expanded locale */
230 static const struct brcms_chanvec
*g_table_restricted_chan
[] = {
231 &chanvec_none
, /* restricted_set_none */
232 &restricted_set_2g_short
,
235 static const struct brcms_chanvec locale_2g_01_11
= {
236 {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00}
242 static const struct brcms_chanvec locale_2g_12_13
= {
243 {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00}
249 static const struct brcms_chanvec locale_2g_14
= {
250 {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00}
256 static const struct brcms_chanvec locale_5g_LOW_JP1
= {
257 {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00}
263 static const struct brcms_chanvec locale_5g_LOW_JP2
= {
264 {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00}
270 static const struct brcms_chanvec locale_5g_LOW1
= {
271 {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0x00, 0x00}
277 static const struct brcms_chanvec locale_5g_LOW2
= {
278 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00}
284 static const struct brcms_chanvec locale_5g_LOW3
= {
285 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
286 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00}
291 static const struct brcms_chanvec locale_5g_MID1
= {
292 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00}
298 static const struct brcms_chanvec locale_5g_MID2
= {
299 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00}
305 static const struct brcms_chanvec locale_5g_MID3
= {
306 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00}
312 static const struct brcms_chanvec locale_5g_HIGH1
= {
313 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00}
319 static const struct brcms_chanvec locale_5g_HIGH2
= {
320 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00}
326 static const struct brcms_chanvec locale_5g_HIGH3
= {
327 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00}
333 static const struct brcms_chanvec locale_5g_52_140_ALL
= {
334 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
335 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
336 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00}
340 static const struct brcms_chanvec locale_5g_HIGH4
= {
341 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
344 0x11, 0x11, 0x11, 0x11}
347 static const struct brcms_chanvec
*g_table_locale_base
[] = {
362 &locale_5g_52_140_ALL
,
366 static void brcms_c_locale_add_channels(struct brcms_chanvec
*target
,
367 const struct brcms_chanvec
*channels
)
370 for (i
= 0; i
< sizeof(struct brcms_chanvec
); i
++)
371 target
->vec
[i
] |= channels
->vec
[i
];
374 static void brcms_c_locale_get_channels(const struct locale_info
*locale
,
375 struct brcms_chanvec
*channels
)
379 memset(channels
, 0, sizeof(struct brcms_chanvec
));
381 for (i
= 0; i
< ARRAY_SIZE(g_table_locale_base
); i
++) {
382 if (locale
->valid_channels
& (1 << i
))
383 brcms_c_locale_add_channels(channels
,
384 g_table_locale_base
[i
]);
389 * Locale Definitions - 2.4 GHz
391 static const struct locale_info locale_i
= { /* locale i. channel 1 - 13 */
392 LOCALE_CHAN_01_11
| LOCALE_CHAN_12_13
,
393 LOCALE_RESTRICTED_SET_2G_SHORT
,
394 {QDB(19), QDB(19), QDB(19),
395 QDB(19), QDB(19), QDB(19)},
400 * Locale Definitions - 5 GHz
402 static const struct locale_info locale_11
= {
403 /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
404 LOCALE_CHAN_36_64
| LOCALE_CHAN_100_140
| LOCALE_CHAN_149_165
,
405 LOCALE_RESTRICTED_NONE
,
406 {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
407 BRCMS_EIRP
| BRCMS_DFS_EU
410 static const struct locale_info
*g_locale_2g_table
[] = {
414 static const struct locale_info
*g_locale_5g_table
[] = {
419 * MIMO Locale Definitions - 2.4 GHz
421 static const struct locale_mimo_info locale_bn
= {
422 {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
423 QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
424 QDB(13), QDB(13), QDB(13)},
425 {0, 0, QDB(13), QDB(13), QDB(13),
426 QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
431 static const struct locale_mimo_info
*g_mimo_2g_table
[] = {
436 * MIMO Locale Definitions - 5 GHz
438 static const struct locale_mimo_info locale_11n
= {
439 { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
440 {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
444 static const struct locale_mimo_info
*g_mimo_5g_table
[] = {
448 static const struct brcms_regd cntry_locales
[] = {
449 /* Worldwide RoW 2, must always be at index 0 */
451 .country
= LOCALES(i
, 11, bn
, 11n
),
452 .regdomain
= &brcms_regdom_x2
,
456 static const struct locale_info
*brcms_c_get_locale_2g(u8 locale_idx
)
458 if (locale_idx
>= ARRAY_SIZE(g_locale_2g_table
))
459 return NULL
; /* error condition */
461 return g_locale_2g_table
[locale_idx
];
464 static const struct locale_info
*brcms_c_get_locale_5g(u8 locale_idx
)
466 if (locale_idx
>= ARRAY_SIZE(g_locale_5g_table
))
467 return NULL
; /* error condition */
469 return g_locale_5g_table
[locale_idx
];
472 static const struct locale_mimo_info
*brcms_c_get_mimo_2g(u8 locale_idx
)
474 if (locale_idx
>= ARRAY_SIZE(g_mimo_2g_table
))
477 return g_mimo_2g_table
[locale_idx
];
480 static const struct locale_mimo_info
*brcms_c_get_mimo_5g(u8 locale_idx
)
482 if (locale_idx
>= ARRAY_SIZE(g_mimo_5g_table
))
485 return g_mimo_5g_table
[locale_idx
];
489 * Indicates whether the country provided is valid to pass
490 * to cfg80211 or not.
492 * returns true if valid; false if not.
494 static bool brcms_c_country_valid(const char *ccode
)
497 * only allow ascii alpha uppercase for the first 2
500 if (!((0x80 & ccode
[0]) == 0 && ccode
[0] >= 0x41 && ccode
[0] <= 0x5A &&
501 (0x80 & ccode
[1]) == 0 && ccode
[1] >= 0x41 && ccode
[1] <= 0x5A &&
506 * do not match ISO 3166-1 user assigned country codes
507 * that may be in the driver table
509 if (!strcmp("AA", ccode
) || /* AA */
510 !strcmp("ZZ", ccode
) || /* ZZ */
511 ccode
[0] == 'X' || /* XA - XZ */
512 (ccode
[0] == 'Q' && /* QM - QZ */
513 (ccode
[1] >= 'M' && ccode
[1] <= 'Z')))
516 if (!strcmp("NA", ccode
))
522 static const struct brcms_regd
*brcms_world_regd(const char *regdom
, int len
)
524 const struct brcms_regd
*regd
= NULL
;
527 for (i
= 0; i
< ARRAY_SIZE(cntry_locales
); i
++) {
528 if (!strncmp(regdom
, cntry_locales
[i
].regdomain
->alpha2
, len
)) {
529 regd
= &cntry_locales
[i
];
537 static const struct brcms_regd
*brcms_default_world_regd(void)
539 return &cntry_locales
[0];
543 * reset the quiet channels vector to the union
544 * of the restricted and radar channel sets
546 static void brcms_c_quiet_channels_reset(struct brcms_cm_info
*wlc_cm
)
548 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
550 struct brcms_band
*band
;
551 const struct brcms_chanvec
*chanvec
;
553 memset(&wlc_cm
->quiet_channels
, 0, sizeof(struct brcms_chanvec
));
556 for (i
= 0; i
< wlc
->pub
->_nbands
;
557 i
++, band
= wlc
->bandstate
[OTHERBANDUNIT(wlc
)]) {
559 /* initialize quiet channels for restricted channels */
560 chanvec
= wlc_cm
->bandstate
[band
->bandunit
].restricted_channels
;
561 for (j
= 0; j
< sizeof(struct brcms_chanvec
); j
++)
562 wlc_cm
->quiet_channels
.vec
[j
] |= chanvec
->vec
[j
];
567 /* Is the channel valid for the current locale and current band? */
568 static bool brcms_c_valid_channel20(struct brcms_cm_info
*wlc_cm
, uint val
)
570 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
572 return ((val
< MAXCHANNEL
) &&
573 isset(wlc_cm
->bandstate
[wlc
->band
->bandunit
].valid_channels
.vec
,
577 /* Is the channel valid for the current locale and specified band? */
578 static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info
*wlc_cm
,
579 uint bandunit
, uint val
)
581 return ((val
< MAXCHANNEL
)
582 && isset(wlc_cm
->bandstate
[bandunit
].valid_channels
.vec
, val
));
585 /* Is the channel valid for the current locale? (but don't consider channels not
586 * available due to bandlocking)
588 static bool brcms_c_valid_channel20_db(struct brcms_cm_info
*wlc_cm
, uint val
)
590 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
592 return brcms_c_valid_channel20(wlc
->cmi
, val
) ||
594 && brcms_c_valid_channel20_in_band(wlc
->cmi
,
595 OTHERBANDUNIT(wlc
), val
));
598 /* JP, J1 - J10 are Japan ccodes */
599 static bool brcms_c_japan_ccode(const char *ccode
)
601 return (ccode
[0] == 'J' &&
602 (ccode
[1] == 'P' || (ccode
[1] >= '1' && ccode
[1] <= '9')));
606 brcms_c_channel_min_txpower_limits_with_local_constraint(
607 struct brcms_cm_info
*wlc_cm
, struct txpwr_limits
*txpwr
,
608 u8 local_constraint_qdbm
)
613 for (j
= 0; j
< WL_TX_POWER_CCK_NUM
; j
++)
614 txpwr
->cck
[j
] = min(txpwr
->cck
[j
], local_constraint_qdbm
);
616 /* 20 MHz Legacy OFDM SISO */
617 for (j
= 0; j
< WL_TX_POWER_OFDM_NUM
; j
++)
618 txpwr
->ofdm
[j
] = min(txpwr
->ofdm
[j
], local_constraint_qdbm
);
620 /* 20 MHz Legacy OFDM CDD */
621 for (j
= 0; j
< BRCMS_NUM_RATES_OFDM
; j
++)
623 min(txpwr
->ofdm_cdd
[j
], local_constraint_qdbm
);
625 /* 40 MHz Legacy OFDM SISO */
626 for (j
= 0; j
< BRCMS_NUM_RATES_OFDM
; j
++)
627 txpwr
->ofdm_40_siso
[j
] =
628 min(txpwr
->ofdm_40_siso
[j
], local_constraint_qdbm
);
630 /* 40 MHz Legacy OFDM CDD */
631 for (j
= 0; j
< BRCMS_NUM_RATES_OFDM
; j
++)
632 txpwr
->ofdm_40_cdd
[j
] =
633 min(txpwr
->ofdm_40_cdd
[j
], local_constraint_qdbm
);
635 /* 20MHz MCS 0-7 SISO */
636 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
637 txpwr
->mcs_20_siso
[j
] =
638 min(txpwr
->mcs_20_siso
[j
], local_constraint_qdbm
);
640 /* 20MHz MCS 0-7 CDD */
641 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
642 txpwr
->mcs_20_cdd
[j
] =
643 min(txpwr
->mcs_20_cdd
[j
], local_constraint_qdbm
);
645 /* 20MHz MCS 0-7 STBC */
646 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
647 txpwr
->mcs_20_stbc
[j
] =
648 min(txpwr
->mcs_20_stbc
[j
], local_constraint_qdbm
);
650 /* 20MHz MCS 8-15 MIMO */
651 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_2_STREAM
; j
++)
652 txpwr
->mcs_20_mimo
[j
] =
653 min(txpwr
->mcs_20_mimo
[j
], local_constraint_qdbm
);
655 /* 40MHz MCS 0-7 SISO */
656 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
657 txpwr
->mcs_40_siso
[j
] =
658 min(txpwr
->mcs_40_siso
[j
], local_constraint_qdbm
);
660 /* 40MHz MCS 0-7 CDD */
661 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
662 txpwr
->mcs_40_cdd
[j
] =
663 min(txpwr
->mcs_40_cdd
[j
], local_constraint_qdbm
);
665 /* 40MHz MCS 0-7 STBC */
666 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_1_STREAM
; j
++)
667 txpwr
->mcs_40_stbc
[j
] =
668 min(txpwr
->mcs_40_stbc
[j
], local_constraint_qdbm
);
670 /* 40MHz MCS 8-15 MIMO */
671 for (j
= 0; j
< BRCMS_NUM_RATES_MCS_2_STREAM
; j
++)
672 txpwr
->mcs_40_mimo
[j
] =
673 min(txpwr
->mcs_40_mimo
[j
], local_constraint_qdbm
);
676 txpwr
->mcs32
= min(txpwr
->mcs32
, local_constraint_qdbm
);
680 /* Update the radio state (enable/disable) and tx power targets
681 * based on a new set of channel/regulatory information
683 static void brcms_c_channels_commit(struct brcms_cm_info
*wlc_cm
)
685 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
688 /* search for the existence of any valid channel */
689 for (chan
= 0; chan
< MAXCHANNEL
; chan
++) {
690 if (brcms_c_valid_channel20_db(wlc
->cmi
, chan
))
693 if (chan
== MAXCHANNEL
)
697 * based on the channel search above, set or
698 * clear WL_RADIO_COUNTRY_DISABLE.
700 if (chan
== INVCHANNEL
) {
702 * country/locale with no valid channels, set
703 * the radio disable bit
705 mboolset(wlc
->pub
->radio_disabled
, WL_RADIO_COUNTRY_DISABLE
);
706 wiphy_err(wlc
->wiphy
, "wl%d: %s: no valid channel for \"%s\" "
707 "nbands %d bandlocked %d\n", wlc
->pub
->unit
,
708 __func__
, wlc_cm
->world_regd
->regdomain
->alpha2
,
709 wlc
->pub
->_nbands
, wlc
->bandlocked
);
710 } else if (mboolisset(wlc
->pub
->radio_disabled
,
711 WL_RADIO_COUNTRY_DISABLE
)) {
713 * country/locale with valid channel, clear
714 * the radio disable bit
716 mboolclr(wlc
->pub
->radio_disabled
, WL_RADIO_COUNTRY_DISABLE
);
721 brcms_c_channels_init(struct brcms_cm_info
*wlc_cm
,
722 const struct country_info
*country
)
724 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
726 struct brcms_band
*band
;
727 const struct locale_info
*li
;
728 struct brcms_chanvec sup_chan
;
729 const struct locale_mimo_info
*li_mimo
;
732 for (i
= 0; i
< wlc
->pub
->_nbands
;
733 i
++, band
= wlc
->bandstate
[OTHERBANDUNIT(wlc
)]) {
735 li
= (band
->bandtype
== BRCM_BAND_5G
) ?
736 brcms_c_get_locale_5g(country
->locale_5G
) :
737 brcms_c_get_locale_2g(country
->locale_2G
);
738 wlc_cm
->bandstate
[band
->bandunit
].locale_flags
= li
->flags
;
739 li_mimo
= (band
->bandtype
== BRCM_BAND_5G
) ?
740 brcms_c_get_mimo_5g(country
->locale_mimo_5G
) :
741 brcms_c_get_mimo_2g(country
->locale_mimo_2G
);
743 /* merge the mimo non-mimo locale flags */
744 wlc_cm
->bandstate
[band
->bandunit
].locale_flags
|=
747 wlc_cm
->bandstate
[band
->bandunit
].restricted_channels
=
748 g_table_restricted_chan
[li
->restricted_channels
];
751 * set the channel availability, masking out the channels
752 * that may not be supported on this phy.
754 wlc_phy_chanspec_band_validch(band
->pi
, band
->bandtype
,
756 brcms_c_locale_get_channels(li
,
757 &wlc_cm
->bandstate
[band
->bandunit
].
759 for (j
= 0; j
< sizeof(struct brcms_chanvec
); j
++)
760 wlc_cm
->bandstate
[band
->bandunit
].valid_channels
.
761 vec
[j
] &= sup_chan
.vec
[j
];
764 brcms_c_quiet_channels_reset(wlc_cm
);
765 brcms_c_channels_commit(wlc_cm
);
771 * set the driver's current country and regulatory information
772 * using a country code as the source. Look up built in country
773 * information found with the country code.
776 brcms_c_set_country(struct brcms_cm_info
*wlc_cm
,
777 const struct brcms_regd
*regd
)
779 const struct country_info
*country
= ®d
->country
;
780 const struct locale_info
*locale
;
781 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
783 if ((wlc
->pub
->_n_enab
& SUPPORT_11N
) !=
784 wlc
->protection
->nmode_user
)
785 brcms_c_set_nmode(wlc
);
787 brcms_c_stf_ss_update(wlc
, wlc
->bandstate
[BAND_2G_INDEX
]);
788 brcms_c_stf_ss_update(wlc
, wlc
->bandstate
[BAND_5G_INDEX
]);
789 /* set or restore gmode as required by regulatory */
790 locale
= brcms_c_get_locale_2g(country
->locale_2G
);
791 if (locale
&& (locale
->flags
& BRCMS_NO_OFDM
))
792 brcms_c_set_gmode(wlc
, GMODE_LEGACY_B
, false);
794 brcms_c_set_gmode(wlc
, wlc
->protection
->gmode_user
, false);
796 brcms_c_channels_init(wlc_cm
, country
);
801 struct brcms_cm_info
*brcms_c_channel_mgr_attach(struct brcms_c_info
*wlc
)
803 struct brcms_cm_info
*wlc_cm
;
804 struct brcms_pub
*pub
= wlc
->pub
;
805 struct ssb_sprom
*sprom
= &wlc
->hw
->d11core
->bus
->sprom
;
806 const char *ccode
= sprom
->alpha2
;
807 int ccode_len
= sizeof(sprom
->alpha2
);
809 BCMMSG(wlc
->wiphy
, "wl%d\n", wlc
->pub
->unit
);
811 wlc_cm
= kzalloc(sizeof(struct brcms_cm_info
), GFP_ATOMIC
);
818 /* store the country code for passing up as a regulatory hint */
819 wlc_cm
->world_regd
= brcms_world_regd(ccode
, ccode_len
);
820 if (brcms_c_country_valid(ccode
))
821 strncpy(wlc
->pub
->srom_ccode
, ccode
, ccode_len
);
824 * If no custom world domain is found in the SROM, use the
825 * default "X2" domain.
827 if (!wlc_cm
->world_regd
) {
828 wlc_cm
->world_regd
= brcms_default_world_regd();
829 ccode
= wlc_cm
->world_regd
->regdomain
->alpha2
;
830 ccode_len
= BRCM_CNTRY_BUF_SZ
- 1;
833 /* save default country for exiting 11d regulatory mode */
834 strncpy(wlc
->country_default
, ccode
, ccode_len
);
836 /* initialize autocountry_default to driver default */
837 strncpy(wlc
->autocountry_default
, ccode
, ccode_len
);
839 brcms_c_set_country(wlc_cm
, wlc_cm
->world_regd
);
844 void brcms_c_channel_mgr_detach(struct brcms_cm_info
*wlc_cm
)
850 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info
*wlc_cm
,
853 return wlc_cm
->bandstate
[bandunit
].locale_flags
;
857 brcms_c_quiet_chanspec(struct brcms_cm_info
*wlc_cm
, u16 chspec
)
859 return (wlc_cm
->wlc
->pub
->_n_enab
& SUPPORT_11N
) &&
860 CHSPEC_IS40(chspec
) ?
861 (isset(wlc_cm
->quiet_channels
.vec
,
862 lower_20_sb(CHSPEC_CHANNEL(chspec
))) ||
863 isset(wlc_cm
->quiet_channels
.vec
,
864 upper_20_sb(CHSPEC_CHANNEL(chspec
)))) :
865 isset(wlc_cm
->quiet_channels
.vec
, CHSPEC_CHANNEL(chspec
));
869 brcms_c_channel_set_chanspec(struct brcms_cm_info
*wlc_cm
, u16 chanspec
,
870 u8 local_constraint_qdbm
)
872 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
873 struct txpwr_limits txpwr
;
875 brcms_c_channel_reg_limits(wlc_cm
, chanspec
, &txpwr
);
877 brcms_c_channel_min_txpower_limits_with_local_constraint(
878 wlc_cm
, &txpwr
, local_constraint_qdbm
881 brcms_b_set_chanspec(wlc
->hw
, chanspec
,
882 (brcms_c_quiet_chanspec(wlc_cm
, chanspec
) != 0),
887 brcms_c_channel_reg_limits(struct brcms_cm_info
*wlc_cm
, u16 chanspec
,
888 struct txpwr_limits
*txpwr
)
890 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
895 const struct country_info
*country
;
896 struct brcms_band
*band
;
897 const struct locale_info
*li
;
898 int conducted_max
= BRCMS_TXPWR_MAX
;
899 int conducted_ofdm_max
= BRCMS_TXPWR_MAX
;
900 const struct locale_mimo_info
*li_mimo
;
901 int maxpwr20
, maxpwr40
;
905 memset(txpwr
, 0, sizeof(struct txpwr_limits
));
907 country
= &wlc_cm
->world_regd
->country
;
909 chan
= CHSPEC_CHANNEL(chanspec
);
910 band
= wlc
->bandstate
[chspec_bandunit(chanspec
)];
911 li
= (band
->bandtype
== BRCM_BAND_5G
) ?
912 brcms_c_get_locale_5g(country
->locale_5G
) :
913 brcms_c_get_locale_2g(country
->locale_2G
);
915 li_mimo
= (band
->bandtype
== BRCM_BAND_5G
) ?
916 brcms_c_get_mimo_5g(country
->locale_mimo_5G
) :
917 brcms_c_get_mimo_2g(country
->locale_mimo_2G
);
919 if (li
->flags
& BRCMS_EIRP
) {
920 delta
= band
->antgain
;
923 if (band
->antgain
> QDB(6))
924 delta
= band
->antgain
- QDB(6); /* Excess over 6 dB */
927 if (li
== &locale_i
) {
928 conducted_max
= QDB(22);
929 conducted_ofdm_max
= QDB(22);
932 /* CCK txpwr limits for 2.4G band */
933 if (band
->bandtype
== BRCM_BAND_2G
) {
934 maxpwr
= li
->maxpwr
[CHANNEL_POWER_IDX_2G_CCK(chan
)];
936 maxpwr
= maxpwr
- delta
;
937 maxpwr
= max(maxpwr
, 0);
938 maxpwr
= min(maxpwr
, conducted_max
);
940 for (i
= 0; i
< BRCMS_NUM_RATES_CCK
; i
++)
941 txpwr
->cck
[i
] = (u8
) maxpwr
;
944 /* OFDM txpwr limits for 2.4G or 5G bands */
945 if (band
->bandtype
== BRCM_BAND_2G
)
946 maxpwr
= li
->maxpwr
[CHANNEL_POWER_IDX_2G_OFDM(chan
)];
948 maxpwr
= li
->maxpwr
[CHANNEL_POWER_IDX_5G(chan
)];
950 maxpwr
= maxpwr
- delta
;
951 maxpwr
= max(maxpwr
, 0);
952 maxpwr
= min(maxpwr
, conducted_ofdm_max
);
954 /* Keep OFDM lmit below CCK limit */
955 if (band
->bandtype
== BRCM_BAND_2G
)
956 maxpwr
= min_t(int, maxpwr
, txpwr
->cck
[0]);
958 for (i
= 0; i
< BRCMS_NUM_RATES_OFDM
; i
++)
959 txpwr
->ofdm
[i
] = (u8
) maxpwr
;
961 for (i
= 0; i
< BRCMS_NUM_RATES_OFDM
; i
++) {
963 * OFDM 40 MHz SISO has the same power as the corresponding
964 * MCS0-7 rate unless overriden by the locale specific code.
965 * We set this value to 0 as a flag (presumably 0 dBm isn't
966 * a possibility) and then copy the MCS0-7 value to the 40 MHz
967 * value if it wasn't explicitly set.
969 txpwr
->ofdm_40_siso
[i
] = 0;
971 txpwr
->ofdm_cdd
[i
] = (u8
) maxpwr
;
973 txpwr
->ofdm_40_cdd
[i
] = 0;
976 /* MIMO/HT specific limits */
977 if (li_mimo
->flags
& BRCMS_EIRP
) {
978 delta
= band
->antgain
;
981 if (band
->antgain
> QDB(6))
982 delta
= band
->antgain
- QDB(6); /* Excess over 6 dB */
985 if (band
->bandtype
== BRCM_BAND_2G
)
986 maxpwr_idx
= (chan
- 1);
988 maxpwr_idx
= CHANNEL_POWER_IDX_5G(chan
);
990 maxpwr20
= li_mimo
->maxpwr20
[maxpwr_idx
];
991 maxpwr40
= li_mimo
->maxpwr40
[maxpwr_idx
];
993 maxpwr20
= maxpwr20
- delta
;
994 maxpwr20
= max(maxpwr20
, 0);
995 maxpwr40
= maxpwr40
- delta
;
996 maxpwr40
= max(maxpwr40
, 0);
998 /* Fill in the MCS 0-7 (SISO) rates */
999 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1002 * 20 MHz has the same power as the corresponding OFDM rate
1003 * unless overriden by the locale specific code.
1005 txpwr
->mcs_20_siso
[i
] = txpwr
->ofdm
[i
];
1006 txpwr
->mcs_40_siso
[i
] = 0;
1009 /* Fill in the MCS 0-7 CDD rates */
1010 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1011 txpwr
->mcs_20_cdd
[i
] = (u8
) maxpwr20
;
1012 txpwr
->mcs_40_cdd
[i
] = (u8
) maxpwr40
;
1016 * These locales have SISO expressed in the
1017 * table and override CDD later
1019 if (li_mimo
== &locale_bn
) {
1020 if (li_mimo
== &locale_bn
) {
1024 if (chan
>= 3 && chan
<= 11)
1028 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1029 txpwr
->mcs_20_siso
[i
] = (u8
) maxpwr20
;
1030 txpwr
->mcs_40_siso
[i
] = (u8
) maxpwr40
;
1034 /* Fill in the MCS 0-7 STBC rates */
1035 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1036 txpwr
->mcs_20_stbc
[i
] = 0;
1037 txpwr
->mcs_40_stbc
[i
] = 0;
1040 /* Fill in the MCS 8-15 SDM rates */
1041 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_2_STREAM
; i
++) {
1042 txpwr
->mcs_20_mimo
[i
] = (u8
) maxpwr20
;
1043 txpwr
->mcs_40_mimo
[i
] = (u8
) maxpwr40
;
1047 txpwr
->mcs32
= (u8
) maxpwr40
;
1049 for (i
= 0, j
= 0; i
< BRCMS_NUM_RATES_OFDM
; i
++, j
++) {
1050 if (txpwr
->ofdm_40_cdd
[i
] == 0)
1051 txpwr
->ofdm_40_cdd
[i
] = txpwr
->mcs_40_cdd
[j
];
1054 if (txpwr
->ofdm_40_cdd
[i
] == 0)
1055 txpwr
->ofdm_40_cdd
[i
] = txpwr
->mcs_40_cdd
[j
];
1060 * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
1061 * value if it wasn't provided explicitly.
1063 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1064 if (txpwr
->mcs_40_siso
[i
] == 0)
1065 txpwr
->mcs_40_siso
[i
] = txpwr
->mcs_40_cdd
[i
];
1068 for (i
= 0, j
= 0; i
< BRCMS_NUM_RATES_OFDM
; i
++, j
++) {
1069 if (txpwr
->ofdm_40_siso
[i
] == 0)
1070 txpwr
->ofdm_40_siso
[i
] = txpwr
->mcs_40_siso
[j
];
1073 if (txpwr
->ofdm_40_siso
[i
] == 0)
1074 txpwr
->ofdm_40_siso
[i
] = txpwr
->mcs_40_siso
[j
];
1079 * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
1080 * STBC values if they weren't provided explicitly.
1082 for (i
= 0; i
< BRCMS_NUM_RATES_MCS_1_STREAM
; i
++) {
1083 if (txpwr
->mcs_20_stbc
[i
] == 0)
1084 txpwr
->mcs_20_stbc
[i
] = txpwr
->mcs_20_cdd
[i
];
1086 if (txpwr
->mcs_40_stbc
[i
] == 0)
1087 txpwr
->mcs_40_stbc
[i
] = txpwr
->mcs_40_cdd
[i
];
1094 * Verify the chanspec is using a legal set of parameters, i.e. that the
1095 * chanspec specified a band, bw, ctl_sb and channel and that the
1096 * combination could be legal given any set of circumstances.
1097 * RETURNS: true is the chanspec is malformed, false if it looks good.
1099 static bool brcms_c_chspec_malformed(u16 chanspec
)
1101 /* must be 2G or 5G band */
1102 if (!CHSPEC_IS5G(chanspec
) && !CHSPEC_IS2G(chanspec
))
1104 /* must be 20 or 40 bandwidth */
1105 if (!CHSPEC_IS40(chanspec
) && !CHSPEC_IS20(chanspec
))
1108 /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
1109 if (CHSPEC_IS20(chanspec
)) {
1110 if (!CHSPEC_SB_NONE(chanspec
))
1112 } else if (!CHSPEC_SB_UPPER(chanspec
) && !CHSPEC_SB_LOWER(chanspec
)) {
1120 * Validate the chanspec for this locale, for 40MHZ we need to also
1121 * check that the sidebands are valid 20MZH channels in this locale
1122 * and they are also a legal HT combination
1125 brcms_c_valid_chanspec_ext(struct brcms_cm_info
*wlc_cm
, u16 chspec
,
1128 struct brcms_c_info
*wlc
= wlc_cm
->wlc
;
1129 u8 channel
= CHSPEC_CHANNEL(chspec
);
1131 /* check the chanspec */
1132 if (brcms_c_chspec_malformed(chspec
)) {
1133 wiphy_err(wlc
->wiphy
, "wl%d: malformed chanspec 0x%x\n",
1134 wlc
->pub
->unit
, chspec
);
1138 if (CHANNEL_BANDUNIT(wlc_cm
->wlc
, channel
) !=
1139 chspec_bandunit(chspec
))
1142 /* Check a 20Mhz channel */
1143 if (CHSPEC_IS20(chspec
)) {
1145 return brcms_c_valid_channel20_db(wlc_cm
->wlc
->cmi
,
1148 return brcms_c_valid_channel20(wlc_cm
->wlc
->cmi
,
1155 bool brcms_c_valid_chanspec_db(struct brcms_cm_info
*wlc_cm
, u16 chspec
)
1157 return brcms_c_valid_chanspec_ext(wlc_cm
, chspec
, true);
1160 static bool brcms_is_radar_freq(u16 center_freq
)
1162 return center_freq
>= 5260 && center_freq
<= 5700;
1165 static void brcms_reg_apply_radar_flags(struct wiphy
*wiphy
)
1167 struct ieee80211_supported_band
*sband
;
1168 struct ieee80211_channel
*ch
;
1171 sband
= wiphy
->bands
[IEEE80211_BAND_5GHZ
];
1175 for (i
= 0; i
< sband
->n_channels
; i
++) {
1176 ch
= &sband
->channels
[i
];
1178 if (!brcms_is_radar_freq(ch
->center_freq
))
1182 * All channels in this range should be passive and have
1185 if (!(ch
->flags
& IEEE80211_CHAN_DISABLED
))
1186 ch
->flags
|= IEEE80211_CHAN_RADAR
|
1187 IEEE80211_CHAN_NO_IBSS
|
1188 IEEE80211_CHAN_PASSIVE_SCAN
;
1193 brcms_reg_apply_beaconing_flags(struct wiphy
*wiphy
,
1194 enum nl80211_reg_initiator initiator
)
1196 struct ieee80211_supported_band
*sband
;
1197 struct ieee80211_channel
*ch
;
1198 const struct ieee80211_reg_rule
*rule
;
1201 for (band
= 0; band
< IEEE80211_NUM_BANDS
; band
++) {
1202 sband
= wiphy
->bands
[band
];
1206 for (i
= 0; i
< sband
->n_channels
; i
++) {
1207 ch
= &sband
->channels
[i
];
1210 (IEEE80211_CHAN_DISABLED
| IEEE80211_CHAN_RADAR
))
1213 if (initiator
== NL80211_REGDOM_SET_BY_COUNTRY_IE
) {
1214 ret
= freq_reg_info(wiphy
, ch
->center_freq
,
1219 if (!(rule
->flags
& NL80211_RRF_NO_IBSS
))
1220 ch
->flags
&= ~IEEE80211_CHAN_NO_IBSS
;
1221 if (!(rule
->flags
& NL80211_RRF_PASSIVE_SCAN
))
1223 ~IEEE80211_CHAN_PASSIVE_SCAN
;
1224 } else if (ch
->beacon_found
) {
1225 ch
->flags
&= ~(IEEE80211_CHAN_NO_IBSS
|
1226 IEEE80211_CHAN_PASSIVE_SCAN
);
1232 static int brcms_reg_notifier(struct wiphy
*wiphy
,
1233 struct regulatory_request
*request
)
1235 struct ieee80211_hw
*hw
= wiphy_to_ieee80211_hw(wiphy
);
1236 struct brcms_info
*wl
= hw
->priv
;
1237 struct brcms_c_info
*wlc
= wl
->wlc
;
1239 brcms_reg_apply_radar_flags(wiphy
);
1241 if (request
->initiator
== NL80211_REGDOM_SET_BY_COUNTRY_IE
)
1242 brcms_reg_apply_beaconing_flags(wiphy
, request
->initiator
);
1244 if (wlc
->pub
->_nbands
> 1 || wlc
->band
->bandtype
== BRCM_BAND_2G
)
1245 wlc_phy_chanspec_ch14_widefilter_set(wlc
->band
->pi
,
1246 brcms_c_japan_ccode(request
->alpha2
));
1251 void brcms_c_regd_init(struct brcms_c_info
*wlc
)
1253 struct wiphy
*wiphy
= wlc
->wiphy
;
1254 const struct brcms_regd
*regd
= wlc
->cmi
->world_regd
;
1255 struct ieee80211_supported_band
*sband
;
1256 struct ieee80211_channel
*ch
;
1257 struct brcms_chanvec sup_chan
;
1258 struct brcms_band
*band
;
1261 /* Disable any channels not supported by the phy */
1262 for (band_idx
= 0; band_idx
< IEEE80211_NUM_BANDS
; band_idx
++) {
1263 if (band_idx
== IEEE80211_BAND_2GHZ
)
1264 band
= wlc
->bandstate
[BAND_2G_INDEX
];
1266 band
= wlc
->bandstate
[BAND_5G_INDEX
];
1267 wlc_phy_chanspec_band_validch(band
->pi
, band
->bandtype
,
1270 sband
= wiphy
->bands
[band_idx
];
1271 for (i
= 0; i
< sband
->n_channels
; i
++) {
1272 ch
= &sband
->channels
[i
];
1273 if (!isset(sup_chan
.vec
, ch
->hw_value
))
1274 ch
->flags
|= IEEE80211_CHAN_DISABLED
;
1278 wlc
->wiphy
->reg_notifier
= brcms_reg_notifier
;
1279 wlc
->wiphy
->flags
|= WIPHY_FLAG_CUSTOM_REGULATORY
|
1280 WIPHY_FLAG_STRICT_REGULATORY
;
1281 wiphy_apply_custom_regulatory(wlc
->wiphy
, regd
->regdomain
);
1282 brcms_reg_apply_beaconing_flags(wiphy
, NL80211_REGDOM_SET_BY_DRIVER
);