diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 96 |
9 files changed, 102 insertions, 65 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bd85e311c51b..7c8409e53598 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 87ba44c06692..fcb36abfc309 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 df1998d48253..615e68276e72 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 4c7020b3a5a0..b2f7b5f89097 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 9cdc41b0ec44..5cfcf8c235a4 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 63549868e686..0cb504d7b8c4 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 fe70f67aa088..7e630a81b453 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 a702089f18d0..953036a4ed53 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 1447b55a8d0a..2d4e9b861b60 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 * might change as a result. */ - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -1029,7 +1035,7 @@ static int ath9k_start(struct ieee80211_hw *hw) /* setup initial channel */ sc->chan_idx = curchan->hw_value; - init_channel = ath_get_curchannel(sc, hw); + init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, 0, 0); @@ -1055,7 +1061,8 @@ static int ath9k_start(struct ieee80211_hw *hw) * This is needed only to setup initial state * but it's best done after a reset. */ - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); /* * Setup the hardware after reset: @@ -1374,6 +1381,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_calculate_iter_data(hw, vif, &iter_data); + ath9k_ps_wakeup(sc); /* Set BSSID mask. */ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1408,6 +1416,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, } ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_ps_restore(sc); /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { @@ -1437,9 +1446,7 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, * there. */ error = ath_beacon_alloc(sc, vif); - if (error) - ath9k_reclaim_beacon(sc, vif); - else + if (!error) ath_beacon_config(sc, vif); } } @@ -1720,7 +1727,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) { sc->config.txpowlimit = 2 * conf->power_level; ath9k_ps_wakeup(sc); - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); ath9k_ps_restore(sc); } |