diff options
author | 2017-04-25 03:31:15 -0700 | |
---|---|---|
committer | 2017-05-22 06:48:08 +0000 | |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c')
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c | 916 |
1 files changed, 0 insertions, 916 deletions
diff --git a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c b/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c deleted file mode 100644 index 0a17b9bcb..000000000 --- a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c +++ /dev/null @@ -1,916 +0,0 @@ -/* - * Copyright (c) 2008-2011 Atheros Communications Inc. - * - * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011 - * Original from Linux kernel 3.0.1 - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <ipxe/io.h> - -#include "ath9k.h" - -static void ath9k_bss_info_changed(struct net80211_device *dev, u32 changed); - -int ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) -{ - int ret; - - ret = ath9k_hw_setpower(sc->sc_ah, mode); - - return ret; -} - -static void ath_start_ani(struct ath_common *common) -{ - struct ath_hw *ah = common->ah; - unsigned long timestamp = ( currticks() * 1000 ) / TICKS_PER_SEC; - struct ath_softc *sc = (struct ath_softc *) common->priv; - - if (!(sc->sc_flags & SC_OP_ANI_RUN)) - return; - - if (sc->sc_flags & SC_OP_OFFCHANNEL) - return; - - common->ani.longcal_timer = timestamp; - common->ani.shortcal_timer = timestamp; - common->ani.checkani_timer = timestamp; - - common->ani.timer = timestamp + ah->config.ani_poll_interval; -} - -static void ath_update_survey_nf(struct ath_softc *sc, int channel) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath9k_channel *chan = &ah->channels[channel]; - struct survey_info *survey = &sc->survey[channel]; - - if (chan->noisefloor) { - survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = chan->noisefloor; - } -} - -/* - * Updates the survey statistics and returns the busy time since last - * update in %, if the measurement duration was long enough for the - * result to be useful, -1 otherwise. - */ -static int ath_update_survey_stats(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int pos = ah->curchan - &ah->channels[0]; - struct survey_info *survey = &sc->survey[pos]; - struct ath_cycle_counters *cc = &common->cc_survey; - unsigned int div = common->clockrate * 1000; - int ret = 0; - - if (!ah->curchan) - return -1; - - if (ah->power_mode == ATH9K_PM_AWAKE) - ath_hw_cycle_counters_update(common); - - if (cc->cycles > 0) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; - survey->channel_time += cc->cycles / div; - survey->channel_time_busy += cc->rx_busy / div; - survey->channel_time_rx += cc->rx_frame / div; - survey->channel_time_tx += cc->tx_frame / div; - } - - if (cc->cycles < div) - return -1; - - if (cc->cycles > 0) - ret = cc->rx_busy * 100 / cc->cycles; - - memset(cc, 0, sizeof(*cc)); - - ath_update_survey_nf(sc, pos); - - return ret; -} - -/* - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff. -*/ -int ath_set_channel(struct ath_softc *sc, struct net80211_device *dev, - struct ath9k_channel *hchan) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int fastcc __unused = 1, stopped __unused; - struct net80211_channel *channel = dev->channels + dev->channel; - struct ath9k_hw_cal_data *caldata = NULL; - int r; - - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - sc->hw_busy_count = 0; - - common->ani.timer = 0; - sc->tx_complete_work_timer = 0; - sc->hw_pll_work_timer = 0; - - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_disable_interrupts(ah); - stopped = ath_drain_all_txq(sc, 0); - - if (!ath_stoprecv(sc)) - stopped = 0; - - if (!ath9k_hw_check_alive(ah)) - stopped = 0; - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) - caldata = &sc->caldata; - - DBG2("ath9k: " - "(%d MHz) -> (%d MHz)\n", - sc->sc_ah->curchan->channel, - channel->center_freq); - - r = ath9k_hw_reset(ah, hchan, caldata, fastcc); - if (r) { - DBG("ath9k: " - "Unable to reset channel (%d MHz), reset status %d\n", - channel->center_freq, r); - goto ps_restore; - } - - if (ath_startrecv(sc) != 0) { - DBG("ath9k: Unable to restart recv logic\n"); - r = -EIO; - goto ps_restore; - } - - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - ath9k_hw_set_interrupts(ah, ah->imask); - - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { - sc->tx_complete_work(sc); - sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 500; - ath_start_ani(common); - } - - ps_restore: - return r; -} - -/* - * This routine performs the periodic noise floor calibration function - * that is used to adjust and optimize the chip performance. This - * takes environmental changes (location, temperature) into account. - * When the task is complete, it reschedules itself depending on the - * appropriate interval that was calculated. - */ -void ath_ani_calibrate(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int longcal = 0; - int shortcal = 0; - int aniflag = 0; - unsigned int timestamp = (currticks() * 1000 ) / TICKS_PER_SEC; - u32 cal_interval, short_cal_interval, long_cal_interval; - - if (ah->caldata && ah->caldata->nfcal_interference) - long_cal_interval = ATH_LONG_CALINTERVAL_INT; - else - long_cal_interval = ATH_LONG_CALINTERVAL; - - short_cal_interval = ATH_STA_SHORT_CALINTERVAL; - - /* Only calibrate if awake */ - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) - goto set_timer; - - /* Long calibration runs independently of short calibration. */ - if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { - longcal = 1; - DBG2("ath9k: longcal @%d\n", timestamp); - common->ani.longcal_timer = timestamp; - } - - /* Short calibration applies only while caldone is false */ - if (!common->ani.caldone) { - if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { - shortcal = 1; - DBG2("ath9k: " - "shortcal @%d\n", timestamp); - common->ani.shortcal_timer = timestamp; - common->ani.resetcal_timer = timestamp; - } - } else { - if ((timestamp - common->ani.resetcal_timer) >= - ATH_RESTART_CALINTERVAL) { - common->ani.caldone = ath9k_hw_reset_calvalid(ah); - if (common->ani.caldone) - common->ani.resetcal_timer = timestamp; - } - } - - /* Verify whether we must check ANI */ - if ((timestamp - common->ani.checkani_timer) >= - ah->config.ani_poll_interval) { - aniflag = 1; - common->ani.checkani_timer = timestamp; - } - - /* Skip all processing if there's nothing to do. */ - if (longcal || shortcal || aniflag) { - /* Call ANI routine if necessary */ - if (aniflag) { - ath9k_hw_ani_monitor(ah, ah->curchan); - ath_update_survey_stats(sc); - } - - /* Perform calibration if necessary */ - if (longcal || shortcal) { - common->ani.caldone = - ath9k_hw_calibrate(ah, - ah->curchan, - common->rx_chainmask, - longcal); - } - } - -set_timer: - /* - * Set timer interval based on previous results. - * The interval must be the shortest necessary to satisfy ANI, - * short calibration and long calibration. - */ - cal_interval = ATH_LONG_CALINTERVAL; - if (sc->sc_ah->config.enable_ani) - cal_interval = min(cal_interval, - (u32)ah->config.ani_poll_interval); - if (!common->ani.caldone) - cal_interval = min(cal_interval, (u32)short_cal_interval); - - common->ani.timer = timestamp + cal_interval; -} - -void ath_hw_check(struct ath_softc *sc) -{ - int busy; - - if (ath9k_hw_check_alive(sc->sc_ah)) - goto out; - - busy = ath_update_survey_stats(sc); - - DBG("ath9k: Possible baseband hang, " - "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); - if (busy >= 99) { - if (++sc->hw_busy_count >= 3) - ath_reset(sc, 1); - } else if (busy >= 0) - sc->hw_busy_count = 0; - -out: - return; -} - -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) -{ - static int count; - - if (pll_sqsum >= 0x40000) { - count++; - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - DBG("ath9k: " - "Possible RX hang, resetting"); - ath_reset(sc, 1); - count = 0; - } - } else - count = 0; -} - -void ath_hw_pll_work(struct ath_softc *sc) -{ - u32 pll_sqsum; - - if (AR_SREV_9485(sc->sc_ah)) { - pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); - - ath_hw_pll_rx_hang_check(sc, pll_sqsum); - - sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 200; - } -} - - -void ath9k_tasklet(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - u32 status = sc->intrstatus; - u32 rxmask; - - if ((status & ATH9K_INT_FATAL) || - (status & ATH9K_INT_BB_WATCHDOG)) { - ath_reset(sc, 1); - return; - } - - rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); - - if (status & rxmask) { - ath_rx_tasklet(sc, 0, 0); - } - - if (status & ATH9K_INT_TX) { - ath_tx_tasklet(sc); - } - - /* re-enable hardware interrupt */ - ath9k_hw_enable_interrupts(ah); -} - -void ath_isr(struct net80211_device *dev) -{ -#define SCHED_INTR ( \ - ATH9K_INT_FATAL | \ - ATH9K_INT_BB_WATCHDOG | \ - ATH9K_INT_RXORN | \ - ATH9K_INT_RXEOL | \ - ATH9K_INT_RX | \ - ATH9K_INT_RXLP | \ - ATH9K_INT_RXHP | \ - ATH9K_INT_TX | \ - ATH9K_INT_BMISS | \ - ATH9K_INT_CST | \ - ATH9K_INT_TSFOOR | \ - ATH9K_INT_GENTIMER) - - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - enum ath9k_int status; - unsigned long timestamp = (currticks() * 1000 ) / TICKS_PER_SEC; - int sched = 0; - - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - if (sc->sc_flags & SC_OP_INVALID) - return; - - - /* Check calibration */ - if(timestamp >= (unsigned int)common->ani.timer && common->ani.timer) - ath_ani_calibrate(sc); - - /* Check tx_complete_work */ - if(timestamp >= (unsigned int)sc->tx_complete_work_timer && sc->tx_complete_work_timer) - sc->tx_complete_work(sc); - - /* Check hw_pll_work */ - if(timestamp >= (unsigned int)sc->hw_pll_work_timer && sc->hw_pll_work_timer) - sc->hw_pll_work(sc); - - /* shared irq, not for us */ - - if (!ath9k_hw_intrpend(ah)) - return; - - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - status &= ah->imask; /* discard unasked-for bits */ - - /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). - */ - if (!status) - return; - - /* Cache the status */ - sc->intrstatus = status; - - if (status & SCHED_INTR) - sched = 1; - - /* - * If a FATAL or RXORN interrupt is received, we have to reset the - * chip immediately. - */ - if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_RXORN)) - goto chip_reset; - - if (status & ATH9K_INT_TXURN) - ath9k_hw_updatetxtriglevel(ah, 1); - - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - if (status & ATH9K_INT_TIM_TIMER) { - if (sc->ps_idle) - goto chip_reset; - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_setpower(sc, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->ps_flags |= PS_WAIT_FOR_BEACON; - } - -chip_reset: - - if (sched) { - /* turn off every interrupt */ - ath9k_hw_disable_interrupts(ah); - sc->intr_tq(sc); - } - - return; - -#undef SCHED_INTR -} - -void ath_radio_disable(struct ath_softc *sc, struct net80211_device *dev) -{ - struct ath_hw *ah = sc->sc_ah; - struct net80211_channel *channel = dev->channels + dev->channel; - int r; - - sc->hw_pll_work_timer = 0; - - /* - * Keep the LED on when the radio is disabled - * during idle unassociated state. - */ - if (!sc->ps_idle) { - ath9k_hw_set_gpio(ah, ah->led_pin, 1); - ath9k_hw_cfg_gpio_input(ah, ah->led_pin); - } - - /* Disable interrupts */ - ath9k_hw_disable_interrupts(ah); - - ath_drain_all_txq(sc, 0); /* clear pending tx frames */ - - ath_stoprecv(sc); /* turn off frame recv */ - ath_flushrecv(sc); /* flush recv queue */ - - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(dev, ah); - - r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, 0); - if (r) { - DBG("ath9k: " - "Unable to reset channel (%d MHz), reset status %d\n", - channel->center_freq, r); - } - - ath9k_hw_phy_disable(ah); - - ath9k_hw_configpcipowersave(ah, 1, 1); -} - -int ath_reset(struct ath_softc *sc, int retry_tx) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int r; - - sc->hw_busy_count = 0; - - /* Stop ANI */ - common->ani.timer = 0; - - ath9k_hw_disable_interrupts(ah); - ath_drain_all_txq(sc, retry_tx); - - ath_stoprecv(sc); - ath_flushrecv(sc); - - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, 0); - if (r) - DBG("ath9k: " - "Unable to reset hardware; reset status %d\n", r); - - if (ath_startrecv(sc) != 0) - DBG("ath9k: Unable to start recv logic\n"); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - ath9k_hw_set_interrupts(ah, ah->imask); - - if (retry_tx) { - int i; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - ath_txq_schedule(sc, &sc->tx.txq[i]); - } - } - } - - /* Start ANI */ - ath_start_ani(common); - - return r; -} - -/**********************/ -/* mac80211 callbacks */ -/**********************/ - -static int ath9k_start(struct net80211_device *dev) -{ - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct net80211_channel *curchan = dev->channels + dev->channel; - struct ath9k_channel *init_channel; - int r; - - DBG("ath9k: " - "Starting driver with initial channel: %d MHz\n", - curchan->center_freq); - - /* setup initial channel */ - sc->chan_idx = curchan->hw_value; - - init_channel = ath9k_cmn_get_curchannel(dev, ah); - - /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0, 0); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - r = ath9k_hw_reset(ah, init_channel, ah->caldata, 0); - if (r) { - DBG("ath9k: " - "Unable to reset hardware; reset status %d (freq %d MHz)\n", - r, curchan->center_freq); - goto mutex_unlock; - } - - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - DBG("ath9k: Unable to start recv logic\n"); - r = -EIO; - goto mutex_unlock; - } - - /* Setup our intr mask. */ - ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | - ATH9K_INT_RXORN | ATH9K_INT_FATAL | - ATH9K_INT_GLOBAL; - - ah->imask |= ATH9K_INT_RX; - - sc->sc_flags &= ~SC_OP_INVALID; - sc->sc_ah->is_monitoring = 0; - - ath9k_hw_set_interrupts(ah, ah->imask); - - sc->tx_complete_work(sc); - - if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) - common->bus_ops->extn_synch_en(common); - -mutex_unlock: - return r; -} - -static int ath9k_tx(struct net80211_device *dev, struct io_buffer *iob) -{ - struct ath_softc *sc = dev->priv; - struct ath_tx_control txctl; - int ret = 0; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.txq = sc->tx.txq_map[0]; - - DBGIO("ath9k: transmitting packet, iob: %p\n", iob); - - ret = ath_tx_start(dev, iob, &txctl); - if (ret) { - DBG("ath9k: TX failed\n"); - goto exit; - } - - return ret; -exit: - free_iob(iob); - return ret; -} - -static void ath9k_stop(struct net80211_device *dev) -{ - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - - sc->tx_complete_work_timer = 0; - sc->hw_pll_work_timer = 0; - - if (sc->sc_flags & SC_OP_INVALID) { - DBG("ath9k: Device not present\n"); - return; - } - - /* prevent tasklets to enable interrupts once we disable them */ - ah->imask &= ~ATH9K_INT_GLOBAL; - - /* make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - ath9k_hw_disable_interrupts(ah); - - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_drain_all_txq(sc, 0); - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->rx.rxlink = NULL; - - if (sc->rx.frag) { - free_iob(sc->rx.frag); - sc->rx.frag = NULL; - } - - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(ah); - ath9k_hw_configpcipowersave(ah, 1, 1); - - ath_radio_disable(sc, dev); - - sc->sc_flags |= SC_OP_INVALID; - - DBG("ath9k: Driver halt\n"); -} - -static int ath9k_config(struct net80211_device *dev, int changed) -{ - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - - if ((changed & NET80211_CFG_RATE) || - (changed & NET80211_CFG_PHY_PARAMS)) { - int spmbl = (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? IEEE80211_TX_RC_USE_SHORT_PREAMBLE : 0; - u16 rate = dev->rates[dev->rate]; - u16 slowrate = dev->rates[dev->rtscts_rate]; - int i; - - for (i = 0; i < NET80211_MAX_RATES; i++) { - if (sc->rates[i].bitrate == rate && - (sc->rates[i].flags & spmbl)) - sc->hw_rix = i; - - if (sc->rates[i].bitrate == slowrate && - (sc->rates[i].flags & spmbl)) - sc->hw_rix = i; - } - } - - ath9k_bss_info_changed(dev, changed); - - if (changed & NET80211_CFG_CHANNEL) { - struct net80211_channel *curchan = dev->channels + dev->channel; - int pos = curchan->hw_value; - int old_pos = -1; - - if (ah->curchan) - old_pos = ah->curchan - &ah->channels[0]; - - sc->sc_flags &= ~SC_OP_OFFCHANNEL; - - DBG2("ath9k: " - "Set channel: %d MHz\n", - curchan->center_freq); - - ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], - curchan); - - /* update survey stats for the old channel before switching */ - ath_update_survey_stats(sc); - - /* - * If the operating channel changes, change the survey in-use flags - * along with it. - * Reset the survey data for the new channel, unless we're switching - * back to the operating channel from an off-channel operation. - */ - if (sc->cur_survey != &sc->survey[pos]) { - - if (sc->cur_survey) - sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; - - sc->cur_survey = &sc->survey[pos]; - - memset(sc->cur_survey, 0, sizeof(struct survey_info)); - sc->cur_survey->filled |= SURVEY_INFO_IN_USE; - } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { - memset(&sc->survey[pos], 0, sizeof(struct survey_info)); - } - - if (ath_set_channel(sc, dev, &sc->sc_ah->channels[pos]) < 0) { - DBG("ath9k: Unable to set channel\n"); - return -EINVAL; - } - - /* - * The most recent snapshot of channel->noisefloor for the old - * channel is only available after the hardware reset. Copy it to - * the survey stats now. - */ - if (old_pos >= 0) - ath_update_survey_nf(sc, old_pos); - } - - if (changed & NET80211_CFG_CHANNEL) { - DBG2("ath9k: " - "Set power: %d\n", (dev->channels + dev->channel)->maxpower); - sc->config.txpowlimit = 2 * (dev->channels + dev->channel)->maxpower; - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - } - - return 0; -} - -static void ath9k_bss_iter(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - if (common->dev->state & NET80211_ASSOCIATED) { - sc->sc_flags |= SC_OP_PRIM_STA_VIF; - memcpy(common->curbssid, common->dev->bssid, ETH_ALEN); - common->curaid = common->dev->aid; - ath9k_hw_write_associd(sc->sc_ah); - DBG("ath9k: " - "Bss Info ASSOC %d, bssid: %pM\n", - common->dev->aid, common->curbssid); - - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); - } -} - -static void ath9k_config_bss(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct net80211_device *dev = common->dev; - - /* Reconfigure bss info */ - if (!(dev->state & NET80211_ASSOCIATED)) { - DBG2("ath9k: " - "ath9k: Bss Info DISASSOC %d, bssid %pM\n", - common->curaid, common->curbssid); - sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); - memset(common->curbssid, 0, ETH_ALEN); - common->curaid = 0; - } - - ath9k_bss_iter(sc); - - /* - * None of station vifs are associated. - * Clear bssid & aid - */ - if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { - ath9k_hw_write_associd(sc->sc_ah); - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - common->ani.timer = 0; - } -} - -static void ath9k_bss_info_changed(struct net80211_device *dev, - u32 changed) -{ - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int slottime; - - if (changed & NET80211_CFG_ASSOC) { - ath9k_config_bss(sc); - - DBG2("ath9k: BSSID: %pM aid: 0x%x\n", - common->curbssid, common->curaid); - } - - if (changed & NET80211_CFG_PHY_PARAMS) { - if (dev->phy_flags & NET80211_PHY_USE_PROTECTION) - slottime = 9; - else - slottime = 20; - ah->slottime = slottime; - ath9k_hw_init_global_settings(ah); - - DBG2("ath9k: BSS Changed PREAMBLE %d\n", - !!(dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)); - if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE) - sc->sc_flags |= SC_OP_PREAMBLE_SHORT; - else - sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; - - DBG2("ath9k: BSS Changed CTS PROT %d\n", - !!(dev->phy_flags & NET80211_PHY_USE_PROTECTION)); - if ((dev->phy_flags & NET80211_PHY_USE_PROTECTION) && - (dev->channels + dev->channel)->band != NET80211_BAND_5GHZ) - sc->sc_flags |= SC_OP_PROTECT_ENABLE; - else - sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; - } -} - -static void ath9k_poll(struct net80211_device *dev) -{ - ath_isr(dev); -} - -static void ath9k_irq(struct net80211_device *dev, int enable) -{ - struct ath_softc *sc = dev->priv; - struct ath_hw *ah = sc->sc_ah; - - ah->ah_ier = enable ? AR_IER_ENABLE : AR_IER_DISABLE; - - ath9k_hw_set_interrupts(ah, ah->imask); -} - -struct net80211_device_operations ath9k_ops = { - .transmit = ath9k_tx, - .open = ath9k_start, - .close = ath9k_stop, - .config = ath9k_config, - .poll = ath9k_poll, - .irq = ath9k_irq, -}; |