bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ struct ath_common *common = ath9k_hw_common(ah); u32 mac_status = 0, last_mac_status = 0; int i; /* Enable access to the DMA observation bus */ REG_WRITE(ah, AR_MACMISC, ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Wait for rx enable bit to go low */ for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) break; if (!AR_SREV_9300_20_OR_LATER(ah)) { mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0; if (mac_status == 0x1c0 && mac_status == last_mac_status) { *reset = true; break; } last_mac_status = mac_status; } udelay(AH_TIME_QUANTUM); } if (i == 0) { if (!AR_SREV_9300_20_OR_LATER(ah) && (mac_status & 0x700) == 0) { /* * DMA is idle but the MAC is still stuck * processing events */ *reset = true; return true; } ath_err(common, "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW), REG_READ(ah, AR_DMADBG_7)); return false; } else { return true; } #undef AH_RX_STOP_DMA_TIMEOUT }
void ath9k_hw_ani_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416AniState *ani = &ah->ani; ath_dbg(common, ANI, "Initialize ANI\n"); ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false; ani->ofdmsTurn = true; ani->ofdmWeakSigDetect = true; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; /* * since we expect some ongoing maintenance on the tables, let's sanity * check here default level should not modify INI setting. */ ah->aniperiod = ATH9K_ANI_PERIOD; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; ath9k_ani_restart(ah); ath9k_enable_mib_counters(ah); }
static int open_file_regdump(struct inode *inode, struct file *file) { struct ath_softc *sc = inode->i_private; unsigned int len = 0; u8 *buf; int i; unsigned long num_regs, regdump_len, max_reg_offset; max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x16bd4 : 0xb500; num_regs = max_reg_offset / 4 + 1; regdump_len = num_regs * REGDUMP_LINE_SIZE + 1; buf = vmalloc(regdump_len); if (!buf) return -ENOMEM; ath9k_ps_wakeup(sc); for (i = 0; i < num_regs; i++) len += scnprintf(buf + len, regdump_len - len, "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); ath9k_ps_restore(sc); file->private_data = buf; return 0; }
static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u8 tx_streams, rx_streams; int i, max_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SM_PS | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) max_streams = 1; else if (AR_SREV_9462(ah)) max_streams = 2; else if (AR_SREV_9300_20_OR_LATER(ah)) max_streams = 3; else max_streams = 2; if (AR_SREV_9280_20_OR_LATER(ah)) { if (max_streams >= 2) ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); } /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); if (tx_streams != rx_streams) { ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } for (i = 0; i < rx_streams; i++) ht_info->mcs.rx_mask[i] = 0xff; ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; }
void ath9k_tx99_init_debug(struct ath_softc *sc) { if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah)) return; debugfs_create_file("tx99", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_tx99); debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_tx99_power); }
void ath9k_rng_start(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; if (sc->rng_task) return; if (!AR_SREV_9300_20_OR_LATER(ah)) return; sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng"); if (IS_ERR(sc->rng_task)) sc->rng_task = NULL; }
bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 struct ath_common *common = ath9k_hw_common(ah); u32 mac_status, last_mac_status = 0; int i; REG_WRITE(ah, AR_MACMISC, ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); REG_WRITE(ah, AR_CR, AR_CR_RXD); for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) break; if (!AR_SREV_9300_20_OR_LATER(ah)) { mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0; if (mac_status == 0x1c0 && mac_status == last_mac_status) { *reset = true; break; } last_mac_status = mac_status; } udelay(AH_TIME_QUANTUM); } if (i == 0) { ath_err(common, "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW), REG_READ(ah, AR_DMADBG_7)); return false; } else { return true; } #undef AH_RX_STOP_DMA_TIMEOUT }
void ath9k_hw_ani_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); int i; ath_dbg(common, ANI, "Initialize ANI\n"); ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { struct ath9k_channel *chan = &ah->channels[i]; struct ar5416AniState *ani = &chan->ani; ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false; ani->ofdmsTurn = true; ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; } /* * since we expect some ongoing maintenance on the tables, let's sanity * check here default level should not modify INI setting. */ ah->aniperiod = ATH9K_ANI_PERIOD; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; ath9k_ani_restart(ah); ath9k_enable_mib_counters(ah); }
/* * Set the ANI settings to match an CCK level. */ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, bool scan) { struct ar5416AniState *aniState = &ah->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->cckNoiseImmunityLevel, immunityLevel, BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL) immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW && immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; if (!scan) aniState->cckNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; if (aniState->firstepLevel != entry_cck->fir_step_level && entry_cck->fir_step_level >= entry_ofdm->fir_step_level) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, entry_cck->fir_step_level); /* Skip MRC CCK for pre AR9003 families */ if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah) || AR_SREV_9561(ah)) return; if (aniState->mrcCCK != entry_cck->mrc_cck_on) ath9k_hw_ani_control(ah, ATH9K_ANI_MRC_CCK, entry_cck->mrc_cck_on); }
/* * Set the ANI settings to match an CCK level. */ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; aniState->noiseFloor = BEACON_RSSI(ah); ath_dbg(common, ATH_DBG_ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->cckNoiseImmunityLevel, immunityLevel, aniState->noiseFloor, aniState->rssiThrLow, aniState->rssiThrHigh); if ((ah->opmode == NL80211_IFTYPE_STATION || ah->opmode == NL80211_IFTYPE_ADHOC) && aniState->noiseFloor <= aniState->rssiThrLow && immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; if (aniState->update_ani) aniState->cckNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; if (aniState->firstepLevel != entry_cck->fir_step_level && entry_cck->fir_step_level >= entry_ofdm->fir_step_level) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, entry_cck->fir_step_level); /* Skip MRC CCK for pre AR9003 families */ if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah)) return; if (aniState->mrcCCKOff == entry_cck->mrc_cck_on) ath9k_hw_ani_control(ah, ATH9K_ANI_MRC_CCK, entry_cck->mrc_cck_on); }
int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; if (AR_SREV_9300_20_OR_LATER(ah)) ah->eep_ops = &eep_ar9300_ops; else if (AR_SREV_9287(ah)) { ah->eep_ops = &eep_ar9287_ops; } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { ah->eep_ops = &eep_4k_ops; } else { ah->eep_ops = &eep_def_ops; } if (!ah->eep_ops->fill_eeprom(ah)) return -EIO; status = ah->eep_ops->check_eeprom(ah); return status; }
static ssize_t read_file_eeprom(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int bytes = 0; int pos = *ppos; int size = 4096; u16 val; int i; if (AR_SREV_9300_20_OR_LATER(ah)) size = 16384; if (*ppos < 0) return -EINVAL; if (count > size - *ppos) count = size - *ppos; for (i = *ppos / 2; count > 0; count -= bytes, *ppos += bytes, i++) { void *from = &val; if (!common->bus_ops->eeprom_read(common, i, &val)) val = 0xffff; if (*ppos % 2) { from++; bytes = 1; } else if (count == 1) { bytes = 1; } else { bytes = 2; } copy_to_user(user_buf, from, bytes); user_buf += bytes; } return *ppos - pos; }
static int open_file_regdump(struct inode *inode, struct file *file) { struct ath_softc *sc = inode->i_private; unsigned int len = 0; u8 *buf; int i, j = 0; unsigned long num_regs, regdump_len, max_reg_offset; const struct reg_hole { u32 start; u32 end; } reg_hole_list[] = { {0x0200, 0x07fc}, {0x0c00, 0x0ffc}, {0x2000, 0x3ffc}, {0x4100, 0x6ffc}, {0x705c, 0x7ffc}, {0x0000, 0x0000} }; max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x8800 : 0xb500; num_regs = max_reg_offset / 4 + 1; regdump_len = num_regs * REGDUMP_LINE_SIZE + 1; buf = vmalloc(regdump_len); if (!buf) return -ENOMEM; ath9k_ps_wakeup(sc); for (i = 0; i < num_regs; i++) { if (reg_hole_list[j].start == i << 2) { i = reg_hole_list[j].end >> 2; j++; continue; } len += scnprintf(buf + len, regdump_len - len, "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); }
/* * Restore the ANI parameters in the HAL and reset the statistics. * This routine should be called for every hardware reset and for * every channel change. */ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); int ofdm_nil, cck_nil; if (!ah->curchan) return; BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; /* only allow a subset of functions in AP mode */ if (ah->opmode == NL80211_IFTYPE_AP) { if (IS_CHAN_2GHZ(chan)) { ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); if (AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function |= ATH9K_ANI_MRC_CCK; } else ah->ani_function = 0; } ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, aniState->cckNoiseImmunityLevel); if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { /* * If we're scanning or in AP mode, the defaults (ini) * should be in place. For an AP we assume the historical * levels for this channel are probably outdated so start * from defaults instead. */ if (aniState->ofdmNoiseImmunityLevel != ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); ofdm_nil = ATH9K_ANI_OFDM_DEF_LEVEL; cck_nil = ATH9K_ANI_CCK_DEF_LEVEL; } } else { /* * restore historical levels for this channel */ ath_dbg(common, ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); } ath9k_hw_set_ofdm_nil(ah, ofdm_nil, is_scanning); ath9k_hw_set_cck_nil(ah, cck_nil, is_scanning); ath9k_ani_restart(ah); }
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, QUEUE, "Reset TXQ, inactive queue: %u\n", q); return true; } ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { chanCwMin = INIT_CWMIN; for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); } else cwMin = qi->tqi_cwmin; ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); REG_WRITE(ah, AR_DRETRY_LIMIT(q), SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah)) REG_WRITE(ah, AR_DMISC(q), AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1); else REG_WRITE(ah, AR_DMISC(q), AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); if (qi->tqi_cbrPeriod) { REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | (qi->tqi_cbrOverflowLimit ? AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); } if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { REG_WRITE(ah, AR_QRDYTIMECFG(q), SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | AR_Q_RDYTIMECFG_EN); } REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); if (qi->tqi_burstTime && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); switch (qi->tqi_type) { case ATH9K_TX_QUEUE_BEACON: ENABLE_REGWRITE_BUFFER(ah); REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_BEACON_USE | AR_Q_MISC_CBR_INCR_DIS1); REG_SET_BIT(ah, AR_DMISC(q), (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); /* * cwmin and cwmax should be 0 for beacon queue * but not for IBSS as we would create an imbalance * on beaconing fairness for participating nodes. */ if (AR_SREV_9300_20_OR_LATER(ah) && ah->opmode != NL80211_IFTYPE_ADHOC) { REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN) | SM(0, AR_D_LCL_IFS_CWMAX) | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); } break; case ATH9K_TX_QUEUE_CAB: ENABLE_REGWRITE_BUFFER(ah); REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - (ah->config.sw_beacon_response_time - ah->config.dma_beacon_response_time)) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); REG_SET_BIT(ah, AR_DMISC(q), (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); REGWRITE_BUFFER_FLUSH(ah); break; case ATH9K_TX_QUEUE_PSPOLL: REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); break; case ATH9K_TX_QUEUE_UAPSD: REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); break; default: break; } if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { REG_SET_BIT(ah, AR_DMISC(q), SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, AR_D_MISC_ARB_LOCKOUT_CNTRL) | AR_D_MISC_POST_FR_BKOFF_DIS); } if (AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); ath9k_hw_clear_queue_interrupts(ah, q); if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) { ah->txok_interrupt_mask |= 1 << q; ah->txerr_interrupt_mask |= 1 << q; } if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) ah->txdesc_interrupt_mask |= 1 << q; if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) ah->txeol_interrupt_mask |= 1 << q; if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) ah->txurn_interrupt_mask |= 1 << q; ath9k_hw_set_txq_interrupts(ah, qi); return true; }
void ath9k_hw_set_interrupts(struct ath_hw *ah) { enum ath9k_int ints = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints); mask = ints & ATH9K_INT_COMMON; mask2 = 0; if (ints & ATH9K_INT_TX) { if (ah->config.tx_intr_mitigation) mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; else { if (ah->txok_interrupt_mask) mask |= AR_IMR_TXOK; if (ah->txdesc_interrupt_mask) mask |= AR_IMR_TXDESC; } if (ah->txerr_interrupt_mask) mask |= AR_IMR_TXERR; if (ah->txeol_interrupt_mask) mask |= AR_IMR_TXEOL; } if (ints & ATH9K_INT_RX) { if (AR_SREV_9300_20_OR_LATER(ah)) { mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) { mask &= ~AR_IMR_RXOK_LP; mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; } else { mask |= AR_IMR_RXOK_LP; } } else { if (ah->config.rx_intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; } if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) mask |= AR_IMR_GENTMR; } if (ints & ATH9K_INT_GENTIMER) mask |= AR_IMR_GENTMR; if (ints & (ATH9K_INT_BMISC)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_TIM) mask2 |= AR_IMR_S2_TIM; if (ints & ATH9K_INT_DTIM) mask2 |= AR_IMR_S2_DTIM; if (ints & ATH9K_INT_DTIMSYNC) mask2 |= AR_IMR_S2_DTIMSYNC; if (ints & ATH9K_INT_CABEND) mask2 |= AR_IMR_S2_CABEND; if (ints & ATH9K_INT_TSFOOR) mask2 |= AR_IMR_S2_TSFOOR; } if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_GTT) mask2 |= AR_IMR_S2_GTT; if (ints & ATH9K_INT_CST) mask2 |= AR_IMR_S2_CST; } if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { if (ints & ATH9K_INT_BB_WATCHDOG) { mask |= AR_IMR_BCNMISC; mask2 |= AR_IMR_S2_BB_WATCHDOG; } } ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { if (ints & ATH9K_INT_BB_WATCHDOG) ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG; } ah->imrs2_reg |= mask2; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if (ints & ATH9K_INT_TIM_TIMER) REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); else REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } return; }
void ath9k_hw_ani_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); int i; ath_dbg(common, ANI, "Initialize ANI\n"); if (use_new_ani(ah)) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW; } else { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; } for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { struct ath9k_channel *chan = &ah->channels[i]; struct ar5416AniState *ani = &chan->ani; if (use_new_ani(ah)) { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; if (AR_SREV_9300_20_OR_LATER(ah)) ani->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; else ani->mrcCCKOff = true; ani->ofdmsTurn = true; } else { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; ani->cckWeakSigThreshold = ATH9K_ANI_CCK_WEAK_SIG_THR; } ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; ani->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; ani->update_ani = false; } /* */ if (use_new_ani(ah)) { ah->aniperiod = ATH9K_ANI_PERIOD_NEW; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; } else { ah->aniperiod = ATH9K_ANI_PERIOD_OLD; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; } if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; ath9k_ani_restart(ah); ath9k_enable_mib_counters(ah); }
/* Adjust the OFDM Noise Immunity Level */ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, bool scan) { struct ar5416AniState *aniState = &ah->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; bool weak_sig; ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->ofdmNoiseImmunityLevel, immunityLevel, BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL) immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; if (!scan) aniState->ofdmNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level) ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, entry_ofdm->spur_immunity_level); if (aniState->firstepLevel != entry_ofdm->fir_step_level && entry_ofdm->fir_step_level >= entry_cck->fir_step_level) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, entry_ofdm->fir_step_level); weak_sig = entry_ofdm->ofdm_weak_signal_on; if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) weak_sig = true; /* * Newer chipsets are better at dealing with high PHY error counts - * keep weak signal detection enabled when no RSSI threshold is * available to determine if it is needed (mode != STA) */ else if (AR_SREV_9300_20_OR_LATER(ah) && ah->opmode != NL80211_IFTYPE_STATION) weak_sig = true; /* Older chipsets are more sensitive to high PHY error counts */ else if (!AR_SREV_9300_20_OR_LATER(ah) && aniState->ofdmNoiseImmunityLevel >= 8) weak_sig = false; if (aniState->ofdmWeakSigDetect != weak_sig) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, weak_sig); if (!AR_SREV_9300_20_OR_LATER(ah)) return; if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI; } else { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; } }
/* * Restore the ANI parameters in the HAL and reset the statistics. * This routine should be called for every hardware reset and for * every channel change. */ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; if (!use_new_ani(ah)) return ath9k_ani_reset_old(ah, is_scanning); BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; /* only allow a subset of functions in AP mode */ if (ah->opmode == NL80211_IFTYPE_AP) { if (IS_CHAN_2GHZ(chan)) { ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); if (AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function |= ATH9K_ANI_MRC_CCK; } else ah->ani_function = 0; } /* always allow mode (on/off) to be controlled */ ah->ani_function |= ATH9K_ANI_MODE; if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { /* * If we're scanning or in AP mode, the defaults (ini) * should be in place. For an AP we assume the historical * levels for this channel are probably outdated so start * from defaults instead. */ if (aniState->ofdmNoiseImmunityLevel != ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ATH_DBG_ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = false; ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); } } else { /* * restore historical levels for this channel */ ath_dbg(common, ATH_DBG_ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = true; ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel); ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel); } /* * enable phy counters if hw supports or if not, enable phy * interrupts (so we can count each one) */ ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); }
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; if (!use_new_ani(ah)) return ath9k_ani_reset_old(ah, is_scanning); BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; /* */ if (ah->opmode == NL80211_IFTYPE_AP) { if (IS_CHAN_2GHZ(chan)) { ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | ATH9K_ANI_FIRSTEP_LEVEL); if (AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function |= ATH9K_ANI_MRC_CCK; } else ah->ani_function = 0; } /* */ ah->ani_function |= ATH9K_ANI_MODE; if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { /* */ if (aniState->ofdmNoiseImmunityLevel != ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = false; ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); } } else { /* */ ath_dbg(common, ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); aniState->update_ani = true; ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel); ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel); } /* */ ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); }
static bool use_new_ani(struct ath_hw *ah) { return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; }