ath9k: Fix ANI management
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Tue, 17 Jul 2012 11:46:29 +0000 (17:16 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 17 Jul 2012 19:11:39 +0000 (15:11 -0400)
Currently, there are problems with how ANI is handled in
multi-VIF scenarios. This patch addresses them by unifying
the start/stop logic.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/main.c

index 41219a5e7f53d95587cb7bc2d009d3f7f4a06f0c..c8af0db97c4f9dea4ea6190387a005fcb58a6508 100644 (file)
@@ -447,7 +447,9 @@ void ath_rx_poll(unsigned long data);
 void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
-void ath_start_ani(struct ath_common *common);
+void ath_start_ani(struct ath_softc *sc);
+void ath_stop_ani(struct ath_softc *sc);
+void ath_check_ani(struct ath_softc *sc);
 int ath_update_survey_stats(struct ath_softc *sc);
 void ath_update_survey_nf(struct ath_softc *sc, int channel);
 
index b9ea067a7bb5e8a5bf7a9c60cd5529b113ba0905..68b643c8943c4c2db074e4ada4eeb2fda397eccc 100644 (file)
@@ -206,10 +206,9 @@ static ssize_t write_file_disable_ani(struct file *file,
 
        if (disable_ani) {
                clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-               del_timer_sync(&common->ani.timer);
+               ath_stop_ani(sc);
        } else {
-               set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-               ath_start_ani(common);
+               ath_check_ani(sc);
        }
 
        return count;
index 91650fe504615247f25d3c1eb153af0ced87657e..42fc0a374c61385dfa92f33c36ded5a66677d9af 100644 (file)
@@ -432,26 +432,72 @@ set_timer:
        }
 }
 
-void ath_start_ani(struct ath_common *common)
+void ath_start_ani(struct ath_softc *sc)
 {
-       struct ath_hw *ah = common->ah;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        unsigned long timestamp = jiffies_to_msecs(jiffies);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-       if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
-               return;
 
-       if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+       if (common->disable_ani ||
+           !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) ||
+           (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
                return;
 
        common->ani.longcal_timer = timestamp;
        common->ani.shortcal_timer = timestamp;
        common->ani.checkani_timer = timestamp;
 
+       ath_dbg(common, ANI, "Starting ANI\n");
        mod_timer(&common->ani.timer,
                  jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
 }
 
+void ath_stop_ani(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ath_dbg(common, ANI, "Stopping ANI\n");
+       del_timer_sync(&common->ani.timer);
+}
+
+void ath_check_ani(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+
+       /*
+        * Check for the various conditions in which ANI has to
+        * be stopped.
+        */
+       if (ah->opmode == NL80211_IFTYPE_ADHOC) {
+               if (!cur_conf->enable_beacon)
+                       goto stop_ani;
+       } else if (ah->opmode == NL80211_IFTYPE_AP) {
+               if (!cur_conf->enable_beacon) {
+                       /*
+                        * Disable ANI only when there are no
+                        * associated stations.
+                        */
+                       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+                               goto stop_ani;
+               }
+       } else if (ah->opmode == NL80211_IFTYPE_STATION) {
+               if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+                       goto stop_ani;
+       }
+
+       if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) {
+               set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
+               ath_start_ani(sc);
+       }
+
+       return;
+
+stop_ani:
+       clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
+       ath_stop_ani(sc);
+}
+
 void ath_update_survey_nf(struct ath_softc *sc, int channel)
 {
        struct ath_hw *ah = sc->sc_ah;
index 915bd4881b3f60b6ad956963ef4bb71fa64792b8..d80d5be2ccb7a3f64b568161943ec278ed300519 100644 (file)
@@ -167,8 +167,6 @@ static void ath_cancel_work(struct ath_softc *sc)
 
 static void ath_restart_work(struct ath_softc *sc)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 
        if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
@@ -177,21 +175,18 @@ static void ath_restart_work(struct ath_softc *sc)
                                     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 
        ath_start_rx_poll(sc, 3);
-
-       if (!common->disable_ani)
-               ath_start_ani(common);
+       ath_start_ani(sc);
 }
 
 static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
 {
        struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
        bool ret = true;
 
        ieee80211_stop_queues(sc->hw);
 
        sc->hw_busy_count = 0;
-       del_timer_sync(&common->ani.timer);
+       ath_stop_ani(sc);
        del_timer_sync(&sc->rx_poll_timer);
 
        ath9k_debug_samp_bb_mac(sc);
@@ -1481,6 +1476,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_bss_conf *bss_conf,
                                   u32 changed)
 {
+#define CHECK_ANI                              \
+       (BSS_CHANGED_ASSOC |                    \
+        BSS_CHANGED_IBSS |                     \
+        BSS_CHANGED_BEACON_ENABLED)
+
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1517,16 +1517,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                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) {
-                       if (!common->disable_ani) {
-                               set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-                               ath_start_ani(common);
-                       }
-               } else {
-                       clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-                       del_timer_sync(&common->ani.timer);
-               }
        }
 
        if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
@@ -1557,8 +1547,13 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if (changed & CHECK_ANI)
+               ath_check_ani(sc);
+
        mutex_unlock(&sc->mutex);
        ath9k_ps_restore(sc);
+
+#undef CHECK_ANI
 }
 
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)