int ar9380_set_synth(struct athn_softc *sc, struct ieee80211_channel *c, struct ieee80211_channel *extc) { uint32_t freq = c->ic_freq; uint32_t chansel, phy; if (IEEE80211_IS_CHAN_2GHZ(c)) { if (AR_SREV_9485(sc)) chansel = ((freq << 16) - 215) / 15; else chansel = (freq << 16) / 15; AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, AR9380_BMODE); } else { chansel = (freq << 15) / 15; chansel >>= 1; AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, 0); } /* Enable Long Shift Select for synthesizer. */ AR_SETBITS(sc, AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT); AR_WRITE_BARRIER(sc); /* Program synthesizer. */ phy = (chansel << 2) | AR9380_FRACMODE; DPRINTFN(4, ("AR_PHY_65NM_CH0_SYNTH7=0x%08x\n", phy)); AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy); AR_WRITE_BARRIER(sc); /* Toggle Load Synth Channel bit. */ AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy | AR9380_LOAD_SYNTH); AR_WRITE_BARRIER(sc); return (0); }
void ar9280olcGetTxGainIndex(struct ath_hal *ah, const struct ieee80211_channel *chan, struct calDataPerFreqOpLoop *rawDatasetOpLoop, uint8_t *calChans, uint16_t availPiers, uint8_t *pwr, uint8_t *pcdacIdx) { uint8_t pcdac, i = 0; uint16_t idxL = 0, idxR = 0, numPiers; HAL_BOOL match; CHAN_CENTERS centers; ar5416GetChannelCenters(ah, chan, ¢ers); for (numPiers = 0; numPiers < availPiers; numPiers++) if (calChans[numPiers] == AR5416_BCHAN_UNUSED) break; match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)), calChans, numPiers, &idxL, &idxR); if (match) { pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; } else { pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; } while (pcdac > AH9280(ah)->originalGain[i] && i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) i++; *pcdacIdx = i; }
void ar9287olcGetTxGainIndex(struct ath_hal *ah, const struct ieee80211_channel *chan, struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr) { uint16_t idxL = 0, idxR = 0, numPiers; HAL_BOOL match; CHAN_CENTERS centers; ar5416GetChannelCenters(ah, chan, ¢ers); for (numPiers = 0; numPiers < availPiers; numPiers++) { if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) break; } match = ath_ee_getLowerUpperIndex( (uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)), pCalChans, numPiers, &idxL, &idxR); if (match) { *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; } else { *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; } }
static void ar5416SanitizeNF(struct ath_hal *ah, int16_t *nf) { struct ar5416NfLimits *limit; int i; if (IEEE80211_IS_CHAN_2GHZ(AH_PRIVATE(ah)->ah_curchan)) limit = &AH5416(ah)->nf_2g; else limit = &AH5416(ah)->nf_5g; for (i = 0; i < AR5416_NUM_NF_READINGS; i++) { if (!nf[i]) continue; if (nf[i] > limit->max) { HALDEBUG(ah, HAL_DEBUG_NFCAL, "NF[%d] (%d) > MAX (%d), correcting to MAX\n", i, nf[i], limit->max); nf[i] = limit->max; } else if (nf[i] < limit->min) { HALDEBUG(ah, HAL_DEBUG_NFCAL, "NF[%d] (%d) < MIN (%d), correcting to NOM\n", i, nf[i], limit->min); nf[i] = limit->nominal; } } }
void ar9380_get_correction(struct athn_softc *sc, struct ieee80211_channel *c, int chain, int *corr, int *temp) { const struct ar9380_eeprom *eep = sc->eep; const struct ar9380_cal_data_per_freq_op_loop *pierdata; const uint8_t *pierfreq; uint8_t fbin; int lo, hi, npiers; if (IEEE80211_IS_CHAN_2GHZ(c)) { pierfreq = eep->calFreqPier2G; pierdata = eep->calPierData2G[chain]; npiers = AR9380_NUM_2G_CAL_PIERS; } else { pierfreq = eep->calFreqPier5G; pierdata = eep->calPierData5G[chain]; npiers = AR9380_NUM_5G_CAL_PIERS; } /* Find channel in ROM pier table. */ fbin = athn_chan2fbin(c); athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); *corr = athn_interpolate(fbin, pierfreq[lo], pierdata[lo].refPower, pierfreq[hi], pierdata[hi].refPower); *temp = athn_interpolate(fbin, pierfreq[lo], pierdata[lo].tempMeas, pierfreq[hi], pierdata[hi].tempMeas); }
static uint32_t iwm_mvm_scan_rxon_flags(struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_2GHZ(c)) return htole32(IWM_PHY_BAND_24); else return htole32(IWM_PHY_BAND_5); }
/* * Reads EEPROM header info from device structure and programs * all rf registers * * REQUIRES: Access to the analog rf device */ static HAL_BOOL ar2133SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan, uint16_t modesIndex, uint16_t *rfXpdGain) { struct ar2133State *priv = AR2133(ah); int writes; HALASSERT(priv); /* Setup Bank 0 Write */ ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1); /* Setup Bank 1 Write */ ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1); /* Setup Bank 2 Write */ ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1); /* Setup Bank 3 Write */ ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex); /* Setup Bank 6 Write */ ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex); /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { ar5416ModifyRfBuffer(priv->Bank6Data, ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0); ar5416ModifyRfBuffer(priv->Bank6Data, ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0); } else { ar5416ModifyRfBuffer(priv->Bank6Data, ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0); ar5416ModifyRfBuffer(priv->Bank6Data, ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0); } /* Setup Bank 7 Setup */ ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1); /* Write Analog registers */ writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0, priv->Bank0Data, 0); writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1, priv->Bank1Data, writes); writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2, priv->Bank2Data, writes); writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3, priv->Bank3Data, writes); writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, priv->Bank6Data, writes); (void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7, priv->Bank7Data, writes); return AH_TRUE; #undef RF_BANK_SETUP }
static int iwm_mvm_scan_skip_channel(struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c)) return 0; else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c)) return 0; else return 1; }
void ar9380_set_correction(struct athn_softc *sc, struct ieee80211_channel *c) { const struct ar9380_eeprom *eep = sc->eep; const struct ar9380_modal_eep_header *modal; uint32_t reg; int8_t slope; int i, corr, temp, temp0; if (IEEE80211_IS_CHAN_2GHZ(c)) modal = &eep->modalHeader2G; else modal = &eep->modalHeader5G; for (i = 0; i < AR9380_MAX_CHAINS; i++) { ar9380_get_correction(sc, c, i, &corr, &temp); if (i == 0) temp0 = temp; reg = AR_READ(sc, AR_PHY_TPC_11_B(i)); reg = RW(reg, AR_PHY_TPC_11_OLPC_GAIN_DELTA, corr); AR_WRITE(sc, AR_PHY_TPC_11_B(i), reg); /* Enable open loop power control. */ reg = AR_READ(sc, AR_PHY_TPC_6_B(i)); reg = RW(reg, AR_PHY_TPC_6_ERROR_EST_MODE, 3); AR_WRITE(sc, AR_PHY_TPC_6_B(i), reg); } /* Enable temperature compensation. */ if (IEEE80211_IS_CHAN_5GHZ(c) && eep->base_ext2.tempSlopeLow != 0) { if (c->ic_freq <= 5500) { slope = athn_interpolate(c->ic_freq, 5180, eep->base_ext2.tempSlopeLow, 5500, modal->tempSlope); } else { slope = athn_interpolate(c->ic_freq, 5500, modal->tempSlope, 5785, eep->base_ext2.tempSlopeHigh); } } else slope = modal->tempSlope; reg = AR_READ(sc, AR_PHY_TPC_19); reg = RW(reg, AR_PHY_TPC_19_ALPHA_THERM, slope); AR_WRITE(sc, AR_PHY_TPC_19, reg); reg = AR_READ(sc, AR_PHY_TPC_18); reg = RW(reg, AR_PHY_TPC_18_THERM_CAL, temp0); AR_WRITE(sc, AR_PHY_TPC_18, reg); AR_WRITE_BARRIER(sc); }
static uint16_t ar5416GetDefaultNF(struct ath_hal *ah, const struct ieee80211_channel *chan) { struct ar5416NfLimits *limit; if (!chan || IEEE80211_IS_CHAN_2GHZ(chan)) limit = &AH5416(ah)->nf_2g; else limit = &AH5416(ah)->nf_5g; return limit->nominal; }
/* * Add the phy configuration to the PHY context command */ static void iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic) { struct ieee80211com *ic = &sc->sc_ic; uint8_t active_cnt, idle_cnt; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD, "%s: 2ghz=%d, channel=%d, chains static=0x%x, dynamic=0x%x, " "rx_ant=0x%x, tx_ant=0x%x\n", __func__, !! IEEE80211_IS_CHAN_2GHZ(chan), ieee80211_chan2ieee(ic, chan), chains_static, chains_dynamic, iwm_fw_valid_rx_ant(sc), iwm_fw_valid_tx_ant(sc)); cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWM_PHY_BAND_24 : IWM_PHY_BAND_5; cmd->ci.channel = ieee80211_chan2ieee(ic, chan); cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20; cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW; /* Set rx the chains */ idle_cnt = chains_static; active_cnt = chains_dynamic; cmd->rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) << IWM_PHY_RX_CHAIN_VALID_POS); cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS); cmd->rxchain_info |= htole32(active_cnt << IWM_PHY_RX_CHAIN_MIMO_CNT_POS); cmd->txchain_info = htole32(iwm_fw_valid_tx_ant(sc)); }
void ar9280_reset_tx_gain(struct athn_softc *sc, struct ieee80211_channel *c) { const struct athn_gain *prog = sc->tx_gain; const uint32_t *pvals; int i; if (IEEE80211_IS_CHAN_2GHZ(c)) pvals = prog->vals_2g; else pvals = prog->vals_5g; for (i = 0; i < prog->nregs; i++) AR_WRITE(sc, prog->regs[i], pvals[i]); }
void ar9380_get_paprd_masks(struct athn_softc *sc, struct ieee80211_channel *c, uint32_t *ht20mask, uint32_t *ht40mask) { const struct ar9380_eeprom *eep = sc->eep; const struct ar9380_modal_eep_header *modal; if (IEEE80211_IS_CHAN_2GHZ(c)) modal = &eep->modalHeader2G; else modal = &eep->modalHeader5G; *ht20mask = modal->papdRateMaskHt20; *ht40mask = modal->papdRateMaskHt40; }
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); } }
static HAL_BOOL ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah, const struct ieee80211_channel *chan, int16_t *nft) { if (IEEE80211_IS_CHAN_5GHZ(chan)) { ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft); return AH_TRUE; } if (IEEE80211_IS_CHAN_2GHZ(chan)) { ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft); return AH_TRUE; } HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", __func__, chan->ic_flags); return AH_FALSE; }
void ar9280_olpc_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c, int chain, uint8_t *boundaries, uint8_t *pdadcs, uint8_t *txgain) { const struct ar5416_eeprom *eep = sc->eep; const struct ar_cal_data_per_freq_olpc *pierdata; const uint8_t *pierfreq; uint8_t fbin, pcdac, pwr, idx; int i, lo, hi, npiers; if (IEEE80211_IS_CHAN_2GHZ(c)) { pierfreq = eep->calFreqPier2G; pierdata = (const struct ar_cal_data_per_freq_olpc *) eep->calPierData2G[chain]; npiers = AR5416_NUM_2G_CAL_PIERS; } else { pierfreq = eep->calFreqPier5G; pierdata = (const struct ar_cal_data_per_freq_olpc *) eep->calPierData5G[chain]; npiers = AR5416_NUM_5G_CAL_PIERS; } /* Find channel in ROM pier table. */ fbin = athn_chan2fbin(c); athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); /* Get average. */ pwr = (pierdata[lo].pwrPdg[0][0] + pierdata[hi].pwrPdg[0][0]) / 2; pwr /= 2; /* Convert to dB. */ /* Find power control digital-to-analog converter (PCDAC) value. */ pcdac = pierdata[hi].pcdac[0][0]; for (idx = 0; idx < AR9280_TX_GAIN_TABLE_SIZE - 1; idx++) if (pcdac <= sc->tx_gain_tbl[idx]) break; *txgain = idx; DPRINTFN(3, ("fbin=%d lo=%d hi=%d pwr=%d pcdac=%d txgain=%d\n", fbin, lo, hi, pwr, pcdac, idx)); /* Fill phase domain analog-to-digital converter (PDADC) table. */ for (i = 0; i < AR_NUM_PDADC_VALUES; i++) pdadcs[i] = (i < pwr) ? 0x00 : 0xff; for (i = 0; i < AR_PD_GAINS_IN_MASK; i++) boundaries[i] = AR9280_PD_GAIN_BOUNDARY_DEFAULT; }
/* * Determine if calibration is supported by device and channel flags */ static OS_INLINE HAL_BOOL ar5416IsCalSupp(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_CAL_TYPE calType) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; switch (calType & cal->suppCals) { case IQ_MISMATCH_CAL: /* Run IQ Mismatch for non-CCK only */ return !IEEE80211_IS_CHAN_B(chan); case ADC_GAIN_CAL: case ADC_DC_CAL: /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ return !IEEE80211_IS_CHAN_B(chan) && !(IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)); } return AH_FALSE; }
static uint8_t iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_lmac *chan, int n_ssids) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211_channel *c; uint8_t nchan; int j; for (nchan = j = 0; j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) { c = ss->ss_chans[j]; /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(c)) { IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n", __func__, c->ic_freq, c->ic_ieee, c->ic_flags); continue; } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "Adding channel %d (%d Mhz) to the list\n", nchan, c->ic_freq); chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0)); chan->iter_count = htole16(1); chan->iter_interval = htole32(0); chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL); chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids)); /* XXX IEEE80211_SCAN_NOBCAST flag is never set. */ if (!IEEE80211_IS_CHAN_PASSIVE(c) && (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0)) chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE); chan++; nchan++; } return nchan; }
static int r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t chan; int group; chan = rtwn_chan2centieee(c); if (IEEE80211_IS_CHAN_2GHZ(c)) { if (chan <= 3) group = 0; else if (chan <= 9) group = 1; else if (chan <= 14) group = 2; else { KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); return (-1); } } else { KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); return (-1); } return (group); }
/* * 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; }
static void iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_ctx_cmd *cmd, uint32_t action) { struct ieee80211com *ic = sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni = vap->iv_bss; int cck_ack_rates, ofdm_ack_rates; int i; int is2ghz; /* * id is the MAC address ID - something to do with MAC filtering. * color - not sure. * * These are both functions of the vap, not of the node. * So, for now, hard-code both to 0 (default). */ cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); cmd->action = htole32(action); cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA); /* * The TSF ID is one of four TSF tracking resources in the firmware. * Read the iwlwifi/mvm code for more details. * * For now, just hard-code it to TSF tracking ID 0; we only support * a single STA mode VAP. * * It's per-vap, not per-node. */ cmd->tsf_id = htole32(IWM_DEFAULT_TSFID); IEEE80211_ADDR_COPY(cmd->node_addr, sc->sc_bssid); /* * XXX should we error out if in_assoc is 1 and ni == NULL? */ if (in->in_assoc) { IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid); } else { /* eth broadcast address */ memset(cmd->bssid_addr, 0xff, sizeof(cmd->bssid_addr)); } /* * Default to 2ghz if no node information is given. */ if (in) { is2ghz = !! IEEE80211_IS_CHAN_2GHZ(in->in_ni.ni_chan); } else { is2ghz = 1; } iwm_mvm_ack_rates(sc, is2ghz, &cck_ack_rates, &ofdm_ack_rates); cmd->cck_rates = htole32(cck_ack_rates); cmd->ofdm_rates = htole32(ofdm_ack_rates); cmd->cck_short_preamble = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? IWM_MAC_FLG_SHORT_PREAMBLE : 0); cmd->short_slot = htole32((ic->ic_flags & IEEE80211_F_SHSLOT) ? IWM_MAC_FLG_SHORT_SLOT : 0); /* XXX TODO: set wme parameters; also handle getting updated wme parameters */ for (i = 0; i < IWM_AC_NUM+1; i++) { int txf = i; cmd->ac[txf].cw_min = htole16(0x0f); cmd->ac[txf].cw_max = htole16(0x3f); cmd->ac[txf].aifsn = 1; cmd->ac[txf].fifos_mask = (1 << txf); cmd->ac[txf].edca_txop = 0; } if (ic->ic_flags & IEEE80211_F_USEPROT) cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT); cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP); }
/* * 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; }
Static void ar9287_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, struct ieee80211_channel *extc) { const struct ar9287_eeprom *eep = sc->sc_eep; const struct ar9287_modal_eep_header *modal = &eep->modalHeader; uint8_t tpow_cck[4], tpow_ofdm[4]; #ifndef IEEE80211_NO_HT uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4]; uint8_t tpow_ht20[8], tpow_ht40[8]; uint8_t ht40inc; #endif int16_t pwr = 0, max_ant_gain, power[ATHN_POWER_COUNT]; int i; ar9287_set_power_calib(sc, c); /* Compute transmit power reduction due to antenna gain. */ max_ant_gain = MAX(modal->antennaGainCh[0], modal->antennaGainCh[1]); /* XXX */ /* * Reduce scaled power by number of active chains to get per-chain * transmit power level. */ if (sc->sc_ntxchains == 2) pwr -= AR_PWR_DECREASE_FOR_2_CHAIN; if (pwr < 0) pwr = 0; /* Get CCK target powers. */ ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck, AR9287_NUM_2G_CCK_TARGET_POWERS, tpow_cck); /* Get OFDM target powers. */ ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G, AR9287_NUM_2G_20_TARGET_POWERS, tpow_ofdm); #ifndef IEEE80211_NO_HT /* Get HT-20 target powers. */ ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20, AR9287_NUM_2G_20_TARGET_POWERS, tpow_ht20); if (extc != NULL) { /* Get HT-40 target powers. */ ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40, eep->calTargetPower2GHT40, AR9287_NUM_2G_40_TARGET_POWERS, tpow_ht40); /* Get secondary channel CCK target powers. */ ar5008_get_lg_tpow(sc, extc, AR_CTL_11B, eep->calTargetPowerCck, AR9287_NUM_2G_CCK_TARGET_POWERS, tpow_cck_ext); /* Get secondary channel OFDM target powers. */ ar5008_get_lg_tpow(sc, extc, AR_CTL_11G, eep->calTargetPower2G, AR9287_NUM_2G_20_TARGET_POWERS, tpow_ofdm_ext); } #endif memset(power, 0, sizeof(power)); /* Shuffle target powers accross transmit rates. */ power[ATHN_POWER_OFDM6 ] = power[ATHN_POWER_OFDM9 ] = power[ATHN_POWER_OFDM12 ] = power[ATHN_POWER_OFDM18 ] = power[ATHN_POWER_OFDM24 ] = tpow_ofdm[0]; power[ATHN_POWER_OFDM36 ] = tpow_ofdm[1]; power[ATHN_POWER_OFDM48 ] = tpow_ofdm[2]; power[ATHN_POWER_OFDM54 ] = tpow_ofdm[3]; power[ATHN_POWER_XR ] = tpow_ofdm[0]; power[ATHN_POWER_CCK1_LP ] = tpow_cck[0]; power[ATHN_POWER_CCK2_LP ] = power[ATHN_POWER_CCK2_SP ] = tpow_cck[1]; power[ATHN_POWER_CCK55_LP] = power[ATHN_POWER_CCK55_SP] = tpow_cck[2]; power[ATHN_POWER_CCK11_LP] = power[ATHN_POWER_CCK11_SP] = tpow_cck[3]; #ifndef IEEE80211_NO_HT for (i = 0; i < nitems(tpow_ht20); i++) power[ATHN_POWER_HT20(i)] = tpow_ht20[i]; if (extc != NULL) { /* Correct PAR difference between HT40 and HT20/Legacy. */ if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_2) ht40inc = modal->ht40PowerIncForPdadc; else ht40inc = AR_HT40_POWER_INC_FOR_PDADC; for (i = 0; i < nitems(tpow_ht40); i++) power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc; power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0]; power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0]; power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0]; if (IEEE80211_IS_CHAN_2GHZ(c)) power[ATHN_POWER_CCK_EXT] = tpow_cck_ext[0]; } #endif for (i = 0; i < ATHN_POWER_COUNT; i++) { power[i] -= AR_PWR_TABLE_OFFSET_DB * 2; /* In half dB. */ if (power[i] > AR_MAX_RATE_POWER) power[i] = AR_MAX_RATE_POWER; } /* Commit transmit power values to hardware. */ ar5008_write_txpower(sc, power); }
/* * Restore/reset the ANI parameters and reset the statistics. * This routine must be called for every channel change. * * NOTE: This is where ah_curani is set; other ani code assumes * it is setup to reflect the current channel. */ void ar5416AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_OPMODE opmode, int restore) { struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); /* XXX bounds check ic_devdata */ struct ar5212AniState *aniState = &ahp->ah_ani[chan->ic_devdata]; uint32_t rxfilter; if ((ichan->privFlags & CHANNEL_ANI_INIT) == 0) { OS_MEMZERO(aniState, sizeof(*aniState)); if (IEEE80211_IS_CHAN_2GHZ(chan)) aniState->params = &ahp->ah_aniParams24; else aniState->params = &ahp->ah_aniParams5; ichan->privFlags |= CHANNEL_ANI_INIT; HALASSERT((ichan->privFlags & CHANNEL_ANI_SETUP) == 0); } ahp->ah_curani = aniState; #if 0 ath_hal_printf(ah,"%s: chan %u/0x%x restore %d opmode %u%s\n", __func__, chan->ic_freq, chan->ic_flags, restore, opmode, ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : ""); #else HALDEBUG(ah, HAL_DEBUG_ANI, "%s: chan %u/0x%x restore %d opmode %u%s\n", __func__, chan->ic_freq, chan->ic_flags, restore, opmode, ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : ""); #endif OS_MARK(ah, AH_MARK_ANI_RESET, opmode); /* * Turn off PHY error frame delivery while we futz with settings. */ rxfilter = ar5212GetRxFilter(ah); ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); /* * Automatic processing is done only in station mode right now. */ if (opmode == HAL_M_STA) ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA; else ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA; /* * Set all ani parameters. We either set them to initial * values or restore the previous ones for the channel. * XXX if ANI follows hardware, we don't care what mode we're * XXX in, we should keep the ani parameters */ if (restore && (ichan->privFlags & CHANNEL_ANI_SETUP)) { ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel); ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel); ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, !aniState->ofdmWeakSigDetectOff); ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, aniState->cckWeakSigThreshold); ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); } else { ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); ichan->privFlags |= CHANNEL_ANI_SETUP; } ar5416AniRestart(ah, aniState); /* restore RX filter mask */ ar5212SetRxFilter(ah, rxfilter); }
void ar9280SpurMitigate(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; static int inc[4] = { 0, 100, 0, 0 }; int bb_spur = AR_NO_SPUR; int freq; int bin, cur_bin; int bb_spur_off, spur_subchannel_sd; int spur_freq_sd; int spur_delta_phase; int denominator; int upper, lower, cur_vit_mask; int tmp, newVal; int i; CHAN_CENTERS centers; int8_t mask_m[123]; int8_t mask_p[123]; int8_t mask_amt; int tmp_mask; int cur_bb_spur; HAL_BOOL is2GHz = IEEE80211_IS_CHAN_2GHZ(chan); OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); ar5416GetChannelCenters(ah, chan, ¢ers); freq = centers.synth_center; /* * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, * otherwise spur is out-of-band and can be ignored. */ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); /* Get actual spur freq in MHz from EEPROM read value */ if (is2GHz) { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; } else { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; } if (AR_NO_SPUR == cur_bb_spur) break; cur_bb_spur = cur_bb_spur - freq; if (IEEE80211_IS_CHAN_HT40(chan)) { if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { bb_spur = cur_bb_spur; break; } } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { bb_spur = cur_bb_spur; break; } } if (AR_NO_SPUR == bb_spur) { #if 1 /* * MRC CCK can interfere with beacon detection and cause deaf/mute. * Disable MRC CCK for now. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #else /* Enable MRC CCK if no spur is found in this channel. */ OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #endif return; } else { /* * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur * is found in this channel. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); } bin = bb_spur * 320; tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), newVal); newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | AR_PHY_SPUR_REG_MASK_RATE_SELECT | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | SM(AR5416_SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); /* Pick control or extn channel to cancel the spur */ if (IEEE80211_IS_CHAN_HT40(chan)) { if (bb_spur < 0) { spur_subchannel_sd = 1; bb_spur_off = bb_spur + 10; } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur - 10; } } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur; } /* * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, * /80 for dyn2040. */ if (IEEE80211_IS_CHAN_HT40(chan)) spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; else spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; /* * in 11A mode the denominator of spur_freq_sd should be 40 and * it should be 44 in 11G */ denominator = IEEE80211_IS_CHAN_2GHZ(chan) ? 44 : 40; spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); /* Choose to cancel between control and extension channels */ newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); /* * ============================================ * Set Pilot and Channel Masks * * pilot mask 1 [31:0] = +6..-26, no 0 bin * pilot mask 2 [19:0] = +26..+7 * * channel mask 1 [31:0] = +6..-26, no 0 bin * channel mask 2 [19:0] = +26..+7 */ cur_bin = -6000; upper = bin + 100; lower = bin - 100; for (i = 0; i < 4; i++) { int pilot_mask = 0; int chan_mask = 0; int bp = 0; for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; chan_mask = chan_mask | 0x1 << bp; } cur_bin += 100; } cur_bin += inc[i]; OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); } /* ================================================= * viterbi mask 1 based on channel magnitude * four levels 0-3 * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) * [1 2 2 1] for -9.6 or [1 2 1] for +16 * - enable_mask_ppm, all bins move with freq * * - mask_select, 8 bits for rates (reg 67,0x990c) * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) * choose which mask to use mask or mask2 */ /* * viterbi mask 2 2nd set for per data rate puncturing * four levels 0-3 * - mask_select, 8 bits for rates (reg 67) * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) * [1 2 2 1] for -9.6 or [1 2 1] for +16 */ cur_vit_mask = 6100; upper = bin + 120; lower = bin - 120; for (i = 0; i < 123; i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { if ((abs(cur_vit_mask - bin)) < 75) { mask_amt = 1; } else { mask_amt = 0; } if (cur_vit_mask < 0) { mask_m[abs(cur_vit_mask / 100)] = mask_amt; } else { mask_p[cur_vit_mask / 100] = mask_amt; } } cur_vit_mask -= 100; } tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) | (mask_m[48] << 26) | (mask_m[49] << 24) | (mask_m[50] << 22) | (mask_m[51] << 20) | (mask_m[52] << 18) | (mask_m[53] << 16) | (mask_m[54] << 14) | (mask_m[55] << 12) | (mask_m[56] << 10) | (mask_m[57] << 8) | (mask_m[58] << 6) | (mask_m[59] << 4) | (mask_m[60] << 2) | (mask_m[61] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); tmp_mask = (mask_m[31] << 28) | (mask_m[32] << 26) | (mask_m[33] << 24) | (mask_m[34] << 22) | (mask_m[35] << 20) | (mask_m[36] << 18) | (mask_m[37] << 16) | (mask_m[48] << 14) | (mask_m[39] << 12) | (mask_m[40] << 10) | (mask_m[41] << 8) | (mask_m[42] << 6) | (mask_m[43] << 4) | (mask_m[44] << 2) | (mask_m[45] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) | (mask_m[18] << 26) | (mask_m[18] << 24) | (mask_m[20] << 22) | (mask_m[20] << 20) | (mask_m[22] << 18) | (mask_m[22] << 16) | (mask_m[24] << 14) | (mask_m[24] << 12) | (mask_m[25] << 10) | (mask_m[26] << 8) | (mask_m[27] << 6) | (mask_m[28] << 4) | (mask_m[29] << 2) | (mask_m[30] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) | (mask_m[10] << 10) | (mask_m[11] << 8) | (mask_m[12] << 6) | (mask_m[13] << 4) | (mask_m[14] << 2) | (mask_m[15] << 0); OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); tmp_mask = (mask_p[15] << 28) | (mask_p[14] << 26) | (mask_p[13] << 24) | (mask_p[12] << 22) | (mask_p[11] << 20) | (mask_p[10] << 18) | (mask_p[ 9] << 16) | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); tmp_mask = (mask_p[30] << 28) | (mask_p[29] << 26) | (mask_p[28] << 24) | (mask_p[27] << 22) | (mask_p[26] << 20) | (mask_p[25] << 18) | (mask_p[24] << 16) | (mask_p[23] << 14) | (mask_p[22] << 12) | (mask_p[21] << 10) | (mask_p[20] << 8) | (mask_p[19] << 6) | (mask_p[18] << 4) | (mask_p[17] << 2) | (mask_p[16] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); tmp_mask = (mask_p[45] << 28) | (mask_p[44] << 26) | (mask_p[43] << 24) | (mask_p[42] << 22) | (mask_p[41] << 20) | (mask_p[40] << 18) | (mask_p[39] << 16) | (mask_p[38] << 14) | (mask_p[37] << 12) | (mask_p[36] << 10) | (mask_p[35] << 8) | (mask_p[34] << 6) | (mask_p[33] << 4) | (mask_p[32] << 2) | (mask_p[31] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) | (mask_p[59] << 26) | (mask_p[58] << 24) | (mask_p[57] << 22) | (mask_p[56] << 20) | (mask_p[55] << 18) | (mask_p[54] << 16) | (mask_p[53] << 14) | (mask_p[52] << 12) | (mask_p[51] << 10) | (mask_p[50] << 8) | (mask_p[49] << 6) | (mask_p[48] << 4) | (mask_p[47] << 2) | (mask_p[46] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); }
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); }
void ar9280_spur_mitigate(struct athn_softc *sc, struct ieee80211_channel *c, struct ieee80211_channel *extc) { const struct ar_spur_chan *spurchans; int spur, bin, spur_delta_phase, spur_freq_sd, spur_subchannel_sd; int spur_off, range, i; /* NB: Always clear. */ AR_CLRBITS(sc, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); range = (extc != NULL) ? 19 : 10; spurchans = sc->ops.get_spur_chans(sc, IEEE80211_IS_CHAN_2GHZ(c)); for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { spur = spurchans[i].spurChan; if (spur == AR_NO_SPUR) return; /* XXX disable if it was enabled! */ spur /= 10; if (IEEE80211_IS_CHAN_2GHZ(c)) spur += AR_BASE_FREQ_2GHZ; else spur += AR_BASE_FREQ_5GHZ; spur -= c->ic_freq; if (abs(spur) < range) break; } if (i == AR_EEPROM_MODAL_SPURS) return; /* XXX disable if it was enabled! */ DPRINTFN(2, ("enabling spur mitigation\n")); AR_SETBITS(sc, AR_PHY_TIMING_CTRL4_0, AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); AR_WRITE(sc, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | AR_PHY_SPUR_REG_MASK_RATE_SELECT | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | SM(AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, AR_SPUR_RSSI_THRESH)); #ifndef IEEE80211_NO_HT if (extc != NULL) { spur_delta_phase = (spur * 262144) / 10; if (spur < 0) { spur_subchannel_sd = 1; spur_off = spur + 10; } else { spur_subchannel_sd = 0; spur_off = spur - 10; } } else #endif { spur_delta_phase = (spur * 524288) / 10; spur_subchannel_sd = 0; spur_off = spur; } if (IEEE80211_IS_CHAN_2GHZ(c)) spur_freq_sd = (spur_off * 2048) / 44; else spur_freq_sd = (spur_off * 2048) / 40; AR_WRITE(sc, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_IN_AGC | SM(AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd) | SM(AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase)); AR_WRITE(sc, AR_PHY_SFCORR_EXT, SM(AR_PHY_SFCORR_SPUR_SUBCHNL_SD, spur_subchannel_sd)); AR_WRITE_BARRIER(sc); bin = spur * 320; ar5008_set_viterbi_mask(sc, bin); }
/* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * bChannelChange is used to preserve DMA/PCU registers across * a HW Reset during channel change. */ HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL bChannelChange, HAL_RESET_TYPE resetType, HAL_STATUS *status) { #define N(a) (sizeof (a) / sizeof (a[0])) #define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; const HAL_EEPROM *ee; uint32_t saveFrameSeqCount, saveDefAntenna; uint32_t macStaId1, synthDelay, txFrm2TxDStart; uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; uint32_t testReg; uint32_t saveLedState = 0; HALASSERT(ah->ah_magic == AR5212_MAGIC); ee = AH_PRIVATE(ah)->ah_eeprom; OS_MARK(ah, AH_MARK_RESET, bChannelChange); /* * Map public channel to private. */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); FAIL(HAL_EINVAL); } switch (opmode) { case HAL_M_STA: case HAL_M_IBSS: case HAL_M_HOSTAP: case HAL_M_MONITOR: break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * On Venice, the TSF is almost preserved across a reset; * it requires the doubling writes to the RESET_TSF * bit in the AR_BEACON register; it also has the quirk * of the TSF going back in time on the station (station * latches onto the last beacon's tsf during a reset 50% * of the times); the latter is not a problem for adhoc * stations since as long as the TSF is behind, it will * get resynchronized on receiving the next beacon; the * TSF going backwards in time could be a problem for the * sleep operation (supported on infrastructure stations * only) - the best and most general fix for this situation * is to resynchronize the various sleep/beacon timers on * the receipt of the next beacon i.e. when the TSF itself * gets resynchronized to the AP's TSF - power save is * needed to be temporarily disabled until that time * * Need to save the sequence number to restore it after * the reset! */ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); } else saveFrameSeqCount = 0; /* NB: silence compiler */ /* If the channel change is across the same mode - perform a fast channel change */ if ((IS_2413(ah) || IS_5413(ah))) { /* * Channel change can only be used when: * -channel change requested - so it's not the initial reset. * -it's not a change to the current channel - often called when switching modes * on a channel * -the modes of the previous and requested channel are the same - some ugly code for XR */ if (bChannelChange && AH_PRIVATE(ah)->ah_curchan != AH_NULL && (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { if (ar5212ChannelChange(ah, chan)) /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) /* XXX magic constants */ saveDefAntenna = 1; /* Save hardware flag before chip reset clears the register */ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); /* Save led state from pci config register */ if (!IS_5315(ah)) saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); ar5312RestoreClock(ah, opmode); /* move to refclk operation */ /* * Adjust gain parameters before reset if * there's an outstanding gain updated. */ (void) ar5212GetRfgain(ah); if (!ar5312ChipReset(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : IEEE80211_IS_CHAN_G(chan) ? 4 : 3; } else { freqIndex = 1; modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, regWrites); ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) ar5212SetIFSTiming(ah, chan); /* Overwrite INI values for revised chipsets */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { /* ADC_CTL */ OS_REG_WRITE(ah, AR_PHY_ADC_CTL, SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | AR_PHY_ADC_CTL_OFF_PWDDAC | AR_PHY_ADC_CTL_OFF_PWDADC); /* TX_PWR_ADJ */ if (chan->channel == 2484) { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); } if (IEEE80211_IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); } else { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); } /* Add barker RSSI thresh enable as disabled */ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); /* Set the mute mask to the correct default */ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { /* Clear reg to alllow RX_CLEAR line debug */ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { #ifdef notyet /* Enable burst prefetch for the data queues */ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); /* Enable double-buffering */ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); #endif } if (IS_5312_2_X(ah)) { /* ADC_CTRL */ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | SM(4, AR_PHY_SIGMA_DELTA_FILT2) | SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); if (IEEE80211_IS_CHAN_2GHZ(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); /* CCK Short parameter adjustment in 11B mode */ if (IEEE80211_IS_CHAN_B(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); /* Increase 11A AGC Settling */ if (IEEE80211_IS_CHAN_A(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); } else { /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); } /* Setup the transmit power values. */ if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan)) { if (IS_5413(ah) || AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) ar5212SetSpurMitigation(ah, chan); ar5212SetDeltaSlope(ah, chan); } /* Setup board specific options for EEPROM version 3 */ if (!ar5212SetBoardValues(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | ahp->ah_staId1Defaults ); ar5212SetOperatingMode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); /* Restore previous led state */ if (!IS_5315(ah)) OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); /* then our BSSID */ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ if (!ar5212SetChannel(ah, chan)) FAIL(HAL_EIO); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); ar5212SetRateDurationTable(ah, chan); /* Set Tx frame start to tx data start delay */ if (IS_RAD5112_ANY(ah) && (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { txFrm2TxDStart = IEEE80211_IS_CHAN_HALF(chan) ? TX_FRAME_D_START_HALF_RATE: TX_FRAME_D_START_QUARTER_RATE; OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); } /* * Setup fast diversity. * Fast diversity can be enabled or disabled via regadd.txt. * Default is enabled. * For reference, * Disable: reg val * 0x00009860 0x00009d18 (if 11a / 11g, else no change) * 0x00009970 0x192bb514 * 0x0000a208 0xd03e4648 * * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) * 0x00009970 0x192fb514 * 0x0000a208 0xd03e6788 */ /* XXX Setup pre PHY ENABLE EAR additions */ /* flush SCAL reg */ if (IS_5312_2_X(ah)) { (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); } /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_B(chan)) { synthDelay = (4 * synthDelay) / 22; } else { synthDelay /= 10; } /* Activate the PHY (includes baseband activate and synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear false triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ if (IEEE80211_IS_CHAN_HALF(chan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* * The udelay method is not reliable with notebooks. * Need to check to see if the baseband is ready */ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); /* Selects the Tx hold */ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); i = 0; while ((i++ < 20) && (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); /* Calibrate the AGC and start a NF calculation */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL | AR_PHY_AGC_CONTROL_NF); if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, INIT_IQCAL_LOG_COUNT_MAX); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL); ahp->ah_bIQCalibration = IQ_CAL_RUNNING; } else ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; /* Setup compression registers */ ar5212SetCompRegs(ah); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); ahp->ah_intrTxqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) ar5212ResetTxQueue(ah, i); /* * Setup interrupt handling. Note that ar5212ResetTxQueue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_HIUERR ; if (opmode == HAL_M_HOSTAP) ahp->ah_maskReg |= AR_IMR_MIB; OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); /* Enable bus errors that are OR'd to set the HIUERR bit */ OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); if (AH_PRIVATE(ah)->ah_rfkillEnabled) ar5212EnableRfKill(ah); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms;" " noisy environment?\n", __func__); } /* * Set clocks back to 32kHz if they had been using refClk, then * use an external 32kHz crystal when sleeping, if one exists. */ ar5312SetupClock(ah, opmode); /* * Writing to AR_BEACON will start timers. Hence it should * be the last register to be written. Do not reset tsf, do * not enable beacons at this point, but preserve other values * like beaconInterval. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); /* XXX Setup post reset EAR additions */ /* QoS support */ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ } /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_NOACK, SM(2, AR_NOACK_2BIT_VALUE) | SM(5, AR_NOACK_BIT_OFFSET) | SM(0, AR_NOACK_BYTE_OFFSET)); /* Restore user-specified settings */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); if (ahp->ah_slottime != (u_int) -1) ar5212SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5212SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); if (ahp->ah_sifstime != (u_int) -1) ar5212SetSifsTime(ah, ahp->ah_sifstime); if (AH_PRIVATE(ah)->ah_diagreg != 0) OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); OS_MARK(ah, AH_MARK_RESET_DONE, 0); return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); if (status != AH_NULL) *status = ecode; return AH_FALSE; #undef FAIL #undef N }
static struct wifi_channels *list_channelsext(const char *ifname, int allchans) { struct ieee80211req_chaninfo chans; struct ieee80211req_chaninfo achans; const struct ieee80211_channel *c; int i; fprintf(stderr, "list channels for %s\n", ifname); if (do80211priv (ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0) { fprintf(stderr, "unable to get channel information\n"); return NULL; } if (!allchans) { uint8_t active[64]; if (do80211priv (ifname, IEEE80211_IOCTL_GETCHANLIST, &active, sizeof(active)) < 0) { fprintf(stderr, "unable to get active channel list\n"); return NULL; } memset(&achans, 0, sizeof(achans)); for (i = 0; i < chans.ic_nchans; i++) { c = &chans.ic_chans[i]; if (isset(active, c->ic_ieee) || allchans) achans.ic_chans[achans.ic_nchans++] = *c; } } else achans = chans; struct wifi_channels *list = (struct wifi_channels *)safe_malloc(sizeof(struct wifi_channels) * (achans.ic_nchans + 1)); (void)memset(list, 0, (sizeof(struct wifi_channels)*((achans.ic_nchans + 1)))); char wl_mode[16]; char wl_turbo[16]; sprintf(wl_mode, "%s_net_mode", ifname); sprintf(wl_turbo, "%s_channelbw", ifname); int l = 0; int up = 0; char sb[32]; sprintf(sb, "%s_nctrlsb", ifname); if (nvram_match(sb, "upper")) up = 1; for (i = 0; i < achans.ic_nchans; i++) { #ifdef HAVE_BUFFALO if (achans.ic_chans[i].ic_flags & IEEE80211_CHAN_RADARFOUND) //filter channels with detected radar continue; #endif // filter out A channels if mode isnt A-Only or mixed if (IEEE80211_IS_CHAN_5GHZ(&achans.ic_chans[i])) { if (nvram_invmatch(wl_mode, "a-only") && nvram_invmatch(wl_mode, "mixed") && nvram_invmatch(wl_mode, "n5-only") && nvram_invmatch(wl_mode, "na-only")) { // fprintf(stderr,"5 Ghz %d is not compatible to a-only/mixed/na-only %X\n",achans.ic_chans[i].ic_freq,achans.ic_chans[i].ic_flags); continue; } if (nvram_match(wl_turbo, "40") && (nvram_match(wl_mode, "n5-only") || nvram_match(wl_mode, "mixed") || nvram_match(wl_mode, "na-only"))) { if (up && !IEEE80211_IS_CHAN_11NA_HT40PLUS (&achans.ic_chans[i])) continue; if (!up && !IEEE80211_IS_CHAN_11NA_HT40MINUS (&achans.ic_chans[i])) continue; } } // filter out B/G channels if mode isnt g-only, b-only or mixed if (IEEE80211_IS_CHAN_2GHZ(&achans.ic_chans[i])) { if (nvram_invmatch(wl_mode, "g-only") && nvram_invmatch(wl_mode, "mixed") && nvram_invmatch(wl_mode, "b-only") && nvram_invmatch(wl_mode, "n2-only") && nvram_invmatch(wl_mode, "bg-mixed") && nvram_invmatch(wl_mode, "ng-only")) { fprintf(stderr, "%s:%d\n", __func__, __LINE__); continue; } #ifdef HAVE_BUFFALO_SA if(nvram_default_match("region", "SA", "") && (!strcmp(getUEnv("region"), "AP") || !strcmp(getUEnv("region"), "US")) && achans.ic_chans[i].ic_ieee > 11 && achans.ic_chans[i].ic_ieee <= 14) continue; #endif if (nvram_match(wl_turbo, "40") && (nvram_match(wl_mode, "n2-only") || nvram_match(wl_mode, "mixed") || nvram_match(wl_mode, "ng-only"))) { if (up && !IEEE80211_IS_CHAN_11NG_HT40PLUS (&achans.ic_chans[i])) { fprintf(stderr, "%s:%d\n", __func__, __LINE__); continue; } if (!up && !IEEE80211_IS_CHAN_11NG_HT40MINUS (&achans.ic_chans[i])) { fprintf(stderr, "%s:%d\n", __func__, __LINE__); continue; } } } list[l].channel = achans.ic_chans[i].ic_ieee; list[l].freq = achans.ic_chans[i].ic_freq; list[l].noise = -95; // achans.ic_chans[i].ic_noise; l++; } list[l].freq = -1; return list; }