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 4e3b97c..b3c7241 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 aa6c32a..6d51147 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) \