static void dumpchannels(struct ath_hal *ah, int nc, const struct ieee80211_channel *chans, int16_t *txpow) { int i; for (i = 0; i < nc; i++) { const struct ieee80211_channel *c = &chans[i]; int type; if (showchannels) printf("%s%3d", sep, ath_hal_mhz2ieee(ah, c->ic_freq, c->ic_flags)); else printf("%s%u", sep, c->ic_freq); if (IEEE80211_IS_CHAN_HALF(c)) type = 'H'; else if (IEEE80211_IS_CHAN_QUARTER(c)) type = 'Q'; else if (IEEE80211_IS_CHAN_TURBO(c)) type = 'T'; else if (IEEE80211_IS_CHAN_HT(c)) type = 'N'; else if (IEEE80211_IS_CHAN_A(c)) type = 'A'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'T'; else if (IEEE80211_IS_CHAN_G(c)) type = 'G'; else type = 'B'; if (dopassive && IEEE80211_IS_CHAN_PASSIVE(c)) type = tolower(type); if (isdfs && is4ms) printf("%c%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (isdfs) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (is4ms) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5); if ((n++ % (showchannels ? 7 : 6)) == 0) sep = "\n"; else sep = " "; } }
static void ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); /* XXX Merlin ini fixups */ /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); if (AR_SREV_MERLIN_20_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, modesIndex, regWrites); } /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* 5GHz channels w/ Fast Clock use different modal values */ regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, modesIndex, regWrites); } }
void icm_display_channel_flags(ICM_CHANNEL_T* pch) { ICM_DEV_INFO_T* pdev = get_pdev(); if (IEEE80211_IS_CHAN_FHSS(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tFHSS\n"); } if (IEEE80211_IS_CHAN_11NA(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\t11na\n"); } else if (IEEE80211_IS_CHAN_A(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\t11a\n"); } else if (IEEE80211_IS_CHAN_11NG(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\t11ng\n"); } else if (IEEE80211_IS_CHAN_G(pch) || IEEE80211_IS_CHAN_PUREG(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\t11g\n"); } else if (IEEE80211_IS_CHAN_B(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\t11b\n"); } if (IEEE80211_IS_CHAN_TURBO(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tTurbo\n"); } if(IEEE80211_IS_CHAN_11N_CTL_CAPABLE(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tControl capable\n"); } if(IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tControl capable upper\n"); } if(IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tControl capable lower\n"); } if (IEEE80211_IS_CHAN_DFSFLAG(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tDFS\n"); } if (IEEE80211_IS_CHAN_HALF(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tHalf\n"); } if (IEEE80211_IS_CHAN_PASSIVE(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tPassive\n"); } if (IEEE80211_IS_CHAN_QUARTER(pch)) { ICM_DPRINTF(pdev, ICM_PRCTRL_FLAG_NONE, ICM_DEBUG_LEVEL_DEFAULT, ICM_MODULE_ID_UTIL, "\tQuarter\n"); } }
static void setchannelflags(struct ieee80211_channel *c, REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd) { if (fband->usePassScan & rd->pscan) c->ic_flags |= IEEE80211_CHAN_PASSIVE; if (fband->useDfs & rd->dfsMask) c->ic_flags |= IEEE80211_CHAN_DFS; if (IEEE80211_IS_CHAN_5GHZ(c) && (rd->flags & DISALLOW_ADHOC_11A)) c->ic_flags |= IEEE80211_CHAN_NOADHOC; if (IEEE80211_IS_CHAN_TURBO(c) && (rd->flags & DISALLOW_ADHOC_11A_TURB)) c->ic_flags |= IEEE80211_CHAN_NOADHOC; if (rd->flags & NO_HOSTAP) c->ic_flags |= IEEE80211_CHAN_NOHOSTAP; if (rd->flags & LIMIT_FRAME_4MS) c->ic_flags |= IEEE80211_CHAN_4MSXMIT; if (rd->flags & NEED_NFC) c->ic_flags |= CHANNEL_NFCREQUIRED; }
/* * Return the test group for the specific channel based on * the current regulatory setup. */ u_int ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c) { u_int ctl; if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz || (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) ctl = SD_NO_CTL; else if (IEEE80211_IS_CHAN_2GHZ(c)) ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit; else ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit; if (IEEE80211_IS_CHAN_B(c)) return ctl | CTL_11B; if (IEEE80211_IS_CHAN_G(c)) return ctl | CTL_11G; if (IEEE80211_IS_CHAN_108G(c)) return ctl | CTL_108G; if (IEEE80211_IS_CHAN_TURBO(c)) return ctl | CTL_TURBO; if (IEEE80211_IS_CHAN_A(c)) return ctl | CTL_11A; return ctl; }
/* * Sets the transmit power in the baseband for the given * operating channel and mode. */ static HAL_BOOL setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan, int16_t tpcScaleReduction, int16_t powerLimit, int16_t *pMinPower, int16_t *pMaxPower) { u_int16_t ratesArray[16]; u_int16_t *rpow = ratesArray; u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck; int8_t twiceAntennaGain, twiceAntennaReduction; TRGT_POWER_INFO targetPowerOfdm, targetPowerCck; RD_EDGES_POWER *rep; int16_t scaledPower; u_int8_t cfgCtl; twiceMaxRDPower = chan->ic_maxregpower * 2; *pMaxPower = -MAX_RATE_POWER; *pMinPower = MAX_RATE_POWER; /* Get conformance test limit maximum for this channel */ cfgCtl = ath_hal_getctl(ah, chan); rep = findEdgePower(ah, cfgCtl); if (rep != AH_NULL) twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->ic_freq, rep); else twiceMaxEdgePower = MAX_RATE_POWER; if (IEEE80211_IS_CHAN_G(chan)) { /* Check for a CCK CTL for 11G CCK powers */ cfgCtl = (cfgCtl & 0xFC) | 0x01; rep = findEdgePower(ah, cfgCtl); if (rep != AH_NULL) twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->ic_freq, rep); else twiceMaxEdgePowerCck = MAX_RATE_POWER; } else { /* Set the 11B cck edge power to the one found before */ twiceMaxEdgePowerCck = twiceMaxEdgePower; } /* Get Antenna Gain reduction */ if (IEEE80211_IS_CHAN_5GHZ(chan)) { twiceAntennaGain = antennaGainMax[0]; } else { twiceAntennaGain = antennaGainMax[1]; } twiceAntennaReduction = ath_hal_getantennareduction(ah, chan, twiceAntennaGain); if (IEEE80211_IS_CHAN_OFDM(chan)) { /* Get final OFDM target powers */ if (IEEE80211_IS_CHAN_G(chan)) { /* TODO - add Turbo 2.4 to this mode check */ ar5212GetTargetPowers(ah, chan, trgtPwr_11g, numTargetPwr_11g, &targetPowerOfdm); } else { ar5212GetTargetPowers(ah, chan, trgtPwr_11a, numTargetPwr_11a, &targetPowerOfdm); } /* Get Maximum OFDM power */ /* Minimum of target and edge powers */ scaledPower = AH_MIN(twiceMaxEdgePower, twiceMaxRDPower - twiceAntennaReduction); /* * If turbo is set, reduce power to keep power * consumption under 2 Watts. Note that we always do * this unless specially configured. Then we limit * power only for non-AP operation. */ if (IEEE80211_IS_CHAN_TURBO(chan) #ifdef AH_ENABLE_AP_SUPPORT && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP #endif ) { /* * If turbo is set, reduce power to keep power * consumption under 2 Watts */ if (eeversion >= AR_EEPROM_VER3_1) scaledPower = AH_MIN(scaledPower, turbo2WMaxPower5); /* * EEPROM version 4.0 added an additional * constraint on 2.4GHz channels. */ if (eeversion >= AR_EEPROM_VER4_0 && IEEE80211_IS_CHAN_2GHZ(chan)) scaledPower = AH_MIN(scaledPower, turbo2WMaxPower2); } /* Reduce power by max regulatory domain allowed restrictions */ scaledPower -= (tpcScaleReduction * 2); scaledPower = (scaledPower < 0) ? 0 : scaledPower; scaledPower = AH_MIN(scaledPower, powerLimit); scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24); /* Set OFDM rates 9, 12, 18, 24, 36, 48, 54, XR */ rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower; rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36); rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48); rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54); #ifdef notyet if (eeversion >= AR_EEPROM_VER4_0) { /* Setup XR target power from EEPROM */ rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ? xrTargetPower2 : xrTargetPower5); } else { /* XR uses 6mb power */ rpow[15] = rpow[0]; } #else rpow[15] = rpow[0]; #endif *pMinPower = rpow[7]; *pMaxPower = rpow[0]; #if 0 ahp->ah_ofdmTxPower = rpow[0]; #endif HALDEBUG(ah, HAL_DEBUG_ANY, "%s: MaxRD: %d TurboMax: %d MaxCTL: %d " "TPC_Reduction %d\n", __func__, twiceMaxRDPower, turbo2WMaxPower5, twiceMaxEdgePower, tpcScaleReduction * 2); } if (IEEE80211_IS_CHAN_CCK(chan)) { /* Get final CCK target powers */ ar5212GetTargetPowers(ah, chan, trgtPwr_11b, numTargetPwr_11b, &targetPowerCck); /* Reduce power by max regulatory domain allowed restrictions */ scaledPower = AH_MIN(twiceMaxEdgePowerCck, twiceMaxRDPower - twiceAntennaReduction); scaledPower -= (tpcScaleReduction * 2); scaledPower = (scaledPower < 0) ? 0 : scaledPower; scaledPower = AH_MIN(scaledPower, powerLimit); rpow[8] = (scaledPower < 1) ? 1 : scaledPower; /* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */ rpow[8] = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24); rpow[9] = AH_MIN(scaledPower, targetPowerCck.twicePwr36); rpow[10] = rpow[9]; rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48); rpow[12] = rpow[11]; rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54); rpow[14] = rpow[13]; /* Set min/max power based off OFDM values or initialization */ if (rpow[13] < *pMinPower) *pMinPower = rpow[13]; if (rpow[9] > *pMaxPower) *pMaxPower = rpow[9]; } #if 0 ahp->ah_tx6PowerInHalfDbm = *pMaxPower; #endif return AH_TRUE; }
/* * Construct the channel list for the specified regulatory config. */ static HAL_STATUS getchannels(struct ath_hal *ah, struct ieee80211_channel chans[], u_int maxchans, int *nchans, u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, HAL_BOOL enableExtendedChannels, COUNTRY_CODE_TO_ENUM_RD **pcountry, REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz) { #define CHANNEL_HALF_BW 10 #define CHANNEL_QUARTER_BW 5 #define HAL_MODE_11A_ALL \ (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \ HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE) REG_DOMAIN *rd5GHz, *rd2GHz; u_int modesAvail; const struct cmode *cm; struct ieee80211_channel *ic; int next, b; HAL_STATUS status; HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n", __func__, cc, regDmn, modeSelect, enableExtendedChannels ? " ecm" : ""); status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz); if (status != HAL_OK) return status; /* get modes that HW is capable of */ modesAvail = ath_hal_getWirelessModes(ah); /* optimize work below if no 11a channels */ if (isChanBitMaskZero(rd5GHz->chan11a) && (modesAvail & HAL_MODE_11A_ALL)) { HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: disallow all 11a\n", __func__); modesAvail &= ~HAL_MODE_11A_ALL; } next = 0; ic = &chans[0]; for (cm = modes; cm < &modes[N(modes)]; cm++) { uint16_t c, c_hi, c_lo; uint64_t *channelBM = AH_NULL; REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs; int low_adj, hi_adj, channelSep, lastc; uint32_t rdflags; uint64_t dfsMask; uint64_t pscan; if ((cm->mode & modeSelect) == 0) { HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: skip mode 0x%x flags 0x%x\n", __func__, cm->mode, cm->flags); continue; } if ((cm->mode & modesAvail) == 0) { HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: !avail mode 0x%x (0x%x) flags 0x%x\n", __func__, modesAvail, cm->mode, cm->flags); continue; } if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) { /* channel not supported by hardware, skip it */ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: channels 0x%x not supported by hardware\n", __func__,cm->flags); continue; } switch (cm->mode) { case HAL_MODE_TURBO: case HAL_MODE_11A_TURBO: rdflags = rd5GHz->flags; dfsMask = rd5GHz->dfsMask; pscan = rd5GHz->pscan; if (cm->mode == HAL_MODE_TURBO) channelBM = rd5GHz->chan11a_turbo; else channelBM = rd5GHz->chan11a_dyn_turbo; freqs = ®Dmn5GhzTurboFreq[0]; break; case HAL_MODE_11G_TURBO: rdflags = rd2GHz->flags; dfsMask = rd2GHz->dfsMask; pscan = rd2GHz->pscan; channelBM = rd2GHz->chan11g_turbo; freqs = ®Dmn2Ghz11gTurboFreq[0]; break; case HAL_MODE_11A: case HAL_MODE_11A_HALF_RATE: case HAL_MODE_11A_QUARTER_RATE: case HAL_MODE_11NA_HT20: case HAL_MODE_11NA_HT40PLUS: case HAL_MODE_11NA_HT40MINUS: rdflags = rd5GHz->flags; dfsMask = rd5GHz->dfsMask; pscan = rd5GHz->pscan; if (cm->mode == HAL_MODE_11A_HALF_RATE) channelBM = rd5GHz->chan11a_half; else if (cm->mode == HAL_MODE_11A_QUARTER_RATE) channelBM = rd5GHz->chan11a_quarter; else channelBM = rd5GHz->chan11a; freqs = ®Dmn5GhzFreq[0]; break; case HAL_MODE_11B: case HAL_MODE_11G: case HAL_MODE_11G_HALF_RATE: case HAL_MODE_11G_QUARTER_RATE: case HAL_MODE_11NG_HT20: case HAL_MODE_11NG_HT40PLUS: case HAL_MODE_11NG_HT40MINUS: rdflags = rd2GHz->flags; dfsMask = rd2GHz->dfsMask; pscan = rd2GHz->pscan; if (cm->mode == HAL_MODE_11G_HALF_RATE) channelBM = rd2GHz->chan11g_half; else if (cm->mode == HAL_MODE_11G_QUARTER_RATE) channelBM = rd2GHz->chan11g_quarter; else if (cm->mode == HAL_MODE_11B) channelBM = rd2GHz->chan11b; else channelBM = rd2GHz->chan11g; if (cm->mode == HAL_MODE_11B) freqs = ®Dmn2GhzFreq[0]; else freqs = ®Dmn2Ghz11gFreq[0]; break; default: HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: Unkonwn HAL mode 0x%x\n", __func__, cm->mode); continue; } if (isChanBitMaskZero(channelBM)) continue; /* * Setup special handling for HT40 channels; e.g. * 5G HT40 channels require 40Mhz channel separation. */ hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS || cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0; low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0; channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS || cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0; for (b = 0; b < 64*BMLEN; b++) { if (!IS_BIT_SET(b, channelBM)) continue; fband = &freqs[b]; lastc = 0; for (c = fband->lowChannel + low_adj; c <= fband->highChannel + hi_adj; c += fband->channelSep) { if (!(c_lo <= c && c <= c_hi)) { HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: c %u out of range [%u..%u]\n", __func__, c, c_lo, c_hi); continue; } if (next >= maxchans){ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: too many channels for channel table\n", __func__); goto done; } if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) { HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "skip ecm channel\n"); continue; } #if 0 if ((fband->useDfs & dfsMask) && (cm->flags & IEEE80211_CHAN_HT40)) { /* NB: DFS and HT40 don't mix */ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "skip HT40 chan, DFS required\n"); continue; } #endif /* * Make sure that channel separation * meets the requirement. */ if (lastc && channelSep && (c-lastc) < channelSep) continue; lastc = c; OS_MEMZERO(ic, sizeof(*ic)); ic->ic_freq = c; ic->ic_flags = cm->flags; ic->ic_maxregpower = fband->powerDfs; ath_hal_getpowerlimits(ah, ic); ic->ic_maxantgain = fband->antennaMax; if (fband->usePassScan & pscan) ic->ic_flags |= IEEE80211_CHAN_PASSIVE; if (fband->useDfs & dfsMask) ic->ic_flags |= IEEE80211_CHAN_DFS; if (IEEE80211_IS_CHAN_5GHZ(ic) && (rdflags & DISALLOW_ADHOC_11A)) ic->ic_flags |= IEEE80211_CHAN_NOADHOC; if (IEEE80211_IS_CHAN_TURBO(ic) && (rdflags & DISALLOW_ADHOC_11A_TURB)) ic->ic_flags |= IEEE80211_CHAN_NOADHOC; if (rdflags & NO_HOSTAP) ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP; if (rdflags & LIMIT_FRAME_4MS) ic->ic_flags |= IEEE80211_CHAN_4MSXMIT; if (rdflags & NEED_NFC) ic->ic_flags |= CHANNEL_NFCREQUIRED; ic++, next++; } } } done: *nchans = next; /* NB: pcountry set above by getregstate */ if (prd2GHz != AH_NULL) *prd2GHz = rd2GHz; if (prd5GHz != AH_NULL) *prd5GHz = rd5GHz; return HAL_OK; #undef HAL_MODE_11A_ALL #undef CHANNEL_HALF_BW #undef CHANNEL_QUARTER_BW }
static void ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; int i; const HAL_INI_ARRAY *ia; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); /* * This is unwound because at the moment, there's a requirement * for Merlin (and later, perhaps) to have a specific bit fixed * in the AR_AN_TOP2 register before writing it. */ ia = &AH5212(ah)->ah_ini_modes; #if 0 regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); #endif HALASSERT(modesIndex < ia->cols); for (i = 0; i < ia->rows; i++) { uint32_t reg = HAL_INI_VAL(ia, i, 0); uint32_t val = HAL_INI_VAL(ia, i, modesIndex); if (reg == AR_AN_TOP2 && AH5416(ah)->ah_need_an_top2_fixup) val &= ~AR_AN_TOP2_PWDCLKIND; OS_REG_WRITE(ah, reg, val); /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ if (reg >= 0x7800 && reg < 0x7900) OS_DELAY(100); DMA_YIELD(regWrites); } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, modesIndex, regWrites); } /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* 5GHz channels w/ Fast Clock use different modal values */ regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, modesIndex, regWrites); } }
static void ar9287AniSetup(struct ath_hal *ah) { /* * These are the parameters from the AR5416 ANI code; * they likely need quite a bit of adjustment for the * AR9280. */ static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 2, .cycPwrThr1 = { 2, 4, 6 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~ HAL_ANI_NOISE_IMMUNITY_LEVEL; /* NB: ANI is not enabled yet */ ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } /* * Attach for an AR9287 part. */ static struct ath_hal * ar9287Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) { struct ath_hal_9287 *ahp9287; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; int8_t pwr_table_offset; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9287 = ath_hal_malloc(sizeof (struct ath_hal_9287)); if (ahp9287 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9287); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9280InitPLL; ah->ah_setAntennaSwitch = ar9287SetAntennaSwitch; ah->ah_configPCIE = ar9287ConfigPCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9287_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9287_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9287_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9287_adc_init_dc_cal; /* Better performance without ADC Gain Calibration */ AH5416(ah)->ah_cal.suppCals = ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9287WriteIni; ah->ah_setTxPower = ar9287SetTransmitPower; ah->ah_setBoardValues = ar9287SetBoardValues; AH5416(ah)->ah_olcInit = ar9287olcInit; AH5416(ah)->ah_olcTempCompensation = ar9287olcTemperatureCompensation; //AH5416(ah)->ah_setPowerCalTable = ar9287SetPowerCalTable; AH5416(ah)->ah_cal_initcal = ar9287InitCalHardware; AH5416(ah)->ah_cal_pacal = ar9287PACal; /* XXX NF calibration */ /* XXX Ini override? (IFS vars - since the kiwi mac clock is faster?) */ /* XXX what else is kiwi-specific in the radio/calibration pathway? */ AH5416(ah)->ah_rx_chainmask = AR9287_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9287_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* Don't support Kiwi < 1.2; those are pre-release chips */ if (! AR_SREV_KIWI_12_OR_LATER(ah)) { ath_hal_printf(ah, "[ath]: Kiwi < 1.2 is not supported\n"); ecode = HAL_EIO; goto bad; } /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar9287Modes_9287_1_1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9287Common_9287_1_1, 2); /* If pcie_clock_req */ HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_always_on_L1_9287_1_1, 2); /* XXX WoW ini values */ /* Else */ #if 0 HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_off_L1_9287_1_1, 2); #endif /* Initialise Japan arrays */ HAL_INI_INIT(&ahp9287->ah_ini_cckFirNormal, ar9287Common_normal_cck_fir_coeff_9287_1_1, 2); HAL_INI_INIT(&ahp9287->ah_ini_cckFirJapan2484, ar9287Common_japan_2484_cck_fir_coeff_9287_1_1, 2); ar5416AttachPCIE(ah); ecode = ath_hal_9287EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9287RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* * We only implement open-loop TX power control * for the AR9287 in this codebase. */ if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { ath_hal_printf(ah, "[ath] AR9287 w/ closed-loop TX power control" " isn't supported.\n"); ecode = HAL_ENOTSUPP; goto bad; } /* * Check whether the power table offset isn't the default. * This can occur with eeprom minor V21 or greater on Merlin. */ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (pwr_table_offset != AR5416_PWR_TABLE_OFFSET_DB) ath_hal_printf(ah, "[ath]: default pwr offset: %d dBm != EEPROM pwr offset: %d dBm; curves will be adjusted.\n", AR5416_PWR_TABLE_OFFSET_DB, (int) pwr_table_offset); /* setup rxgain table */ HAL_INI_INIT(&ahp9287->ah_ini_rxgain, ar9287Modes_rx_gain_9287_1_1, 6); /* setup txgain table */ HAL_INI_INIT(&ahp9287->ah_ini_txgain, ar9287Modes_tx_gain_9287_1_1, 6); /* * Got everything we need now to setup the capabilities. */ if (!ar9287FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = AR9287_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9287AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9287_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; } static void ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) { if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* Yes, Kiwi uses the Kite PCIe PHY WA */ } } static void ar9287WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_txgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); }
/* * Places the hardware into reset and then pulls it out of reset * * TODO: Only write the PLL if we're changing to or from CCK mode * * WARNING: The order of the PLL and mode registers must be correct. */ HAL_BOOL ar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan) { OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); /* * Reset the HW */ if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", __func__); return AH_FALSE; } /* Bring out of sleep mode (AGAIN) */ if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n", __func__); return AH_FALSE; } /* Clear warm reset register */ if (!ar5312SetResetReg(ah, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", __func__); return AH_FALSE; } /* * Perform warm reset before the mode/PLL/turbo registers * are changed in order to deactivate the radio. Mode changes * with an active radio can result in corrupted shifts to the * radio device. */ /* * Set CCK and Turbo modes correctly. */ if (chan != AH_NULL) { /* NB: can be null during attach */ uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo; if (IS_RAD5112_ANY(ah)) { rfMode = AR_PHY_MODE_AR5112; if (!IS_5315(ah)) { if (IEEE80211_IS_CHAN_CCK(chan)) { phyPLL = AR_PHY_PLL_CTL_44_5312; } else { if (IEEE80211_IS_CHAN_HALF(chan)) { phyPLL = AR_PHY_PLL_CTL_40_5312_HALF; } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER; } else { phyPLL = AR_PHY_PLL_CTL_40_5312; } } } else { if (IEEE80211_IS_CHAN_CCK(chan)) phyPLL = AR_PHY_PLL_CTL_44_5112; else phyPLL = AR_PHY_PLL_CTL_40_5112; if (IEEE80211_IS_CHAN_HALF(chan)) phyPLL |= AR_PHY_PLL_CTL_HALF; else if (IEEE80211_IS_CHAN_QUARTER(chan)) phyPLL |= AR_PHY_PLL_CTL_QUARTER; } } else { rfMode = AR_PHY_MODE_AR5111; if (IEEE80211_IS_CHAN_CCK(chan)) phyPLL = AR_PHY_PLL_CTL_44; else phyPLL = AR_PHY_PLL_CTL_40; if (IEEE80211_IS_CHAN_HALF(chan)) phyPLL = AR_PHY_PLL_CTL_HALF; else if (IEEE80211_IS_CHAN_QUARTER(chan)) phyPLL = AR_PHY_PLL_CTL_QUARTER; } if (IEEE80211_IS_CHAN_G(chan)) rfMode |= AR_PHY_MODE_DYNAMIC; else if (IEEE80211_IS_CHAN_OFDM(chan)) rfMode |= AR_PHY_MODE_OFDM; else rfMode |= AR_PHY_MODE_CCK; if (IEEE80211_IS_CHAN_5GHZ(chan)) rfMode |= AR_PHY_MODE_RF5GHZ; else rfMode |= AR_PHY_MODE_RF2GHZ; turbo = IEEE80211_IS_CHAN_TURBO(chan) ? (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0; curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL); /* * PLL, Mode, and Turbo values must be written in the correct * order to ensure: * - The PLL cannot be set to 44 unless the CCK or DYNAMIC * mode bit is set * - Turbo cannot be set at the same time as CCK or DYNAMIC */ if (IEEE80211_IS_CHAN_CCK(chan)) { OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); if (curPhyPLL != phyPLL) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); /* Wait for the PLL to settle */ OS_DELAY(PLL_SETTLE_DELAY); } } else { if (curPhyPLL != phyPLL) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); /* Wait for the PLL to settle */ OS_DELAY(PLL_SETTLE_DELAY); } OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); } } return AH_TRUE; }
HAL_BOOL ar5210ResetTxQueue(struct ath_hal *ah, u_int q) { struct ath_hal_5210 *ahp = AH5210(ah); const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; HAL_TX_QUEUE_INFO *qi; uint32_t cwMin; if (q >= HAL_NUM_TX_QUEUES) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", __func__, q); return AH_FALSE; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", __func__, q); return AH_FALSE; } /* * Ignore any non-data queue(s). */ if (qi->tqi_type != HAL_TX_QUEUE_DATA) return AH_TRUE; /* Set turbo mode / base mode parameters on or off */ if (IEEE80211_IS_CHAN_TURBO(chan)) { OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO); OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO); OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO); OS_REG_WRITE(ah, AR_IFS0, ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO) << AR_IFS0_DIFS_S) | INIT_SIFS_TURBO); OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO); OS_REG_WRITE(ah, AR_PHY(17), (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38); OS_REG_WRITE(ah, AR_PHY_FRCTL, AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x2020 | AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT); } else { OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME); OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT); OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY); OS_REG_WRITE(ah, AR_IFS0, ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME) << AR_IFS0_DIFS_S) | INIT_SIFS); OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL); OS_REG_WRITE(ah, AR_PHY(17), (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C); OS_REG_WRITE(ah, AR_PHY_FRCTL, AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020); } if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) cwMin = INIT_CWMIN; else cwMin = qi->tqi_cwmin; /* Set cwmin and retry limit values */ OS_REG_WRITE(ah, AR_RETRY_LMT, (cwMin << AR_RETRY_LMT_CW_MIN_S) | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY) | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY) | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY) | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY) ); if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) ahp->ah_txOkInterruptMask |= 1 << q; else ahp->ah_txOkInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) ahp->ah_txErrInterruptMask |= 1 << q; else ahp->ah_txErrInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) ahp->ah_txDescInterruptMask |= 1 << q; else ahp->ah_txDescInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) ahp->ah_txEolInterruptMask |= 1 << q; else ahp->ah_txEolInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) ahp->ah_txUrnInterruptMask |= 1 << q; else ahp->ah_txUrnInterruptMask &= ~(1 << q); return AH_TRUE; }
/* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, struct sk_buff *skb, int mcast) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; u_int16_t capinfo; IEEE80211_LOCK(ic); if ((ic->ic_flags & IEEE80211_F_DOTH) && (vap->iv_flags & IEEE80211_F_CHANSWITCH) && (vap->iv_chanchange_count == ic->ic_chanchange_tbtt)) { u_int8_t *frm; struct ieee80211_channel *c; vap->iv_chanchange_count = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: reinit beacon\n", __func__); /* * NB: ic_bsschan is in the DSPARMS beacon IE, so must set this * prior to the beacon re-init, below. */ c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan); if (c == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: find channel failure\n", __func__); IEEE80211_UNLOCK(ic); return 0; } ic->ic_bsschan = c; skb_pull(skb, sizeof(struct ieee80211_frame)); skb_trim(skb, 0); frm = skb->data; skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm); skb_push(skb, sizeof(struct ieee80211_frame)); vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; ic->ic_flags &= ~IEEE80211_F_CHANSWITCH; /* NB: only for the first VAP to get here */ if (ic->ic_curchan != c) { ic->ic_curchan = c; ic->ic_set_channel(ic); } len_changed = 1; } /* XXX faster to recalculate entirely or just changes? */ if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (vap->iv_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ic->ic_flags & IEEE80211_F_DOTH) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *bo->bo_caps = htole16(capinfo); if (vap->iv_flags & IEEE80211_F_WME) { struct ieee80211_wme_state *wme = &ic->ic_wme; /* * Check for aggressive mode change. When there is * significant high priority traffic in the BSS * throttle back BE traffic by using conservative * parameters. Otherwise BE uses aggressive params * to optimize performance of legacy/non-QoS traffic. */ if (wme->wme_flags & WME_F_AGGRMODE) { if (wme->wme_hipri_traffic > wme->wme_hipri_switch_thresh) { IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni, "%s: traffic %u, disable aggressive mode", __func__, wme->wme_hipri_traffic); wme->wme_flags &= ~WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(vap); wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } else wme->wme_hipri_traffic = 0; } else { if (wme->wme_hipri_traffic <= wme->wme_hipri_switch_thresh) { IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni, "%s: traffic %u, enable aggressive mode", __func__, wme->wme_hipri_traffic); wme->wme_flags |= WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(vap); wme->wme_hipri_traffic = 0; } else wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } /* XXX multi-bss */ if (vap->iv_flags & IEEE80211_F_WMEUPDATE) { (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } } if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) bo->bo_tim; if (vap->iv_flags & IEEE80211_F_TIMUPDATE) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * ensures there is space in the mbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (vap->iv_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < vap->iv_tim_len; i++) if (vap->iv_tim_bitmap[i]) { timoff = i &~ 1; break; } KASSERT(timoff != 128, ("tim bitmap empty!")); for (i = vap->iv_tim_len-1; i >= timoff; i--) if (vap->iv_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } if (timlen != bo->bo_tim_len) { /* copy up/down trailer */ int trailer_adjust = (tie->tim_bitmap+timlen) - (bo->bo_tim_trailer); memmove(tie->tim_bitmap+timlen, bo->bo_tim_trailer, bo->bo_tim_trailerlen); bo->bo_tim_trailer = tie->tim_bitmap+timlen; bo->bo_chanswitch += trailer_adjust; bo->bo_wme += trailer_adjust; bo->bo_erp += trailer_adjust; bo->bo_ath_caps += trailer_adjust; bo->bo_xr += trailer_adjust; if (timlen > bo->bo_tim_len) skb_put(skb, timlen - bo->bo_tim_len); else skb_trim(skb, skb->len - (bo->bo_tim_len - timlen)); bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; tie->tim_bitctl = timoff; len_changed = 1; } memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, bo->bo_tim_len); vap->iv_flags &= ~IEEE80211_F_TIMUPDATE; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s: TIM updated, pending %u, off %u, len %u", __func__, vap->iv_ps_pending, timoff, timlen); } /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 0)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; if ((ic->ic_flags & IEEE80211_F_DOTH) && (ic->ic_flags & IEEE80211_F_CHANSWITCH)) { if (!vap->iv_chanchange_count) { vap->iv_flags |= IEEE80211_F_CHANSWITCH; /* copy out trailer to open up a slot */ memmove(bo->bo_chanswitch + IEEE80211_CHANSWITCHANN_BYTES, bo->bo_chanswitch, bo->bo_chanswitch_trailerlen); /* add ie in opened slot */ bo->bo_chanswitch[0] = IEEE80211_ELEMID_CHANSWITCHANN; bo->bo_chanswitch[1] = 3; /* fixed length */ bo->bo_chanswitch[2] = 1; /* stas get off for now */ bo->bo_chanswitch[3] = ic->ic_chanchange_chan; bo->bo_chanswitch[4] = ic->ic_chanchange_tbtt; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_tim_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_wme += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_erp += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_ath_caps += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_xr += IEEE80211_CHANSWITCHANN_BYTES; /* indicate new beacon length so other layers may manage memory */ skb_put(skb, IEEE80211_CHANSWITCHANN_BYTES); len_changed = 1; } else bo->bo_chanswitch[4]--; vap->iv_chanchange_count++; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: CHANSWITCH IE, change in %d\n", __func__, bo->bo_chanswitch[4]); } #ifdef ATH_SUPERG_XR if (vap->iv_flags & IEEE80211_F_XRUPDATE) { if (vap->iv_xrvap) (void) ieee80211_add_xr_param(bo->bo_xr, vap); vap->iv_flags &= ~IEEE80211_F_XRUPDATE; } #endif if (ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) { (void) ieee80211_add_erp(bo->bo_erp, ic); ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE; } } /* if it is a mode change beacon for dynamic turbo case */ if (((ic->ic_ath_cap & IEEE80211_ATHC_BOOST) != 0) ^ IEEE80211_IS_CHAN_TURBO(ic->ic_curchan)) ieee80211_add_athAdvCap(bo->bo_ath_caps, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); /* add APP_IE buffer if app updated it */ if (vap->iv_flags_ext & IEEE80211_FEXT_APPIE_UPDATE) { /* adjust the buffer size if the size is changed */ if (vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length != bo->bo_appie_buf_len) { int diff_len; diff_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length - bo->bo_appie_buf_len; if (diff_len > 0) skb_put(skb, diff_len); else skb_trim(skb, skb->len + diff_len); bo->bo_appie_buf_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += diff_len; bo->bo_tim_trailerlen += diff_len; len_changed = 1; } memcpy(bo->bo_appie_buf,vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].ie, vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length); vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE; } IEEE80211_UNLOCK(ic); return len_changed; }
/* * Build the country information element. */ void ieee80211_build_countryie(struct ieee80211vap *vap) { struct country_ie_triplet *pTriplet; struct ieee80211_channel *c; int i, j, chanflags, chancnt, isnewband; u_int8_t chanlist[IEEE80211_CHAN_MAX + 1]; u_int8_t prevchan; struct ieee80211com *ic = vap->iv_ic; if (!ic->ic_country_iso[0] || !ic->ic_country_iso[1] || !ic->ic_country_iso[2]) { /* Default, no country is set */ vap->iv_country_ie_data.country_len = 0; IEEE80211_DISABLE_COUNTRYIE(ic); return; } IEEE80211_ENABLE_COUNTRYIE(ic); /* * Construct the country IE: * 1. The country string come first. * 2. Then construct the channel triplets from lowest channel to highest channel. * 3. If we support the regulatory domain class (802.11J) * then add the class triplets before the channel triplets of each band. */ OS_MEMZERO(&vap->iv_country_ie_data, sizeof(vap->iv_country_ie_data)); vap->iv_country_ie_data.country_id = IEEE80211_ELEMID_COUNTRY; vap->iv_country_ie_data.country_len = 3; vap->iv_country_ie_data.country_str[0] = ic->ic_country_iso[0]; vap->iv_country_ie_data.country_str[1] = ic->ic_country_iso[1]; vap->iv_country_ie_data.country_str[2] = ic->ic_country_iso[2]; pTriplet = (struct country_ie_triplet*)&vap->iv_country_ie_data.country_triplet; if(IEEE80211_IS_CHAN_2GHZ(vap->iv_bsschan)) chanflags = IEEE80211_CHAN_2GHZ; else chanflags = IEEE80211_CHAN_5GHZ; vap->iv_country_ie_chanflags = chanflags; OS_MEMZERO(&chanlist[0], sizeof(chanlist)); prevchan = 0; chancnt = 0; isnewband = 1; ieee80211_enumerate_channels(c, ic, i) { /* Does channel belong to current operation mode */ if (!(c->ic_flags & chanflags)) continue; /* Skip previously reported channels */ for (j=0; j < chancnt; j++) { if (c->ic_ieee == chanlist[j]) break; } if (j != chancnt) /* found a match */ continue; chanlist[chancnt] = c->ic_ieee; chancnt++; /* Skip turbo channels */ if (IEEE80211_IS_CHAN_TURBO(c)) continue; /* Skip half/quarter rate channels */ if (IEEE80211_IS_CHAN_HALF(c) || IEEE80211_IS_CHAN_QUARTER(c)) continue; if (isnewband) { isnewband = 0; } else if ((pTriplet->maxtxpwr == c->ic_maxregpower) && (c->ic_ieee == prevchan + 1)) { pTriplet->nchan ++; prevchan = c->ic_ieee; continue; } else { pTriplet ++; } prevchan = c->ic_ieee; pTriplet->schan = c->ic_ieee; pTriplet->nchan = 1; /* init as 1 channel */ pTriplet->maxtxpwr = c->ic_maxregpower; vap->iv_country_ie_data.country_len += 3; } /* pad */ if (vap->iv_country_ie_data.country_len & 1) { vap->iv_country_ie_data.country_triplet[vap->iv_country_ie_data.country_len] = 0; vap->iv_country_ie_data.country_len++; } }