Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010 Broadcom Corporation
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0011  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0013  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0014  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/types.h>
0018 #include <net/cfg80211.h>
0019 #include <net/mac80211.h>
0020 #include <net/regulatory.h>
0021 
0022 #include <defs.h>
0023 #include "pub.h"
0024 #include "phy/phy_hal.h"
0025 #include "main.h"
0026 #include "stf.h"
0027 #include "channel.h"
0028 #include "mac80211_if.h"
0029 #include "debug.h"
0030 
0031 /* QDB() macro takes a dB value and converts to a quarter dB value */
0032 #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
0033 
0034 #define LOCALE_MIMO_IDX_bn      0
0035 #define LOCALE_MIMO_IDX_11n     0
0036 
0037 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
0038 #define BRCMS_MAXPWR_MIMO_TBL_SIZE  14
0039 
0040 /* maxpwr mapping to 5GHz band channels:
0041  * maxpwr[0] - channels [34-48]
0042  * maxpwr[1] - channels [52-60]
0043  * maxpwr[2] - channels [62-64]
0044  * maxpwr[3] - channels [100-140]
0045  * maxpwr[4] - channels [149-165]
0046  */
0047 #define BAND_5G_PWR_LVLS    5   /* 5 power levels for 5G */
0048 
0049 #define LC(id)  LOCALE_MIMO_IDX_ ## id
0050 
0051 #define LOCALES(mimo2, mimo5) \
0052         {LC(mimo2), LC(mimo5)}
0053 
0054 /* macro to get 5 GHz channel group index for tx power */
0055 #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
0056                  (((c) < 62) ? 1 : \
0057                  (((c) < 100) ? 2 : \
0058                  (((c) < 149) ? 3 : 4))))
0059 
0060 #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
0061 #define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
0062                      NL80211_RRF_NO_IR)
0063 
0064 #define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
0065                      NL80211_RRF_NO_IR)
0066 #define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
0067                      NL80211_RRF_DFS | \
0068                      NL80211_RRF_NO_IR)
0069 #define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
0070                      NL80211_RRF_DFS | \
0071                      NL80211_RRF_NO_IR)
0072 #define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
0073                      NL80211_RRF_NO_IR)
0074 
0075 static const struct ieee80211_regdomain brcms_regdom_x2 = {
0076     .n_reg_rules = 6,
0077     .alpha2 = "X2",
0078     .reg_rules = {
0079         BRCM_2GHZ_2412_2462,
0080         BRCM_2GHZ_2467_2472,
0081         BRCM_5GHZ_5180_5240,
0082         BRCM_5GHZ_5260_5320,
0083         BRCM_5GHZ_5500_5700,
0084         BRCM_5GHZ_5745_5825,
0085     }
0086 };
0087 
0088  /* locale per-channel tx power limits for MIMO frames
0089   * maxpwr arrays are index by channel for 2.4 GHz limits, and
0090   * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
0091   */
0092 struct locale_mimo_info {
0093     /* tx 20 MHz power limits, qdBm units */
0094     s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
0095     /* tx 40 MHz power limits, qdBm units */
0096     s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
0097 };
0098 
0099 /* Country names and abbreviations with locale defined from ISO 3166 */
0100 struct country_info {
0101     const u8 locale_mimo_2G;    /* 2.4G mimo info */
0102     const u8 locale_mimo_5G;    /* 5G mimo info */
0103 };
0104 
0105 struct brcms_regd {
0106     struct country_info country;
0107     const struct ieee80211_regdomain *regdomain;
0108 };
0109 
0110 struct brcms_cm_info {
0111     struct brcms_pub *pub;
0112     struct brcms_c_info *wlc;
0113     const struct brcms_regd *world_regd;
0114 };
0115 
0116 /*
0117  * MIMO Locale Definitions - 2.4 GHz
0118  */
0119 static const struct locale_mimo_info locale_bn = {
0120     {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
0121      QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
0122      QDB(13), QDB(13), QDB(13)},
0123     {0, 0, QDB(13), QDB(13), QDB(13),
0124      QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
0125      QDB(13), 0, 0},
0126 };
0127 
0128 static const struct locale_mimo_info *g_mimo_2g_table[] = {
0129     &locale_bn
0130 };
0131 
0132 /*
0133  * MIMO Locale Definitions - 5 GHz
0134  */
0135 static const struct locale_mimo_info locale_11n = {
0136     { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
0137     {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
0138 };
0139 
0140 static const struct locale_mimo_info *g_mimo_5g_table[] = {
0141     &locale_11n
0142 };
0143 
0144 static const struct brcms_regd cntry_locales[] = {
0145     /* Worldwide RoW 2, must always be at index 0 */
0146     {
0147         .country = LOCALES(bn, 11n),
0148         .regdomain = &brcms_regdom_x2,
0149     },
0150 };
0151 
0152 static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
0153 {
0154     if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
0155         return NULL;
0156 
0157     return g_mimo_2g_table[locale_idx];
0158 }
0159 
0160 static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
0161 {
0162     if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))
0163         return NULL;
0164 
0165     return g_mimo_5g_table[locale_idx];
0166 }
0167 
0168 /*
0169  * Indicates whether the country provided is valid to pass
0170  * to cfg80211 or not.
0171  *
0172  * returns true if valid; false if not.
0173  */
0174 static bool brcms_c_country_valid(const char *ccode)
0175 {
0176     /*
0177      * only allow ascii alpha uppercase for the first 2
0178      * chars.
0179      */
0180     if (!((ccode[0] & 0x80) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
0181           (ccode[1] & 0x80) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))
0182         return false;
0183 
0184     /*
0185      * do not match ISO 3166-1 user assigned country codes
0186      * that may be in the driver table
0187      */
0188     if (!strcmp("AA", ccode) ||        /* AA */
0189         !strcmp("ZZ", ccode) ||        /* ZZ */
0190         ccode[0] == 'X' ||             /* XA - XZ */
0191         (ccode[0] == 'Q' &&            /* QM - QZ */
0192          (ccode[1] >= 'M' && ccode[1] <= 'Z')))
0193         return false;
0194 
0195     if (!strcmp("NA", ccode))
0196         return false;
0197 
0198     return true;
0199 }
0200 
0201 static const struct brcms_regd *brcms_world_regd(const char *regdom, int len)
0202 {
0203     const struct brcms_regd *regd = NULL;
0204     int i;
0205 
0206     for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
0207         if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) {
0208             regd = &cntry_locales[i];
0209             break;
0210         }
0211     }
0212 
0213     return regd;
0214 }
0215 
0216 static const struct brcms_regd *brcms_default_world_regd(void)
0217 {
0218     return &cntry_locales[0];
0219 }
0220 
0221 /* JP, J1 - J10 are Japan ccodes */
0222 static bool brcms_c_japan_ccode(const char *ccode)
0223 {
0224     return (ccode[0] == 'J' &&
0225         (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
0226 }
0227 
0228 static void
0229 brcms_c_channel_min_txpower_limits_with_local_constraint(
0230         struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
0231         u8 local_constraint_qdbm)
0232 {
0233     int j;
0234 
0235     /* CCK Rates */
0236     for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)
0237         txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
0238 
0239     /* 20 MHz Legacy OFDM SISO */
0240     for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)
0241         txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
0242 
0243     /* 20 MHz Legacy OFDM CDD */
0244     for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
0245         txpwr->ofdm_cdd[j] =
0246             min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
0247 
0248     /* 40 MHz Legacy OFDM SISO */
0249     for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
0250         txpwr->ofdm_40_siso[j] =
0251             min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
0252 
0253     /* 40 MHz Legacy OFDM CDD */
0254     for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
0255         txpwr->ofdm_40_cdd[j] =
0256             min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
0257 
0258     /* 20MHz MCS 0-7 SISO */
0259     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0260         txpwr->mcs_20_siso[j] =
0261             min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
0262 
0263     /* 20MHz MCS 0-7 CDD */
0264     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0265         txpwr->mcs_20_cdd[j] =
0266             min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
0267 
0268     /* 20MHz MCS 0-7 STBC */
0269     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0270         txpwr->mcs_20_stbc[j] =
0271             min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
0272 
0273     /* 20MHz MCS 8-15 MIMO */
0274     for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
0275         txpwr->mcs_20_mimo[j] =
0276             min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
0277 
0278     /* 40MHz MCS 0-7 SISO */
0279     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0280         txpwr->mcs_40_siso[j] =
0281             min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
0282 
0283     /* 40MHz MCS 0-7 CDD */
0284     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0285         txpwr->mcs_40_cdd[j] =
0286             min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
0287 
0288     /* 40MHz MCS 0-7 STBC */
0289     for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
0290         txpwr->mcs_40_stbc[j] =
0291             min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
0292 
0293     /* 40MHz MCS 8-15 MIMO */
0294     for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
0295         txpwr->mcs_40_mimo[j] =
0296             min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
0297 
0298     /* 40MHz MCS 32 */
0299     txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
0300 
0301 }
0302 
0303 /*
0304  * set the driver's current country and regulatory information
0305  * using a country code as the source. Look up built in country
0306  * information found with the country code.
0307  */
0308 static void
0309 brcms_c_set_country(struct brcms_cm_info *wlc_cm,
0310             const struct brcms_regd *regd)
0311 {
0312     struct brcms_c_info *wlc = wlc_cm->wlc;
0313 
0314     if ((wlc->pub->_n_enab & SUPPORT_11N) !=
0315         wlc->protection->nmode_user)
0316         brcms_c_set_nmode(wlc);
0317 
0318     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
0319     brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
0320 
0321     brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
0322 
0323     return;
0324 }
0325 
0326 struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
0327 {
0328     struct brcms_cm_info *wlc_cm;
0329     struct brcms_pub *pub = wlc->pub;
0330     struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
0331     const char *ccode = sprom->alpha2;
0332     int ccode_len = sizeof(sprom->alpha2);
0333 
0334     wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
0335     if (wlc_cm == NULL)
0336         return NULL;
0337     wlc_cm->pub = pub;
0338     wlc_cm->wlc = wlc;
0339     wlc->cmi = wlc_cm;
0340 
0341     /* store the country code for passing up as a regulatory hint */
0342     wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);
0343     if (brcms_c_country_valid(ccode))
0344         strncpy(wlc->pub->srom_ccode, ccode, ccode_len);
0345 
0346     /*
0347      * If no custom world domain is found in the SROM, use the
0348      * default "X2" domain.
0349      */
0350     if (!wlc_cm->world_regd) {
0351         wlc_cm->world_regd = brcms_default_world_regd();
0352         ccode = wlc_cm->world_regd->regdomain->alpha2;
0353         ccode_len = BRCM_CNTRY_BUF_SZ - 1;
0354     }
0355 
0356     /* save default country for exiting 11d regulatory mode */
0357     strncpy(wlc->country_default, ccode, ccode_len);
0358 
0359     /* initialize autocountry_default to driver default */
0360     strncpy(wlc->autocountry_default, ccode, ccode_len);
0361 
0362     brcms_c_set_country(wlc_cm, wlc_cm->world_regd);
0363 
0364     return wlc_cm;
0365 }
0366 
0367 void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
0368 {
0369     kfree(wlc_cm);
0370 }
0371 
0372 void
0373 brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
0374              u8 local_constraint_qdbm)
0375 {
0376     struct brcms_c_info *wlc = wlc_cm->wlc;
0377     struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
0378     struct txpwr_limits txpwr;
0379 
0380     brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
0381 
0382     brcms_c_channel_min_txpower_limits_with_local_constraint(
0383         wlc_cm, &txpwr, local_constraint_qdbm
0384     );
0385 
0386     /* set or restore gmode as required by regulatory */
0387     if (ch->flags & IEEE80211_CHAN_NO_OFDM)
0388         brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
0389     else
0390         brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
0391 
0392     brcms_b_set_chanspec(wlc->hw, chanspec,
0393                   !!(ch->flags & IEEE80211_CHAN_NO_IR),
0394                   &txpwr);
0395 }
0396 
0397 void
0398 brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
0399                struct txpwr_limits *txpwr)
0400 {
0401     struct brcms_c_info *wlc = wlc_cm->wlc;
0402     struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
0403     uint i;
0404     uint chan;
0405     int maxpwr;
0406     int delta;
0407     const struct country_info *country;
0408     struct brcms_band *band;
0409     int conducted_max = BRCMS_TXPWR_MAX;
0410     const struct locale_mimo_info *li_mimo;
0411     int maxpwr20, maxpwr40;
0412     int maxpwr_idx;
0413     uint j;
0414 
0415     memset(txpwr, 0, sizeof(struct txpwr_limits));
0416 
0417     if (WARN_ON(!ch))
0418         return;
0419 
0420     country = &wlc_cm->world_regd->country;
0421 
0422     chan = CHSPEC_CHANNEL(chanspec);
0423     band = wlc->bandstate[chspec_bandunit(chanspec)];
0424     li_mimo = (band->bandtype == BRCM_BAND_5G) ?
0425         brcms_c_get_mimo_5g(country->locale_mimo_5G) :
0426         brcms_c_get_mimo_2g(country->locale_mimo_2G);
0427 
0428     delta = band->antgain;
0429 
0430     if (band->bandtype == BRCM_BAND_2G)
0431         conducted_max = QDB(22);
0432 
0433     maxpwr = QDB(ch->max_power) - delta;
0434     maxpwr = max(maxpwr, 0);
0435     maxpwr = min(maxpwr, conducted_max);
0436 
0437     /* CCK txpwr limits for 2.4G band */
0438     if (band->bandtype == BRCM_BAND_2G) {
0439         for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
0440             txpwr->cck[i] = (u8) maxpwr;
0441     }
0442 
0443     for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
0444         txpwr->ofdm[i] = (u8) maxpwr;
0445 
0446         /*
0447          * OFDM 40 MHz SISO has the same power as the corresponding
0448          * MCS0-7 rate unless overriden by the locale specific code.
0449          * We set this value to 0 as a flag (presumably 0 dBm isn't
0450          * a possibility) and then copy the MCS0-7 value to the 40 MHz
0451          * value if it wasn't explicitly set.
0452          */
0453         txpwr->ofdm_40_siso[i] = 0;
0454 
0455         txpwr->ofdm_cdd[i] = (u8) maxpwr;
0456 
0457         txpwr->ofdm_40_cdd[i] = 0;
0458     }
0459 
0460     delta = 0;
0461     if (band->antgain > QDB(6))
0462         delta = band->antgain - QDB(6); /* Excess over 6 dB */
0463 
0464     if (band->bandtype == BRCM_BAND_2G)
0465         maxpwr_idx = (chan - 1);
0466     else
0467         maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
0468 
0469     maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
0470     maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
0471 
0472     maxpwr20 = maxpwr20 - delta;
0473     maxpwr20 = max(maxpwr20, 0);
0474     maxpwr40 = maxpwr40 - delta;
0475     maxpwr40 = max(maxpwr40, 0);
0476 
0477     /* Fill in the MCS 0-7 (SISO) rates */
0478     for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0479 
0480         /*
0481          * 20 MHz has the same power as the corresponding OFDM rate
0482          * unless overriden by the locale specific code.
0483          */
0484         txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
0485         txpwr->mcs_40_siso[i] = 0;
0486     }
0487 
0488     /* Fill in the MCS 0-7 CDD rates */
0489     for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0490         txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
0491         txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
0492     }
0493 
0494     /*
0495      * These locales have SISO expressed in the
0496      * table and override CDD later
0497      */
0498     if (li_mimo == &locale_bn) {
0499         maxpwr20 = QDB(16);
0500         maxpwr40 = 0;
0501 
0502         if (chan >= 3 && chan <= 11)
0503             maxpwr40 = QDB(16);
0504 
0505         for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0506             txpwr->mcs_20_siso[i] = (u8) maxpwr20;
0507             txpwr->mcs_40_siso[i] = (u8) maxpwr40;
0508         }
0509     }
0510 
0511     /* Fill in the MCS 0-7 STBC rates */
0512     for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0513         txpwr->mcs_20_stbc[i] = 0;
0514         txpwr->mcs_40_stbc[i] = 0;
0515     }
0516 
0517     /* Fill in the MCS 8-15 SDM rates */
0518     for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
0519         txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
0520         txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
0521     }
0522 
0523     /* Fill in MCS32 */
0524     txpwr->mcs32 = (u8) maxpwr40;
0525 
0526     for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
0527         if (txpwr->ofdm_40_cdd[i] == 0)
0528             txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
0529         if (i == 0) {
0530             i = i + 1;
0531             if (txpwr->ofdm_40_cdd[i] == 0)
0532                 txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
0533         }
0534     }
0535 
0536     /*
0537      * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
0538      * value if it wasn't provided explicitly.
0539      */
0540     for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0541         if (txpwr->mcs_40_siso[i] == 0)
0542             txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
0543     }
0544 
0545     for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
0546         if (txpwr->ofdm_40_siso[i] == 0)
0547             txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
0548         if (i == 0) {
0549             i = i + 1;
0550             if (txpwr->ofdm_40_siso[i] == 0)
0551                 txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
0552         }
0553     }
0554 
0555     /*
0556      * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
0557      * STBC values if they weren't provided explicitly.
0558      */
0559     for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
0560         if (txpwr->mcs_20_stbc[i] == 0)
0561             txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
0562 
0563         if (txpwr->mcs_40_stbc[i] == 0)
0564             txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
0565     }
0566 
0567     return;
0568 }
0569 
0570 /*
0571  * Verify the chanspec is using a legal set of parameters, i.e. that the
0572  * chanspec specified a band, bw, ctl_sb and channel and that the
0573  * combination could be legal given any set of circumstances.
0574  * RETURNS: true is the chanspec is malformed, false if it looks good.
0575  */
0576 static bool brcms_c_chspec_malformed(u16 chanspec)
0577 {
0578     /* must be 2G or 5G band */
0579     if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
0580         return true;
0581     /* must be 20 or 40 bandwidth */
0582     if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
0583         return true;
0584 
0585     /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
0586     if (CHSPEC_IS20(chanspec)) {
0587         if (!CHSPEC_SB_NONE(chanspec))
0588             return true;
0589     } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {
0590         return true;
0591     }
0592 
0593     return false;
0594 }
0595 
0596 /*
0597  * Validate the chanspec for this locale, for 40MHZ we need to also
0598  * check that the sidebands are valid 20MZH channels in this locale
0599  * and they are also a legal HT combination
0600  */
0601 static bool
0602 brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
0603 {
0604     struct brcms_c_info *wlc = wlc_cm->wlc;
0605     u8 channel = CHSPEC_CHANNEL(chspec);
0606 
0607     /* check the chanspec */
0608     if (brcms_c_chspec_malformed(chspec)) {
0609         brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n",
0610               wlc->pub->unit, chspec);
0611         return false;
0612     }
0613 
0614     if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
0615         chspec_bandunit(chspec))
0616         return false;
0617 
0618     return true;
0619 }
0620 
0621 bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
0622 {
0623     return brcms_c_valid_chanspec_ext(wlc_cm, chspec);
0624 }
0625 
0626 static bool brcms_is_radar_freq(u16 center_freq)
0627 {
0628     return center_freq >= 5260 && center_freq <= 5700;
0629 }
0630 
0631 static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
0632 {
0633     struct ieee80211_supported_band *sband;
0634     struct ieee80211_channel *ch;
0635     int i;
0636 
0637     sband = wiphy->bands[NL80211_BAND_5GHZ];
0638     if (!sband)
0639         return;
0640 
0641     for (i = 0; i < sband->n_channels; i++) {
0642         ch = &sband->channels[i];
0643 
0644         if (!brcms_is_radar_freq(ch->center_freq))
0645             continue;
0646 
0647         /*
0648          * All channels in this range should be passive and have
0649          * DFS enabled.
0650          */
0651         if (!(ch->flags & IEEE80211_CHAN_DISABLED))
0652             ch->flags |= IEEE80211_CHAN_RADAR |
0653                      IEEE80211_CHAN_NO_IR;
0654     }
0655 }
0656 
0657 static void
0658 brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
0659                 enum nl80211_reg_initiator initiator)
0660 {
0661     struct ieee80211_supported_band *sband;
0662     struct ieee80211_channel *ch;
0663     const struct ieee80211_reg_rule *rule;
0664     int band, i;
0665 
0666     for (band = 0; band < NUM_NL80211_BANDS; band++) {
0667         sband = wiphy->bands[band];
0668         if (!sband)
0669             continue;
0670 
0671         for (i = 0; i < sband->n_channels; i++) {
0672             ch = &sband->channels[i];
0673 
0674             if (ch->flags &
0675                 (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))
0676                 continue;
0677 
0678             if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
0679                 rule = freq_reg_info(wiphy,
0680                              MHZ_TO_KHZ(ch->center_freq));
0681                 if (IS_ERR(rule))
0682                     continue;
0683 
0684                 if (!(rule->flags & NL80211_RRF_NO_IR))
0685                     ch->flags &= ~IEEE80211_CHAN_NO_IR;
0686             } else if (ch->beacon_found) {
0687                 ch->flags &= ~IEEE80211_CHAN_NO_IR;
0688             }
0689         }
0690     }
0691 }
0692 
0693 static void brcms_reg_notifier(struct wiphy *wiphy,
0694                    struct regulatory_request *request)
0695 {
0696     struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
0697     struct brcms_info *wl = hw->priv;
0698     struct brcms_c_info *wlc = wl->wlc;
0699     struct ieee80211_supported_band *sband;
0700     struct ieee80211_channel *ch;
0701     int band, i;
0702     bool ch_found = false;
0703 
0704     brcms_reg_apply_radar_flags(wiphy);
0705 
0706     if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
0707         brcms_reg_apply_beaconing_flags(wiphy, request->initiator);
0708 
0709     /* Disable radio if all channels disallowed by regulatory */
0710     for (band = 0; !ch_found && band < NUM_NL80211_BANDS; band++) {
0711         sband = wiphy->bands[band];
0712         if (!sband)
0713             continue;
0714 
0715         for (i = 0; !ch_found && i < sband->n_channels; i++) {
0716             ch = &sband->channels[i];
0717 
0718             if (!(ch->flags & IEEE80211_CHAN_DISABLED))
0719                 ch_found = true;
0720         }
0721     }
0722 
0723     if (ch_found) {
0724         mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
0725     } else {
0726         mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
0727         brcms_err(wlc->hw->d11core,
0728               "wl%d: %s: no valid channel for \"%s\"\n",
0729               wlc->pub->unit, __func__, request->alpha2);
0730     }
0731 
0732     if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
0733         wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
0734                     brcms_c_japan_ccode(request->alpha2));
0735 }
0736 
0737 void brcms_c_regd_init(struct brcms_c_info *wlc)
0738 {
0739     struct wiphy *wiphy = wlc->wiphy;
0740     const struct brcms_regd *regd = wlc->cmi->world_regd;
0741     struct ieee80211_supported_band *sband;
0742     struct ieee80211_channel *ch;
0743     struct brcms_chanvec sup_chan;
0744     struct brcms_band *band;
0745     int band_idx, i;
0746 
0747     /* Disable any channels not supported by the phy */
0748     for (band_idx = 0; band_idx < wlc->pub->_nbands; band_idx++) {
0749         band = wlc->bandstate[band_idx];
0750 
0751         wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
0752                           &sup_chan);
0753 
0754         if (band_idx == BAND_2G_INDEX)
0755             sband = wiphy->bands[NL80211_BAND_2GHZ];
0756         else
0757             sband = wiphy->bands[NL80211_BAND_5GHZ];
0758 
0759         for (i = 0; i < sband->n_channels; i++) {
0760             ch = &sband->channels[i];
0761             if (!isset(sup_chan.vec, ch->hw_value))
0762                 ch->flags |= IEEE80211_CHAN_DISABLED;
0763         }
0764     }
0765 
0766     wlc->wiphy->reg_notifier = brcms_reg_notifier;
0767     wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
0768                     REGULATORY_STRICT_REG;
0769     wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
0770     brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
0771 }