1 --- /dev/null 2009-03-26 21:01:06.000000000 +0100
2 +++ ./ath/ath_wprobe.c 2009-03-26 20:58:07.000000000 +0100
4 +#include <net80211/ieee80211_node.h>
5 +#include <linux/wprobe.h>
7 +atomic_t cleanup_tasks = ATOMIC_INIT(0);
14 + WP_NODE_RETRANSMIT_200,
15 + WP_NODE_RETRANSMIT_400,
16 + WP_NODE_RETRANSMIT_800,
17 + WP_NODE_RETRANSMIT_1600,
27 +static struct wprobe_item ath_wprobe_globals[] = {
28 + [WP_GLOBAL_NOISE] = {
30 + .type = WPROBE_VAL_S16,
31 + .flags = WPROBE_F_KEEPSTAT
33 + [WP_GLOBAL_PHY_BUSY] = {
35 + .type = WPROBE_VAL_U8,
36 + .flags = WPROBE_F_KEEPSTAT
38 + [WP_GLOBAL_PHY_RX] = {
40 + .type = WPROBE_VAL_U8,
41 + .flags = WPROBE_F_KEEPSTAT
43 + [WP_GLOBAL_PHY_TX] = {
45 + .type = WPROBE_VAL_U8,
46 + .flags = WPROBE_F_KEEPSTAT
50 +static struct wprobe_item ath_wprobe_link[] = {
53 + .type = WPROBE_VAL_U8,
54 + .flags = WPROBE_F_KEEPSTAT
56 + [WP_NODE_SIGNAL] = {
58 + .type = WPROBE_VAL_S16,
59 + .flags = WPROBE_F_KEEPSTAT
61 + [WP_NODE_RX_RATE] = {
63 + .type = WPROBE_VAL_U16,
64 + .flags = WPROBE_F_KEEPSTAT
66 + [WP_NODE_TX_RATE] = {
68 + .type = WPROBE_VAL_U16,
69 + .flags = WPROBE_F_KEEPSTAT
71 + [WP_NODE_RETRANSMIT_200] = {
72 + .name = "retransmit_200",
73 + .type = WPROBE_VAL_U8,
74 + .flags = WPROBE_F_KEEPSTAT
76 + [WP_NODE_RETRANSMIT_400] = {
77 + .name = "retransmit_400",
78 + .type = WPROBE_VAL_U8,
79 + .flags = WPROBE_F_KEEPSTAT
81 + [WP_NODE_RETRANSMIT_800] = {
82 + .name = "retransmit_800",
83 + .type = WPROBE_VAL_U8,
84 + .flags = WPROBE_F_KEEPSTAT
86 + [WP_NODE_RETRANSMIT_1600] = {
87 + .name = "retransmit_1600",
88 + .type = WPROBE_VAL_U8,
89 + .flags = WPROBE_F_KEEPSTAT
93 +#define AR5K_MIBC 0x0040
94 +#define AR5K_MIBC_FREEZE (1 << 1)
95 +#define AR5K_TXFC 0x80ec
96 +#define AR5K_RXFC 0x80f0
97 +#define AR5K_RXCLEAR 0x80f4
98 +#define AR5K_CYCLES 0x80f8
100 +#define READ_CLR(_ah, _reg) \
101 + ({ u32 __val = OS_REG_READ(_ah, _reg); OS_REG_WRITE(_ah, _reg, 0); __val; })
104 +wprobe_disabled(void)
106 + return (!wprobe_add_iface || IS_ERR(wprobe_add_iface));
110 +ath_wprobe_sync(struct wprobe_iface *dev, struct wprobe_link *l, struct wprobe_value *val, bool measure)
112 + struct ath_vap *avp = container_of(dev, struct ath_vap, av_wpif);
113 + struct ieee80211vap *vap = &avp->av_vap;
114 + struct ieee80211com *ic = vap->iv_ic;
115 + struct ath_softc *sc = ic->ic_dev->priv;
116 + struct ath_hal *ah = sc->sc_ah;
117 + u32 cc, busy, rx, tx;
123 + OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE);
124 + cc = READ_CLR(ah, AR5K_CYCLES);
125 + busy = READ_CLR(ah, AR5K_RXCLEAR);
126 + rx = READ_CLR(ah, AR5K_RXFC);
127 + tx = READ_CLR(ah, AR5K_TXFC);
128 + OS_REG_WRITE(ah, AR5K_MIBC, 0);
129 + noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
130 + ic->ic_channoise = noise;
132 + WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
133 + if (cc & 0xf0000000) {
134 + /* scale down if the counters are near max */
140 + if (ah->ah_macType < 5212)
150 + busy = (busy * 100) / cc;
151 + rx = (rx * 100) / cc;
152 + tx = (tx * 100) / cc;
153 + WPROBE_SET(WP_GLOBAL_PHY_BUSY, U8, busy);
154 + WPROBE_SET(WP_GLOBAL_PHY_RX, U8, rx);
155 + WPROBE_SET(WP_GLOBAL_PHY_TX, U8, tx);
157 + WPROBE_SET(WP_GLOBAL_NOISE, S16, noise);
169 +#undef AR5K_MIBC_FREEZE
172 +static const struct wprobe_iface ath_wprobe_dev = {
173 + .link_items = ath_wprobe_link,
174 + .n_link_items = ARRAY_SIZE(ath_wprobe_link),
175 + .global_items = ath_wprobe_globals,
176 + .n_global_items = ARRAY_SIZE(ath_wprobe_globals),
177 + .sync_data = ath_wprobe_sync,
181 +ath_lookup_rateval(struct ieee80211_node *ni, int rate)
183 + struct ieee80211vap *vap = ni->ni_vap;
184 + struct ieee80211com *ic = vap->iv_ic;
185 + struct ath_softc *sc = ic->ic_dev->priv;
186 + const HAL_RATE_TABLE *rt = sc->sc_currates;
188 + if ((!rt) || (rate < 0) || (rate >= ARRAY_SIZE(sc->sc_hwmap)))
191 + rate = sc->sc_hwmap[rate].ieeerate;
192 + rate = sc->sc_rixmap[rate & IEEE80211_RATE_VAL];
193 + if ((rate < 0) || (rate >= rt->rateCount))
196 + return rt->info[rate].rateKbps / 10;
200 +ath_node_sample_rx(struct ieee80211_node *ni, struct ath_rx_status *rs)
202 + struct ath_node *an = ATH_NODE(ni);
203 + struct ieee80211vap *vap = ni->ni_vap;
204 + struct ieee80211com *ic = vap->iv_ic;
205 + struct wprobe_link *l = &an->an_wplink;
206 + struct wprobe_value *v = l->val;
207 + unsigned long flags;
210 + if (wprobe_disabled() || !an->an_wplink_active || !l->val)
213 + rate = ath_lookup_rateval(ni, rs->rs_rate);
215 + spin_lock_irqsave(&l->iface->lock, flags);
216 + WPROBE_FILL_BEGIN(v, ath_wprobe_link);
217 + WPROBE_SET(WP_NODE_RSSI, U8, rs->rs_rssi);
218 + WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + rs->rs_rssi);
219 + if ((rate > 0) && (rate <= 600000))
220 + WPROBE_SET(WP_NODE_RX_RATE, U16, rate);
222 + wprobe_update_stats(l->iface, l);
223 + spin_unlock_irqrestore(&l->iface->lock, flags);
227 +ath_node_sample_tx(struct ieee80211_node *ni, struct ath_tx_status *ts, int len)
229 + struct ath_node *an = ATH_NODE(ni);
230 + struct ieee80211vap *vap = ni->ni_vap;
231 + struct ieee80211com *ic = vap->iv_ic;
232 + struct wprobe_link *l = &an->an_wplink;
233 + struct wprobe_value *v = l->val;
234 + unsigned long flags;
235 + int rate, rexmit_counter;
237 + if (wprobe_disabled() || !an->an_wplink_active || !l->val)
240 + rate = ath_lookup_rateval(ni, ts->ts_rate);
242 + spin_lock_irqsave(&l->iface->lock, flags);
243 + WPROBE_FILL_BEGIN(v, ath_wprobe_link);
244 + WPROBE_SET(WP_NODE_RSSI, U8, ts->ts_rssi);
245 + WPROBE_SET(WP_NODE_SIGNAL, S16, ic->ic_channoise + ts->ts_rssi);
248 + rexmit_counter = WP_NODE_RETRANSMIT_200;
249 + else if (len <= 400)
250 + rexmit_counter = WP_NODE_RETRANSMIT_400;
251 + else if (len <= 800)
252 + rexmit_counter = WP_NODE_RETRANSMIT_800;
254 + rexmit_counter = WP_NODE_RETRANSMIT_1600;
255 + WPROBE_SET(rexmit_counter, U8, ts->ts_longretry);
257 + if ((rate > 0) && (rate <= 600000))
258 + WPROBE_SET(WP_NODE_TX_RATE, U16, rate);
260 + wprobe_update_stats(l->iface, l);
261 + spin_unlock_irqrestore(&l->iface->lock, flags);
265 +ath_wprobe_node_join(struct ieee80211vap *vap, struct ieee80211_node *ni)
267 + struct wprobe_iface *dev;
268 + struct wprobe_link *l;
269 + struct ath_vap *avp;
270 + struct ath_node *an = ATH_NODE(ni);
272 + if (wprobe_disabled() || an->an_wplink_active)
275 + avp = ATH_VAP(vap);
276 + dev = &avp->av_wpif;
277 + l = &an->an_wplink;
279 + ieee80211_ref_node(ni);
280 + wprobe_add_link(dev, l, ni->ni_macaddr);
281 + an->an_wplink_active = 1;
285 +ath_wprobe_do_node_leave(struct work_struct *work)
287 + struct ath_node *an = container_of(work, struct ath_node, an_destroy);
288 + struct ieee80211_node *ni = &an->an_node;
289 + struct ieee80211vap *vap = ni->ni_vap;
290 + struct wprobe_iface *dev;
291 + struct wprobe_link *l;
292 + struct ath_vap *avp;
294 + avp = ATH_VAP(vap);
295 + dev = &avp->av_wpif;
296 + l = &an->an_wplink;
298 + wprobe_remove_link(dev, l);
299 + ieee80211_unref_node(&ni);
300 + atomic_dec(&cleanup_tasks);
304 +ath_wprobe_node_leave(struct ieee80211vap *vap, struct ieee80211_node *ni)
306 + struct ath_node *an = ATH_NODE(ni);
308 + if (wprobe_disabled() || !an->an_wplink_active)
311 + atomic_inc(&cleanup_tasks);
312 + an->an_wplink_active = 0;
313 + IEEE80211_INIT_WORK(&an->an_destroy, ath_wprobe_do_node_leave);
314 + schedule_work(&an->an_destroy);
318 +ath_init_wprobe_dev(struct ath_vap *avp)
320 + struct ieee80211vap *vap = &avp->av_vap;
321 + struct wprobe_iface *dev = &avp->av_wpif;
323 + if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
326 + memcpy(dev, &ath_wprobe_dev, sizeof(struct wprobe_iface));
327 + dev->addr = vap->iv_myaddr;
328 + dev->name = vap->iv_dev->name;
329 + wprobe_add_iface(dev);
333 +ath_remove_wprobe_dev(struct ath_vap *avp)
335 + struct ieee80211vap *vap = &avp->av_vap;
336 + struct ieee80211com *ic = vap->iv_ic;
337 + struct ieee80211_node *ni;
338 + struct wprobe_iface *dev = &avp->av_wpif;
339 + struct wprobe_link *l;
340 + struct ath_node *an;
341 + unsigned long flags;
343 + if (wprobe_disabled() || (vap->iv_opmode == IEEE80211_M_WDS))
348 + list_for_each_entry_rcu(l, &dev->links, list) {
349 + an = container_of(l, struct ath_node, an_wplink);
351 + if (!an->an_wplink_active)
355 + ath_wprobe_node_leave(vap, ni);
361 + /* wait for the cleanup tasks to finish */
362 + while (atomic_read(&cleanup_tasks) != 0) {
366 + wprobe_remove_iface(dev);
368 --- a/ath/if_ath.c 2009-03-26 19:54:36.000000000 +0100
369 +++ /var/folders/DB/DBZUyxsHGRKP0B3nCU1mmU+++TI/-Tmp-/cocci-output-73937-18abc0-if_ath.c 2009-03-26 21:08:34.000000000 +0100
370 @@ -400,6 +400,7 @@ static int countrycode = -1;
371 static int maxvaps = -1;
372 static int outdoor = -1;
373 static int xchanmode = -1;
374 +#include "ath_wprobe.c"
375 static int beacon_cal = 1;
377 static const struct ath_hw_detect generic_hw_info = {
378 @@ -1525,6 +1526,7 @@ ath_vap_create(struct ieee80211com *ic,
379 ath_hal_intrset(ah, sc->sc_imask);
382 + ath_init_wprobe_dev(avp);
386 @@ -1605,6 +1607,7 @@ ath_vap_delete(struct ieee80211vap *vap)
389 ieee80211_vap_detach(vap);
390 + ath_remove_wprobe_dev(ATH_VAP(vap));
391 /* NB: memory is reclaimed through dev->destructor callback */
394 @@ -5931,6 +5934,7 @@ ath_node_cleanup(struct ieee80211_node *
395 /* Clean up node-specific rate things - this currently appears to
396 * always be a no-op */
397 sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni));
398 + ath_wprobe_node_leave(ni->ni_vap, ni);
400 ATH_NODE_UAPSD_LOCK_IRQ(an);
401 #ifdef IEEE80211_DEBUG_REFCNT
402 @@ -7001,6 +7005,7 @@ drop_micfail:
403 goto lookup_slowpath;
405 ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
406 + ath_node_sample_rx(ni, rs);
407 type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
408 ieee80211_unref_node(&ni);
410 @@ -7020,6 +7025,7 @@ lookup_slowpath:
411 ieee80211_keyix_t keyix;
413 ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
414 + ath_node_sample_rx(ni, rs);
415 type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
417 * If the station has a key cache slot assigned
418 @@ -8599,6 +8605,7 @@ ath_tx_processq(struct ath_softc *sc, st
419 sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
420 ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
422 + ath_node_sample_tx(&an->an_node, ts, bf->bf_skb->len);
423 if (bf->bf_skb->priority == WME_AC_VO ||
424 bf->bf_skb->priority == WME_AC_VI)
425 ni->ni_ic->ic_wme.wme_hipri_traffic++;
426 @@ -10090,6 +10097,7 @@ ath_newassoc(struct ieee80211_node *ni,
427 struct ath_softc *sc = ic->ic_dev->priv;
429 sc->sc_rc->ops->newassoc(sc, ATH_NODE(ni), isnew);
430 + ath_wprobe_node_join(ni->ni_vap, ni);
432 /* are we supporting compression? */
433 if (!(vap->iv_ath_cap & ni->ni_ath_flags & IEEE80211_NODE_COMP))
434 --- a/ath/if_athvar.h 2009-03-26 19:54:35.000000000 +0100
435 +++ /var/folders/DB/DBZUyxsHGRKP0B3nCU1mmU+++TI/-Tmp-/cocci-output-73937-80429d-if_athvar.h 2009-03-26 21:08:42.000000000 +0100
439 #include "if_athioctl.h"
440 +#include <linux/wprobe.h>
441 #include "net80211/ieee80211.h" /* XXX for WME_NUM_AC */
443 #include <linux/list.h>
444 @@ -352,6 +353,9 @@ typedef STAILQ_HEAD(, ath_buf) ath_bufhe
445 /* driver-specific node state */
447 struct ieee80211_node an_node; /* base class */
448 + struct wprobe_link an_wplink;
449 + uint8_t an_wplink_active;
450 + struct work_struct an_destroy;
451 u_int16_t an_decomp_index; /* decompression mask index */
452 u_int32_t an_avgrssi; /* average rssi over all rx frames */
453 u_int8_t an_prevdatarix; /* rate ix of last data frame */
454 @@ -521,6 +525,7 @@ struct ath_vap {
456 unsigned int av_beacon_alloc;
458 + struct wprobe_iface av_wpif;
460 #define ATH_VAP(_v) ((struct ath_vap *)(_v))