1143392Ssam/*-
2143392Ssam * Copyright (c) 2005 John Bicket
3143392Ssam * All rights reserved.
4143392Ssam *
5143392Ssam * Redistribution and use in source and binary forms, with or without
6143392Ssam * modification, are permitted provided that the following conditions
7143392Ssam * are met:
8143392Ssam * 1. Redistributions of source code must retain the above copyright
9143392Ssam *    notice, this list of conditions and the following disclaimer,
10143392Ssam *    without modification.
11143392Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12143392Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13143392Ssam *    redistribution must be conditioned upon including a substantially
14143392Ssam *    similar Disclaimer requirement for further binary redistribution.
15143392Ssam * 3. Neither the names of the above-listed copyright holders nor the names
16143392Ssam *    of any contributors may be used to endorse or promote products derived
17143392Ssam *    from this software without specific prior written permission.
18143392Ssam *
19143392Ssam * Alternatively, this software may be distributed under the terms of the
20143392Ssam * GNU General Public License ("GPL") version 2 as published by the Free
21143392Ssam * Software Foundation.
22143392Ssam *
23143392Ssam * NO WARRANTY
24143392Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25143392Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26143392Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27143392Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28143392Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29143392Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30143392Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31143392Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32143392Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33143392Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34143392Ssam * THE POSSIBILITY OF SUCH DAMAGES.
35170530Ssam *
36143392Ssam */
37143392Ssam
38143392Ssam#include <sys/cdefs.h>
39143392Ssam__FBSDID("$FreeBSD$");
40143392Ssam
41143392Ssam/*
42143392Ssam * John Bicket's SampleRate control algorithm.
43143392Ssam */
44237529Sadrian#include "opt_ath.h"
45143392Ssam#include "opt_inet.h"
46178354Ssam#include "opt_wlan.h"
47227340Sadrian#include "opt_ah.h"
48143392Ssam
49143392Ssam#include <sys/param.h>
50143392Ssam#include <sys/systm.h>
51143392Ssam#include <sys/sysctl.h>
52143392Ssam#include <sys/kernel.h>
53143392Ssam#include <sys/lock.h>
54143392Ssam#include <sys/mutex.h>
55143392Ssam#include <sys/errno.h>
56143392Ssam
57143392Ssam#include <machine/bus.h>
58143392Ssam#include <machine/resource.h>
59143392Ssam#include <sys/bus.h>
60143392Ssam
61143392Ssam#include <sys/socket.h>
62143392Ssam
63143392Ssam#include <net/if.h>
64143392Ssam#include <net/if_media.h>
65143392Ssam#include <net/if_arp.h>
66185482Ssam#include <net/ethernet.h>		/* XXX for ether_sprintf */
67143392Ssam
68143392Ssam#include <net80211/ieee80211_var.h>
69143392Ssam
70143392Ssam#include <net/bpf.h>
71143392Ssam
72143392Ssam#ifdef INET
73143392Ssam#include <netinet/in.h>
74143392Ssam#include <netinet/if_ether.h>
75143392Ssam#endif
76143392Ssam
77143392Ssam#include <dev/ath/if_athvar.h>
78143392Ssam#include <dev/ath/ath_rate/sample/sample.h>
79185522Ssam#include <dev/ath/ath_hal/ah_desc.h>
80218013Sadrian#include <dev/ath/ath_rate/sample/tx_schedules.h>
81143392Ssam
82143392Ssam/*
83143392Ssam * This file is an implementation of the SampleRate algorithm
84143392Ssam * in "Bit-rate Selection in Wireless Networks"
85143392Ssam * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
86143392Ssam *
87143392Ssam * SampleRate chooses the bit-rate it predicts will provide the most
88143392Ssam * throughput based on estimates of the expected per-packet
89143392Ssam * transmission time for each bit-rate.  SampleRate periodically sends
90143392Ssam * packets at bit-rates other than the current one to estimate when
91143392Ssam * another bit-rate will provide better performance. SampleRate
92143392Ssam * switches to another bit-rate when its estimated per-packet
93143392Ssam * transmission time becomes smaller than the current bit-rate's.
94143392Ssam * SampleRate reduces the number of bit-rates it must sample by
95143392Ssam * eliminating those that could not perform better than the one
96143392Ssam * currently being used.  SampleRate also stops probing at a bit-rate
97143392Ssam * if it experiences several successive losses.
98143392Ssam *
99143392Ssam * The difference between the algorithm in the thesis and the one in this
100143392Ssam * file is that the one in this file uses a ewma instead of a window.
101143392Ssam *
102155476Ssam * Also, this implementation tracks the average transmission time for
103155476Ssam * a few different packet sizes independently for each link.
104143392Ssam */
105143392Ssam
106143853Ssamstatic void	ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
107143853Ssam
108155476Ssamstatic __inline int
109155476Ssamsize_to_bin(int size)
110143392Ssam{
111185482Ssam#if NUM_PACKET_SIZE_BINS > 1
112185482Ssam	if (size <= packet_size_bins[0])
113185482Ssam		return 0;
114185482Ssam#endif
115185482Ssam#if NUM_PACKET_SIZE_BINS > 2
116185482Ssam	if (size <= packet_size_bins[1])
117185482Ssam		return 1;
118185482Ssam#endif
119185482Ssam#if NUM_PACKET_SIZE_BINS > 3
120185482Ssam	if (size <= packet_size_bins[2])
121185482Ssam		return 2;
122185482Ssam#endif
123185482Ssam#if NUM_PACKET_SIZE_BINS > 4
124185482Ssam#error "add support for more packet sizes"
125185482Ssam#endif
126143392Ssam	return NUM_PACKET_SIZE_BINS-1;
127143392Ssam}
128185482Ssam
129143392Ssamvoid
130143392Ssamath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
131143392Ssam{
132143392Ssam	/* NB: assumed to be zero'd by caller */
133143392Ssam}
134143392Ssam
135143392Ssamvoid
136143392Ssamath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
137143392Ssam{
138143392Ssam}
139143392Ssam
140218013Sadrianstatic int
141218013Sadriandot11rate(const HAL_RATE_TABLE *rt, int rix)
142218013Sadrian{
143227340Sadrian	if (rix < 0)
144227340Sadrian		return -1;
145218013Sadrian	return rt->info[rix].phy == IEEE80211_T_HT ?
146218013Sadrian	    rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;
147218013Sadrian}
148218013Sadrian
149219216Sadrianstatic const char *
150219216Sadriandot11rate_label(const HAL_RATE_TABLE *rt, int rix)
151219216Sadrian{
152227340Sadrian	if (rix < 0)
153227340Sadrian		return "";
154219216Sadrian	return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";
155219216Sadrian}
156219216Sadrian
157143392Ssam/*
158185482Ssam * Return the rix with the lowest average_tx_time,
159143392Ssam * or -1 if all the average_tx_times are 0.
160143392Ssam */
161185482Ssamstatic __inline int
162222049Sadrianpick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt,
163185482Ssam    int size_bin, int require_acked_before)
164143392Ssam{
165222049Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
166227364Sadrian        int best_rate_rix, best_rate_tt, best_rate_pct;
167239284Sadrian	uint64_t mask;
168227364Sadrian	int rix, tt, pct;
169185482Ssam
170185482Ssam        best_rate_rix = 0;
171185482Ssam        best_rate_tt = 0;
172227364Sadrian	best_rate_pct = 0;
173185482Ssam	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
174185482Ssam		if ((mask & 1) == 0)		/* not a supported rate */
175143853Ssam			continue;
176155476Ssam
177222049Sadrian		/* Don't pick a non-HT rate for a HT node */
178222049Sadrian		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
179222049Sadrian		    (rt->info[rix].phy != IEEE80211_T_HT)) {
180222049Sadrian			continue;
181222049Sadrian		}
182222049Sadrian
183185482Ssam		tt = sn->stats[size_bin][rix].average_tx_time;
184185482Ssam		if (tt <= 0 ||
185185482Ssam		    (require_acked_before &&
186185482Ssam		     !sn->stats[size_bin][rix].packets_acked))
187155476Ssam			continue;
188155476Ssam
189227364Sadrian		/* Calculate percentage if possible */
190227364Sadrian		if (sn->stats[size_bin][rix].total_packets > 0) {
191227364Sadrian			pct = sn->stats[size_bin][rix].ewma_pct;
192227364Sadrian		} else {
193227364Sadrian			/* XXX for now, assume 95% ok */
194227364Sadrian			pct = 95;
195227364Sadrian		}
196227364Sadrian
197155476Ssam		/* don't use a bit-rate that has been failing */
198185482Ssam		if (sn->stats[size_bin][rix].successive_failures > 3)
199155476Ssam			continue;
200155476Ssam
201227364Sadrian		/*
202227364Sadrian		 * For HT, Don't use a bit rate that is much more
203227364Sadrian		 * lossy than the best.
204227364Sadrian		 *
205227364Sadrian		 * XXX this isn't optimal; it's just designed to
206227364Sadrian		 * eliminate rates that are going to be obviously
207227364Sadrian		 * worse.
208227364Sadrian		 */
209227364Sadrian		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
210227364Sadrian			if (best_rate_pct > (pct + 50))
211227364Sadrian				continue;
212143853Ssam		}
213227364Sadrian
214227364Sadrian		/*
215227364Sadrian		 * For non-MCS rates, use the current average txtime for
216227364Sadrian		 * comparison.
217227364Sadrian		 */
218227364Sadrian		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
219227364Sadrian			if (best_rate_tt == 0 || tt <= best_rate_tt) {
220227364Sadrian				best_rate_tt = tt;
221227364Sadrian				best_rate_rix = rix;
222227364Sadrian				best_rate_pct = pct;
223227364Sadrian			}
224227364Sadrian		}
225227364Sadrian
226227364Sadrian		/*
227227364Sadrian		 * Since 2 stream rates have slightly higher TX times,
228227364Sadrian		 * allow a little bit of leeway. This should later
229227364Sadrian		 * be abstracted out and properly handled.
230227364Sadrian		 */
231227364Sadrian		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
232227364Sadrian			if (best_rate_tt == 0 || (tt * 8 <= best_rate_tt * 10)) {
233227364Sadrian				best_rate_tt = tt;
234227364Sadrian				best_rate_rix = rix;
235227364Sadrian				best_rate_pct = pct;
236227364Sadrian			}
237227364Sadrian		}
238143392Ssam        }
239185482Ssam        return (best_rate_tt ? best_rate_rix : -1);
240143392Ssam}
241143392Ssam
242143392Ssam/*
243185482Ssam * Pick a good "random" bit-rate to sample other than the current one.
244143392Ssam */
245155476Ssamstatic __inline int
246222049Sadrianpick_sample_rate(struct sample_softc *ssc , struct ath_node *an,
247185482Ssam    const HAL_RATE_TABLE *rt, int size_bin)
248143392Ssam{
249185482Ssam#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
250218013Sadrian#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
251222049Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
252185482Ssam	int current_rix, rix;
253185482Ssam	unsigned current_tt;
254239284Sadrian	uint64_t mask;
255143392Ssam
256185482Ssam	current_rix = sn->current_rix[size_bin];
257185482Ssam	if (current_rix < 0) {
258143392Ssam		/* no successes yet, send at the lowest bit-rate */
259222049Sadrian		/* XXX should return MCS0 if HT */
260143392Ssam		return 0;
261143392Ssam	}
262155476Ssam
263185482Ssam	current_tt = sn->stats[size_bin][current_rix].average_tx_time;
264185482Ssam
265185482Ssam	rix = sn->last_sample_rix[size_bin]+1;	/* next sample rate */
266239284Sadrian	mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
267185482Ssam	while (mask != 0) {
268239284Sadrian		if ((mask & ((uint64_t) 1<<rix)) == 0) {	/* not a supported rate */
269185482Ssam	nextrate:
270185482Ssam			if (++rix >= rt->rateCount)
271185482Ssam				rix = 0;
272155476Ssam			continue;
273185482Ssam		}
274155476Ssam
275242392Sadrian		/*
276242392Sadrian		 * The following code stops trying to sample
277242392Sadrian		 * non-MCS rates when speaking to an MCS node.
278242392Sadrian		 * However, at least for CCK rates in 2.4GHz mode,
279242392Sadrian		 * the non-MCS rates MAY actually provide better
280242392Sadrian		 * PER at the very far edge of reception.
281242392Sadrian		 *
282242392Sadrian		 * However! Until ath_rate_form_aggr() grows
283242392Sadrian		 * some logic to not form aggregates if the
284242392Sadrian		 * selected rate is non-MCS, this won't work.
285242392Sadrian		 *
286242392Sadrian		 * So don't disable this code until you've taught
287242392Sadrian		 * ath_rate_form_aggr() to drop out if any of
288242392Sadrian		 * the selected rates are non-MCS.
289242392Sadrian		 */
290242392Sadrian#if 1
291222049Sadrian		/* if the node is HT and the rate isn't HT, don't bother sample */
292222049Sadrian		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
293222049Sadrian		    (rt->info[rix].phy != IEEE80211_T_HT)) {
294239284Sadrian			mask &= ~((uint64_t) 1<<rix);
295222049Sadrian			goto nextrate;
296222049Sadrian		}
297242392Sadrian#endif
298222049Sadrian
299155476Ssam		/* this bit-rate is always worse than the current one */
300185482Ssam		if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {
301239284Sadrian			mask &= ~((uint64_t) 1<<rix);
302185482Ssam			goto nextrate;
303185482Ssam		}
304155476Ssam
305155476Ssam		/* rarely sample bit-rates that fail a lot */
306185482Ssam		if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
307185482Ssam		    ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
308239284Sadrian			mask &= ~((uint64_t) 1<<rix);
309185482Ssam			goto nextrate;
310185482Ssam		}
311155476Ssam
312227364Sadrian		/*
313240583Sadrian		 * For HT, only sample a few rates on either side of the
314240583Sadrian		 * current rix; there's quite likely a lot of them.
315227364Sadrian		 */
316227364Sadrian		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
317240583Sadrian			if (rix < (current_rix - 3) ||
318240583Sadrian			    rix > (current_rix + 3)) {
319239284Sadrian				mask &= ~((uint64_t) 1<<rix);
320227364Sadrian				goto nextrate;
321227364Sadrian			}
322227364Sadrian		}
323227364Sadrian
324222049Sadrian		/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
325222049Sadrian		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
326222049Sadrian			if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
327239284Sadrian				mask &= ~((uint64_t) 1<<rix);
328222049Sadrian				goto nextrate;
329222049Sadrian			}
330185482Ssam		}
331143853Ssam
332185482Ssam		sn->last_sample_rix[size_bin] = rix;
333185482Ssam		return rix;
334143392Ssam	}
335185482Ssam	return current_rix;
336185482Ssam#undef DOT11RATE
337218013Sadrian#undef	MCS
338143392Ssam}
339143392Ssam
340219822Sadrianstatic int
341219822Sadrianath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni)
342219822Sadrian{
343219822Sadrian#define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
344219822Sadrian#define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
345219822Sadrian#define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
346219822Sadrian	const struct ieee80211_txparam *tp = ni->ni_txparms;
347219822Sadrian	int srate;
348219822Sadrian
349219822Sadrian	/* Check MCS rates */
350219822Sadrian	for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) {
351219822Sadrian		if (MCS(srate) == tp->ucastrate)
352219822Sadrian			return sc->sc_rixmap[tp->ucastrate];
353219822Sadrian	}
354219822Sadrian
355219822Sadrian	/* Check legacy rates */
356219822Sadrian	for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) {
357219822Sadrian		if (RATE(srate) == tp->ucastrate)
358219822Sadrian			return sc->sc_rixmap[tp->ucastrate];
359219822Sadrian	}
360219822Sadrian	return -1;
361219822Sadrian#undef	RATE
362219822Sadrian#undef	DOT11RATE
363219822Sadrian#undef	MCS
364219822Sadrian}
365219822Sadrian
366219822Sadrianstatic void
367219822Sadrianath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni)
368219822Sadrian{
369219822Sadrian	struct ath_node *an = ATH_NODE(ni);
370219822Sadrian	const struct ieee80211_txparam *tp = ni->ni_txparms;
371219822Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
372219822Sadrian
373219822Sadrian	if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
374219822Sadrian		/*
375219822Sadrian		 * A fixed rate is to be used; ucastrate is the IEEE code
376219822Sadrian		 * for this rate (sans basic bit).  Check this against the
377219822Sadrian		 * negotiated rate set for the node.  Note the fixed rate
378219822Sadrian		 * may not be available for various reasons so we only
379219822Sadrian		 * setup the static rate index if the lookup is successful.
380219822Sadrian		 */
381219822Sadrian		sn->static_rix = ath_rate_get_static_rix(sc, ni);
382219822Sadrian	} else {
383219822Sadrian		sn->static_rix = -1;
384219822Sadrian	}
385219822Sadrian}
386219822Sadrian
387227364Sadrian/*
388227364Sadrian * Pick a non-HT rate to begin using.
389227364Sadrian */
390227364Sadrianstatic int
391227364Sadrianath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an,
392227364Sadrian    int frameLen)
393227364Sadrian{
394227364Sadrian#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
395227364Sadrian#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
396227364Sadrian#define	RATE(ix)	(DOT11RATE(ix) / 2)
397227364Sadrian	int rix = -1;
398227364Sadrian	const HAL_RATE_TABLE *rt = sc->sc_currates;
399227364Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
400227364Sadrian	const int size_bin = size_to_bin(frameLen);
401219822Sadrian
402227364Sadrian	/* no packet has been sent successfully yet */
403227364Sadrian	for (rix = rt->rateCount-1; rix > 0; rix--) {
404239284Sadrian		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
405227364Sadrian			continue;
406219822Sadrian
407227364Sadrian		/* Skip HT rates */
408227364Sadrian		if (rt->info[rix].phy == IEEE80211_T_HT)
409227364Sadrian			continue;
410227364Sadrian
411227364Sadrian		/*
412227364Sadrian		 * Pick the highest rate <= 36 Mbps
413227364Sadrian		 * that hasn't failed.
414227364Sadrian		 */
415227364Sadrian		if (DOT11RATE(rix) <= 72 &&
416227364Sadrian		    sn->stats[size_bin][rix].successive_failures == 0) {
417227364Sadrian			break;
418227364Sadrian		}
419227364Sadrian	}
420227364Sadrian	return rix;
421227364Sadrian#undef	RATE
422227364Sadrian#undef	MCS
423227364Sadrian#undef	DOT11RATE
424227364Sadrian}
425227364Sadrian
426227364Sadrian/*
427227364Sadrian * Pick a HT rate to begin using.
428227364Sadrian *
429227364Sadrian * Don't use any non-HT rates; only consider HT rates.
430227364Sadrian */
431227364Sadrianstatic int
432227364Sadrianath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an,
433227364Sadrian    int frameLen)
434227364Sadrian{
435227364Sadrian#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
436227364Sadrian#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
437227364Sadrian#define	RATE(ix)	(DOT11RATE(ix) / 2)
438227364Sadrian	int rix = -1, ht_rix = -1;
439227364Sadrian	const HAL_RATE_TABLE *rt = sc->sc_currates;
440227364Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
441227364Sadrian	const int size_bin = size_to_bin(frameLen);
442227364Sadrian
443227364Sadrian	/* no packet has been sent successfully yet */
444227364Sadrian	for (rix = rt->rateCount-1; rix > 0; rix--) {
445227364Sadrian		/* Skip rates we can't use */
446239284Sadrian		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
447227364Sadrian			continue;
448227364Sadrian
449227364Sadrian		/* Keep a copy of the last seen HT rate index */
450227364Sadrian		if (rt->info[rix].phy == IEEE80211_T_HT)
451227364Sadrian			ht_rix = rix;
452227364Sadrian
453227364Sadrian		/* Skip non-HT rates */
454227364Sadrian		if (rt->info[rix].phy != IEEE80211_T_HT)
455227364Sadrian			continue;
456227364Sadrian
457227364Sadrian		/*
458227364Sadrian		 * Pick a medium-speed rate regardless of stream count
459227364Sadrian		 * which has not seen any failures. Higher rates may fail;
460227364Sadrian		 * we'll try them later.
461227364Sadrian		 */
462227364Sadrian		if (((MCS(rix) & 0x7) <= 4) &&
463227364Sadrian		    sn->stats[size_bin][rix].successive_failures == 0) {
464227364Sadrian			break;
465227364Sadrian		}
466227364Sadrian	}
467227364Sadrian
468227364Sadrian	/*
469227364Sadrian	 * If all the MCS rates have successive failures, rix should be
470227364Sadrian	 * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)
471227364Sadrian	 */
472227364Sadrian	return MAX(rix, ht_rix);
473227364Sadrian#undef	RATE
474227364Sadrian#undef	MCS
475227364Sadrian#undef	DOT11RATE
476227364Sadrian}
477227364Sadrian
478227364Sadrian
479143392Ssamvoid
480143392Ssamath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
481144546Ssam		  int shortPreamble, size_t frameLen,
482185482Ssam		  u_int8_t *rix0, int *try0, u_int8_t *txrate)
483143392Ssam{
484185482Ssam#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
485218013Sadrian#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
486185482Ssam#define	RATE(ix)	(DOT11RATE(ix) / 2)
487143392Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(an);
488143392Ssam	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
489178354Ssam	struct ifnet *ifp = sc->sc_ifp;
490178354Ssam	struct ieee80211com *ic = ifp->if_l2com;
491185482Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
492185482Ssam	const int size_bin = size_to_bin(frameLen);
493185482Ssam	int rix, mrr, best_rix, change_rates;
494143853Ssam	unsigned average_tx_time;
495143392Ssam
496219822Sadrian	ath_rate_update_static_rix(sc, &an->an_node);
497219822Sadrian
498232170Sadrian	if (sn->currates != sc->sc_currates) {
499232170Sadrian		device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",
500232170Sadrian		    __func__);
501232170Sadrian		rix = 0;
502232170Sadrian		*try0 = ATH_TXMAXTRY;
503232170Sadrian		goto done;
504232170Sadrian	}
505232170Sadrian
506185482Ssam	if (sn->static_rix != -1) {
507185482Ssam		rix = sn->static_rix;
508185482Ssam		*try0 = ATH_TXMAXTRY;
509185482Ssam		goto done;
510185482Ssam	}
511185482Ssam
512238961Sadrian	mrr = sc->sc_mrretry;
513238961Sadrian	/* XXX check HT protmode too */
514238962Sadrian	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
515238961Sadrian		mrr = 0;
516143853Ssam
517222049Sadrian	best_rix = pick_best_rate(an, rt, size_bin, !mrr);
518185482Ssam	if (best_rix >= 0) {
519185482Ssam		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
520143853Ssam	} else {
521143853Ssam		average_tx_time = 0;
522143853Ssam	}
523185482Ssam	/*
524185482Ssam	 * Limit the time measuring the performance of other tx
525185482Ssam	 * rates to sample_rate% of the total transmission time.
526185482Ssam	 */
527185482Ssam	if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
528222049Sadrian		rix = pick_sample_rate(ssc, an, rt, size_bin);
529185482Ssam		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
530227364Sadrian		     &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s",
531227364Sadrian		     average_tx_time,
532227364Sadrian		     sn->sample_tt[size_bin],
533227364Sadrian		     bin_to_size(size_bin),
534227364Sadrian		     dot11rate(rt, rix),
535227364Sadrian		     dot11rate_label(rt, rix),
536227364Sadrian		     dot11rate(rt, sn->current_rix[size_bin]),
537227364Sadrian		     dot11rate_label(rt, sn->current_rix[size_bin]));
538185482Ssam		if (rix != sn->current_rix[size_bin]) {
539185482Ssam			sn->current_sample_rix[size_bin] = rix;
540185482Ssam		} else {
541185482Ssam			sn->current_sample_rix[size_bin] = -1;
542185482Ssam		}
543185482Ssam		sn->packets_since_sample[size_bin] = 0;
544143853Ssam	} else {
545185482Ssam		change_rates = 0;
546185482Ssam		if (!sn->packets_sent[size_bin] || best_rix == -1) {
547185482Ssam			/* no packet has been sent successfully yet */
548185482Ssam			change_rates = 1;
549227364Sadrian			if (an->an_node.ni_flags & IEEE80211_NODE_HT)
550227364Sadrian				best_rix =
551227364Sadrian				    ath_rate_pick_seed_rate_ht(sc, an, frameLen);
552227364Sadrian			else
553227364Sadrian				best_rix =
554227364Sadrian				    ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
555185482Ssam		} else if (sn->packets_sent[size_bin] < 20) {
556185482Ssam			/* let the bit-rate switch quickly during the first few packets */
557227364Sadrian			IEEE80211_NOTE(an->an_node.ni_vap,
558227364Sadrian			    IEEE80211_MSG_RATECTL, &an->an_node,
559227364Sadrian			    "%s: switching quickly..", __func__);
560185482Ssam			change_rates = 1;
561185482Ssam		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
562185482Ssam			/* min_switch seconds have gone by */
563227364Sadrian			IEEE80211_NOTE(an->an_node.ni_vap,
564227364Sadrian			    IEEE80211_MSG_RATECTL, &an->an_node,
565227364Sadrian			    "%s: min_switch %d > ticks_since_switch %d..",
566227364Sadrian			    __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
567185482Ssam			change_rates = 1;
568227364Sadrian		} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
569227364Sadrian		    (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
570185482Ssam			/* the current bit-rate is twice as slow as the best one */
571227364Sadrian			IEEE80211_NOTE(an->an_node.ni_vap,
572227364Sadrian			    IEEE80211_MSG_RATECTL, &an->an_node,
573227364Sadrian			    "%s: 2x att (= %d) < cur_rix att %d",
574227364Sadrian			    __func__,
575227364Sadrian			    2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
576185482Ssam			change_rates = 1;
577227364Sadrian		} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
578227364Sadrian			int cur_rix = sn->current_rix[size_bin];
579227364Sadrian			int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
580227364Sadrian			/*
581227364Sadrian			 * If the node is HT, upgrade it if the MCS rate is
582227364Sadrian			 * higher and the average tx time is within 20% of
583227364Sadrian			 * the current rate. It can fail a little.
584227364Sadrian			 *
585227364Sadrian			 * This is likely not optimal!
586227364Sadrian			 */
587227364Sadrian#if 0
588227364Sadrian			printf("cur rix/att %x/%d, best rix/att %x/%d\n",
589227364Sadrian			    MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
590227364Sadrian#endif
591227364Sadrian			if ((MCS(best_rix) > MCS(cur_rix)) &&
592227364Sadrian			    (average_tx_time * 8) <= (cur_att * 10)) {
593227364Sadrian				IEEE80211_NOTE(an->an_node.ni_vap,
594227364Sadrian				    IEEE80211_MSG_RATECTL, &an->an_node,
595227364Sadrian				    "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d",
596227364Sadrian				    __func__,
597227364Sadrian				    MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att);
598227364Sadrian				change_rates = 1;
599227364Sadrian			}
600185482Ssam		}
601155476Ssam
602185482Ssam		sn->packets_since_sample[size_bin]++;
603185482Ssam
604185482Ssam		if (change_rates) {
605185482Ssam			if (best_rix != sn->current_rix[size_bin]) {
606185482Ssam				IEEE80211_NOTE(an->an_node.ni_vap,
607185482Ssam				    IEEE80211_MSG_RATECTL,
608185482Ssam				    &an->an_node,
609178354Ssam"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
610185482Ssam				    __func__,
611185482Ssam				    bin_to_size(size_bin),
612185482Ssam				    RATE(sn->current_rix[size_bin]),
613185482Ssam				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
614185482Ssam				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
615185482Ssam				    RATE(best_rix),
616185482Ssam				    sn->stats[size_bin][best_rix].average_tx_time,
617185482Ssam				    sn->stats[size_bin][best_rix].perfect_tx_time,
618185482Ssam				    sn->packets_since_switch[size_bin],
619185482Ssam				    mrr);
620143392Ssam			}
621185482Ssam			sn->packets_since_switch[size_bin] = 0;
622185482Ssam			sn->current_rix[size_bin] = best_rix;
623185482Ssam			sn->ticks_since_switch[size_bin] = ticks;
624185482Ssam			/*
625185482Ssam			 * Set the visible txrate for this node.
626185482Ssam			 */
627218013Sadrian			an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ?  MCS(best_rix) : DOT11RATE(best_rix);
628143392Ssam		}
629185482Ssam		rix = sn->current_rix[size_bin];
630185482Ssam		sn->packets_since_switch[size_bin]++;
631143853Ssam	}
632185482Ssam	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
633185482Ssamdone:
634232170Sadrian
635232170Sadrian	/*
636232170Sadrian	 * This bug totally sucks and should be fixed.
637232170Sadrian	 *
638232170Sadrian	 * For now though, let's not panic, so we can start to figure
639232170Sadrian	 * out how to better reproduce it.
640232170Sadrian	 */
641232170Sadrian	if (rix < 0 || rix >= rt->rateCount) {
642232170Sadrian		printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
643232170Sadrian		    __func__,
644232170Sadrian		    rix,
645232170Sadrian		    rt->rateCount);
646232170Sadrian		    rix = 0;	/* XXX just default for now */
647232170Sadrian	}
648185482Ssam	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));
649143392Ssam
650185482Ssam	*rix0 = rix;
651185482Ssam	*txrate = rt->info[rix].rateCode
652185482Ssam		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
653143392Ssam	sn->packets_sent[size_bin]++;
654185482Ssam#undef DOT11RATE
655218013Sadrian#undef MCS
656185482Ssam#undef RATE
657143392Ssam}
658143392Ssam
659218160Sadrian/*
660218160Sadrian * Get the TX rates. Don't fiddle with short preamble flags for them;
661218160Sadrian * the caller can do that.
662218160Sadrian */
663143392Ssamvoid
664218160Sadrianath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
665227364Sadrian    uint8_t rix0, struct ath_rc_series *rc)
666218160Sadrian{
667218160Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
668218160Sadrian	const struct txschedule *sched = &sn->sched[rix0];
669218160Sadrian
670239284Sadrian	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
671239284Sadrian	    rix0, sched->r0));
672218160Sadrian
673227364Sadrian	rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
674218160Sadrian
675227364Sadrian	rc[0].rix = sched->r0;
676227364Sadrian	rc[1].rix = sched->r1;
677227364Sadrian	rc[2].rix = sched->r2;
678227364Sadrian	rc[3].rix = sched->r3;
679227364Sadrian
680227364Sadrian	rc[0].tries = sched->t0;
681227364Sadrian	rc[1].tries = sched->t1;
682227364Sadrian	rc[2].tries = sched->t2;
683227364Sadrian	rc[3].tries = sched->t3;
684218160Sadrian}
685218160Sadrian
686218160Sadrianvoid
687143392Ssamath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
688144546Ssam		      struct ath_desc *ds, int shortPreamble, u_int8_t rix)
689143392Ssam{
690143392Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(an);
691185482Ssam	const struct txschedule *sched = &sn->sched[rix];
692185482Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
693185482Ssam	uint8_t rix1, s1code, rix2, s2code, rix3, s3code;
694143392Ssam
695185482Ssam	/* XXX precalculate short preamble tables */
696185482Ssam	rix1 = sched->r1;
697185482Ssam	s1code = rt->info[rix1].rateCode
698185482Ssam	       | (shortPreamble ? rt->info[rix1].shortPreamble : 0);
699185482Ssam	rix2 = sched->r2;
700185482Ssam	s2code = rt->info[rix2].rateCode
701185482Ssam	       | (shortPreamble ? rt->info[rix2].shortPreamble : 0);
702185482Ssam	rix3 = sched->r3;
703185482Ssam	s3code = rt->info[rix3].rateCode
704185482Ssam	       | (shortPreamble ? rt->info[rix3].shortPreamble : 0);
705185482Ssam	ath_hal_setupxtxdesc(sc->sc_ah, ds,
706185482Ssam	    s1code, sched->t1,		/* series 1 */
707185482Ssam	    s2code, sched->t2,		/* series 2 */
708185482Ssam	    s3code, sched->t3);		/* series 3 */
709143392Ssam}
710143392Ssam
711143853Ssamstatic void
712143853Ssamupdate_stats(struct ath_softc *sc, struct ath_node *an,
713143853Ssam		  int frame_size,
714185482Ssam		  int rix0, int tries0,
715185482Ssam		  int rix1, int tries1,
716185482Ssam		  int rix2, int tries2,
717185482Ssam		  int rix3, int tries3,
718227364Sadrian		  int short_tries, int tries, int status,
719227364Sadrian		  int nframes, int nbad)
720143392Ssam{
721143392Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(an);
722143392Ssam	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
723227371Sadrian#ifdef IEEE80211_DEBUG
724227364Sadrian	const HAL_RATE_TABLE *rt = sc->sc_currates;
725227371Sadrian#endif
726185482Ssam	const int size_bin = size_to_bin(frame_size);
727185482Ssam	const int size = bin_to_size(size_bin);
728185482Ssam	int tt, tries_so_far;
729219985Sadrian	int is_ht40 = (an->an_node.ni_chw == 40);
730247372Sadrian	int pct;
731143392Ssam
732185482Ssam	if (!IS_RATE_DEFINED(sn, rix0))
733165185Ssam		return;
734185482Ssam	tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
735218761Sadrian		MIN(tries0, tries) - 1, is_ht40);
736185482Ssam	tries_so_far = tries0;
737143853Ssam
738185482Ssam	if (tries1 && tries_so_far < tries) {
739185482Ssam		if (!IS_RATE_DEFINED(sn, rix1))
740165185Ssam			return;
741185482Ssam		tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
742218761Sadrian			MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
743185482Ssam		tries_so_far += tries1;
744143392Ssam	}
745143853Ssam
746185482Ssam	if (tries2 && tries_so_far < tries) {
747185482Ssam		if (!IS_RATE_DEFINED(sn, rix2))
748165185Ssam			return;
749185482Ssam		tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
750218761Sadrian			MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
751185482Ssam		tries_so_far += tries2;
752143392Ssam	}
753143392Ssam
754185482Ssam	if (tries3 && tries_so_far < tries) {
755185482Ssam		if (!IS_RATE_DEFINED(sn, rix3))
756165185Ssam			return;
757185482Ssam		tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries,
758218761Sadrian			MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
759143853Ssam	}
760185482Ssam
761185482Ssam	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
762143392Ssam		/* just average the first few packets */
763185482Ssam		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
764185482Ssam		int packets = sn->stats[size_bin][rix0].total_packets;
765227364Sadrian		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
766143392Ssam	} else {
767143392Ssam		/* use a ewma */
768185482Ssam		sn->stats[size_bin][rix0].average_tx_time =
769185482Ssam			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) +
770185482Ssam			 (tt * (100 - ssc->smoothing_rate))) / 100;
771143392Ssam	}
772143392Ssam
773227364Sadrian	/*
774227364Sadrian	 * XXX Don't mark the higher bit rates as also having failed; as this
775227364Sadrian	 * unfortunately stops those rates from being tasted when trying to
776227364Sadrian	 * TX. This happens with 11n aggregation.
777227364Sadrian	 */
778227364Sadrian	if (nframes == nbad) {
779227364Sadrian#if 0
780143392Ssam		int y;
781227364Sadrian#endif
782227364Sadrian		sn->stats[size_bin][rix0].successive_failures += nbad;
783227364Sadrian#if 0
784155476Ssam		for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
785185482Ssam			/*
786185482Ssam			 * Also say larger packets failed since we
787185482Ssam			 * assume if a small packet fails at a
788155476Ssam			 * bit-rate then a larger one will also.
789155476Ssam			 */
790227364Sadrian			sn->stats[y][rix0].successive_failures += nbad;
791185482Ssam			sn->stats[y][rix0].last_tx = ticks;
792185482Ssam			sn->stats[y][rix0].tries += tries;
793227364Sadrian			sn->stats[y][rix0].total_packets += nframes;
794143392Ssam		}
795227364Sadrian#endif
796143392Ssam	} else {
797227364Sadrian		sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
798185482Ssam		sn->stats[size_bin][rix0].successive_failures = 0;
799143392Ssam	}
800185482Ssam	sn->stats[size_bin][rix0].tries += tries;
801185482Ssam	sn->stats[size_bin][rix0].last_tx = ticks;
802227364Sadrian	sn->stats[size_bin][rix0].total_packets += nframes;
803143853Ssam
804247372Sadrian	/* update EWMA for this rix */
805247372Sadrian
806247372Sadrian	/* Calculate percentage based on current rate */
807247372Sadrian	if (nframes == 0)
808247372Sadrian		nframes = nbad = 1;
809247372Sadrian	pct = ((nframes - nbad) * 1000) / nframes;
810247372Sadrian
811247372Sadrian	if (sn->stats[size_bin][rix0].total_packets <
812247372Sadrian	    ssc->smoothing_minpackets) {
813247372Sadrian		/* just average the first few packets */
814247372Sadrian		int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /
815247372Sadrian		    (sn->stats[size_bin][rix0].total_packets);
816247372Sadrian		sn->stats[size_bin][rix0].ewma_pct = a_pct;
817247372Sadrian	} else {
818247372Sadrian		/* use a ewma */
819247372Sadrian		sn->stats[size_bin][rix0].ewma_pct =
820247372Sadrian			((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +
821247372Sadrian			 (pct * (100 - ssc->smoothing_rate))) / 100;
822247372Sadrian	}
823247372Sadrian
824247372Sadrian
825185482Ssam	if (rix0 == sn->current_sample_rix[size_bin]) {
826178354Ssam		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
827178354Ssam		   &an->an_node,
828227364Sadrian"%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d",
829178354Ssam		    __func__,
830165185Ssam		    size,
831165185Ssam		    status ? "FAIL" : "OK",
832227364Sadrian		    dot11rate(rt, rix0),
833227364Sadrian		    dot11rate_label(rt, rix0),
834227364Sadrian		    short_tries, tries, tt,
835185482Ssam		    sn->stats[size_bin][rix0].average_tx_time,
836227364Sadrian		    sn->stats[size_bin][rix0].perfect_tx_time,
837227364Sadrian		    nframes, nbad);
838143853Ssam		sn->sample_tt[size_bin] = tt;
839185482Ssam		sn->current_sample_rix[size_bin] = -1;
840143853Ssam	}
841143392Ssam}
842143392Ssam
843184348Ssamstatic void
844184348Ssambadrate(struct ifnet *ifp, int series, int hwrate, int tries, int status)
845184348Ssam{
846184348Ssam	if_printf(ifp, "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n",
847184348Ssam	    series, hwrate, tries, status);
848184348Ssam}
849184348Ssam
850143392Ssamvoid
851144348Ssamath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
852227364Sadrian	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
853227364Sadrian	int frame_size, int nframes, int nbad)
854143392Ssam{
855178354Ssam	struct ifnet *ifp = sc->sc_ifp;
856178354Ssam	struct ieee80211com *ic = ifp->if_l2com;
857143392Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(an);
858227364Sadrian	int final_rix, short_tries, long_tries;
859184368Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
860227364Sadrian	int status = ts->ts_status;
861172620Ssam	int mrr;
862143392Ssam
863194135Ssam	final_rix = rt->rateCodeToIndex[ts->ts_rate];
864165185Ssam	short_tries = ts->ts_shortretry;
865165185Ssam	long_tries = ts->ts_longretry + 1;
866227364Sadrian
867247372Sadrian	if (nframes == 0) {
868247372Sadrian		device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);
869247372Sadrian		return;
870247372Sadrian	}
871247372Sadrian
872144348Ssam	if (frame_size == 0)		    /* NB: should not happen */
873143853Ssam		frame_size = 1500;
874143392Ssam
875185482Ssam	if (sn->ratemask == 0) {
876178354Ssam		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
877178354Ssam		    &an->an_node,
878178354Ssam		    "%s: size %d %s rate/try %d/%d no rates yet",
879178354Ssam		    __func__,
880165185Ssam		    bin_to_size(size_to_bin(frame_size)),
881227364Sadrian		    status ? "FAIL" : "OK",
882165185Ssam		    short_tries, long_tries);
883143853Ssam		return;
884143853Ssam	}
885238961Sadrian	mrr = sc->sc_mrretry;
886238961Sadrian	/* XXX check HT protmode too */
887238962Sadrian	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
888238961Sadrian		mrr = 0;
889238961Sadrian
890194135Ssam	if (!mrr || ts->ts_finaltsi == 0) {
891185482Ssam		if (!IS_RATE_DEFINED(sn, final_rix)) {
892239284Sadrian			device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n",
893239284Sadrian			    __func__, ts->ts_rate, ts->ts_finaltsi);
894227364Sadrian			badrate(ifp, 0, ts->ts_rate, long_tries, status);
895184348Ssam			return;
896184348Ssam		}
897165185Ssam		/*
898165185Ssam		 * Only one rate was used; optimize work.
899165185Ssam		 */
900178354Ssam		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
901239756Sadrian		     &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",
902178354Ssam		     __func__,
903165185Ssam		     bin_to_size(size_to_bin(frame_size)),
904219822Sadrian		     frame_size,
905227364Sadrian		     status ? "FAIL" : "OK",
906227364Sadrian		     dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
907227364Sadrian		     short_tries, long_tries, nframes, nbad);
908165185Ssam		update_stats(sc, an, frame_size,
909185482Ssam			     final_rix, long_tries,
910165185Ssam			     0, 0,
911165185Ssam			     0, 0,
912165185Ssam			     0, 0,
913227364Sadrian			     short_tries, long_tries, status,
914227364Sadrian			     nframes, nbad);
915227364Sadrian
916143853Ssam	} else {
917165185Ssam		int finalTSIdx = ts->ts_finaltsi;
918217628Sadrian		int i;
919143392Ssam
920143853Ssam		/*
921143853Ssam		 * Process intermediate rates that failed.
922143853Ssam		 */
923218013Sadrian
924178354Ssam		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
925178354Ssam		    &an->an_node,
926239756Sadrian"%s: size %d (%d bytes) finaltsidx %d short %d long %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]",
927178354Ssam		     __func__,
928165185Ssam		     bin_to_size(size_to_bin(frame_size)),
929219822Sadrian		     frame_size,
930165185Ssam		     finalTSIdx,
931239756Sadrian		     short_tries,
932227364Sadrian		     long_tries,
933227364Sadrian		     status ? "FAIL" : "OK",
934227364Sadrian		     dot11rate(rt, rc[0].rix),
935227364Sadrian		      dot11rate_label(rt, rc[0].rix), rc[0].tries,
936227364Sadrian		     dot11rate(rt, rc[1].rix),
937227364Sadrian		      dot11rate_label(rt, rc[1].rix), rc[1].tries,
938227364Sadrian		     dot11rate(rt, rc[2].rix),
939227364Sadrian		      dot11rate_label(rt, rc[2].rix), rc[2].tries,
940227364Sadrian		     dot11rate(rt, rc[3].rix),
941227364Sadrian		      dot11rate_label(rt, rc[3].rix), rc[3].tries,
942227364Sadrian		     nframes, nbad);
943143853Ssam
944218013Sadrian		for (i = 0; i < 4; i++) {
945227364Sadrian			if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
946227364Sadrian				badrate(ifp, 0, rc[i].ratecode, rc[i].tries,
947227364Sadrian				    status);
948218013Sadrian		}
949185482Ssam
950165185Ssam		/*
951165185Ssam		 * NB: series > 0 are not penalized for failure
952165185Ssam		 * based on the try counts under the assumption
953165185Ssam		 * that losses are often bursty and since we
954165185Ssam		 * sample higher rates 1 try at a time doing so
955165185Ssam		 * may unfairly penalize them.
956165185Ssam		 */
957227364Sadrian		if (rc[0].tries) {
958227364Sadrian			update_stats(sc, an, frame_size,
959227364Sadrian				     rc[0].rix, rc[0].tries,
960227364Sadrian				     rc[1].rix, rc[1].tries,
961227364Sadrian				     rc[2].rix, rc[2].tries,
962227364Sadrian				     rc[3].rix, rc[3].tries,
963227364Sadrian				     short_tries, long_tries,
964227364Sadrian				     long_tries > rc[0].tries,
965227364Sadrian				     nframes, nbad);
966227364Sadrian			long_tries -= rc[0].tries;
967143853Ssam		}
968143853Ssam
969227364Sadrian		if (rc[1].tries && finalTSIdx > 0) {
970227364Sadrian			update_stats(sc, an, frame_size,
971227364Sadrian				     rc[1].rix, rc[1].tries,
972227364Sadrian				     rc[2].rix, rc[2].tries,
973227364Sadrian				     rc[3].rix, rc[3].tries,
974227364Sadrian				     0, 0,
975227364Sadrian				     short_tries, long_tries,
976227364Sadrian				     status,
977227364Sadrian				     nframes, nbad);
978227364Sadrian			long_tries -= rc[1].tries;
979143853Ssam		}
980143853Ssam
981227364Sadrian		if (rc[2].tries && finalTSIdx > 1) {
982227364Sadrian			update_stats(sc, an, frame_size,
983227364Sadrian				     rc[2].rix, rc[2].tries,
984227364Sadrian				     rc[3].rix, rc[3].tries,
985143853Ssam				     0, 0,
986143853Ssam				     0, 0,
987227364Sadrian				     short_tries, long_tries,
988227364Sadrian				     status,
989227364Sadrian				     nframes, nbad);
990227364Sadrian			long_tries -= rc[2].tries;
991143853Ssam		}
992143853Ssam
993227364Sadrian		if (rc[3].tries && finalTSIdx > 2) {
994227364Sadrian			update_stats(sc, an, frame_size,
995227364Sadrian				     rc[3].rix, rc[3].tries,
996143853Ssam				     0, 0,
997143853Ssam				     0, 0,
998143853Ssam				     0, 0,
999227364Sadrian				     short_tries, long_tries,
1000227364Sadrian				     status,
1001227364Sadrian				     nframes, nbad);
1002143853Ssam		}
1003143392Ssam	}
1004143853Ssam}
1005143392Ssam
1006143853Ssamvoid
1007143853Ssamath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
1008143853Ssam{
1009143853Ssam	if (isnew)
1010143853Ssam		ath_rate_ctl_reset(sc, &an->an_node);
1011143392Ssam}
1012143392Ssam
1013185482Ssamstatic const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {
1014185482Ssam	NULL,		/* IEEE80211_MODE_AUTO */
1015185482Ssam	series_11a,	/* IEEE80211_MODE_11A */
1016185482Ssam	series_11g,	/* IEEE80211_MODE_11B */
1017185482Ssam	series_11g,	/* IEEE80211_MODE_11G */
1018185482Ssam	NULL,		/* IEEE80211_MODE_FH */
1019185482Ssam	series_11a,	/* IEEE80211_MODE_TURBO_A */
1020185482Ssam	series_11g,	/* IEEE80211_MODE_TURBO_G */
1021185482Ssam	series_11a,	/* IEEE80211_MODE_STURBO_A */
1022218013Sadrian	series_11na,	/* IEEE80211_MODE_11NA */
1023218013Sadrian	series_11ng,	/* IEEE80211_MODE_11NG */
1024185482Ssam	series_half,	/* IEEE80211_MODE_HALF */
1025185482Ssam	series_quarter,	/* IEEE80211_MODE_QUARTER */
1026185482Ssam};
1027185482Ssam
1028143392Ssam/*
1029143392Ssam * Initialize the tables for a node.
1030143392Ssam */
1031143392Ssamstatic void
1032143853Ssamath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
1033143392Ssam{
1034143392Ssam#define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
1035185482Ssam#define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
1036218013Sadrian#define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
1037143392Ssam	struct ath_node *an = ATH_NODE(ni);
1038143392Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1039143392Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
1040219822Sadrian	int x, y, rix;
1041143392Ssam
1042143392Ssam	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
1043185482Ssam
1044185482Ssam	KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
1045185482Ssam	    ("curmode %u", sc->sc_curmode));
1046239284Sadrian
1047185482Ssam	sn->sched = mrr_schedules[sc->sc_curmode];
1048185482Ssam	KASSERT(sn->sched != NULL,
1049185482Ssam	    ("no mrr schedule for mode %u", sc->sc_curmode));
1050185482Ssam
1051185482Ssam        sn->static_rix = -1;
1052219822Sadrian	ath_rate_update_static_rix(sc, ni);
1053218013Sadrian
1054232170Sadrian	sn->currates = sc->sc_currates;
1055232170Sadrian
1056185482Ssam	/*
1057185482Ssam	 * Construct a bitmask of usable rates.  This has all
1058185482Ssam	 * negotiated rates minus those marked by the hal as
1059185482Ssam	 * to be ignored for doing rate control.
1060185482Ssam	 */
1061185482Ssam	sn->ratemask = 0;
1062218013Sadrian	/* MCS rates */
1063218013Sadrian	if (ni->ni_flags & IEEE80211_NODE_HT) {
1064218013Sadrian		for (x = 0; x < ni->ni_htrates.rs_nrates; x++) {
1065218013Sadrian			rix = sc->sc_rixmap[MCS(x)];
1066218013Sadrian			if (rix == 0xff)
1067218013Sadrian				continue;
1068218013Sadrian			/* skip rates marked broken by hal */
1069218013Sadrian			if (!rt->info[rix].valid)
1070218013Sadrian				continue;
1071218013Sadrian			KASSERT(rix < SAMPLE_MAXRATES,
1072218013Sadrian			    ("mcs %u has rix %d", MCS(x), rix));
1073239284Sadrian			sn->ratemask |= (uint64_t) 1<<rix;
1074218013Sadrian		}
1075218013Sadrian	}
1076218013Sadrian
1077218013Sadrian	/* Legacy rates */
1078185482Ssam	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
1079185482Ssam		rix = sc->sc_rixmap[RATE(x)];
1080185482Ssam		if (rix == 0xff)
1081152447Ssam			continue;
1082185482Ssam		/* skip rates marked broken by hal */
1083185482Ssam		if (!rt->info[rix].valid)
1084185482Ssam			continue;
1085185482Ssam		KASSERT(rix < SAMPLE_MAXRATES,
1086185482Ssam		    ("rate %u has rix %d", RATE(x), rix));
1087239284Sadrian		sn->ratemask |= (uint64_t) 1<<rix;
1088143392Ssam	}
1089178354Ssam#ifdef IEEE80211_DEBUG
1090178354Ssam	if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
1091239284Sadrian		uint64_t mask;
1092185482Ssam
1093178354Ssam		ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",
1094185482Ssam		    ni->ni_macaddr, ":", __func__);
1095185482Ssam		for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1096185482Ssam			if ((mask & 1) == 0)
1097178354Ssam				continue;
1098219216Sadrian			printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix),
1099218761Sadrian			    calc_usecs_unicast_packet(sc, 1600, rix, 0,0,
1100219985Sadrian			        (ni->ni_chw == 40)));
1101178354Ssam		}
1102178354Ssam		printf("\n");
1103178354Ssam	}
1104178354Ssam#endif
1105143853Ssam	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1106143853Ssam		int size = bin_to_size(y);
1107239284Sadrian		uint64_t mask;
1108185482Ssam
1109143853Ssam		sn->packets_sent[y] = 0;
1110185482Ssam		sn->current_sample_rix[y] = -1;
1111185482Ssam		sn->last_sample_rix[y] = 0;
1112185482Ssam		/* XXX start with first valid rate */
1113185482Ssam		sn->current_rix[y] = ffs(sn->ratemask)-1;
1114143853Ssam
1115185482Ssam		/*
1116185482Ssam		 * Initialize the statistics buckets; these are
1117185482Ssam		 * indexed by the rate code index.
1118185482Ssam		 */
1119185482Ssam		for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) {
1120185482Ssam			if ((mask & 1) == 0)		/* not a valid rate */
1121185482Ssam				continue;
1122185482Ssam			sn->stats[y][rix].successive_failures = 0;
1123185482Ssam			sn->stats[y][rix].tries = 0;
1124185482Ssam			sn->stats[y][rix].total_packets = 0;
1125185482Ssam			sn->stats[y][rix].packets_acked = 0;
1126185482Ssam			sn->stats[y][rix].last_tx = 0;
1127227364Sadrian			sn->stats[y][rix].ewma_pct = 0;
1128143853Ssam
1129185482Ssam			sn->stats[y][rix].perfect_tx_time =
1130218761Sadrian			    calc_usecs_unicast_packet(sc, size, rix, 0, 0,
1131219985Sadrian			    (ni->ni_chw == 40));
1132185482Ssam			sn->stats[y][rix].average_tx_time =
1133185482Ssam			    sn->stats[y][rix].perfect_tx_time;
1134143853Ssam		}
1135143853Ssam	}
1136185482Ssam#if 0
1137185482Ssam	/* XXX 0, num_rates-1 are wrong */
1138178354Ssam	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
1139178354Ssam	    "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__,
1140165185Ssam	    sn->num_rates,
1141185482Ssam	    DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "",
1142165185Ssam	    sn->stats[1][0].perfect_tx_time,
1143185482Ssam	    DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "",
1144165185Ssam	    sn->stats[1][sn->num_rates-1].perfect_tx_time
1145155476Ssam	);
1146185482Ssam#endif
1147178354Ssam	/* set the visible bit-rate */
1148185482Ssam	if (sn->static_rix != -1)
1149185482Ssam		ni->ni_txrate = DOT11RATE(sn->static_rix);
1150156463Ssam	else
1151185482Ssam		ni->ni_txrate = RATE(0);
1152143392Ssam#undef RATE
1153185482Ssam#undef DOT11RATE
1154143392Ssam}
1155143392Ssam
1156238633Sadrian/*
1157238633Sadrian * Fetch the statistics for the given node.
1158238633Sadrian *
1159238633Sadrian * The ieee80211 node must be referenced and unlocked, however the ath_node
1160238633Sadrian * must be locked.
1161238633Sadrian *
1162238633Sadrian * The main difference here is that we convert the rate indexes
1163238633Sadrian * to 802.11 rates, or the userland output won't make much sense
1164238633Sadrian * as it has no access to the rix table.
1165238633Sadrian */
1166238633Sadrianint
1167238633Sadrianath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
1168238633Sadrian    struct ath_rateioctl *rs)
1169238633Sadrian{
1170238633Sadrian	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1171238633Sadrian	const HAL_RATE_TABLE *rt = sc->sc_currates;
1172238633Sadrian	struct ath_rateioctl_tlv av;
1173238638Sadrian	struct ath_rateioctl_rt *tv;
1174238633Sadrian	int y;
1175238638Sadrian	int o = 0;
1176238633Sadrian
1177238633Sadrian	ATH_NODE_LOCK_ASSERT(an);
1178238633Sadrian
1179238633Sadrian	/*
1180238633Sadrian	 * Ensure there's enough space for the statistics.
1181238633Sadrian	 */
1182238633Sadrian	if (rs->len <
1183238633Sadrian	    sizeof(struct ath_rateioctl_tlv) +
1184238638Sadrian	    sizeof(struct ath_rateioctl_rt) +
1185238638Sadrian	    sizeof(struct ath_rateioctl_tlv) +
1186238638Sadrian	    sizeof(struct sample_node)) {
1187238638Sadrian		device_printf(sc->sc_dev, "%s: len=%d, too short\n",
1188238638Sadrian		    __func__,
1189238638Sadrian		    rs->len);
1190238633Sadrian		return (EINVAL);
1191238638Sadrian	}
1192238633Sadrian
1193238633Sadrian	/*
1194238633Sadrian	 * Take a temporary copy of the sample node state so we can
1195238633Sadrian	 * modify it before we copy it.
1196238633Sadrian	 */
1197238638Sadrian	tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,
1198238638Sadrian	    M_NOWAIT | M_ZERO);
1199238638Sadrian	if (tv == NULL) {
1200238633Sadrian		return (ENOMEM);
1201238638Sadrian	}
1202238633Sadrian
1203238638Sadrian	/*
1204238638Sadrian	 * Populate the rate table mapping TLV.
1205238638Sadrian	 */
1206238638Sadrian	tv->nentries = rt->rateCount;
1207238638Sadrian	for (y = 0; y < rt->rateCount; y++) {
1208238638Sadrian		tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;
1209238638Sadrian		if (rt->info[y].phy == IEEE80211_T_HT)
1210238638Sadrian			tv->ratecode[y] |= IEEE80211_RATE_MCS;
1211238633Sadrian	}
1212238633Sadrian
1213238638Sadrian	o = 0;
1214238633Sadrian	/*
1215238638Sadrian	 * First TLV - rate code mapping
1216238633Sadrian	 */
1217238638Sadrian	av.tlv_id = ATH_RATE_TLV_RATETABLE;
1218238638Sadrian	av.tlv_len = sizeof(struct ath_rateioctl_rt);
1219238638Sadrian	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1220238638Sadrian	o += sizeof(struct ath_rateioctl_tlv);
1221238638Sadrian	copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));
1222238638Sadrian	o += sizeof(struct ath_rateioctl_rt);
1223238638Sadrian
1224238638Sadrian	/*
1225238638Sadrian	 * Second TLV - sample node statistics
1226238638Sadrian	 */
1227238633Sadrian	av.tlv_id = ATH_RATE_TLV_SAMPLENODE;
1228238633Sadrian	av.tlv_len = sizeof(struct sample_node);
1229238638Sadrian	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1230238638Sadrian	o += sizeof(struct ath_rateioctl_tlv);
1231238633Sadrian
1232238633Sadrian	/*
1233238633Sadrian	 * Copy the statistics over to the provided buffer.
1234238633Sadrian	 */
1235238638Sadrian	copyout(sn, rs->buf + o, sizeof(struct sample_node));
1236238638Sadrian	o += sizeof(struct sample_node);
1237238633Sadrian
1238238638Sadrian	free(tv, M_TEMP);
1239238633Sadrian
1240238633Sadrian	return (0);
1241238633Sadrian}
1242238633Sadrian
1243144307Ssamstatic void
1244185482Ssamsample_stats(void *arg, struct ieee80211_node *ni)
1245143392Ssam{
1246185482Ssam	struct ath_softc *sc = arg;
1247185482Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
1248185482Ssam	struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));
1249239284Sadrian	uint64_t mask;
1250185482Ssam	int rix, y;
1251185482Ssam
1252239300Skib	printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",
1253185482Ssam	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
1254227364Sadrian	    dot11rate(rt, sn->static_rix),
1255227364Sadrian	    dot11rate_label(rt, sn->static_rix),
1256239300Skib	    (uintmax_t)sn->ratemask);
1257185482Ssam	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1258219216Sadrian		printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",
1259185482Ssam		    bin_to_size(y), sn->current_rix[y],
1260219216Sadrian		    dot11rate(rt, sn->current_rix[y]),
1261219216Sadrian		    dot11rate_label(rt, sn->current_rix[y]),
1262185482Ssam		    sn->packets_since_switch[y], sn->ticks_since_switch[y]);
1263227364Sadrian		printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",
1264227364Sadrian		    bin_to_size(y),
1265227364Sadrian		    dot11rate(rt, sn->last_sample_rix[y]),
1266227364Sadrian		    dot11rate_label(rt, sn->last_sample_rix[y]),
1267227364Sadrian		    dot11rate(rt, sn->current_sample_rix[y]),
1268227364Sadrian		    dot11rate_label(rt, sn->current_sample_rix[y]),
1269227364Sadrian		    sn->packets_sent[y]);
1270185482Ssam		printf("[%4u] packets since sample %d sample tt %u\n",
1271185482Ssam		    bin_to_size(y), sn->packets_since_sample[y],
1272185482Ssam		    sn->sample_tt[y]);
1273185482Ssam	}
1274185482Ssam	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1275185482Ssam		if ((mask & 1) == 0)
1276185482Ssam				continue;
1277185482Ssam		for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1278185482Ssam			if (sn->stats[y][rix].total_packets == 0)
1279185482Ssam				continue;
1280227364Sadrian			printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",
1281219216Sadrian			    dot11rate(rt, rix), dot11rate_label(rt, rix),
1282185482Ssam			    bin_to_size(y),
1283227340Sadrian			    (uintmax_t) sn->stats[y][rix].total_packets,
1284227340Sadrian			    (uintmax_t) sn->stats[y][rix].packets_acked,
1285227340Sadrian			    (int) ((sn->stats[y][rix].packets_acked * 100ULL) /
1286227340Sadrian			     sn->stats[y][rix].total_packets),
1287227364Sadrian			    sn->stats[y][rix].ewma_pct / 10,
1288227364Sadrian			    sn->stats[y][rix].ewma_pct % 10,
1289227340Sadrian			    (uintmax_t) sn->stats[y][rix].tries,
1290185482Ssam			    sn->stats[y][rix].successive_failures,
1291185482Ssam			    sn->stats[y][rix].average_tx_time,
1292185482Ssam			    ticks - sn->stats[y][rix].last_tx);
1293185482Ssam		}
1294185482Ssam	}
1295185482Ssam}
1296185482Ssam
1297185482Ssamstatic int
1298185482Ssamath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS)
1299185482Ssam{
1300185482Ssam	struct ath_softc *sc = arg1;
1301185482Ssam	struct ifnet *ifp = sc->sc_ifp;
1302185482Ssam	struct ieee80211com *ic = ifp->if_l2com;
1303185482Ssam	int error, v;
1304185482Ssam
1305185482Ssam	v = 0;
1306185482Ssam	error = sysctl_handle_int(oidp, &v, 0, req);
1307185482Ssam	if (error || !req->newptr)
1308185482Ssam		return error;
1309185482Ssam	ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc);
1310185482Ssam	return 0;
1311185482Ssam}
1312185482Ssam
1313185482Ssamstatic int
1314185482Ssamath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)
1315185482Ssam{
1316185482Ssam	struct sample_softc *ssc = arg1;
1317185482Ssam	int rate, error;
1318185482Ssam
1319185482Ssam	rate = ssc->smoothing_rate;
1320185482Ssam	error = sysctl_handle_int(oidp, &rate, 0, req);
1321185482Ssam	if (error || !req->newptr)
1322185482Ssam		return error;
1323185482Ssam	if (!(0 <= rate && rate < 100))
1324185482Ssam		return EINVAL;
1325185482Ssam	ssc->smoothing_rate = rate;
1326185482Ssam	ssc->smoothing_minpackets = 100 / (100 - rate);
1327185482Ssam	return 0;
1328185482Ssam}
1329185482Ssam
1330185482Ssamstatic int
1331185482Ssamath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
1332185482Ssam{
1333185482Ssam	struct sample_softc *ssc = arg1;
1334185482Ssam	int rate, error;
1335185482Ssam
1336185482Ssam	rate = ssc->sample_rate;
1337185482Ssam	error = sysctl_handle_int(oidp, &rate, 0, req);
1338185482Ssam	if (error || !req->newptr)
1339185482Ssam		return error;
1340185482Ssam	if (!(2 <= rate && rate <= 100))
1341185482Ssam		return EINVAL;
1342185482Ssam	ssc->sample_rate = rate;
1343185482Ssam	return 0;
1344185482Ssam}
1345185482Ssam
1346185482Ssamstatic void
1347185482Ssamath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc)
1348185482Ssam{
1349143392Ssam	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
1350143392Ssam	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
1351143392Ssam
1352185482Ssam	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1353185482Ssam	    "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0,
1354185482Ssam	    ath_rate_sysctl_smoothing_rate, "I",
1355185482Ssam	    "sample: smoothing rate for avg tx time (%%)");
1356185482Ssam	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1357185482Ssam	    "sample_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0,
1358185482Ssam	    ath_rate_sysctl_sample_rate, "I",
1359185482Ssam	    "sample: percent air time devoted to sampling new rates (%%)");
1360185482Ssam	/* XXX max_successive_failures, stale_failure_timeout, min_switch */
1361185482Ssam	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1362185482Ssam	    "sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
1363185482Ssam	    ath_rate_sysctl_stats, "I", "sample: print statistics");
1364143392Ssam}
1365143392Ssam
1366143392Ssamstruct ath_ratectrl *
1367143392Ssamath_rate_attach(struct ath_softc *sc)
1368143392Ssam{
1369185482Ssam	struct sample_softc *ssc;
1370143392Ssam
1371185482Ssam	ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
1372185482Ssam	if (ssc == NULL)
1373143392Ssam		return NULL;
1374185482Ssam	ssc->arc.arc_space = sizeof(struct sample_node);
1375240583Sadrian	ssc->smoothing_rate = 75;		/* ewma percentage ([0..99]) */
1376185482Ssam	ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);
1377185482Ssam	ssc->sample_rate = 10;			/* %time to try diff tx rates */
1378185482Ssam	ssc->max_successive_failures = 3;	/* threshold for rate sampling*/
1379185482Ssam	ssc->stale_failure_timeout = 10 * hz;	/* 10 seconds */
1380185482Ssam	ssc->min_switch = hz;			/* 1 second */
1381185482Ssam	ath_rate_sysctlattach(sc, ssc);
1382185482Ssam	return &ssc->arc;
1383143392Ssam}
1384143392Ssam
1385143392Ssamvoid
1386143392Ssamath_rate_detach(struct ath_ratectrl *arc)
1387143392Ssam{
1388185482Ssam	struct sample_softc *ssc = (struct sample_softc *) arc;
1389143392Ssam
1390185482Ssam	free(ssc, M_DEVBUF);
1391143392Ssam}
1392