Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/channel.c
178665 views
/*1* Copyright (c) 2010 Broadcom Corporation2*3* Permission to use, copy, modify, and/or distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES8* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF9* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY10* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES11* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION12* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN13* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.14*/1516#include <linux/types.h>17#include <net/cfg80211.h>18#include <net/mac80211.h>19#include <net/regulatory.h>2021#include <defs.h>22#include "pub.h"23#include "phy/phy_hal.h"24#include "main.h"25#include "stf.h"26#include "channel.h"27#include "mac80211_if.h"28#include "debug.h"2930/* QDB() macro takes a dB value and converts to a quarter dB value */31#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)3233#define LOCALE_MIMO_IDX_bn 034#define LOCALE_MIMO_IDX_11n 03536/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */37#define BRCMS_MAXPWR_MIMO_TBL_SIZE 143839/* maxpwr mapping to 5GHz band channels:40* maxpwr[0] - channels [34-48]41* maxpwr[1] - channels [52-60]42* maxpwr[2] - channels [62-64]43* maxpwr[3] - channels [100-140]44* maxpwr[4] - channels [149-165]45*/46#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */4748#define LC(id) LOCALE_MIMO_IDX_ ## id4950#define LOCALES(mimo2, mimo5) \51{LC(mimo2), LC(mimo5)}5253/* macro to get 5 GHz channel group index for tx power */54#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \55(((c) < 62) ? 1 : \56(((c) < 100) ? 2 : \57(((c) < 149) ? 3 : 4))))5859#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)60#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \61NL80211_RRF_NO_IR)6263#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \64NL80211_RRF_NO_IR)65#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \66NL80211_RRF_DFS | \67NL80211_RRF_NO_IR)68#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \69NL80211_RRF_DFS | \70NL80211_RRF_NO_IR)71#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \72NL80211_RRF_NO_IR)7374static const struct ieee80211_regdomain brcms_regdom_x2 = {75.n_reg_rules = 6,76.alpha2 = "X2",77.reg_rules = {78BRCM_2GHZ_2412_2462,79BRCM_2GHZ_2467_2472,80BRCM_5GHZ_5180_5240,81BRCM_5GHZ_5260_5320,82BRCM_5GHZ_5500_5700,83BRCM_5GHZ_5745_5825,84}85};8687/* locale per-channel tx power limits for MIMO frames88* maxpwr arrays are index by channel for 2.4 GHz limits, and89* by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)90*/91struct locale_mimo_info {92/* tx 20 MHz power limits, qdBm units */93s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];94/* tx 40 MHz power limits, qdBm units */95s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];96};9798/* Country names and abbreviations with locale defined from ISO 3166 */99struct country_info {100const u8 locale_mimo_2G; /* 2.4G mimo info */101const u8 locale_mimo_5G; /* 5G mimo info */102};103104struct brcms_regd {105struct country_info country;106const struct ieee80211_regdomain *regdomain;107};108109struct brcms_cm_info {110struct brcms_pub *pub;111struct brcms_c_info *wlc;112const struct brcms_regd *world_regd;113};114115/*116* MIMO Locale Definitions - 2.4 GHz117*/118static const struct locale_mimo_info locale_bn = {119{QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),120QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),121QDB(13), QDB(13), QDB(13)},122{0, 0, QDB(13), QDB(13), QDB(13),123QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),124QDB(13), 0, 0},125};126127static const struct locale_mimo_info *g_mimo_2g_table[] = {128&locale_bn129};130131/*132* MIMO Locale Definitions - 5 GHz133*/134static const struct locale_mimo_info locale_11n = {135{ /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},136{QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},137};138139static const struct locale_mimo_info *g_mimo_5g_table[] = {140&locale_11n141};142143static const struct brcms_regd cntry_locales[] = {144/* Worldwide RoW 2, must always be at index 0 */145{146.country = LOCALES(bn, 11n),147.regdomain = &brcms_regdom_x2,148},149};150151static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)152{153if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))154return NULL;155156return g_mimo_2g_table[locale_idx];157}158159static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)160{161if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))162return NULL;163164return g_mimo_5g_table[locale_idx];165}166167/*168* Indicates whether the country provided is valid to pass169* to cfg80211 or not.170*171* returns true if valid; false if not.172*/173static bool brcms_c_country_valid(const char *ccode)174{175/*176* only allow ascii alpha uppercase for the first 2177* chars.178*/179if (!((ccode[0] & 0x80) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&180(ccode[1] & 0x80) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))181return false;182183/*184* do not match ISO 3166-1 user assigned country codes185* that may be in the driver table186*/187if (!strcmp("AA", ccode) || /* AA */188!strcmp("ZZ", ccode) || /* ZZ */189ccode[0] == 'X' || /* XA - XZ */190(ccode[0] == 'Q' && /* QM - QZ */191(ccode[1] >= 'M' && ccode[1] <= 'Z')))192return false;193194if (!strcmp("NA", ccode))195return false;196197return true;198}199200static const struct brcms_regd *brcms_world_regd(const char *regdom, int len)201{202const struct brcms_regd *regd = NULL;203int i;204205for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {206if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) {207regd = &cntry_locales[i];208break;209}210}211212return regd;213}214215static const struct brcms_regd *brcms_default_world_regd(void)216{217return &cntry_locales[0];218}219220/* JP, J1 - J10 are Japan ccodes */221static bool brcms_c_japan_ccode(const char *ccode)222{223return (ccode[0] == 'J' &&224(ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));225}226227static void228brcms_c_channel_min_txpower_limits_with_local_constraint(229struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,230u8 local_constraint_qdbm)231{232int j;233234/* CCK Rates */235for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)236txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);237238/* 20 MHz Legacy OFDM SISO */239for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)240txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);241242/* 20 MHz Legacy OFDM CDD */243for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)244txpwr->ofdm_cdd[j] =245min(txpwr->ofdm_cdd[j], local_constraint_qdbm);246247/* 40 MHz Legacy OFDM SISO */248for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)249txpwr->ofdm_40_siso[j] =250min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);251252/* 40 MHz Legacy OFDM CDD */253for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)254txpwr->ofdm_40_cdd[j] =255min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);256257/* 20MHz MCS 0-7 SISO */258for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)259txpwr->mcs_20_siso[j] =260min(txpwr->mcs_20_siso[j], local_constraint_qdbm);261262/* 20MHz MCS 0-7 CDD */263for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)264txpwr->mcs_20_cdd[j] =265min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);266267/* 20MHz MCS 0-7 STBC */268for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)269txpwr->mcs_20_stbc[j] =270min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);271272/* 20MHz MCS 8-15 MIMO */273for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)274txpwr->mcs_20_mimo[j] =275min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);276277/* 40MHz MCS 0-7 SISO */278for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)279txpwr->mcs_40_siso[j] =280min(txpwr->mcs_40_siso[j], local_constraint_qdbm);281282/* 40MHz MCS 0-7 CDD */283for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)284txpwr->mcs_40_cdd[j] =285min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);286287/* 40MHz MCS 0-7 STBC */288for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)289txpwr->mcs_40_stbc[j] =290min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);291292/* 40MHz MCS 8-15 MIMO */293for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)294txpwr->mcs_40_mimo[j] =295min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);296297/* 40MHz MCS 32 */298txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);299300}301302/*303* set the driver's current country and regulatory information304* using a country code as the source. Look up built in country305* information found with the country code.306*/307static void308brcms_c_set_country(struct brcms_cm_info *wlc_cm,309const struct brcms_regd *regd)310{311struct brcms_c_info *wlc = wlc_cm->wlc;312313if ((wlc->pub->_n_enab & SUPPORT_11N) !=314wlc->protection->nmode_user)315brcms_c_set_nmode(wlc);316317brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);318brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);319320brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);321322return;323}324325struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)326{327struct brcms_cm_info *wlc_cm;328struct brcms_pub *pub = wlc->pub;329struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;330const char *ccode = sprom->alpha2;331int ccode_len = sizeof(sprom->alpha2);332333wlc_cm = kzalloc(sizeof(*wlc_cm), GFP_ATOMIC);334if (wlc_cm == NULL)335return NULL;336wlc_cm->pub = pub;337wlc_cm->wlc = wlc;338wlc->cmi = wlc_cm;339340/* store the country code for passing up as a regulatory hint */341wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);342if (brcms_c_country_valid(ccode))343memcpy(wlc->pub->srom_ccode, ccode, ccode_len);344345/*346* If no custom world domain is found in the SROM, use the347* default "X2" domain.348*/349if (!wlc_cm->world_regd) {350wlc_cm->world_regd = brcms_default_world_regd();351ccode = wlc_cm->world_regd->regdomain->alpha2;352ccode_len = BRCM_CNTRY_BUF_SZ - 1;353}354355/* save default country for exiting 11d regulatory mode */356memcpy(wlc->country_default, ccode, ccode_len);357358/* initialize autocountry_default to driver default */359memcpy(wlc->autocountry_default, ccode, ccode_len);360361brcms_c_set_country(wlc_cm, wlc_cm->world_regd);362363return wlc_cm;364}365366void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)367{368kfree(wlc_cm);369}370371void372brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,373u8 local_constraint_qdbm)374{375struct brcms_c_info *wlc = wlc_cm->wlc;376struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;377struct txpwr_limits txpwr;378379brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);380381brcms_c_channel_min_txpower_limits_with_local_constraint(382wlc_cm, &txpwr, local_constraint_qdbm383);384385/* set or restore gmode as required by regulatory */386if (ch->flags & IEEE80211_CHAN_NO_OFDM)387brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);388else389brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);390391brcms_b_set_chanspec(wlc->hw, chanspec,392!!(ch->flags & IEEE80211_CHAN_NO_IR),393&txpwr);394}395396void397brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,398struct txpwr_limits *txpwr)399{400struct brcms_c_info *wlc = wlc_cm->wlc;401struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;402uint i;403uint chan;404int maxpwr;405int delta;406const struct country_info *country;407struct brcms_band *band;408int conducted_max = BRCMS_TXPWR_MAX;409const struct locale_mimo_info *li_mimo;410int maxpwr20, maxpwr40;411int maxpwr_idx;412uint j;413414memset(txpwr, 0, sizeof(struct txpwr_limits));415416if (WARN_ON(!ch))417return;418419country = &wlc_cm->world_regd->country;420421chan = CHSPEC_CHANNEL(chanspec);422band = wlc->bandstate[chspec_bandunit(chanspec)];423li_mimo = (band->bandtype == BRCM_BAND_5G) ?424brcms_c_get_mimo_5g(country->locale_mimo_5G) :425brcms_c_get_mimo_2g(country->locale_mimo_2G);426427delta = band->antgain;428429if (band->bandtype == BRCM_BAND_2G)430conducted_max = QDB(22);431432maxpwr = QDB(ch->max_power) - delta;433maxpwr = max(maxpwr, 0);434maxpwr = min(maxpwr, conducted_max);435436/* CCK txpwr limits for 2.4G band */437if (band->bandtype == BRCM_BAND_2G) {438for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)439txpwr->cck[i] = (u8) maxpwr;440}441442for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {443txpwr->ofdm[i] = (u8) maxpwr;444445/*446* OFDM 40 MHz SISO has the same power as the corresponding447* MCS0-7 rate unless overridden by the locale specific code.448* We set this value to 0 as a flag (presumably 0 dBm isn't449* a possibility) and then copy the MCS0-7 value to the 40 MHz450* value if it wasn't explicitly set.451*/452txpwr->ofdm_40_siso[i] = 0;453454txpwr->ofdm_cdd[i] = (u8) maxpwr;455456txpwr->ofdm_40_cdd[i] = 0;457}458459delta = 0;460if (band->antgain > QDB(6))461delta = band->antgain - QDB(6); /* Excess over 6 dB */462463if (band->bandtype == BRCM_BAND_2G)464maxpwr_idx = (chan - 1);465else466maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);467468maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];469maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];470471maxpwr20 = maxpwr20 - delta;472maxpwr20 = max(maxpwr20, 0);473maxpwr40 = maxpwr40 - delta;474maxpwr40 = max(maxpwr40, 0);475476/* Fill in the MCS 0-7 (SISO) rates */477for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {478479/*480* 20 MHz has the same power as the corresponding OFDM rate481* unless overridden by the locale specific code.482*/483txpwr->mcs_20_siso[i] = txpwr->ofdm[i];484txpwr->mcs_40_siso[i] = 0;485}486487/* Fill in the MCS 0-7 CDD rates */488for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {489txpwr->mcs_20_cdd[i] = (u8) maxpwr20;490txpwr->mcs_40_cdd[i] = (u8) maxpwr40;491}492493/*494* These locales have SISO expressed in the495* table and override CDD later496*/497if (li_mimo == &locale_bn) {498maxpwr20 = QDB(16);499maxpwr40 = 0;500501if (chan >= 3 && chan <= 11)502maxpwr40 = QDB(16);503504for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {505txpwr->mcs_20_siso[i] = (u8) maxpwr20;506txpwr->mcs_40_siso[i] = (u8) maxpwr40;507}508}509510/* Fill in the MCS 0-7 STBC rates */511for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {512txpwr->mcs_20_stbc[i] = 0;513txpwr->mcs_40_stbc[i] = 0;514}515516/* Fill in the MCS 8-15 SDM rates */517for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {518txpwr->mcs_20_mimo[i] = (u8) maxpwr20;519txpwr->mcs_40_mimo[i] = (u8) maxpwr40;520}521522/* Fill in MCS32 */523txpwr->mcs32 = (u8) maxpwr40;524525for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {526if (txpwr->ofdm_40_cdd[i] == 0)527txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];528if (i == 0) {529i = i + 1;530if (txpwr->ofdm_40_cdd[i] == 0)531txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];532}533}534535/*536* Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO537* value if it wasn't provided explicitly.538*/539for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {540if (txpwr->mcs_40_siso[i] == 0)541txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];542}543544for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {545if (txpwr->ofdm_40_siso[i] == 0)546txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];547if (i == 0) {548i = i + 1;549if (txpwr->ofdm_40_siso[i] == 0)550txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];551}552}553554/*555* Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding556* STBC values if they weren't provided explicitly.557*/558for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {559if (txpwr->mcs_20_stbc[i] == 0)560txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];561562if (txpwr->mcs_40_stbc[i] == 0)563txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];564}565566return;567}568569/*570* Verify the chanspec is using a legal set of parameters, i.e. that the571* chanspec specified a band, bw, ctl_sb and channel and that the572* combination could be legal given any set of circumstances.573* RETURNS: true is the chanspec is malformed, false if it looks good.574*/575static bool brcms_c_chspec_malformed(u16 chanspec)576{577/* must be 2G or 5G band */578if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))579return true;580/* must be 20 or 40 bandwidth */581if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))582return true;583584/* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */585if (CHSPEC_IS20(chanspec)) {586if (!CHSPEC_SB_NONE(chanspec))587return true;588} else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {589return true;590}591592return false;593}594595/*596* Validate the chanspec for this locale, for 40MHZ we need to also597* check that the sidebands are valid 20MZH channels in this locale598* and they are also a legal HT combination599*/600static bool601brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)602{603struct brcms_c_info *wlc = wlc_cm->wlc;604u8 channel = CHSPEC_CHANNEL(chspec);605606/* check the chanspec */607if (brcms_c_chspec_malformed(chspec)) {608brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n",609wlc->pub->unit, chspec);610return false;611}612613if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=614chspec_bandunit(chspec))615return false;616617return true;618}619620bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)621{622return brcms_c_valid_chanspec_ext(wlc_cm, chspec);623}624625static bool brcms_is_radar_freq(u16 center_freq)626{627return center_freq >= 5260 && center_freq <= 5700;628}629630static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)631{632struct ieee80211_supported_band *sband;633struct ieee80211_channel *ch;634int i;635636sband = wiphy->bands[NL80211_BAND_5GHZ];637if (!sband)638return;639640for (i = 0; i < sband->n_channels; i++) {641ch = &sband->channels[i];642643if (!brcms_is_radar_freq(ch->center_freq))644continue;645646/*647* All channels in this range should be passive and have648* DFS enabled.649*/650if (!(ch->flags & IEEE80211_CHAN_DISABLED))651ch->flags |= IEEE80211_CHAN_RADAR |652IEEE80211_CHAN_NO_IR;653}654}655656static void657brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,658enum nl80211_reg_initiator initiator)659{660struct ieee80211_supported_band *sband;661struct ieee80211_channel *ch;662const struct ieee80211_reg_rule *rule;663int band, i;664665for (band = 0; band < NUM_NL80211_BANDS; band++) {666sband = wiphy->bands[band];667if (!sband)668continue;669670for (i = 0; i < sband->n_channels; i++) {671ch = &sband->channels[i];672673if (ch->flags &674(IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))675continue;676677if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {678rule = freq_reg_info(wiphy,679MHZ_TO_KHZ(ch->center_freq));680if (IS_ERR(rule))681continue;682683if (!(rule->flags & NL80211_RRF_NO_IR))684ch->flags &= ~IEEE80211_CHAN_NO_IR;685} else if (ch->beacon_found) {686ch->flags &= ~IEEE80211_CHAN_NO_IR;687}688}689}690}691692static void brcms_reg_notifier(struct wiphy *wiphy,693struct regulatory_request *request)694{695struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);696struct brcms_info *wl = hw->priv;697struct brcms_c_info *wlc = wl->wlc;698struct ieee80211_supported_band *sband;699struct ieee80211_channel *ch;700int band, i;701bool ch_found = false;702703brcms_reg_apply_radar_flags(wiphy);704705if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)706brcms_reg_apply_beaconing_flags(wiphy, request->initiator);707708/* Disable radio if all channels disallowed by regulatory */709for (band = 0; !ch_found && band < NUM_NL80211_BANDS; band++) {710sband = wiphy->bands[band];711if (!sband)712continue;713714for (i = 0; !ch_found && i < sband->n_channels; i++) {715ch = &sband->channels[i];716717if (!(ch->flags & IEEE80211_CHAN_DISABLED))718ch_found = true;719}720}721722if (ch_found) {723mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);724} else {725mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);726brcms_err(wlc->hw->d11core,727"wl%d: %s: no valid channel for \"%s\"\n",728wlc->pub->unit, __func__, request->alpha2);729}730731if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)732wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,733brcms_c_japan_ccode(request->alpha2));734}735736void brcms_c_regd_init(struct brcms_c_info *wlc)737{738struct wiphy *wiphy = wlc->wiphy;739const struct brcms_regd *regd = wlc->cmi->world_regd;740struct ieee80211_supported_band *sband;741struct ieee80211_channel *ch;742struct brcms_chanvec sup_chan;743struct brcms_band *band;744int band_idx, i;745746/* Disable any channels not supported by the phy */747for (band_idx = 0; band_idx < wlc->pub->_nbands; band_idx++) {748band = wlc->bandstate[band_idx];749750wlc_phy_chanspec_band_validch(band->pi, band->bandtype,751&sup_chan);752753if (band_idx == BAND_2G_INDEX)754sband = wiphy->bands[NL80211_BAND_2GHZ];755else756sband = wiphy->bands[NL80211_BAND_5GHZ];757758for (i = 0; i < sband->n_channels; i++) {759ch = &sband->channels[i];760if (!isset(sup_chan.vec, ch->hw_value))761ch->flags |= IEEE80211_CHAN_DISABLED;762}763}764765wlc->wiphy->reg_notifier = brcms_reg_notifier;766wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |767REGULATORY_STRICT_REG;768wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);769brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);770}771772773