aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-10-10 12:21:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-11 15:04:21 -0400
commit3430098ae463e31ab16926ac3eb295368a3ca5d9 (patch)
tree9a0ffbd469bfce751ddc30e09efdbfe69353bd75
parentcac4220b2e93e6344f987581d52d5bd71ff2cc0e (diff)
ath9k: implement channel utilization stats for survey
Results for the active channel are updated whenever a new survey dump is requested, the old data is kept to allow multiple processes to make their own channel utilization averages. All other channels only contain the data for the last time that the hardware was on the channel, i.e. the last scan result or other off-channel activity. Running a background scan does not clear the data for the active channel. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c112
2 files changed, 98 insertions, 16 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index de2b18ee7f77..4e81fe35aa3f 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -593,6 +593,8 @@ struct ath_softc {
593 struct delayed_work wiphy_work; 593 struct delayed_work wiphy_work;
594 unsigned long wiphy_scheduler_int; 594 unsigned long wiphy_scheduler_int;
595 int wiphy_scheduler_index; 595 int wiphy_scheduler_index;
596 struct survey_info *cur_survey;
597 struct survey_info survey[ATH9K_NUM_CHANNELS];
596 598
597 struct tasklet_struct intr_tq; 599 struct tasklet_struct intr_tq;
598 struct tasklet_struct bcon_tasklet; 600 struct tasklet_struct bcon_tasklet;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 360c6f5e843a..865649120075 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -175,6 +175,44 @@ static void ath_start_ani(struct ath_common *common)
175 msecs_to_jiffies((u32)ah->config.ani_poll_interval)); 175 msecs_to_jiffies((u32)ah->config.ani_poll_interval));
176} 176}
177 177
178static void ath_update_survey_nf(struct ath_softc *sc, int channel)
179{
180 struct ath_hw *ah = sc->sc_ah;
181 struct ath9k_channel *chan = &ah->channels[channel];
182 struct survey_info *survey = &sc->survey[channel];
183
184 if (chan->noisefloor) {
185 survey->filled |= SURVEY_INFO_NOISE_DBM;
186 survey->noise = chan->noisefloor;
187 }
188}
189
190static void ath_update_survey_stats(struct ath_softc *sc)
191{
192 struct ath_hw *ah = sc->sc_ah;
193 struct ath_common *common = ath9k_hw_common(ah);
194 int pos = ah->curchan - &ah->channels[0];
195 struct survey_info *survey = &sc->survey[pos];
196 struct ath_cycle_counters *cc = &common->cc_survey;
197 unsigned int div = common->clockrate * 1000;
198
199 ath_hw_cycle_counters_update(common);
200
201 if (cc->cycles > 0) {
202 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
203 SURVEY_INFO_CHANNEL_TIME_BUSY |
204 SURVEY_INFO_CHANNEL_TIME_RX |
205 SURVEY_INFO_CHANNEL_TIME_TX;
206 survey->channel_time += cc->cycles / div;
207 survey->channel_time_busy += cc->rx_busy / div;
208 survey->channel_time_rx += cc->rx_frame / div;
209 survey->channel_time_tx += cc->tx_frame / div;
210 }
211 memset(cc, 0, sizeof(*cc));
212
213 ath_update_survey_nf(sc, pos);
214}
215
178/* 216/*
179 * Set/change channels. If the channel is really being changed, it's done 217 * Set/change channels. If the channel is really being changed, it's done
180 * by reseting the chip. To accomplish this we must first cleanup any pending 218 * by reseting the chip. To accomplish this we must first cleanup any pending
@@ -453,6 +491,7 @@ void ath_ani_calibrate(unsigned long data)
453 if (aniflag) { 491 if (aniflag) {
454 spin_lock_irqsave(&common->cc_lock, flags); 492 spin_lock_irqsave(&common->cc_lock, flags);
455 ath9k_hw_ani_monitor(ah, ah->curchan); 493 ath9k_hw_ani_monitor(ah, ah->curchan);
494 ath_update_survey_stats(sc);
456 spin_unlock_irqrestore(&common->cc_lock, flags); 495 spin_unlock_irqrestore(&common->cc_lock, flags);
457 } 496 }
458 497
@@ -1532,7 +1571,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1532{ 1571{
1533 struct ath_wiphy *aphy = hw->priv; 1572 struct ath_wiphy *aphy = hw->priv;
1534 struct ath_softc *sc = aphy->sc; 1573 struct ath_softc *sc = aphy->sc;
1535 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 1574 struct ath_hw *ah = sc->sc_ah;
1575 struct ath_common *common = ath9k_hw_common(ah);
1536 struct ieee80211_conf *conf = &hw->conf; 1576 struct ieee80211_conf *conf = &hw->conf;
1537 bool disable_radio; 1577 bool disable_radio;
1538 1578
@@ -1598,6 +1638,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1598 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 1638 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1599 struct ieee80211_channel *curchan = hw->conf.channel; 1639 struct ieee80211_channel *curchan = hw->conf.channel;
1600 int pos = curchan->hw_value; 1640 int pos = curchan->hw_value;
1641 int old_pos = -1;
1642 unsigned long flags;
1643
1644 if (ah->curchan)
1645 old_pos = ah->curchan - &ah->channels[0];
1601 1646
1602 aphy->chan_idx = pos; 1647 aphy->chan_idx = pos;
1603 aphy->chan_is_ht = conf_is_ht(conf); 1648 aphy->chan_is_ht = conf_is_ht(conf);
@@ -1625,12 +1670,45 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1625 1670
1626 ath_update_chainmask(sc, conf_is_ht(conf)); 1671 ath_update_chainmask(sc, conf_is_ht(conf));
1627 1672
1673 /* update survey stats for the old channel before switching */
1674 spin_lock_irqsave(&common->cc_lock, flags);
1675 ath_update_survey_stats(sc);
1676 spin_unlock_irqrestore(&common->cc_lock, flags);
1677
1678 /*
1679 * If the operating channel changes, change the survey in-use flags
1680 * along with it.
1681 * Reset the survey data for the new channel, unless we're switching
1682 * back to the operating channel from an off-channel operation.
1683 */
1684 if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
1685 sc->cur_survey != &sc->survey[pos]) {
1686
1687 if (sc->cur_survey)
1688 sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
1689
1690 sc->cur_survey = &sc->survey[pos];
1691
1692 memset(sc->cur_survey, 0, sizeof(struct survey_info));
1693 sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
1694 } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
1695 memset(&sc->survey[pos], 0, sizeof(struct survey_info));
1696 }
1697
1628 if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { 1698 if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
1629 ath_print(common, ATH_DBG_FATAL, 1699 ath_print(common, ATH_DBG_FATAL,
1630 "Unable to set channel\n"); 1700 "Unable to set channel\n");
1631 mutex_unlock(&sc->mutex); 1701 mutex_unlock(&sc->mutex);
1632 return -EINVAL; 1702 return -EINVAL;
1633 } 1703 }
1704
1705 /*
1706 * The most recent snapshot of channel->noisefloor for the old
1707 * channel is only available after the hardware reset. Copy it to
1708 * the survey stats now.
1709 */
1710 if (old_pos >= 0)
1711 ath_update_survey_nf(sc, old_pos);
1634 } 1712 }
1635 1713
1636skip_chan_change: 1714skip_chan_change:
@@ -2000,9 +2078,15 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
2000{ 2078{
2001 struct ath_wiphy *aphy = hw->priv; 2079 struct ath_wiphy *aphy = hw->priv;
2002 struct ath_softc *sc = aphy->sc; 2080 struct ath_softc *sc = aphy->sc;
2003 struct ath_hw *ah = sc->sc_ah; 2081 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2004 struct ieee80211_supported_band *sband; 2082 struct ieee80211_supported_band *sband;
2005 struct ath9k_channel *chan; 2083 struct ieee80211_channel *chan;
2084 unsigned long flags;
2085 int pos;
2086
2087 spin_lock_irqsave(&common->cc_lock, flags);
2088 if (idx == 0)
2089 ath_update_survey_stats(sc);
2006 2090
2007 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; 2091 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
2008 if (sband && idx >= sband->n_channels) { 2092 if (sband && idx >= sband->n_channels) {
@@ -2013,21 +2097,17 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
2013 if (!sband) 2097 if (!sband)
2014 sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; 2098 sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
2015 2099
2016 if (!sband || idx >= sband->n_channels) 2100 if (!sband || idx >= sband->n_channels) {
2017 return -ENOENT; 2101 spin_unlock_irqrestore(&common->cc_lock, flags);
2018 2102 return -ENOENT;
2019 survey->channel = &sband->channels[idx];
2020 chan = &ah->channels[survey->channel->hw_value];
2021 survey->filled = 0;
2022
2023 if (chan == ah->curchan)
2024 survey->filled |= SURVEY_INFO_IN_USE;
2025
2026 if (chan->noisefloor) {
2027 survey->filled |= SURVEY_INFO_NOISE_DBM;
2028 survey->noise = chan->noisefloor;
2029 } 2103 }
2030 2104
2105 chan = &sband->channels[idx];
2106 pos = chan->hw_value;
2107 memcpy(survey, &sc->survey[pos], sizeof(*survey));
2108 survey->channel = chan;
2109 spin_unlock_irqrestore(&common->cc_lock, flags);
2110
2031 return 0; 2111 return 0;
2032} 2112}
2033 2113