Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/channel.c
178665 views
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/types.h>
18
#include <net/cfg80211.h>
19
#include <net/mac80211.h>
20
#include <net/regulatory.h>
21
22
#include <defs.h>
23
#include "pub.h"
24
#include "phy/phy_hal.h"
25
#include "main.h"
26
#include "stf.h"
27
#include "channel.h"
28
#include "mac80211_if.h"
29
#include "debug.h"
30
31
/* QDB() macro takes a dB value and converts to a quarter dB value */
32
#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
33
34
#define LOCALE_MIMO_IDX_bn 0
35
#define LOCALE_MIMO_IDX_11n 0
36
37
/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
38
#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
39
40
/* maxpwr mapping to 5GHz band channels:
41
* maxpwr[0] - channels [34-48]
42
* maxpwr[1] - channels [52-60]
43
* maxpwr[2] - channels [62-64]
44
* maxpwr[3] - channels [100-140]
45
* maxpwr[4] - channels [149-165]
46
*/
47
#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
48
49
#define LC(id) LOCALE_MIMO_IDX_ ## id
50
51
#define LOCALES(mimo2, mimo5) \
52
{LC(mimo2), LC(mimo5)}
53
54
/* macro to get 5 GHz channel group index for tx power */
55
#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
56
(((c) < 62) ? 1 : \
57
(((c) < 100) ? 2 : \
58
(((c) < 149) ? 3 : 4))))
59
60
#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
61
#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
62
NL80211_RRF_NO_IR)
63
64
#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
65
NL80211_RRF_NO_IR)
66
#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
67
NL80211_RRF_DFS | \
68
NL80211_RRF_NO_IR)
69
#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
70
NL80211_RRF_DFS | \
71
NL80211_RRF_NO_IR)
72
#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
73
NL80211_RRF_NO_IR)
74
75
static const struct ieee80211_regdomain brcms_regdom_x2 = {
76
.n_reg_rules = 6,
77
.alpha2 = "X2",
78
.reg_rules = {
79
BRCM_2GHZ_2412_2462,
80
BRCM_2GHZ_2467_2472,
81
BRCM_5GHZ_5180_5240,
82
BRCM_5GHZ_5260_5320,
83
BRCM_5GHZ_5500_5700,
84
BRCM_5GHZ_5745_5825,
85
}
86
};
87
88
/* locale per-channel tx power limits for MIMO frames
89
* maxpwr arrays are index by channel for 2.4 GHz limits, and
90
* by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
91
*/
92
struct locale_mimo_info {
93
/* tx 20 MHz power limits, qdBm units */
94
s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
95
/* tx 40 MHz power limits, qdBm units */
96
s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
97
};
98
99
/* Country names and abbreviations with locale defined from ISO 3166 */
100
struct country_info {
101
const u8 locale_mimo_2G; /* 2.4G mimo info */
102
const u8 locale_mimo_5G; /* 5G mimo info */
103
};
104
105
struct brcms_regd {
106
struct country_info country;
107
const struct ieee80211_regdomain *regdomain;
108
};
109
110
struct brcms_cm_info {
111
struct brcms_pub *pub;
112
struct brcms_c_info *wlc;
113
const struct brcms_regd *world_regd;
114
};
115
116
/*
117
* MIMO Locale Definitions - 2.4 GHz
118
*/
119
static const struct locale_mimo_info locale_bn = {
120
{QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
121
QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
122
QDB(13), QDB(13), QDB(13)},
123
{0, 0, QDB(13), QDB(13), QDB(13),
124
QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
125
QDB(13), 0, 0},
126
};
127
128
static const struct locale_mimo_info *g_mimo_2g_table[] = {
129
&locale_bn
130
};
131
132
/*
133
* MIMO Locale Definitions - 5 GHz
134
*/
135
static const struct locale_mimo_info locale_11n = {
136
{ /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
137
{QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
138
};
139
140
static const struct locale_mimo_info *g_mimo_5g_table[] = {
141
&locale_11n
142
};
143
144
static const struct brcms_regd cntry_locales[] = {
145
/* Worldwide RoW 2, must always be at index 0 */
146
{
147
.country = LOCALES(bn, 11n),
148
.regdomain = &brcms_regdom_x2,
149
},
150
};
151
152
static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
153
{
154
if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
155
return NULL;
156
157
return g_mimo_2g_table[locale_idx];
158
}
159
160
static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
161
{
162
if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))
163
return NULL;
164
165
return g_mimo_5g_table[locale_idx];
166
}
167
168
/*
169
* Indicates whether the country provided is valid to pass
170
* to cfg80211 or not.
171
*
172
* returns true if valid; false if not.
173
*/
174
static bool brcms_c_country_valid(const char *ccode)
175
{
176
/*
177
* only allow ascii alpha uppercase for the first 2
178
* chars.
179
*/
180
if (!((ccode[0] & 0x80) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
181
(ccode[1] & 0x80) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))
182
return false;
183
184
/*
185
* do not match ISO 3166-1 user assigned country codes
186
* that may be in the driver table
187
*/
188
if (!strcmp("AA", ccode) || /* AA */
189
!strcmp("ZZ", ccode) || /* ZZ */
190
ccode[0] == 'X' || /* XA - XZ */
191
(ccode[0] == 'Q' && /* QM - QZ */
192
(ccode[1] >= 'M' && ccode[1] <= 'Z')))
193
return false;
194
195
if (!strcmp("NA", ccode))
196
return false;
197
198
return true;
199
}
200
201
static const struct brcms_regd *brcms_world_regd(const char *regdom, int len)
202
{
203
const struct brcms_regd *regd = NULL;
204
int i;
205
206
for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
207
if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) {
208
regd = &cntry_locales[i];
209
break;
210
}
211
}
212
213
return regd;
214
}
215
216
static const struct brcms_regd *brcms_default_world_regd(void)
217
{
218
return &cntry_locales[0];
219
}
220
221
/* JP, J1 - J10 are Japan ccodes */
222
static bool brcms_c_japan_ccode(const char *ccode)
223
{
224
return (ccode[0] == 'J' &&
225
(ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
226
}
227
228
static void
229
brcms_c_channel_min_txpower_limits_with_local_constraint(
230
struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
231
u8 local_constraint_qdbm)
232
{
233
int j;
234
235
/* CCK Rates */
236
for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)
237
txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
238
239
/* 20 MHz Legacy OFDM SISO */
240
for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)
241
txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
242
243
/* 20 MHz Legacy OFDM CDD */
244
for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
245
txpwr->ofdm_cdd[j] =
246
min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
247
248
/* 40 MHz Legacy OFDM SISO */
249
for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
250
txpwr->ofdm_40_siso[j] =
251
min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
252
253
/* 40 MHz Legacy OFDM CDD */
254
for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
255
txpwr->ofdm_40_cdd[j] =
256
min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
257
258
/* 20MHz MCS 0-7 SISO */
259
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
260
txpwr->mcs_20_siso[j] =
261
min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
262
263
/* 20MHz MCS 0-7 CDD */
264
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
265
txpwr->mcs_20_cdd[j] =
266
min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
267
268
/* 20MHz MCS 0-7 STBC */
269
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
270
txpwr->mcs_20_stbc[j] =
271
min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
272
273
/* 20MHz MCS 8-15 MIMO */
274
for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
275
txpwr->mcs_20_mimo[j] =
276
min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
277
278
/* 40MHz MCS 0-7 SISO */
279
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
280
txpwr->mcs_40_siso[j] =
281
min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
282
283
/* 40MHz MCS 0-7 CDD */
284
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
285
txpwr->mcs_40_cdd[j] =
286
min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
287
288
/* 40MHz MCS 0-7 STBC */
289
for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
290
txpwr->mcs_40_stbc[j] =
291
min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
292
293
/* 40MHz MCS 8-15 MIMO */
294
for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
295
txpwr->mcs_40_mimo[j] =
296
min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
297
298
/* 40MHz MCS 32 */
299
txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
300
301
}
302
303
/*
304
* set the driver's current country and regulatory information
305
* using a country code as the source. Look up built in country
306
* information found with the country code.
307
*/
308
static void
309
brcms_c_set_country(struct brcms_cm_info *wlc_cm,
310
const struct brcms_regd *regd)
311
{
312
struct brcms_c_info *wlc = wlc_cm->wlc;
313
314
if ((wlc->pub->_n_enab & SUPPORT_11N) !=
315
wlc->protection->nmode_user)
316
brcms_c_set_nmode(wlc);
317
318
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
319
brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
320
321
brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
322
323
return;
324
}
325
326
struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
327
{
328
struct brcms_cm_info *wlc_cm;
329
struct brcms_pub *pub = wlc->pub;
330
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
331
const char *ccode = sprom->alpha2;
332
int ccode_len = sizeof(sprom->alpha2);
333
334
wlc_cm = kzalloc(sizeof(*wlc_cm), GFP_ATOMIC);
335
if (wlc_cm == NULL)
336
return NULL;
337
wlc_cm->pub = pub;
338
wlc_cm->wlc = wlc;
339
wlc->cmi = wlc_cm;
340
341
/* store the country code for passing up as a regulatory hint */
342
wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);
343
if (brcms_c_country_valid(ccode))
344
memcpy(wlc->pub->srom_ccode, ccode, ccode_len);
345
346
/*
347
* If no custom world domain is found in the SROM, use the
348
* default "X2" domain.
349
*/
350
if (!wlc_cm->world_regd) {
351
wlc_cm->world_regd = brcms_default_world_regd();
352
ccode = wlc_cm->world_regd->regdomain->alpha2;
353
ccode_len = BRCM_CNTRY_BUF_SZ - 1;
354
}
355
356
/* save default country for exiting 11d regulatory mode */
357
memcpy(wlc->country_default, ccode, ccode_len);
358
359
/* initialize autocountry_default to driver default */
360
memcpy(wlc->autocountry_default, ccode, ccode_len);
361
362
brcms_c_set_country(wlc_cm, wlc_cm->world_regd);
363
364
return wlc_cm;
365
}
366
367
void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
368
{
369
kfree(wlc_cm);
370
}
371
372
void
373
brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
374
u8 local_constraint_qdbm)
375
{
376
struct brcms_c_info *wlc = wlc_cm->wlc;
377
struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
378
struct txpwr_limits txpwr;
379
380
brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
381
382
brcms_c_channel_min_txpower_limits_with_local_constraint(
383
wlc_cm, &txpwr, local_constraint_qdbm
384
);
385
386
/* set or restore gmode as required by regulatory */
387
if (ch->flags & IEEE80211_CHAN_NO_OFDM)
388
brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
389
else
390
brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
391
392
brcms_b_set_chanspec(wlc->hw, chanspec,
393
!!(ch->flags & IEEE80211_CHAN_NO_IR),
394
&txpwr);
395
}
396
397
void
398
brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
399
struct txpwr_limits *txpwr)
400
{
401
struct brcms_c_info *wlc = wlc_cm->wlc;
402
struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
403
uint i;
404
uint chan;
405
int maxpwr;
406
int delta;
407
const struct country_info *country;
408
struct brcms_band *band;
409
int conducted_max = BRCMS_TXPWR_MAX;
410
const struct locale_mimo_info *li_mimo;
411
int maxpwr20, maxpwr40;
412
int maxpwr_idx;
413
uint j;
414
415
memset(txpwr, 0, sizeof(struct txpwr_limits));
416
417
if (WARN_ON(!ch))
418
return;
419
420
country = &wlc_cm->world_regd->country;
421
422
chan = CHSPEC_CHANNEL(chanspec);
423
band = wlc->bandstate[chspec_bandunit(chanspec)];
424
li_mimo = (band->bandtype == BRCM_BAND_5G) ?
425
brcms_c_get_mimo_5g(country->locale_mimo_5G) :
426
brcms_c_get_mimo_2g(country->locale_mimo_2G);
427
428
delta = band->antgain;
429
430
if (band->bandtype == BRCM_BAND_2G)
431
conducted_max = QDB(22);
432
433
maxpwr = QDB(ch->max_power) - delta;
434
maxpwr = max(maxpwr, 0);
435
maxpwr = min(maxpwr, conducted_max);
436
437
/* CCK txpwr limits for 2.4G band */
438
if (band->bandtype == BRCM_BAND_2G) {
439
for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
440
txpwr->cck[i] = (u8) maxpwr;
441
}
442
443
for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
444
txpwr->ofdm[i] = (u8) maxpwr;
445
446
/*
447
* OFDM 40 MHz SISO has the same power as the corresponding
448
* MCS0-7 rate unless overridden by the locale specific code.
449
* We set this value to 0 as a flag (presumably 0 dBm isn't
450
* a possibility) and then copy the MCS0-7 value to the 40 MHz
451
* value if it wasn't explicitly set.
452
*/
453
txpwr->ofdm_40_siso[i] = 0;
454
455
txpwr->ofdm_cdd[i] = (u8) maxpwr;
456
457
txpwr->ofdm_40_cdd[i] = 0;
458
}
459
460
delta = 0;
461
if (band->antgain > QDB(6))
462
delta = band->antgain - QDB(6); /* Excess over 6 dB */
463
464
if (band->bandtype == BRCM_BAND_2G)
465
maxpwr_idx = (chan - 1);
466
else
467
maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
468
469
maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
470
maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
471
472
maxpwr20 = maxpwr20 - delta;
473
maxpwr20 = max(maxpwr20, 0);
474
maxpwr40 = maxpwr40 - delta;
475
maxpwr40 = max(maxpwr40, 0);
476
477
/* Fill in the MCS 0-7 (SISO) rates */
478
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
479
480
/*
481
* 20 MHz has the same power as the corresponding OFDM rate
482
* unless overridden by the locale specific code.
483
*/
484
txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
485
txpwr->mcs_40_siso[i] = 0;
486
}
487
488
/* Fill in the MCS 0-7 CDD rates */
489
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
490
txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
491
txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
492
}
493
494
/*
495
* These locales have SISO expressed in the
496
* table and override CDD later
497
*/
498
if (li_mimo == &locale_bn) {
499
maxpwr20 = QDB(16);
500
maxpwr40 = 0;
501
502
if (chan >= 3 && chan <= 11)
503
maxpwr40 = QDB(16);
504
505
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
506
txpwr->mcs_20_siso[i] = (u8) maxpwr20;
507
txpwr->mcs_40_siso[i] = (u8) maxpwr40;
508
}
509
}
510
511
/* Fill in the MCS 0-7 STBC rates */
512
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
513
txpwr->mcs_20_stbc[i] = 0;
514
txpwr->mcs_40_stbc[i] = 0;
515
}
516
517
/* Fill in the MCS 8-15 SDM rates */
518
for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
519
txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
520
txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
521
}
522
523
/* Fill in MCS32 */
524
txpwr->mcs32 = (u8) maxpwr40;
525
526
for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
527
if (txpwr->ofdm_40_cdd[i] == 0)
528
txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
529
if (i == 0) {
530
i = i + 1;
531
if (txpwr->ofdm_40_cdd[i] == 0)
532
txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
533
}
534
}
535
536
/*
537
* Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
538
* value if it wasn't provided explicitly.
539
*/
540
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
541
if (txpwr->mcs_40_siso[i] == 0)
542
txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
543
}
544
545
for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
546
if (txpwr->ofdm_40_siso[i] == 0)
547
txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
548
if (i == 0) {
549
i = i + 1;
550
if (txpwr->ofdm_40_siso[i] == 0)
551
txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
552
}
553
}
554
555
/*
556
* Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
557
* STBC values if they weren't provided explicitly.
558
*/
559
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
560
if (txpwr->mcs_20_stbc[i] == 0)
561
txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
562
563
if (txpwr->mcs_40_stbc[i] == 0)
564
txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
565
}
566
567
return;
568
}
569
570
/*
571
* Verify the chanspec is using a legal set of parameters, i.e. that the
572
* chanspec specified a band, bw, ctl_sb and channel and that the
573
* combination could be legal given any set of circumstances.
574
* RETURNS: true is the chanspec is malformed, false if it looks good.
575
*/
576
static bool brcms_c_chspec_malformed(u16 chanspec)
577
{
578
/* must be 2G or 5G band */
579
if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
580
return true;
581
/* must be 20 or 40 bandwidth */
582
if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
583
return true;
584
585
/* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
586
if (CHSPEC_IS20(chanspec)) {
587
if (!CHSPEC_SB_NONE(chanspec))
588
return true;
589
} else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {
590
return true;
591
}
592
593
return false;
594
}
595
596
/*
597
* Validate the chanspec for this locale, for 40MHZ we need to also
598
* check that the sidebands are valid 20MZH channels in this locale
599
* and they are also a legal HT combination
600
*/
601
static bool
602
brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
603
{
604
struct brcms_c_info *wlc = wlc_cm->wlc;
605
u8 channel = CHSPEC_CHANNEL(chspec);
606
607
/* check the chanspec */
608
if (brcms_c_chspec_malformed(chspec)) {
609
brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n",
610
wlc->pub->unit, chspec);
611
return false;
612
}
613
614
if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
615
chspec_bandunit(chspec))
616
return false;
617
618
return true;
619
}
620
621
bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
622
{
623
return brcms_c_valid_chanspec_ext(wlc_cm, chspec);
624
}
625
626
static bool brcms_is_radar_freq(u16 center_freq)
627
{
628
return center_freq >= 5260 && center_freq <= 5700;
629
}
630
631
static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
632
{
633
struct ieee80211_supported_band *sband;
634
struct ieee80211_channel *ch;
635
int i;
636
637
sband = wiphy->bands[NL80211_BAND_5GHZ];
638
if (!sband)
639
return;
640
641
for (i = 0; i < sband->n_channels; i++) {
642
ch = &sband->channels[i];
643
644
if (!brcms_is_radar_freq(ch->center_freq))
645
continue;
646
647
/*
648
* All channels in this range should be passive and have
649
* DFS enabled.
650
*/
651
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
652
ch->flags |= IEEE80211_CHAN_RADAR |
653
IEEE80211_CHAN_NO_IR;
654
}
655
}
656
657
static void
658
brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
659
enum nl80211_reg_initiator initiator)
660
{
661
struct ieee80211_supported_band *sband;
662
struct ieee80211_channel *ch;
663
const struct ieee80211_reg_rule *rule;
664
int band, i;
665
666
for (band = 0; band < NUM_NL80211_BANDS; band++) {
667
sband = wiphy->bands[band];
668
if (!sband)
669
continue;
670
671
for (i = 0; i < sband->n_channels; i++) {
672
ch = &sband->channels[i];
673
674
if (ch->flags &
675
(IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))
676
continue;
677
678
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
679
rule = freq_reg_info(wiphy,
680
MHZ_TO_KHZ(ch->center_freq));
681
if (IS_ERR(rule))
682
continue;
683
684
if (!(rule->flags & NL80211_RRF_NO_IR))
685
ch->flags &= ~IEEE80211_CHAN_NO_IR;
686
} else if (ch->beacon_found) {
687
ch->flags &= ~IEEE80211_CHAN_NO_IR;
688
}
689
}
690
}
691
}
692
693
static void brcms_reg_notifier(struct wiphy *wiphy,
694
struct regulatory_request *request)
695
{
696
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
697
struct brcms_info *wl = hw->priv;
698
struct brcms_c_info *wlc = wl->wlc;
699
struct ieee80211_supported_band *sband;
700
struct ieee80211_channel *ch;
701
int band, i;
702
bool ch_found = false;
703
704
brcms_reg_apply_radar_flags(wiphy);
705
706
if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
707
brcms_reg_apply_beaconing_flags(wiphy, request->initiator);
708
709
/* Disable radio if all channels disallowed by regulatory */
710
for (band = 0; !ch_found && band < NUM_NL80211_BANDS; band++) {
711
sband = wiphy->bands[band];
712
if (!sband)
713
continue;
714
715
for (i = 0; !ch_found && i < sband->n_channels; i++) {
716
ch = &sband->channels[i];
717
718
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
719
ch_found = true;
720
}
721
}
722
723
if (ch_found) {
724
mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
725
} else {
726
mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
727
brcms_err(wlc->hw->d11core,
728
"wl%d: %s: no valid channel for \"%s\"\n",
729
wlc->pub->unit, __func__, request->alpha2);
730
}
731
732
if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
733
wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
734
brcms_c_japan_ccode(request->alpha2));
735
}
736
737
void brcms_c_regd_init(struct brcms_c_info *wlc)
738
{
739
struct wiphy *wiphy = wlc->wiphy;
740
const struct brcms_regd *regd = wlc->cmi->world_regd;
741
struct ieee80211_supported_band *sband;
742
struct ieee80211_channel *ch;
743
struct brcms_chanvec sup_chan;
744
struct brcms_band *band;
745
int band_idx, i;
746
747
/* Disable any channels not supported by the phy */
748
for (band_idx = 0; band_idx < wlc->pub->_nbands; band_idx++) {
749
band = wlc->bandstate[band_idx];
750
751
wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
752
&sup_chan);
753
754
if (band_idx == BAND_2G_INDEX)
755
sband = wiphy->bands[NL80211_BAND_2GHZ];
756
else
757
sband = wiphy->bands[NL80211_BAND_5GHZ];
758
759
for (i = 0; i < sband->n_channels; i++) {
760
ch = &sband->channels[i];
761
if (!isset(sup_chan.vec, ch->hw_value))
762
ch->flags |= IEEE80211_CHAN_DISABLED;
763
}
764
}
765
766
wlc->wiphy->reg_notifier = brcms_reg_notifier;
767
wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
768
REGULATORY_STRICT_REG;
769
wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
770
brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
771
}
772
773