diff options
author | David S. Miller <davem@davemloft.net> | 2011-02-08 13:52:31 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-08 13:52:31 -0800 |
commit | c0c84ef5c130f8871adbdaac2ba824b9195cb6d9 (patch) | |
tree | d7221b5323d5a4d3d84676d32bdca21d21d85a18 | |
parent | 2360d2e8f01043632d6b651672bec66c49892f94 (diff) | |
parent | 3ad97fbcc233a295f2ccc2c6bdeb32323e360a5e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
61 files changed, 2215 insertions, 872 deletions
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 78c26fdccad..d673ab2f6cd 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -282,6 +282,34 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } +/* + * Wait for synth to settle + */ +static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + /* + * On 5211+ read activation -> rx delay + * and use it (100ns steps). + */ + if (ah->ah_version != AR5K_AR5210) { + u32 delay; + delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + delay = (channel->hw_value & CHANNEL_CCK) ? + ((delay << 2) / 22) : (delay / 10); + if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) + delay = delay << 1; + if (ah->ah_bwmode == AR5K_BWMODE_5MHZ) + delay = delay << 2; + /* XXX: /2 on turbo ? Let's be safe + * for now */ + udelay(100 + delay); + } else { + mdelay(1); + } +} + /**********************\ * RF Gain optimization * @@ -3237,6 +3265,13 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* Failed */ if (i >= 100) return -EIO; + + /* Set channel and wait for synth */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + ath5k_hw_wait_for_synth(ah, channel); } /* @@ -3251,13 +3286,53 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; + /* Write OFDM timings on 5212*/ + if (ah->ah_version == AR5K_AR5212 && + channel->hw_value & CHANNEL_OFDM) { + + ret = ath5k_hw_write_ofdm_timings(ah, channel); + if (ret) + return ret; + + /* Spur info is available only from EEPROM versions + * greater than 5.3, but the EEPROM routines will use + * static values for older versions */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424) + ath5k_hw_set_spur_mitigation_filter(ah, + channel); + } + + /* If we used fast channel switching + * we are done, release RF bus and + * fire up NF calibration. + * + * Note: Only NF calibration due to + * channel change, not AGC calibration + * since AGC is still running ! + */ + if (fast) { + /* + * Release RF Bus grant + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, + AR5K_PHY_RFBUS_REQ_REQUEST); + + /* + * Start NF calibration + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF); + + return ret; + } + /* * For 5210 we do all initialization using * initvals, so we don't have to modify * any settings (5210 also only supports * a/aturbo modes) */ - if ((ah->ah_version != AR5K_AR5210) && !fast) { + if (ah->ah_version != AR5K_AR5210) { /* * Write initial RF gain settings @@ -3276,22 +3351,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; - /* Write OFDM timings on 5212*/ - if (ah->ah_version == AR5K_AR5212 && - channel->hw_value & CHANNEL_OFDM) { - - ret = ath5k_hw_write_ofdm_timings(ah, channel); - if (ret) - return ret; - - /* Spur info is available only from EEPROM versions - * greater than 5.3, but the EEPROM routines will use - * static values for older versions */ - if (ah->ah_mac_srev >= AR5K_SREV_AR5424) - ath5k_hw_set_spur_mitigation_filter(ah, - channel); - } - /*Enable/disable 802.11b mode on 5111 (enable 2111 frequency converter + CCK)*/ if (ah->ah_radio == AR5K_RF5111) { @@ -3322,47 +3381,20 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + ath5k_hw_wait_for_synth(ah, channel); + /* - * On 5211+ read activation -> rx delay - * and use it. + * Perform ADC test to see if baseband is ready + * Set tx hold and check adc test register */ - if (ah->ah_version != AR5K_AR5210) { - u32 delay; - delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & - AR5K_PHY_RX_DELAY_M; - delay = (channel->hw_value & CHANNEL_CCK) ? - ((delay << 2) / 22) : (delay / 10); - if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) - delay = delay << 1; - if (ah->ah_bwmode == AR5K_BWMODE_5MHZ) - delay = delay << 2; - /* XXX: /2 on turbo ? Let's be safe - * for now */ - udelay(100 + delay); - } else { - mdelay(1); - } - - if (fast) - /* - * Release RF Bus grant - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, - AR5K_PHY_RFBUS_REQ_REQUEST); - else { - /* - * Perform ADC test to see if baseband is ready - * Set tx hold and check adc test register - */ - phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); - ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); - for (i = 0; i <= 20; i++) { - if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) - break; - udelay(200); - } - ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); + phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); + ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); + for (i = 0; i <= 20; i++) { + if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) + break; + udelay(200); } + ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); /* * Start automatic gain control calibration diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bd85e311c51..7c8409e5359 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -602,6 +602,8 @@ struct ath_softc { struct completion paprd_complete; bool paprd_pending; + unsigned int hw_busy_count; + u32 intrstatus; u32 sc_flags; /* SC_OP_* */ u16 ps_flags; /* PS_* */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 87ba44c0669..fcb36abfc30 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -721,8 +721,9 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) cur_conf->beacon_interval = 100; /* - * Some times we dont parse dtim period from mac80211, in that case - * use a default value + * We don't parse dtim period from mac80211 during the driver + * initialization as it breaks association with hidden-ssid + * AP and it causes latency in roaming */ if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index df1998d4825..615e68276e7 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -189,6 +189,17 @@ void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, } EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); +void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, + u16 new_txpow, u16 *txpower) +{ + if (cur_txpow != new_txpow) { + ath9k_hw_set_txpowerlimit(ah, new_txpow, false); + /* read back in case value is clamped */ + *txpower = ath9k_hw_regulatory(ah)->power_limit; + } +} +EXPORT_SYMBOL(ath9k_cmn_update_txpow); + static int __init ath9k_cmn_init(void) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 4c7020b3a5a..b2f7b5f8909 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -68,3 +68,5 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, int ath9k_cmn_count_streams(unsigned int chainmask, int max); void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, enum ath_stomp_type stomp_type); +void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, + u16 new_txpow, u16 *txpower); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9cdc41b0ec4..5cfcf8c235a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -381,21 +381,40 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; +static const char *channel_type_str(enum nl80211_channel_type t) +{ + switch (t) { + case NL80211_CHAN_NO_HT: + return "no ht"; + case NL80211_CHAN_HT20: + return "ht20"; + case NL80211_CHAN_HT40MINUS: + return "ht40-"; + case NL80211_CHAN_HT40PLUS: + return "ht40+"; + default: + return "???"; + } +} + static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ieee80211_channel *chan = sc->hw->conf.channel; + struct ieee80211_conf *conf = &(sc->hw->conf); char buf[512]; unsigned int len = 0; u8 addr[ETH_ALEN]; u32 tmp; len += snprintf(buf + len, sizeof(buf) - len, - "%s (chan=%d ht=%d)\n", + "%s (chan=%d center-freq: %d MHz channel-type: %d (%s))\n", wiphy_name(sc->hw->wiphy), ieee80211_frequency_to_channel(chan->center_freq), - conf_is_ht(&sc->hw->conf)); + chan->center_freq, + conf->channel_type, + channel_type_str(conf->channel_type)); put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 63549868e68..0cb504d7b8c 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -460,7 +460,6 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); void ath9k_ps_work(struct work_struct *work); bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, enum ath9k_power_mode mode); -void ath_update_txpow(struct ath9k_htc_priv *priv); void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index fe70f67aa08..7e630a81b45 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -389,7 +389,8 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw) ret, ah->curchan->channel); } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); /* Start RX */ WMI_CMD(WMI_START_RECV_CMDID); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a702089f18d..953036a4ed5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -24,17 +24,6 @@ static struct dentry *ath9k_debugfs_root; /* Utilities */ /*************/ -void ath_update_txpow(struct ath9k_htc_priv *priv) -{ - struct ath_hw *ah = priv->ah; - - if (priv->curtxpow != priv->txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false); - /* read back in case value is clamped */ - priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - } -} - /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, struct ath9k_channel *ichan) @@ -147,7 +136,8 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) channel->center_freq, ret); } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); ath9k_host_rx_init(priv); @@ -212,7 +202,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, goto err; } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); if (ret) @@ -988,7 +979,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) return ret; } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); mode = ath9k_htc_get_curmode(priv, init_channel); htc_mode = cpu_to_be16(mode); @@ -1052,6 +1044,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) cancel_work_sync(&priv->fatal_work); cancel_work_sync(&priv->ps_work); cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + cancel_delayed_work_sync(&priv->ath9k_ani_work); ath9k_led_stop_brightness(priv); mutex_lock(&priv->mutex); @@ -1253,7 +1246,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) { priv->txpowlimit = 2 * conf->power_level; - ath_update_txpow(priv); + ath9k_cmn_update_txpow(priv->ah, priv->curtxpow, + priv->txpowlimit, &priv->curtxpow); } if (changed & IEEE80211_CONF_CHANGE_IDLE) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1447b55a8d0..2d4e9b861b6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -18,17 +18,6 @@ #include "ath9k.h" #include "btcoex.h" -static void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (sc->curtxpow != sc->config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); - /* read back in case value is clamped */ - sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - } -} - static u8 parse_mpdudensity(u8 mpdudensity) { /* @@ -64,19 +53,6 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, - struct ieee80211_hw *hw) -{ - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath9k_channel *channel; - u8 chan_idx; - - chan_idx = curchan->hw_value; - channel = &sc->sc_ah->channels[chan_idx]; - ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type); - return channel; -} - bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; @@ -177,7 +153,12 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel) } } -static void ath_update_survey_stats(struct ath_softc *sc) +/* + * 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); @@ -185,9 +166,10 @@ static void ath_update_survey_stats(struct ath_softc *sc) 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; + return -1; if (ah->power_mode == ATH9K_PM_AWAKE) ath_hw_cycle_counters_update(common); @@ -202,9 +184,18 @@ static void ath_update_survey_stats(struct ath_softc *sc) 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; } /* @@ -226,6 +217,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (sc->sc_flags & SC_OP_INVALID) return -EIO; + sc->hw_busy_count = 0; + del_timer_sync(&common->ani.timer); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); @@ -284,7 +277,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, goto ps_restore; } - ath_update_txpow(sc); + 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))) { @@ -592,17 +586,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) void ath_hw_check(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); - int i; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long flags; + int busy; ath9k_ps_wakeup(sc); + if (ath9k_hw_check_alive(sc->sc_ah)) + goto out; - for (i = 0; i < 3; i++) { - if (ath9k_hw_check_alive(sc->sc_ah)) - goto out; + spin_lock_irqsave(&common->cc_lock, flags); + busy = ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); - msleep(1); - } - ath_reset(sc, true); + ath_dbg(common, ATH_DBG_RESET, "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, true); + } else if (busy >= 0) + sc->hw_busy_count = 0; out: ath9k_ps_restore(sc); @@ -867,7 +869,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_configpcipowersave(ah, 0, 0); if (!ah->curchan) - ah->curchan = ath_get_curchannel(sc, sc->hw); + ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -876,7 +878,8 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) channel->center_freq, r); } - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); goto out; @@ -928,7 +931,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_flushrecv(sc); /* flush recv queue */ if (!ah->curchan) - ah->curchan = ath_get_curchannel(sc, hw); + ah->curchan = ath9k_cmn_get_curchannel(hw, ah); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -952,6 +955,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) struct ieee80211_hw *hw = sc->hw; int r; + sc->hw_busy_count = 0; + /* Stop ANI */ del_timer_sync(&common->ani.timer); @@ -979,7 +984,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that |