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