ath5k: Fix survey
authorBruno Randolf <br1@einfach.org>
Thu, 16 Dec 2010 07:22:20 +0000 (16:22 +0900)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 16 Dec 2010 20:22:32 +0000 (15:22 -0500)
The old survey implementation was broken and returned nonsense data.

Clear cycle counters and survey data on reset. Since the cycle counters easily
overflow it's better to keep a local version of collected survey data (in ms
resolution, instead of clockrate) and update this every time survey is
retrieved. If survey is retrieved often enough to avoid cycle counter overflows
this works fine, otherwise we could update survey more often, like ath9k does.
Still only the survey for the current channel is kept.

Signed-off-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h

index 4e3b97c3d7c2de5a7b0cdb096af5e370a44426ac..b3c7241a62a5b9cebf6dc757e806448bc983c8c5 100644 (file)
@@ -2654,6 +2654,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
                                                        bool skip_pcu)
 {
        struct ath5k_hw *ah = sc->ah;
+       struct ath_common *common = ath5k_hw_common(ah);
        int ret, ani_mode;
 
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
@@ -2696,6 +2697,14 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
        ah->ah_cal_next_nf = jiffies;
        ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
 
+       /* clear survey data and cycle counters */
+       memset(&sc->survey, 0, sizeof(sc->survey));
+       spin_lock(&common->cc_lock);
+       ath_hw_cycle_counters_update(common);
+       memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+       memset(&common->cc_ani, 0, sizeof(common->cc_ani));
+       spin_unlock(&common->cc_lock);
+
        /*
         * Change channels and update the h/w rate map if we're switching;
         * e.g. 11a to 11b/g.
@@ -3362,25 +3371,27 @@ static int ath5k_get_survey(struct ieee80211_hw *hw, int idx,
        if (idx != 0)
                return -ENOENT;
 
-       survey->channel = conf->channel;
-       survey->filled = SURVEY_INFO_NOISE_DBM;
-       survey->noise = sc->ah->ah_noise_floor;
-
        spin_lock_bh(&common->cc_lock);
        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;
+               sc->survey.channel_time += cc->cycles / div;
+               sc->survey.channel_time_busy += cc->rx_busy / div;
+               sc->survey.channel_time_rx += cc->rx_frame / div;
+               sc->survey.channel_time_tx += cc->tx_frame / div;
        }
        memset(cc, 0, sizeof(*cc));
        spin_unlock_bh(&common->cc_lock);
 
+       memcpy(survey, &sc->survey, sizeof(*survey));
+
+       survey->channel = conf->channel;
+       survey->noise = sc->ah->ah_noise_floor;
+       survey->filled = SURVEY_INFO_NOISE_DBM |
+                       SURVEY_INFO_CHANNEL_TIME |
+                       SURVEY_INFO_CHANNEL_TIME_BUSY |
+                       SURVEY_INFO_CHANNEL_TIME_RX |
+                       SURVEY_INFO_CHANNEL_TIME_TX;
+
        return 0;
 }
 
index aa6c32aafb5927102160c0aba6f6dd77074800b5..6d511476e4d2695c1b0a8edb1eac552620cd06eb 100644 (file)
@@ -258,6 +258,8 @@ struct ath5k_softc {
        struct tasklet_struct   ani_tasklet;    /* ANI calibration */
 
        struct delayed_work     tx_complete_work;
+
+       struct survey_info      survey;         /* collected survey info */
 };
 
 #define ath5k_hw_hasbssidmask(_ah) \