ath9k: implement extended channel utilization statistics via survey
[openwrt.git] / package / mac80211 / patches / 526-ath9k_survey_channel_stats.patch
1 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
2 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
3 @@ -594,6 +594,8 @@ struct ath_softc {
4 struct delayed_work wiphy_work;
5 unsigned long wiphy_scheduler_int;
6 int wiphy_scheduler_index;
7 + struct survey_info *cur_survey;
8 + struct survey_info survey[ATH9K_NUM_CHANNELS];
9
10 struct tasklet_struct intr_tq;
11 struct tasklet_struct bcon_tasklet;
12 --- a/drivers/net/wireless/ath/ath9k/main.c
13 +++ b/drivers/net/wireless/ath/ath9k/main.c
14 @@ -176,6 +176,49 @@ static void ath_start_ani(struct ath_com
15 msecs_to_jiffies((u32)ah->config.ani_poll_interval));
16 }
17
18 +static void ath_update_survey_nf(struct ath_softc *sc, int channel)
19 +{
20 + struct ath_hw *ah = sc->sc_ah;
21 + struct ath9k_channel *chan = &ah->channels[channel];
22 + struct survey_info *survey = &sc->survey[channel];
23 +
24 + if (chan->noisefloor) {
25 + survey->filled |= SURVEY_INFO_NOISE_DBM;
26 + survey->noise = chan->noisefloor;
27 + }
28 +}
29 +
30 +static void ath_update_survey_stats(struct ath_softc *sc)
31 +{
32 + struct ath_hw *ah = sc->sc_ah;
33 + struct ath_common *common = ath9k_hw_common(ah);
34 + int pos = ah->curchan - &ah->channels[0];
35 + struct survey_info *survey = &sc->survey[pos];
36 + struct ath_cycle_counters *cc = &common->cc_survey;
37 + unsigned long flags;
38 + unsigned int div = common->clockrate * 1000;
39 +
40 + spin_lock_irqsave(&common->cc_lock, flags);
41 +
42 + ath_hw_cycle_counters_update(common);
43 +
44 + if (cc->cycles > 0) {
45 + survey->filled |= SURVEY_INFO_CHANNEL_TIME |
46 + SURVEY_INFO_CHANNEL_TIME_BUSY |
47 + SURVEY_INFO_CHANNEL_TIME_RX |
48 + SURVEY_INFO_CHANNEL_TIME_TX;
49 + survey->channel_time += cc->cycles / div;
50 + survey->channel_time_busy += cc->rx_busy / div;
51 + survey->channel_time_rx += cc->rx_frame / div;
52 + survey->channel_time_tx += cc->tx_frame / div;
53 + }
54 + memset(cc, 0, sizeof(*cc));
55 +
56 + ath_update_survey_nf(sc, pos);
57 +
58 + spin_unlock_irqrestore(&common->cc_lock, flags);
59 +}
60 +
61 /*
62 * Set/change channels. If the channel is really being changed, it's done
63 * by reseting the chip. To accomplish this we must first cleanup any pending
64 @@ -1533,7 +1576,8 @@ static int ath9k_config(struct ieee80211
65 {
66 struct ath_wiphy *aphy = hw->priv;
67 struct ath_softc *sc = aphy->sc;
68 - struct ath_common *common = ath9k_hw_common(sc->sc_ah);
69 + struct ath_hw *ah = sc->sc_ah;
70 + struct ath_common *common = ath9k_hw_common(ah);
71 struct ieee80211_conf *conf = &hw->conf;
72 bool disable_radio;
73
74 @@ -1599,6 +1643,10 @@ static int ath9k_config(struct ieee80211
75 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
76 struct ieee80211_channel *curchan = hw->conf.channel;
77 int pos = curchan->hw_value;
78 + int old_pos = -1;
79 +
80 + if (ah->curchan)
81 + old_pos = ah->curchan - &ah->channels[0];
82
83 aphy->chan_idx = pos;
84 aphy->chan_is_ht = conf_is_ht(conf);
85 @@ -1626,12 +1674,43 @@ static int ath9k_config(struct ieee80211
86
87 ath_update_chainmask(sc, conf_is_ht(conf));
88
89 + /* update survey stats for the old channel before switching */
90 + ath_update_survey_stats(sc);
91 +
92 + /*
93 + * If the operating channel changes, change the survey in-use flags
94 + * along with it.
95 + * Reset the survey data for the new channel, unless we're switching
96 + * back to the operating channel from an off-channel operation.
97 + */
98 + if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
99 + sc->cur_survey != &sc->survey[pos]) {
100 +
101 + if (sc->cur_survey)
102 + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
103 +
104 + sc->cur_survey = &sc->survey[pos];
105 +
106 + memset(sc->cur_survey, 0, sizeof(struct survey_info));
107 + sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
108 + } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
109 + memset(&sc->survey[pos], 0, sizeof(struct survey_info));
110 + }
111 +
112 if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
113 ath_print(common, ATH_DBG_FATAL,
114 "Unable to set channel\n");
115 mutex_unlock(&sc->mutex);
116 return -EINVAL;
117 }
118 +
119 + /*
120 + * The most recent snapshot of channel->noisefloor for the old
121 + * channel is only available after the hardware reset. Copy it to
122 + * the survey stats now.
123 + */
124 + if (old_pos >= 0)
125 + ath_update_survey_nf(sc, old_pos);
126 }
127
128 skip_chan_change:
129 @@ -2001,9 +2080,12 @@ static int ath9k_get_survey(struct ieee8
130 {
131 struct ath_wiphy *aphy = hw->priv;
132 struct ath_softc *sc = aphy->sc;
133 - struct ath_hw *ah = sc->sc_ah;
134 struct ieee80211_supported_band *sband;
135 - struct ath9k_channel *chan;
136 + struct ieee80211_channel *chan;
137 + int pos;
138 +
139 + if (idx == 0)
140 + ath_update_survey_stats(sc);
141
142 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
143 if (sband && idx >= sband->n_channels) {
144 @@ -2017,17 +2099,10 @@ static int ath9k_get_survey(struct ieee8
145 if (!sband || idx >= sband->n_channels)
146 return -ENOENT;
147
148 - survey->channel = &sband->channels[idx];
149 - chan = &ah->channels[survey->channel->hw_value];
150 - survey->filled = 0;
151 -
152 - if (chan == ah->curchan)
153 - survey->filled |= SURVEY_INFO_IN_USE;
154 -
155 - if (chan->noisefloor) {
156 - survey->filled |= SURVEY_INFO_NOISE_DBM;
157 - survey->noise = chan->noisefloor;
158 - }
159 + chan = &sband->channels[idx];
160 + pos = chan->hw_value;
161 + memcpy(survey, &sc->survey[pos], sizeof(*survey));
162 + survey->channel = chan;
163
164 return 0;
165 }
This page took 0.047479 seconds and 5 git commands to generate.