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 OS_INLINE uint16_t 129 getEepromRD(struct ath_hal *ah) 130 { 131 return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG; 132 } 133 134 /* 135 * Test to see if the bitmask array is all zeros 136 */ 137 static HAL_BOOL 138 isChanBitMaskZero(const uint64_t *bitmask) 139 { 140 #if BMLEN > 2 141 #error "add more cases" 142 #endif 143 #if BMLEN > 1 144 if (bitmask[1] != 0) 145 return AH_FALSE; 146 #endif 147 return (bitmask[0] == 0); 148 } 149 150 /* 151 * Return whether or not the regulatory domain/country in EEPROM 152 * is acceptable. 153 */ 154 static HAL_BOOL 155 isEepromValid(struct ath_hal *ah) 156 { 157 uint16_t rd = getEepromRD(ah); 158 int i; 159 160 if (rd & COUNTRY_ERD_FLAG) { 161 uint16_t cc = rd &~ COUNTRY_ERD_FLAG; 162 for (i = 0; i < N(allCountries); i++) 163 if (allCountries[i].countryCode == cc) 164 return AH_TRUE; 165 } else { 166 for (i = 0; i < N(regDomainPairs); i++) 167 if (regDomainPairs[i].regDmnEnum == rd) 168 return AH_TRUE; 169 } 170 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 171 "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd); 172 return AH_FALSE; 173 } 174 175 /* 176 * Find the pointer to the country element in the country table 177 * corresponding to the country code 178 */ 179 static COUNTRY_CODE_TO_ENUM_RD* 180 findCountry(HAL_CTRY_CODE countryCode) 181 { 182 int i; 183 184 for (i = 0; i < N(allCountries); i++) { 185 if (allCountries[i].countryCode == countryCode) 186 return &allCountries[i]; 187 } 188 return AH_NULL; 189 } 190 191 static REG_DOMAIN * 192 findRegDmn(int regDmn) 193 { 194 int i; 195 196 for (i = 0; i < N(regDomains); i++) { 197 if (regDomains[i].regDmnEnum == regDmn) 198 return ®Domains[i]; 199 } 200 return AH_NULL; 201 } 202 203 static REG_DMN_PAIR_MAPPING * 204 findRegDmnPair(int regDmnPair) 205 { 206 int i; 207 208 if (regDmnPair != NO_ENUMRD) { 209 for (i = 0; i < N(regDomainPairs); i++) { 210 if (regDomainPairs[i].regDmnEnum == regDmnPair) 211 return ®DomainPairs[i]; 212 } 213 } 214 return AH_NULL; 215 } 216 217 /* 218 * Calculate a default country based on the EEPROM setting. 219 */ 220 static HAL_CTRY_CODE 221 getDefaultCountry(struct ath_hal *ah) 222 { 223 REG_DMN_PAIR_MAPPING *regpair; 224 uint16_t rd; 225 226 rd = getEepromRD(ah); 227 if (rd & COUNTRY_ERD_FLAG) { 228 COUNTRY_CODE_TO_ENUM_RD *country; 229 uint16_t cc = rd & ~COUNTRY_ERD_FLAG; 230 country = findCountry(cc); 231 if (country != AH_NULL) 232 return cc; 233 } 234 /* 235 * Check reg domains that have only one country 236 */ 237 regpair = findRegDmnPair(rd); 238 return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT; 239 } 240 241 static HAL_BOOL 242 IS_BIT_SET(int bit, const uint64_t bitmask[]) 243 { 244 int byteOffset, bitnum; 245 uint64_t val; 246 247 byteOffset = bit/64; 248 bitnum = bit - byteOffset*64; 249 val = ((uint64_t) 1) << bitnum; 250 return (bitmask[byteOffset] & val) != 0; 251 } 252 253 static HAL_STATUS 254 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 255 COUNTRY_CODE_TO_ENUM_RD **pcountry, 256 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz) 257 { 258 COUNTRY_CODE_TO_ENUM_RD *country; 259 REG_DOMAIN *rd5GHz, *rd2GHz; 260 261 if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) { 262 /* 263 * Validate the EEPROM setting and setup defaults 264 */ 265 if (!isEepromValid(ah)) { 266 /* 267 * Don't return any channels if the EEPROM has an 268 * invalid regulatory domain/country code setting. 269 */ 270 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 271 "%s: invalid EEPROM contents\n",__func__); 272 return HAL_EEBADREG; 273 } 274 275 cc = getDefaultCountry(ah); 276 country = findCountry(cc); 277 if (country == AH_NULL) { 278 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 279 "NULL Country!, cc %d\n", cc); 280 return HAL_EEBADCC; 281 } 282 regDmn = country->regDmnEnum; 283 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n", 284 __func__, cc, regDmn); 285 286 if (country->countryCode == CTRY_DEFAULT) { 287 /* 288 * Check EEPROM; SKU may be for a country, single 289 * domain, or multiple domains (WWR). 290 */ 291 uint16_t rdnum = getEepromRD(ah); 292 if ((rdnum & COUNTRY_ERD_FLAG) == 0 && 293 (findRegDmn(rdnum) != AH_NULL || 294 findRegDmnPair(rdnum) != AH_NULL)) { 295 regDmn = rdnum; 296 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 297 "%s: EEPROM rd 0x%x\n", __func__, rdnum); 298 } 299 } 300 } else { 301 country = findCountry(cc); 302 if (country == AH_NULL) { 303 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 304 "unknown country, cc %d\n", cc); 305 return HAL_EINVAL; 306 } 307 if (regDmn == SKU_NONE) 308 regDmn = country->regDmnEnum; 309 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n", 310 __func__, cc, regDmn); 311 } 312 313 /* 314 * Setup per-band state. 315 */ 316 if ((regDmn & MULTI_DOMAIN_MASK) == 0) { 317 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn); 318 if (regpair == AH_NULL) { 319 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 320 "%s: no reg domain pair %u for country %u\n", 321 __func__, regDmn, country->countryCode); 322 return HAL_EINVAL; 323 } 324 rd5GHz = findRegDmn(regpair->regDmn5GHz); 325 if (rd5GHz == AH_NULL) { 326 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 327 "%s: no 5GHz reg domain %u for country %u\n", 328 __func__, regpair->regDmn5GHz, country->countryCode); 329 return HAL_EINVAL; 330 } 331 rd2GHz = findRegDmn(regpair->regDmn2GHz); 332 if (rd2GHz == AH_NULL) { 333 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 334 "%s: no 2GHz reg domain %u for country %u\n", 335 __func__, regpair->regDmn2GHz, country->countryCode); 336 return HAL_EINVAL; 337 } 338 } else { 339 rd5GHz = rd2GHz = findRegDmn(regDmn); 340 if (rd2GHz == AH_NULL) { 341 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 342 "%s: no unitary reg domain %u for country %u\n", 343 __func__, regDmn, country->countryCode); 344 return HAL_EINVAL; 345 } 346 } 347 if (pcountry != AH_NULL) 348 *pcountry = country; 349 *prd2GHz = rd2GHz; 350 *prd5GHz = rd5GHz; 351 return HAL_OK; 352 } 353 354 /* 355 * Construct the channel list for the specified regulatory config. 356 */ 357 static HAL_STATUS 358 getchannels(struct ath_hal *ah, 359 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 360 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 361 HAL_BOOL enableExtendedChannels, 362 COUNTRY_CODE_TO_ENUM_RD **pcountry, 363 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz) 364 { 365 #define CHANNEL_HALF_BW 10 366 #define CHANNEL_QUARTER_BW 5 367 #define HAL_MODE_11A_ALL \ 368 (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \ 369 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE) 370 REG_DOMAIN *rd5GHz, *rd2GHz; 371 u_int modesAvail; 372 const struct cmode *cm; 373 struct ieee80211_channel *ic; 374 int next, b; 375 HAL_STATUS status; 376 377 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n", 378 __func__, cc, regDmn, modeSelect, 379 enableExtendedChannels ? " ecm" : ""); 380 381 status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz); 382 if (status != HAL_OK) 383 return status; 384 385 /* get modes that HW is capable of */ 386 modesAvail = ath_hal_getWirelessModes(ah); 387 /* optimize work below if no 11a channels */ 388 if (isChanBitMaskZero(rd5GHz->chan11a) && 389 (modesAvail & HAL_MODE_11A_ALL)) { 390 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 391 "%s: disallow all 11a\n", __func__); 392 modesAvail &= ~HAL_MODE_11A_ALL; 393 } 394 395 next = 0; 396 ic = &chans[0]; 397 for (cm = modes; cm < &modes[N(modes)]; cm++) { 398 uint16_t c, c_hi, c_lo; 399 uint64_t *channelBM = AH_NULL; 400 REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs; 401 int low_adj, hi_adj, channelSep, lastc; 402 uint32_t rdflags; 403 uint64_t dfsMask; 404 uint64_t pscan; 405 406 if ((cm->mode & modeSelect) == 0) { 407 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 408 "%s: skip mode 0x%x flags 0x%x\n", 409 __func__, cm->mode, cm->flags); 410 continue; 411 } 412 if ((cm->mode & modesAvail) == 0) { 413 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 414 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n", 415 __func__, modesAvail, cm->mode, cm->flags); 416 continue; 417 } 418 if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) { 419 /* channel not supported by hardware, skip it */ 420 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 421 "%s: channels 0x%x not supported by hardware\n", 422 __func__,cm->flags); 423 continue; 424 } 425 switch (cm->mode) { 426 case HAL_MODE_TURBO: 427 case HAL_MODE_11A_TURBO: 428 rdflags = rd5GHz->flags; 429 dfsMask = rd5GHz->dfsMask; 430 pscan = rd5GHz->pscan; 431 if (cm->mode == HAL_MODE_TURBO) 432 channelBM = rd5GHz->chan11a_turbo; 433 else 434 channelBM = rd5GHz->chan11a_dyn_turbo; 435 freqs = ®Dmn5GhzTurboFreq[0]; 436 break; 437 case HAL_MODE_11G_TURBO: 438 rdflags = rd2GHz->flags; 439 dfsMask = rd2GHz->dfsMask; 440 pscan = rd2GHz->pscan; 441 channelBM = rd2GHz->chan11g_turbo; 442 freqs = ®Dmn2Ghz11gTurboFreq[0]; 443 break; 444 case HAL_MODE_11A: 445 case HAL_MODE_11A_HALF_RATE: 446 case HAL_MODE_11A_QUARTER_RATE: 447 case HAL_MODE_11NA_HT20: 448 case HAL_MODE_11NA_HT40PLUS: 449 case HAL_MODE_11NA_HT40MINUS: 450 rdflags = rd5GHz->flags; 451 dfsMask = rd5GHz->dfsMask; 452 pscan = rd5GHz->pscan; 453 if (cm->mode == HAL_MODE_11A_HALF_RATE) 454 channelBM = rd5GHz->chan11a_half; 455 else if (cm->mode == HAL_MODE_11A_QUARTER_RATE) 456 channelBM = rd5GHz->chan11a_quarter; 457 else 458 channelBM = rd5GHz->chan11a; 459 freqs = ®Dmn5GhzFreq[0]; 460 break; 461 case HAL_MODE_11B: 462 case HAL_MODE_11G: 463 case HAL_MODE_11G_HALF_RATE: 464 case HAL_MODE_11G_QUARTER_RATE: 465 case HAL_MODE_11NG_HT20: 466 case HAL_MODE_11NG_HT40PLUS: 467 case HAL_MODE_11NG_HT40MINUS: 468 rdflags = rd2GHz->flags; 469 dfsMask = rd2GHz->dfsMask; 470 pscan = rd2GHz->pscan; 471 if (cm->mode == HAL_MODE_11G_HALF_RATE) 472 channelBM = rd2GHz->chan11g_half; 473 else if (cm->mode == HAL_MODE_11G_QUARTER_RATE) 474 channelBM = rd2GHz->chan11g_quarter; 475 else if (cm->mode == HAL_MODE_11B) 476 channelBM = rd2GHz->chan11b; 477 else 478 channelBM = rd2GHz->chan11g; 479 if (cm->mode == HAL_MODE_11B) 480 freqs = ®Dmn2GhzFreq[0]; 481 else 482 freqs = ®Dmn2Ghz11gFreq[0]; 483 break; 484 default: 485 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 486 "%s: Unkonwn HAL mode 0x%x\n", __func__, cm->mode); 487 continue; 488 } 489 if (isChanBitMaskZero(channelBM)) 490 continue; 491 /* 492 * Setup special handling for HT40 channels; e.g. 493 * 5G HT40 channels require 40Mhz channel separation. 494 */ 495 hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS || 496 cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0; 497 low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || 498 cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0; 499 channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS || 500 cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0; 501 502 for (b = 0; b < 64*BMLEN; b++) { 503 if (!IS_BIT_SET(b, channelBM)) 504 continue; 505 fband = &freqs[b]; 506 lastc = 0; 507 508 for (c = fband->lowChannel + low_adj; 509 c <= fband->highChannel + hi_adj; 510 c += fband->channelSep) { 511 if (!(c_lo <= c && c <= c_hi)) { 512 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 513 "%s: c %u out of range [%u..%u]\n", 514 __func__, c, c_lo, c_hi); 515 continue; 516 } 517 if (next >= maxchans){ 518 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 519 "%s: too many channels for channel table\n", 520 __func__); 521 goto done; 522 } 523 if ((fband->usePassScan & IS_ECM_CHAN) && 524 !enableExtendedChannels) { 525 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 526 "skip ecm channel\n"); 527 continue; 528 } 529 if ((fband->useDfs & dfsMask) && 530 (cm->flags & IEEE80211_CHAN_HT40)) { 531 /* NB: DFS and HT40 don't mix */ 532 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 533 "skip HT40 chan, DFS required\n"); 534 continue; 535 } 536 /* 537 * Make sure that channel separation 538 * meets the requirement. 539 */ 540 if (lastc && channelSep && 541 (c-lastc) < channelSep) 542 continue; 543 lastc = c; 544 545 OS_MEMZERO(ic, sizeof(*ic)); 546 ic->ic_freq = c; 547 ic->ic_flags = cm->flags; 548 ic->ic_maxregpower = fband->powerDfs; 549 ath_hal_getpowerlimits(ah, ic); 550 ic->ic_maxantgain = fband->antennaMax; 551 if (fband->usePassScan & pscan) 552 ic->ic_flags |= IEEE80211_CHAN_PASSIVE; 553 if (fband->useDfs & dfsMask) 554 ic->ic_flags |= IEEE80211_CHAN_DFS; 555 if (IEEE80211_IS_CHAN_5GHZ(ic) && 556 (rdflags & DISALLOW_ADHOC_11A)) 557 ic->ic_flags |= IEEE80211_CHAN_NOADHOC; 558 if (IEEE80211_IS_CHAN_TURBO(ic) && 559 (rdflags & DISALLOW_ADHOC_11A_TURB)) 560 ic->ic_flags |= IEEE80211_CHAN_NOADHOC; 561 if (rdflags & NO_HOSTAP) 562 ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP; 563 if (rdflags & LIMIT_FRAME_4MS) 564 ic->ic_flags |= IEEE80211_CHAN_4MSXMIT; 565 if (rdflags & NEED_NFC) 566 ic->ic_flags |= CHANNEL_NFCREQUIRED; 567 568 ic++, next++; 569 } 570 } 571 } 572 done: 573 *nchans = next; 574 /* NB: pcountry set above by getregstate */ 575 if (prd2GHz != AH_NULL) 576 *prd2GHz = rd2GHz; 577 if (prd5GHz != AH_NULL) 578 *prd5GHz = rd5GHz; 579 return HAL_OK; 580 #undef HAL_MODE_11A_ALL 581 #undef CHANNEL_HALF_BW 582 #undef CHANNEL_QUARTER_BW 583 } 584 585 /* 586 * Retrieve a channel list without affecting runtime state. 587 */ 588 HAL_STATUS 589 ath_hal_getchannels(struct ath_hal *ah, 590 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 591 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 592 HAL_BOOL enableExtendedChannels) 593 { 594 return getchannels(ah, chans, maxchans, nchans, modeSelect, 595 cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL); 596 } 597 598 /* 599 * Handle frequency mapping from 900Mhz range to 2.4GHz range 600 * for GSM radios. This is done when we need the h/w frequency 601 * and the channel is marked IEEE80211_CHAN_GSM. 602 */ 603 static int 604 ath_hal_mapgsm(int sku, int freq) 605 { 606 if (sku == SKU_XR9) 607 return 1520 + freq; 608 if (sku == SKU_GZ901) 609 return 1544 + freq; 610 if (sku == SKU_SR9) 611 return 3344 - freq; 612 HALDEBUG(AH_NULL, HAL_DEBUG_ANY, 613 "%s: cannot map freq %u unknown gsm sku %u\n", 614 __func__, freq, sku); 615 return freq; 616 } 617 618 /* 619 * Setup the internal/private channel state given a table of 620 * net80211 channels. We collapse entries for the same frequency 621 * and record the frequency for doing noise floor processing 622 * where we don't have net80211 channel context. 623 */ 624 static HAL_BOOL 625 assignPrivateChannels(struct ath_hal *ah, 626 struct ieee80211_channel chans[], int nchans, int sku) 627 { 628 HAL_CHANNEL_INTERNAL *ic; 629 int i, j, next, freq; 630 631 next = 0; 632 for (i = 0; i < nchans; i++) { 633 struct ieee80211_channel *c = &chans[i]; 634 for (j = i-1; j >= 0; j--) 635 if (chans[j].ic_freq == c->ic_freq) { 636 c->ic_devdata = chans[j].ic_devdata; 637 break; 638 } 639 if (j < 0) { 640 /* new entry, assign a private channel entry */ 641 if (next >= N(AH_PRIVATE(ah)->ah_channels)) { 642 HALDEBUG(ah, HAL_DEBUG_ANY, 643 "%s: too many channels, max %zu\n", 644 __func__, N(AH_PRIVATE(ah)->ah_channels)); 645 return AH_FALSE; 646 } 647 /* 648 * Handle frequency mapping for 900MHz devices. 649 * The hardware uses 2.4GHz frequencies that are 650 * down-converted. The 802.11 layer uses the 651 * true frequencies. 652 */ 653 freq = IEEE80211_IS_CHAN_GSM(c) ? 654 ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq; 655 656 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 657 "%s: private[%3u] %u/0x%x -> channel %u\n", 658 __func__, next, c->ic_freq, c->ic_flags, freq); 659 660 ic = &AH_PRIVATE(ah)->ah_channels[next]; 661 /* 662 * NB: This clears privFlags which means ancillary 663 * code like ANI and IQ calibration will be 664 * restarted and re-setup any per-channel state. 665 */ 666 OS_MEMZERO(ic, sizeof(*ic)); 667 ic->channel = freq; 668 c->ic_devdata = next; 669 next++; 670 } 671 } 672 AH_PRIVATE(ah)->ah_nchan = next; 673 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n", 674 __func__, nchans, next); 675 return AH_TRUE; 676 } 677 678 /* 679 * Setup the channel list based on the information in the EEPROM. 680 */ 681 HAL_STATUS 682 ath_hal_init_channels(struct ath_hal *ah, 683 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 684 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 685 HAL_BOOL enableExtendedChannels) 686 { 687 COUNTRY_CODE_TO_ENUM_RD *country; 688 REG_DOMAIN *rd5GHz, *rd2GHz; 689 HAL_STATUS status; 690 691 status = getchannels(ah, chans, maxchans, nchans, modeSelect, 692 cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz); 693 if (status == HAL_OK && 694 assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) { 695 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz; 696 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz; 697 698 ah->ah_countryCode = country->countryCode; 699 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n", 700 __func__, ah->ah_countryCode); 701 } else 702 status = HAL_EINVAL; 703 return status; 704 } 705 706 /* 707 * Set the channel list. 708 */ 709 HAL_STATUS 710 ath_hal_set_channels(struct ath_hal *ah, 711 struct ieee80211_channel chans[], int nchans, 712 HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd) 713 { 714 COUNTRY_CODE_TO_ENUM_RD *country; 715 REG_DOMAIN *rd5GHz, *rd2GHz; 716 HAL_STATUS status; 717 718 switch (rd) { 719 case SKU_SR9: 720 case SKU_XR9: 721 case SKU_GZ901: 722 /* 723 * Map 900MHz sku's. The frequencies will be mapped 724 * according to the sku to compensate for the down-converter. 725 * We use the FCC for these sku's as the mapped channel 726 * list is known compatible (will need to change if/when 727 * vendors do different mapping in different locales). 728 */ 729 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC, 730 &country, &rd2GHz, &rd5GHz); 731 break; 732 default: 733 status = getregstate(ah, cc, rd, 734 &country, &rd2GHz, &rd5GHz); 735 rd = AH_PRIVATE(ah)->ah_currentRD; 736 break; 737 } 738 if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) { 739 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz; 740 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz; 741 742 ah->ah_countryCode = country->countryCode; 743 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n", 744 __func__, ah->ah_countryCode); 745 } else 746 status = HAL_EINVAL; 747 return status; 748 } 749 750 #ifdef AH_DEBUG 751 /* 752 * Return the internal channel corresponding to a public channel. 753 * NB: normally this routine is inline'd (see ah_internal.h) 754 */ 755 HAL_CHANNEL_INTERNAL * 756 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c) 757 { 758 HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata]; 759 760 if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan && 761 (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c))) 762 return cc; 763 if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) { 764 HALDEBUG(ah, HAL_DEBUG_ANY, 765 "%s: bad mapping, devdata %u nchans %u\n", 766 __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan); 767 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan); 768 } else { 769 HALDEBUG(ah, HAL_DEBUG_ANY, 770 "%s: no match for %u/0x%x devdata %u channel %u\n", 771 __func__, c->ic_freq, c->ic_flags, c->ic_devdata, 772 cc->channel); 773 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)); 774 } 775 return AH_NULL; 776 } 777 #endif /* AH_DEBUG */ 778 779 #define isWwrSKU(_ah) \ 780 ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \ 781 getEepromRD(_ah) == WORLD) 782 783 /* 784 * Return the test group for the specific channel based on 785 * the current regulatory setup. 786 */ 787 u_int 788 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c) 789 { 790 u_int ctl; 791 792 if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz || 793 (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) 794 ctl = SD_NO_CTL; 795 else if (IEEE80211_IS_CHAN_2GHZ(c)) 796 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit; 797 else 798 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit; 799 if (IEEE80211_IS_CHAN_B(c)) 800 return ctl | CTL_11B; 801 if (IEEE80211_IS_CHAN_G(c)) 802 return ctl | CTL_11G; 803 if (IEEE80211_IS_CHAN_108G(c)) 804 return ctl | CTL_108G; 805 if (IEEE80211_IS_CHAN_TURBO(c)) 806 return ctl | CTL_TURBO; 807 if (IEEE80211_IS_CHAN_A(c)) 808 return ctl | CTL_11A; 809 return ctl; 810 } 811 812 /* 813 * Return the max allowed antenna gain and apply any regulatory 814 * domain specific changes. 815 * 816 * NOTE: a negative reduction is possible in RD's that only 817 * measure radiated power (e.g., ETSI) which would increase 818 * that actual conducted output power (though never beyond 819 * the calibrated target power). 820 */ 821 u_int 822 ath_hal_getantennareduction(struct ath_hal *ah, 823 const struct ieee80211_channel *chan, u_int twiceGain) 824 { 825 int8_t antennaMax = twiceGain - chan->ic_maxantgain*2; 826 return (antennaMax < 0) ? 0 : antennaMax; 827 } 828