The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/ath_hal/ah_regdomain.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: ISC
    3  *
    4  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
    5  * Copyright (c) 2005-2006 Atheros Communications, Inc.
    6  * All rights reserved.
    7  *
    8  * Permission to use, copy, modify, and/or distribute this software for any
    9  * purpose with or without fee is hereby granted, provided that the above
   10  * copyright notice and this permission notice appear in all copies.
   11  *
   12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   19  *
   20  * $FreeBSD$
   21  */
   22 #include "opt_ah.h"
   23 
   24 #include "ah.h"
   25 
   26 #include <net80211/_ieee80211.h>
   27 #include <net80211/ieee80211_regdomain.h>
   28 
   29 #include "ah_internal.h"
   30 #include "ah_eeprom.h"
   31 #include "ah_devid.h"
   32 
   33 #include "ah_regdomain.h"
   34 
   35 /*
   36  * XXX this code needs a audit+review
   37  */
   38 
   39 /* used throughout this file... */
   40 #define N(a)            nitems(a)
   41 
   42 #define HAL_MODE_11A_TURBO      HAL_MODE_108A
   43 #define HAL_MODE_11G_TURBO      HAL_MODE_108G
   44 
   45 /*
   46  * Mask to check whether a domain is a multidomain or a single domain
   47  */
   48 #define MULTI_DOMAIN_MASK 0xFF00
   49 
   50 /*
   51  * Enumerated Regulatory Domain Information 8 bit values indicate that
   52  * the regdomain is really a pair of unitary regdomains.  12 bit values
   53  * are the real unitary regdomains and are the only ones which have the
   54  * frequency bitmasks and flags set.
   55  */
   56 #include "ah_regdomain/ah_rd_regenum.h"
   57 
   58 #define WORLD_SKU_MASK          0x00F0
   59 #define WORLD_SKU_PREFIX        0x0060
   60 
   61 /*
   62  * THE following table is the mapping of regdomain pairs specified by
   63  * an 8 bit regdomain value to the individual unitary reg domains
   64  */
   65 #include "ah_regdomain/ah_rd_regmap.h"
   66 
   67 /* 
   68  * The following tables are the master list for all different freqeuncy
   69  * bands with the complete matrix of all possible flags and settings
   70  * for each band if it is used in ANY reg domain.
   71  */
   72 
   73 #define COUNTRY_ERD_FLAG        0x8000
   74 #define WORLDWIDE_ROAMING_FLAG  0x4000
   75 
   76 /*
   77  * This table maps country ISO codes from net80211 into regulatory
   78  * domains which the ath regulatory domain code understands.
   79  */
   80 #include "ah_regdomain/ah_rd_ctry.h"
   81 
   82 /*
   83  * The frequency band collections are a set of frequency ranges
   84  * with shared properties - max tx power, max antenna gain, channel width,
   85  * channel spacing, DFS requirements and passive scanning requirements.
   86  *
   87  * These are represented as entries in a frequency band bitmask.
   88  * Each regulatory domain entry in ah_regdomain_domains.h uses one
   89  * or more frequency band entries for each of the channel modes
   90  * supported (11bg, 11a, half, quarter, turbo, etc.)
   91  *
   92  */
   93 #include "ah_regdomain/ah_rd_freqbands.h"
   94 
   95 /*
   96  * This is the main regulatory database. It defines the supported
   97  * set of features and requirements for each of the defined regulatory
   98  * zones. It uses combinations of frequency ranges - represented in
   99  * a bitmask - to determine the requirements and limitations needed.
  100  */
  101 #include "ah_regdomain/ah_rd_domains.h"
  102 
  103 static const struct cmode modes[] = {
  104         { HAL_MODE_TURBO,       IEEE80211_CHAN_ST,      &regDmn5GhzTurboFreq[0] },
  105         { HAL_MODE_11A,         IEEE80211_CHAN_A,       &regDmn5GhzFreq[0] },
  106         { HAL_MODE_11B,         IEEE80211_CHAN_B,       &regDmn2GhzFreq[0] },
  107         { HAL_MODE_11G,         IEEE80211_CHAN_G,       &regDmn2Ghz11gFreq[0] },
  108         { HAL_MODE_11G_TURBO,   IEEE80211_CHAN_108G,    &regDmn2Ghz11gTurboFreq[0] },
  109         { HAL_MODE_11A_TURBO,   IEEE80211_CHAN_108A,    &regDmn5GhzTurboFreq[0] },
  110         { HAL_MODE_11A_QUARTER_RATE,
  111           IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER,    &regDmn5GhzFreq[0] },
  112         { HAL_MODE_11A_HALF_RATE,
  113           IEEE80211_CHAN_A | IEEE80211_CHAN_HALF,       &regDmn5GhzFreq[0] },
  114         { HAL_MODE_11G_QUARTER_RATE,
  115           IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER,    &regDmn2Ghz11gFreq[0] },
  116         { HAL_MODE_11G_HALF_RATE,
  117           IEEE80211_CHAN_G | IEEE80211_CHAN_HALF,       &regDmn2Ghz11gFreq[0] },
  118         { HAL_MODE_11NG_HT20,
  119           IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,       &regDmn2Ghz11gFreq[0] },
  120         { HAL_MODE_11NG_HT40PLUS,
  121           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,      &regDmn2Ghz11gFreq[0] },
  122         { HAL_MODE_11NG_HT40MINUS,
  123           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,      &regDmn2Ghz11gFreq[0] },
  124         { HAL_MODE_11NA_HT20,
  125           IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,       &regDmn5GhzFreq[0] },
  126         { HAL_MODE_11NA_HT40PLUS,
  127           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,      &regDmn5GhzFreq[0] },
  128         { HAL_MODE_11NA_HT40MINUS,
  129           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,      &regDmn5GhzFreq[0] },
  130 };
  131 
  132 static void ath_hal_update_dfsdomain(struct ath_hal *ah);
  133 
  134 static OS_INLINE uint16_t
  135 getEepromRD(struct ath_hal *ah)
  136 {
  137         return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG;
  138 }
  139 
  140 /*
  141  * Test to see if the bitmask array is all zeros
  142  */
  143 static HAL_BOOL
  144 isChanBitMaskZero(const uint64_t *bitmask)
  145 {
  146 #if BMLEN > 2
  147 #error  "add more cases"
  148 #endif
  149 #if BMLEN > 1
  150         if (bitmask[1] != 0)
  151                 return AH_FALSE;
  152 #endif
  153         return (bitmask[0] == 0);
  154 }
  155 
  156 /*
  157  * Return whether or not the regulatory domain/country in EEPROM
  158  * is acceptable.
  159  */
  160 static HAL_BOOL
  161 isEepromValid(struct ath_hal *ah)
  162 {
  163         uint16_t rd = getEepromRD(ah);
  164         int i;
  165 
  166         if (rd & COUNTRY_ERD_FLAG) {
  167                 uint16_t cc = rd &~ COUNTRY_ERD_FLAG;
  168                 for (i = 0; i < N(allCountries); i++)
  169                         if (allCountries[i].countryCode == cc)
  170                                 return AH_TRUE;
  171         } else {
  172                 for (i = 0; i < N(regDomainPairs); i++)
  173                         if (regDomainPairs[i].regDmnEnum == rd)
  174                                 return AH_TRUE;
  175         }
  176 
  177         if (rd == FCC_UBNT) {
  178                 return AH_TRUE;
  179         }
  180 
  181         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  182             "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
  183         return AH_FALSE;
  184 }
  185 
  186 /*
  187  * Find the pointer to the country element in the country table
  188  * corresponding to the country code
  189  */
  190 static COUNTRY_CODE_TO_ENUM_RD*
  191 findCountry(HAL_CTRY_CODE countryCode)
  192 {
  193         int i;
  194 
  195         for (i = 0; i < N(allCountries); i++) {
  196                 if (allCountries[i].countryCode == countryCode)
  197                         return &allCountries[i];
  198         }
  199         return AH_NULL;
  200 }
  201 
  202 static REG_DOMAIN *
  203 findRegDmn(int regDmn)
  204 {
  205         int i;
  206 
  207         for (i = 0; i < N(regDomains); i++) {
  208                 if (regDomains[i].regDmnEnum == regDmn)
  209                         return &regDomains[i];
  210         }
  211         return AH_NULL;
  212 }
  213 
  214 static REG_DMN_PAIR_MAPPING *
  215 findRegDmnPair(int regDmnPair)
  216 {
  217         int i;
  218 
  219         if (regDmnPair != NO_ENUMRD) {
  220                 for (i = 0; i < N(regDomainPairs); i++) {
  221                         if (regDomainPairs[i].regDmnEnum == regDmnPair)
  222                                 return &regDomainPairs[i];
  223                 }
  224         }
  225         return AH_NULL;
  226 }
  227 
  228 /*
  229  * Calculate a default country based on the EEPROM setting.
  230  */
  231 static HAL_CTRY_CODE
  232 getDefaultCountry(struct ath_hal *ah)
  233 {
  234         REG_DMN_PAIR_MAPPING *regpair;
  235         uint16_t rd;
  236 
  237         rd = getEepromRD(ah);
  238         if (rd & COUNTRY_ERD_FLAG) {
  239                 COUNTRY_CODE_TO_ENUM_RD *country;
  240                 uint16_t cc = rd & ~COUNTRY_ERD_FLAG;
  241                 country = findCountry(cc);
  242                 if (country != AH_NULL)
  243                         return cc;
  244         }
  245         /*
  246          * Check reg domains that have only one country
  247          */
  248         regpair = findRegDmnPair(rd);
  249         return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT;
  250 }
  251 
  252 static HAL_BOOL
  253 IS_BIT_SET(int bit, const uint64_t bitmask[])
  254 {
  255         int byteOffset, bitnum;
  256         uint64_t val;
  257 
  258         byteOffset = bit/64;
  259         bitnum = bit - byteOffset*64;
  260         val = ((uint64_t) 1) << bitnum;
  261         return (bitmask[byteOffset] & val) != 0;
  262 }
  263 
  264 static HAL_STATUS
  265 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
  266     COUNTRY_CODE_TO_ENUM_RD **pcountry,
  267     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
  268 {
  269         COUNTRY_CODE_TO_ENUM_RD *country;
  270         REG_DOMAIN *rd5GHz, *rd2GHz;
  271 
  272         if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) {
  273                 /*
  274                  * Validate the EEPROM setting and setup defaults
  275                  */
  276                 if (!isEepromValid(ah)) {
  277                         /*
  278                          * Don't return any channels if the EEPROM has an
  279                          * invalid regulatory domain/country code setting.
  280                          */
  281                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  282                             "%s: invalid EEPROM contents\n",__func__);
  283                         return HAL_EEBADREG;
  284                 }
  285 
  286                 cc = getDefaultCountry(ah);
  287                 country = findCountry(cc);
  288                 if (country == AH_NULL) {
  289                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  290                             "NULL Country!, cc %d\n", cc);
  291                         return HAL_EEBADCC;
  292                 }
  293                 regDmn = country->regDmnEnum;
  294                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n",
  295                     __func__, cc, regDmn);
  296 
  297                 if (country->countryCode == CTRY_DEFAULT) {
  298                         /*
  299                          * Check EEPROM; SKU may be for a country, single
  300                          * domain, or multiple domains (WWR).
  301                          */
  302                         uint16_t rdnum = getEepromRD(ah);
  303                         if ((rdnum & COUNTRY_ERD_FLAG) == 0 &&
  304                             (findRegDmn(rdnum) != AH_NULL ||
  305                              findRegDmnPair(rdnum) != AH_NULL)) {
  306                                 regDmn = rdnum;
  307                                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  308                                     "%s: EEPROM rd 0x%x\n", __func__, rdnum);
  309                         }
  310                 }
  311         } else {
  312                 country = findCountry(cc);
  313                 if (country == AH_NULL) {
  314                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  315                             "unknown country, cc %d\n", cc);
  316                         return HAL_EINVAL;
  317                 }
  318                 if (regDmn == SKU_NONE)
  319                         regDmn = country->regDmnEnum;
  320                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n",
  321                     __func__, cc, regDmn);
  322         }
  323 
  324         /*
  325          * Setup per-band state.
  326          */
  327         if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
  328                 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn);
  329                 if (regpair == AH_NULL) {
  330                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  331                             "%s: no reg domain pair %u for country %u\n",
  332                             __func__, regDmn, country->countryCode);
  333                         return HAL_EINVAL;
  334                 }
  335                 rd5GHz = findRegDmn(regpair->regDmn5GHz);
  336                 if (rd5GHz == AH_NULL) {
  337                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  338                             "%s: no 5GHz reg domain %u for country %u\n",
  339                             __func__, regpair->regDmn5GHz, country->countryCode);
  340                         return HAL_EINVAL;
  341                 }
  342                 rd2GHz = findRegDmn(regpair->regDmn2GHz);
  343                 if (rd2GHz == AH_NULL) {
  344                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  345                             "%s: no 2GHz reg domain %u for country %u\n",
  346                             __func__, regpair->regDmn2GHz, country->countryCode);
  347                         return HAL_EINVAL;
  348                 }
  349         } else {
  350                 rd5GHz = rd2GHz = findRegDmn(regDmn);
  351                 if (rd2GHz == AH_NULL) {
  352                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  353                             "%s: no unitary reg domain %u for country %u\n",
  354                             __func__, regDmn, country->countryCode);
  355                         return HAL_EINVAL;
  356                 }
  357         }
  358         if (pcountry != AH_NULL)
  359                 *pcountry = country;
  360         *prd2GHz = rd2GHz;
  361         *prd5GHz = rd5GHz;
  362         return HAL_OK;
  363 }
  364 
  365 static uint64_t *
  366 getchannelBM(u_int mode, REG_DOMAIN *rd)
  367 {
  368         switch (mode) {
  369         case HAL_MODE_11B:
  370                 return (rd->chan11b);
  371         case HAL_MODE_11G_QUARTER_RATE:
  372                 return (rd->chan11g_quarter);
  373         case HAL_MODE_11G_HALF_RATE:
  374                 return (rd->chan11g_half);
  375         case HAL_MODE_11G:
  376         case HAL_MODE_11NG_HT20:
  377         case HAL_MODE_11NG_HT40PLUS:
  378         case HAL_MODE_11NG_HT40MINUS:
  379                 return (rd->chan11g);
  380         case HAL_MODE_11G_TURBO:
  381                 return (rd->chan11g_turbo);
  382         case HAL_MODE_11A_QUARTER_RATE:
  383                 return (rd->chan11a_quarter);
  384         case HAL_MODE_11A_HALF_RATE:
  385                 return (rd->chan11a_half);
  386         case HAL_MODE_11A:
  387         case HAL_MODE_11NA_HT20:
  388         case HAL_MODE_11NA_HT40PLUS:
  389         case HAL_MODE_11NA_HT40MINUS:
  390                 return (rd->chan11a);
  391         case HAL_MODE_TURBO:
  392                 return (rd->chan11a_turbo);
  393         case HAL_MODE_11A_TURBO:
  394                 return (rd->chan11a_dyn_turbo);
  395         default:
  396                 return (AH_NULL);
  397         }
  398 }
  399 
  400 static void
  401 setchannelflags(struct ieee80211_channel *c, REG_DMN_FREQ_BAND *fband,
  402     REG_DOMAIN *rd)
  403 {
  404         if (fband->usePassScan & rd->pscan)
  405                 c->ic_flags |= IEEE80211_CHAN_PASSIVE;
  406         if (fband->useDfs & rd->dfsMask)
  407                 c->ic_flags |= IEEE80211_CHAN_DFS;
  408         if (IEEE80211_IS_CHAN_5GHZ(c) && (rd->flags & DISALLOW_ADHOC_11A))
  409                 c->ic_flags |= IEEE80211_CHAN_NOADHOC;
  410         if (IEEE80211_IS_CHAN_TURBO(c) &&
  411             (rd->flags & DISALLOW_ADHOC_11A_TURB))
  412                 c->ic_flags |= IEEE80211_CHAN_NOADHOC;
  413         if (rd->flags & NO_HOSTAP)
  414                 c->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
  415         if (rd->flags & LIMIT_FRAME_4MS)
  416                 c->ic_flags |= IEEE80211_CHAN_4MSXMIT;
  417         if (rd->flags & NEED_NFC)
  418                 c->ic_flags |= CHANNEL_NFCREQUIRED;
  419 }
  420 
  421 static int
  422 addchan(struct ath_hal *ah, struct ieee80211_channel chans[],
  423     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags,
  424     REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
  425 {
  426         struct ieee80211_channel *c;
  427 
  428         if (*nchans >= maxchans)
  429                 return (HAL_ENOMEM);
  430 
  431         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  432             "%s: %d: freq=%d, flags=0x%08x\n",
  433             __func__, *nchans, (int) freq, flags);
  434 
  435         c = &chans[(*nchans)++];
  436         c->ic_freq = freq;
  437         c->ic_flags = flags;
  438         setchannelflags(c, fband, rd);
  439         c->ic_maxregpower = fband->powerDfs;
  440         ath_hal_getpowerlimits(ah, c);
  441         c->ic_maxantgain = fband->antennaMax;
  442 
  443         return (0);
  444 }
  445 
  446 static int
  447 copychan_prev(struct ath_hal *ah, struct ieee80211_channel chans[],
  448     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags)
  449 {
  450         struct ieee80211_channel *c;
  451 
  452         if (*nchans == 0)
  453                 return (HAL_EINVAL);
  454 
  455         if (*nchans >= maxchans)
  456                 return (HAL_ENOMEM);
  457 
  458         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  459             "%s: %d: freq=%d, flags=0x%08x\n",
  460             __func__, *nchans, (int) freq, flags);
  461 
  462         c = &chans[(*nchans)++];
  463         c[0] = c[-1];
  464         c->ic_freq = freq;
  465         /* XXX is it needed here? */
  466         ath_hal_getpowerlimits(ah, c);
  467 
  468         return (0);
  469 }
  470 
  471 static int
  472 add_chanlist_band(struct ath_hal *ah, struct ieee80211_channel chans[],
  473     int maxchans, int *nchans, uint16_t freq_lo, uint16_t freq_hi, int step,
  474     uint32_t flags, REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
  475 {
  476         uint16_t freq = freq_lo;
  477         int error;
  478 
  479         if (freq_hi < freq_lo)
  480                 return (0);
  481 
  482         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  483             "%s: freq=%d..%d, flags=0x%08x, step=%d\n", __func__,
  484             (int) freq_lo, (int) freq_hi, flags, step);
  485 
  486         error = addchan(ah, chans, maxchans, nchans, freq, flags, fband, rd);
  487         for (freq += step; freq <= freq_hi && error == 0; freq += step)
  488                 error = copychan_prev(ah, chans, maxchans, nchans, freq, flags);
  489 
  490         return (error);
  491 }
  492 
  493 static void
  494 adj_freq_ht40(u_int mode, int *low_adj, int *hi_adj, int *channelSep)
  495 {
  496 
  497         *low_adj = *hi_adj = *channelSep = 0;
  498         switch (mode) {
  499         case HAL_MODE_11NA_HT40PLUS:
  500                 *channelSep = 40;
  501                 /* FALLTHROUGH */
  502         case HAL_MODE_11NG_HT40PLUS:
  503                 *hi_adj = -20;
  504                 break;
  505         case HAL_MODE_11NA_HT40MINUS:
  506                 *channelSep = 40;
  507                 /* FALLTHROUGH */
  508         case HAL_MODE_11NG_HT40MINUS:
  509                 *low_adj = 20;
  510                 break;
  511         }
  512 }
  513 
  514 static void
  515 add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[],
  516     u_int maxchans, int *nchans, const struct cmode *cm, REG_DOMAIN *rd,
  517     HAL_BOOL enableExtendedChannels)
  518 {
  519         uint64_t *channelBM;
  520         uint16_t freq_lo, freq_hi;
  521         int b, error, low_adj, hi_adj, channelSep;
  522 
  523         if (!ath_hal_getChannelEdges(ah, cm->flags, &freq_lo, &freq_hi)) {
  524                 /* channel not supported by hardware, skip it */
  525                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  526                     "%s: channels 0x%x not supported by hardware\n",
  527                     __func__, cm->flags);
  528                 return;
  529         }
  530 
  531         channelBM = getchannelBM(cm->mode, rd);
  532         if (isChanBitMaskZero(channelBM))
  533                 return;
  534 
  535         /*
  536          * Setup special handling for HT40 channels; e.g.
  537          * 5G HT40 channels require 40Mhz channel separation.
  538          */
  539         adj_freq_ht40(cm->mode, &low_adj, &hi_adj, &channelSep);
  540 
  541         for (b = 0; b < 64*BMLEN; b++) {
  542                 REG_DMN_FREQ_BAND *fband;
  543                 uint16_t bfreq_lo, bfreq_hi;
  544                 int step;
  545 
  546                 if (!IS_BIT_SET(b, channelBM))
  547                         continue;
  548                 fband = &cm->freqs[b];
  549 
  550                 if ((fband->usePassScan & IS_ECM_CHAN) &&
  551                     !enableExtendedChannels) {
  552                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  553                             "skip ecm channels\n");
  554                         continue;
  555                 }
  556 #if 0
  557                 if ((fband->useDfs & rd->dfsMask) && 
  558                     (cm->flags & IEEE80211_CHAN_HT40)) {
  559                         /* NB: DFS and HT40 don't mix */
  560                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  561                             "skip HT40 chan, DFS required\n");
  562                         continue;
  563                 }
  564 #endif
  565                 /*
  566                  * XXX TODO: handle REG_EXT_FCC_CH_144.
  567                  *
  568                  * Figure out which instances/uses cause us to not
  569                  * be allowed to use channel 144 (pri or sec overlap.)
  570                  */
  571 
  572                 bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo);
  573                 bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi);
  574 
  575                 /*
  576                  * Don't start the 5GHz channel list at 5120MHz.
  577                  *
  578                  * Unfortunately (sigh) the HT40 channel creation
  579                  * logic will create HT40U channels at 5120, 5160, 5200.
  580                  * This means that 36 (5180) isn't considered as a
  581                  * HT40 channel, and everything goes messed up from there.
  582                  */
  583                 if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
  584                     (cm->flags & IEEE80211_CHAN_HT40U)) {
  585                         if (bfreq_lo < 5180)
  586                                 bfreq_lo = 5180;
  587                 }
  588 
  589                 /*
  590                  * Same with HT40D - need to start at 5200 or the low
  591                  * channels are all wrong again.
  592                  */
  593                 if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
  594                     (cm->flags & IEEE80211_CHAN_HT40D)) {
  595                         if (bfreq_lo < 5200)
  596                                 bfreq_lo = 5200;
  597                 }
  598 
  599                 if (fband->channelSep >= channelSep)
  600                         step = fband->channelSep;
  601                 else
  602                         step = roundup(channelSep, fband->channelSep);
  603 
  604                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  605                     "%s: freq_lo=%d, freq_hi=%d, low_adj=%d, hi_adj=%d, "
  606                     "bandlo=%d, bandhi=%d, bfreqlo=%d, bfreqhi=%d, step=%d, "
  607                     "flags=0x%08x\n",
  608                     __func__,
  609                     (int) freq_lo,
  610                     (int) freq_hi,
  611                     (int) low_adj,
  612                     (int) hi_adj,
  613                     (int) fband->lowChannel,
  614                     (int) fband->highChannel,
  615                     (int) bfreq_lo,
  616                     (int) bfreq_hi,
  617                     step,
  618                     (int) cm->flags);
  619 
  620                 error = add_chanlist_band(ah, chans, maxchans, nchans,
  621                     bfreq_lo, bfreq_hi, step, cm->flags, fband, rd);
  622                 if (error != 0) {
  623                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  624                             "%s: too many channels for channel table\n",
  625                             __func__);
  626                         return;
  627                 }
  628         }
  629 }
  630 
  631 static u_int
  632 getmodesmask(struct ath_hal *ah, REG_DOMAIN *rd5GHz, u_int modeSelect)
  633 {
  634 #define HAL_MODE_11A_ALL \
  635         (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
  636          HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
  637         u_int modesMask;
  638 
  639         /* get modes that HW is capable of */
  640         modesMask = ath_hal_getWirelessModes(ah);
  641         modesMask &= modeSelect;
  642         /* optimize work below if no 11a channels */
  643         if (isChanBitMaskZero(rd5GHz->chan11a) &&
  644             (modesMask & HAL_MODE_11A_ALL)) {
  645                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  646                     "%s: disallow all 11a\n", __func__);
  647                 modesMask &= ~HAL_MODE_11A_ALL;
  648         }
  649 
  650         return (modesMask);
  651 #undef HAL_MODE_11A_ALL
  652 }
  653 
  654 /*
  655  * Construct the channel list for the specified regulatory config.
  656  */
  657 static HAL_STATUS
  658 getchannels(struct ath_hal *ah,
  659     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
  660     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
  661     HAL_BOOL enableExtendedChannels,
  662     COUNTRY_CODE_TO_ENUM_RD **pcountry,
  663     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
  664 {
  665         REG_DOMAIN *rd5GHz, *rd2GHz;
  666         u_int modesMask;
  667         const struct cmode *cm;
  668         HAL_STATUS status;
  669 
  670         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
  671             __func__, cc, regDmn, modeSelect, 
  672             enableExtendedChannels ? " ecm" : "");
  673 
  674         status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
  675         if (status != HAL_OK)
  676                 return status;
  677 
  678         modesMask = getmodesmask(ah, rd5GHz, modeSelect);
  679         /* XXX error? */
  680         if (modesMask == 0)
  681                 goto done;
  682 
  683         for (cm = modes; cm < &modes[N(modes)]; cm++) {
  684                 REG_DOMAIN *rd;
  685 
  686                 if ((cm->mode & modesMask) == 0) {
  687                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  688                             "%s: skip mode 0x%x flags 0x%x\n",
  689                             __func__, cm->mode, cm->flags);
  690                         continue;
  691                 }
  692 
  693                 if (cm->flags & IEEE80211_CHAN_5GHZ)
  694                         rd = rd5GHz;
  695                 else if (cm->flags & IEEE80211_CHAN_2GHZ)
  696                         rd = rd2GHz;
  697                 else {
  698                         ath_hal_printf(ah, "%s: Unknown HAL flags 0x%x\n",
  699                             __func__, cm->flags);
  700                         return HAL_EINVAL;
  701                 }
  702 
  703                 add_chanlist_mode(ah, chans, maxchans, nchans, cm,
  704                     rd, enableExtendedChannels);
  705                 if (*nchans >= maxchans)
  706                         goto done;
  707         }
  708 done:
  709         /* NB: pcountry set above by getregstate */
  710         if (prd2GHz != AH_NULL)
  711                 *prd2GHz = rd2GHz;
  712         if (prd5GHz != AH_NULL)
  713                 *prd5GHz = rd5GHz;
  714         return HAL_OK;
  715 }
  716 
  717 /*
  718  * Retrieve a channel list without affecting runtime state.
  719  */
  720 HAL_STATUS
  721 ath_hal_getchannels(struct ath_hal *ah,
  722     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
  723     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
  724     HAL_BOOL enableExtendedChannels)
  725 {
  726         return getchannels(ah, chans, maxchans, nchans, modeSelect,
  727             cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
  728 }
  729 
  730 /*
  731  * Handle frequency mapping from 900Mhz range to 2.4GHz range
  732  * for GSM radios.  This is done when we need the h/w frequency
  733  * and the channel is marked IEEE80211_CHAN_GSM.
  734  */
  735 static int
  736 ath_hal_mapgsm(int sku, int freq)
  737 {
  738         if (sku == SKU_XR9)
  739                 return 1520 + freq;
  740         if (sku == SKU_GZ901)
  741                 return 1544 + freq;
  742         if (sku == SKU_SR9)
  743                 return 3344 - freq;
  744         if (sku == SKU_XC900M)
  745                 return 1517 + freq;
  746         HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
  747             "%s: cannot map freq %u unknown gsm sku %u\n",
  748             __func__, freq, sku);
  749         return freq;
  750 }
  751 
  752 /*
  753  * Setup the internal/private channel state given a table of
  754  * net80211 channels.  We collapse entries for the same frequency
  755  * and record the frequency for doing noise floor processing
  756  * where we don't have net80211 channel context.
  757  */
  758 static HAL_BOOL
  759 assignPrivateChannels(struct ath_hal *ah,
  760         struct ieee80211_channel chans[], int nchans, int sku)
  761 {
  762         HAL_CHANNEL_INTERNAL *ic;
  763         int i, j, next, freq;
  764 
  765         next = 0;
  766         for (i = 0; i < nchans; i++) {
  767                 struct ieee80211_channel *c = &chans[i];
  768                 for (j = i-1; j >= 0; j--)
  769                         if (chans[j].ic_freq == c->ic_freq) {
  770                                 c->ic_devdata = chans[j].ic_devdata;
  771                                 break;
  772                         }
  773                 if (j < 0) {
  774                         /* new entry, assign a private channel entry */
  775                         if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
  776                                 HALDEBUG(ah, HAL_DEBUG_ANY,
  777                                     "%s: too many channels, max %zu\n",
  778                                     __func__, N(AH_PRIVATE(ah)->ah_channels));
  779                                 return AH_FALSE;
  780                         }
  781                         /*
  782                          * Handle frequency mapping for 900MHz devices.
  783                          * The hardware uses 2.4GHz frequencies that are
  784                          * down-converted.  The 802.11 layer uses the
  785                          * true frequencies.
  786                          */
  787                         freq = IEEE80211_IS_CHAN_GSM(c) ?
  788                             ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
  789 
  790                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
  791                             "%s: private[%3u] %u/0x%x -> channel %u\n",
  792                             __func__, next, c->ic_freq, c->ic_flags, freq);
  793 
  794                         ic = &AH_PRIVATE(ah)->ah_channels[next];
  795                         /*
  796                          * NB: This clears privFlags which means ancillary
  797                          *     code like ANI and IQ calibration will be
  798                          *     restarted and re-setup any per-channel state.
  799                          */
  800                         OS_MEMZERO(ic, sizeof(*ic));
  801                         ic->channel = freq;
  802                         c->ic_devdata = next;
  803                         next++;
  804                 }
  805         }
  806         AH_PRIVATE(ah)->ah_nchan = next;
  807         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
  808             __func__, nchans, next);
  809         return AH_TRUE;
  810 }
  811 
  812 /*
  813  * Setup the channel list based on the information in the EEPROM.
  814  */
  815 HAL_STATUS
  816 ath_hal_init_channels(struct ath_hal *ah,
  817     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
  818     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
  819     HAL_BOOL enableExtendedChannels)
  820 {
  821         COUNTRY_CODE_TO_ENUM_RD *country;
  822         REG_DOMAIN *rd5GHz, *rd2GHz;
  823         HAL_STATUS status;
  824 
  825         status = getchannels(ah, chans, maxchans, nchans, modeSelect,
  826             cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
  827         if (status == HAL_OK &&
  828             assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
  829                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
  830                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
  831 
  832                 ah->ah_countryCode = country->countryCode;
  833                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
  834                     __func__, ah->ah_countryCode);
  835 
  836                 /* Update current DFS domain */
  837                 ath_hal_update_dfsdomain(ah);
  838         } else
  839                 status = HAL_EINVAL;
  840 
  841         return status;
  842 }
  843 
  844 /*
  845  * Set the channel list.
  846  */
  847 HAL_STATUS
  848 ath_hal_set_channels(struct ath_hal *ah,
  849     struct ieee80211_channel chans[], int nchans,
  850     HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
  851 {
  852         COUNTRY_CODE_TO_ENUM_RD *country;
  853         REG_DOMAIN *rd5GHz, *rd2GHz;
  854         HAL_STATUS status;
  855 
  856         switch (rd) {
  857         case SKU_SR9:
  858         case SKU_XR9:
  859         case SKU_GZ901:
  860         case SKU_XC900M:
  861                 /*
  862                  * Map 900MHz sku's.  The frequencies will be mapped
  863                  * according to the sku to compensate for the down-converter.
  864                  * We use the FCC for these sku's as the mapped channel
  865                  * list is known compatible (will need to change if/when
  866                  * vendors do different mapping in different locales).
  867                  */
  868                 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
  869                     &country, &rd2GHz, &rd5GHz);
  870                 break;
  871         default:
  872                 status = getregstate(ah, cc, rd,
  873                     &country, &rd2GHz, &rd5GHz);
  874                 rd = AH_PRIVATE(ah)->ah_currentRD;
  875                 break;
  876         }
  877         if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
  878                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
  879                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
  880 
  881                 ah->ah_countryCode = country->countryCode;
  882                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
  883                     __func__, ah->ah_countryCode);
  884         } else
  885                 status = HAL_EINVAL;
  886 
  887         if (status == HAL_OK) {
  888                 /* Update current DFS domain */
  889                 (void) ath_hal_update_dfsdomain(ah);
  890         }
  891         return status;
  892 }
  893 
  894 #ifdef AH_DEBUG
  895 /*
  896  * Return the internal channel corresponding to a public channel.
  897  * NB: normally this routine is inline'd (see ah_internal.h)
  898  */
  899 HAL_CHANNEL_INTERNAL *
  900 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
  901 {
  902         HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
  903 
  904         if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
  905             (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
  906                 return cc;
  907         if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
  908                 HALDEBUG(ah, HAL_DEBUG_ANY,
  909                     "%s: bad mapping, devdata %u nchans %u\n",
  910                    __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
  911                 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
  912         } else {
  913                 HALDEBUG(ah, HAL_DEBUG_ANY,
  914                     "%s: no match for %u/0x%x devdata %u channel %u\n",
  915                    __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
  916                    cc->channel);
  917                 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
  918         }
  919         return AH_NULL;
  920 }
  921 #endif /* AH_DEBUG */
  922 
  923 #define isWwrSKU(_ah) \
  924         ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
  925           getEepromRD(_ah) == WORLD)
  926 
  927 /*
  928  * Return the test group for the specific channel based on
  929  * the current regulatory setup.
  930  */
  931 u_int
  932 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
  933 {
  934         u_int ctl;
  935 
  936         if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
  937             (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
  938                 ctl = SD_NO_CTL;
  939         else if (IEEE80211_IS_CHAN_2GHZ(c))
  940                 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
  941         else
  942                 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
  943         if (IEEE80211_IS_CHAN_B(c))
  944                 return ctl | CTL_11B;
  945         if (IEEE80211_IS_CHAN_G(c))
  946                 return ctl | CTL_11G;
  947         if (IEEE80211_IS_CHAN_108G(c))
  948                 return ctl | CTL_108G;
  949         if (IEEE80211_IS_CHAN_TURBO(c))
  950                 return ctl | CTL_TURBO;
  951         if (IEEE80211_IS_CHAN_A(c))
  952                 return ctl | CTL_11A;
  953         return ctl;
  954 }
  955 
  956 /*
  957  * Update the current dfsDomain setting based on the given
  958  * country code.
  959  *
  960  * Since FreeBSD/net80211 allows the channel set to change
  961  * after the card has been setup (via ath_hal_init_channels())
  962  * this function method is needed to update ah_dfsDomain.
  963  */
  964 void
  965 ath_hal_update_dfsdomain(struct ath_hal *ah)
  966 {
  967         const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz;
  968         HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN;
  969 
  970         if (rd5GHz->dfsMask & DFS_FCC3)
  971                 dfsDomain = HAL_DFS_FCC_DOMAIN;
  972         if (rd5GHz->dfsMask & DFS_ETSI)
  973                 dfsDomain = HAL_DFS_ETSI_DOMAIN;
  974         if (rd5GHz->dfsMask & DFS_MKK4)
  975                 dfsDomain = HAL_DFS_MKK4_DOMAIN;
  976         AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain;
  977         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n",
  978             __func__, AH_PRIVATE(ah)->ah_dfsDomain);
  979 }
  980 
  981 /*
  982  * Return the max allowed antenna gain and apply any regulatory
  983  * domain specific changes.
  984  *
  985  * NOTE: a negative reduction is possible in RD's that only
  986  * measure radiated power (e.g., ETSI) which would increase
  987  * that actual conducted output power (though never beyond
  988  * the calibrated target power).
  989  */
  990 u_int
  991 ath_hal_getantennareduction(struct ath_hal *ah,
  992     const struct ieee80211_channel *chan, u_int twiceGain)
  993 {
  994         int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
  995         return (antennaMax < 0) ? 0 : antennaMax;
  996 }

Cache object: b6759ac2c9a30e718c6ead0d28208d8d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.