diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 179 |
1 files changed, 101 insertions, 78 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ca351fe6d3..9098aaad97a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -62,14 +62,12 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) if (txq->axq_depth || !list_empty(&txq->axq_acq)) pending = true; - else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) - pending = !list_empty(&txq->txq_fifo_pending); spin_unlock_bh(&txq->axq_lock); return pending; } -bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) +static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; bool ret; @@ -136,7 +134,7 @@ void ath9k_ps_restore(struct ath_softc *sc) spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } -static void ath_start_ani(struct ath_common *common) +void ath_start_ani(struct ath_common *common) { struct ath_hw *ah = common->ah; unsigned long timestamp = jiffies_to_msecs(jiffies); @@ -219,7 +217,7 @@ static int ath_update_survey_stats(struct ath_softc *sc) * 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 ieee80211_hw *hw, +static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; @@ -302,7 +300,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_set_beacon(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); - ath_start_ani(common); + if (!common->disable_ani) + ath_start_ani(common); } ps_restore: @@ -361,7 +360,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int txctl.paprd = BIT(chain); if (ath_tx_start(hw, skb, &txctl) != 0) { - ath_dbg(common, ATH_DBG_XMIT, "PAPRD TX failed\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD TX failed\n"); dev_kfree_skb_any(skb); return false; } @@ -370,7 +369,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); if (!time_left) - ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Timeout waiting for paprd training on TX chain %d\n", chain); @@ -394,12 +393,14 @@ void ath_paprd_calibrate(struct work_struct *work) if (!caldata) return; + ath9k_ps_wakeup(sc); + if (ar9003_paprd_init_table(ah) < 0) - return; + goto fail_paprd; skb = alloc_skb(len, GFP_KERNEL); if (!skb) - return; + goto fail_paprd; skb_put(skb, len); memset(skb->data, 0, len); @@ -411,7 +412,6 @@ void ath_paprd_calibrate(struct work_struct *work) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - ath9k_ps_wakeup(sc); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { if (!(common->tx_chainmask & BIT(chain))) continue; @@ -431,11 +431,18 @@ void ath_paprd_calibrate(struct work_struct *work) if (!ath_paprd_send_frame(sc, skb, chain)) goto fail_paprd; - if (!ar9003_paprd_is_done(ah)) + if (!ar9003_paprd_is_done(ah)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "PAPRD not yet done on chain %d\n", chain); break; + } - if (ar9003_paprd_create_curve(ah, caldata, chain) != 0) + if (ar9003_paprd_create_curve(ah, caldata, chain)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "PAPRD create curve failed on chain %d\n", + chain); break; + } chain_ok = 1; } @@ -515,24 +522,19 @@ void ath_ani_calibrate(unsigned long data) 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) { - spin_lock_irqsave(&common->cc_lock, flags); - ath9k_hw_ani_monitor(ah, ah->curchan); - ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - } + /* Call ANI routine if necessary */ + if (aniflag) { + spin_lock_irqsave(&common->cc_lock, flags); + ath9k_hw_ani_monitor(ah, ah->curchan); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + } - /* Perform calibration if necessary */ - if (longcal || shortcal) { - common->ani.caldone = - ath9k_hw_calibrate(ah, - ah->curchan, - common->rx_chainmask, - longcal); - } + /* Perform calibration if necessary */ + if (longcal || shortcal) { + common->ani.caldone = + ath9k_hw_calibrate(ah, ah->curchan, + common->rx_chainmask, longcal); } ath9k_ps_restore(sc); @@ -615,8 +617,11 @@ void ath_hw_check(struct work_struct *work) 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) + if (++sc->hw_busy_count >= 3) { + spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); + } } else if (busy >= 0) sc->hw_busy_count = 0; @@ -635,7 +640,9 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) /* Rx is hung for more than 500ms. Reset it */ ath_dbg(common, ATH_DBG_RESET, "Possible RX hang, resetting"); + spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); count = 0; } } else @@ -672,7 +679,9 @@ void ath9k_tasklet(unsigned long data) if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { + spin_lock(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock(&sc->sc_pcu_lock); return; } @@ -868,7 +877,7 @@ chip_reset: #undef SCHED_INTR } -void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) +static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -974,10 +983,10 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->hw_busy_count = 0; /* Stop ANI */ + del_timer_sync(&common->ani.timer); ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_pcu_lock); ieee80211_stop_queues(hw); @@ -1020,10 +1029,11 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } ieee80211_wake_queues(hw); - spin_unlock_bh(&sc->sc_pcu_lock); /* Start ANI */ - ath_start_ani(common); + if (!common->disable_ani) + ath_start_ani(common); + ath9k_ps_restore(sc); return r; @@ -1261,7 +1271,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); - ath9k_hw_configpcipowersave(ah, 1, 1); spin_unlock_bh(&sc->sc_pcu_lock); @@ -1412,10 +1421,14 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah, ah->imask); /* Set up ANI */ - if ((iter_data.naps + iter_data.nadhocs) > 0) { + if (iter_data.naps > 0) { sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); + + if (!common->disable_ani) { + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + } else { sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); @@ -1952,50 +1965,38 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; - switch (sc->sc_ah->opmode) { - case NL80211_IFTYPE_ADHOC: - /* There can be only one vif available */ + /* + * Skip iteration if primary station vif's bss info + * was not changed + */ + if (sc->sc_flags & SC_OP_PRIM_STA_VIF) + return; + + if (bss_conf->assoc) { + sc->sc_flags |= SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = true; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - /* configure beacon */ - if (bss_conf->enable_beacon) - ath_beacon_config(sc, vif); - break; - case NL80211_IFTYPE_STATION: - /* - * Skip iteration if primary station vif's bss info - * was not changed - */ - if (sc->sc_flags & SC_OP_PRIM_STA_VIF) - break; - - if (bss_conf->assoc) { - sc->sc_flags |= SC_OP_PRIM_STA_VIF; - avp->primary_sta_vif = true; - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah); - ath_dbg(common, ATH_DBG_CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); - ath_beacon_config(sc, vif); - /* - * 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; + ath_beacon_config(sc, vif); + /* + * 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; + if (!common->disable_ani) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } - break; - default: - break; + } } @@ -2005,6 +2006,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + return; + /* Reconfigure bss info */ if (avp->primary_sta_vif && !bss_conf->assoc) { ath_dbg(common, ATH_DBG_CONFIG, @@ -2023,8 +2027,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) * None of station vifs are associated. * Clear bssid & aid */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { + 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; @@ -2054,6 +2057,26 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, common->curbssid, common->curaid); } + if (changed & BSS_CHANGED_IBSS) { + /* There can be only one vif available */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + + if (bss_conf->ibss_joined) { + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + + if (!common->disable_ani) { + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + + } else { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } + } + /* Enable transmission of beacons (AP, IBSS, MESH) */ if ((changed & BSS_CHANGED_BEACON) || ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { @@ -2308,9 +2331,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); drain_txq = ath_drain_all_txq(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); if (!drain_txq) ath_reset(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); ieee80211_wake_queues(hw); @@ -2334,7 +2357,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) return false; } -int ath9k_tx_last_beacon(struct ieee80211_hw *hw) +static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; |