xref: /freebsd/sys/dev/ath/ath_rate/sample/sample.c (revision a4d8dd103ec09245e239bc560cc00a0517f21b43)
1fa20c234SSam Leffler /*-
2fa20c234SSam Leffler  * Copyright (c) 2005 John Bicket
3fa20c234SSam Leffler  * All rights reserved.
4fa20c234SSam Leffler  *
5fa20c234SSam Leffler  * Redistribution and use in source and binary forms, with or without
6fa20c234SSam Leffler  * modification, are permitted provided that the following conditions
7fa20c234SSam Leffler  * are met:
8fa20c234SSam Leffler  * 1. Redistributions of source code must retain the above copyright
9fa20c234SSam Leffler  *    notice, this list of conditions and the following disclaimer,
10fa20c234SSam Leffler  *    without modification.
11fa20c234SSam Leffler  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12fa20c234SSam Leffler  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13fa20c234SSam Leffler  *    redistribution must be conditioned upon including a substantially
14fa20c234SSam Leffler  *    similar Disclaimer requirement for further binary redistribution.
15fa20c234SSam Leffler  * 3. Neither the names of the above-listed copyright holders nor the names
16fa20c234SSam Leffler  *    of any contributors may be used to endorse or promote products derived
17fa20c234SSam Leffler  *    from this software without specific prior written permission.
18fa20c234SSam Leffler  *
19fa20c234SSam Leffler  * Alternatively, this software may be distributed under the terms of the
20fa20c234SSam Leffler  * GNU General Public License ("GPL") version 2 as published by the Free
21fa20c234SSam Leffler  * Software Foundation.
22fa20c234SSam Leffler  *
23fa20c234SSam Leffler  * NO WARRANTY
24fa20c234SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25fa20c234SSam Leffler  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26fa20c234SSam Leffler  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27fa20c234SSam Leffler  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28fa20c234SSam Leffler  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29fa20c234SSam Leffler  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30fa20c234SSam Leffler  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31fa20c234SSam Leffler  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32fa20c234SSam Leffler  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33fa20c234SSam Leffler  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34fa20c234SSam Leffler  * THE POSSIBILITY OF SUCH DAMAGES.
35fa20c234SSam Leffler  */
36fa20c234SSam Leffler 
37fa20c234SSam Leffler #include <sys/cdefs.h>
38fa20c234SSam Leffler __FBSDID("$FreeBSD$");
39fa20c234SSam Leffler 
40fa20c234SSam Leffler /*
41fa20c234SSam Leffler  * John Bicket's SampleRate control algorithm.
42fa20c234SSam Leffler  */
43fa20c234SSam Leffler #include "opt_inet.h"
44fa20c234SSam Leffler 
45fa20c234SSam Leffler #include <sys/param.h>
46fa20c234SSam Leffler #include <sys/systm.h>
47fa20c234SSam Leffler #include <sys/sysctl.h>
48fa20c234SSam Leffler #include <sys/module.h>
49fa20c234SSam Leffler #include <sys/kernel.h>
50fa20c234SSam Leffler #include <sys/lock.h>
51fa20c234SSam Leffler #include <sys/mutex.h>
52fa20c234SSam Leffler #include <sys/errno.h>
53fa20c234SSam Leffler 
54fa20c234SSam Leffler #include <machine/bus.h>
55fa20c234SSam Leffler #include <machine/resource.h>
56fa20c234SSam Leffler #include <sys/bus.h>
57fa20c234SSam Leffler 
58fa20c234SSam Leffler #include <sys/socket.h>
59fa20c234SSam Leffler 
60fa20c234SSam Leffler #include <net/if.h>
61fa20c234SSam Leffler #include <net/if_media.h>
62fa20c234SSam Leffler #include <net/if_arp.h>
63fa20c234SSam Leffler #include <net/ethernet.h>		/* XXX for ether_sprintf */
64fa20c234SSam Leffler 
65fa20c234SSam Leffler #include <net80211/ieee80211_var.h>
66fa20c234SSam Leffler 
67fa20c234SSam Leffler #include <net/bpf.h>
68fa20c234SSam Leffler 
69fa20c234SSam Leffler #ifdef INET
70fa20c234SSam Leffler #include <netinet/in.h>
71fa20c234SSam Leffler #include <netinet/if_ether.h>
72fa20c234SSam Leffler #endif
73fa20c234SSam Leffler 
74fa20c234SSam Leffler #include <dev/ath/if_athvar.h>
75fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h>
76fa20c234SSam Leffler #include <contrib/dev/ath/ah_desc.h>
77fa20c234SSam Leffler 
78fa20c234SSam Leffler #define	SAMPLE_DEBUG
79fa20c234SSam Leffler #ifdef SAMPLE_DEBUG
80fa20c234SSam Leffler enum {
81fa20c234SSam Leffler 	ATH_DEBUG_RATE		= 0x00000010,	/* rate control */
82fa20c234SSam Leffler };
83fa20c234SSam Leffler #define	DPRINTF(sc, _fmt, ...) do {				\
84fa20c234SSam Leffler 	if (sc->sc_debug & ATH_DEBUG_RATE)			\
85fa20c234SSam Leffler 		printf(_fmt, __VA_ARGS__);			\
86fa20c234SSam Leffler } while (0)
87fa20c234SSam Leffler #else
88fa20c234SSam Leffler #define	DPRINTF(sc, _fmt, ...)
89fa20c234SSam Leffler #endif
90fa20c234SSam Leffler 
91fa20c234SSam Leffler /*
92fa20c234SSam Leffler  * This file is an implementation of the SampleRate algorithm
93fa20c234SSam Leffler  * in "Bit-rate Selection in Wireless Networks"
94fa20c234SSam Leffler  * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
95fa20c234SSam Leffler  *
96fa20c234SSam Leffler  * SampleRate chooses the bit-rate it predicts will provide the most
97fa20c234SSam Leffler  * throughput based on estimates of the expected per-packet
98fa20c234SSam Leffler  * transmission time for each bit-rate.  SampleRate periodically sends
99fa20c234SSam Leffler  * packets at bit-rates other than the current one to estimate when
100fa20c234SSam Leffler  * another bit-rate will provide better performance. SampleRate
101fa20c234SSam Leffler  * switches to another bit-rate when its estimated per-packet
102fa20c234SSam Leffler  * transmission time becomes smaller than the current bit-rate's.
103fa20c234SSam Leffler  * SampleRate reduces the number of bit-rates it must sample by
104fa20c234SSam Leffler  * eliminating those that could not perform better than the one
105fa20c234SSam Leffler  * currently being used.  SampleRate also stops probing at a bit-rate
106fa20c234SSam Leffler  * if it experiences several successive losses.
107fa20c234SSam Leffler  *
108fa20c234SSam Leffler  * The difference between the algorithm in the thesis and the one in this
109fa20c234SSam Leffler  * file is that the one in this file uses a ewma instead of a window.
110fa20c234SSam Leffler  *
111fa20c234SSam Leffler  */
112fa20c234SSam Leffler 
113b2763056SSam Leffler #define STALE_FAILURE_TIMEOUT_MS 10000
114b2763056SSam Leffler 
115b2763056SSam Leffler static void	ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
116fa20c234SSam Leffler 
117fa20c234SSam Leffler static __inline int size_to_bin(int size)
118fa20c234SSam Leffler {
119fa20c234SSam Leffler 	int x = 0;
120fa20c234SSam Leffler 	for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
121fa20c234SSam Leffler 		if (size < packet_size_bins[x]) {
122fa20c234SSam Leffler 			return x;
123fa20c234SSam Leffler 		}
124fa20c234SSam Leffler 	}
125fa20c234SSam Leffler 	return NUM_PACKET_SIZE_BINS-1;
126fa20c234SSam Leffler }
127fa20c234SSam Leffler static __inline int bin_to_size(int index) {
128fa20c234SSam Leffler 	return packet_size_bins[index];
129fa20c234SSam Leffler }
130fa20c234SSam Leffler 
131b2763056SSam Leffler static __inline int rate_to_ndx(struct sample_node *sn, int rate) {
132b2763056SSam Leffler 	int x = 0;
133b2763056SSam Leffler 	for (x = 0; x < sn->num_rates; x++) {
134b2763056SSam Leffler 		if (sn->rates[x].rate == rate) {
135b2763056SSam Leffler 			return x;
136b2763056SSam Leffler 		}
137b2763056SSam Leffler 	}
138b2763056SSam Leffler 	return -1;
139b2763056SSam Leffler }
140b2763056SSam Leffler 
141fa20c234SSam Leffler /*
142fa20c234SSam Leffler  * Setup rate codes for management/control frames.  We force
143fa20c234SSam Leffler  * all such frames to the lowest rate.
144fa20c234SSam Leffler  */
145fa20c234SSam Leffler static void
146fa20c234SSam Leffler ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an)
147fa20c234SSam Leffler {
148fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
149fa20c234SSam Leffler 
150fa20c234SSam Leffler 	/* setup rates for management frames */
151fa20c234SSam Leffler 	/* XXX management/control frames always go at lowest speed */
152fa20c234SSam Leffler 	an->an_tx_mgtrate = rt->info[0].rateCode;
153fa20c234SSam Leffler 	an->an_tx_mgtratesp = an->an_tx_mgtrate
154fa20c234SSam Leffler 			    | rt->info[0].shortPreamble;
155fa20c234SSam Leffler }
156fa20c234SSam Leffler 
157fa20c234SSam Leffler void
158fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
159fa20c234SSam Leffler {
160fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
161fa20c234SSam Leffler 	/* NB: assumed to be zero'd by caller */
162fa20c234SSam Leffler 	ath_rate_setmgtrates(sc, an);
163fa20c234SSam Leffler }
164fa20c234SSam Leffler 
165fa20c234SSam Leffler void
166fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
167fa20c234SSam Leffler {
168fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
169fa20c234SSam Leffler }
170fa20c234SSam Leffler 
171fa20c234SSam Leffler 
172fa20c234SSam Leffler /*
173fa20c234SSam Leffler  * returns the ndx with the lowest average_tx_time,
174fa20c234SSam Leffler  * or -1 if all the average_tx_times are 0.
175fa20c234SSam Leffler  */
176b2763056SSam Leffler static __inline int best_rate_ndx(struct sample_node *sn, int size_bin,
177b2763056SSam Leffler 				  int require_acked_before)
178fa20c234SSam Leffler {
179fa20c234SSam Leffler 	int x = 0;
180fa20c234SSam Leffler         int best_rate_ndx = 0;
181fa20c234SSam Leffler         int best_rate_tt = 0;
182fa20c234SSam Leffler         for (x = 0; x < sn->num_rates; x++) {
183fa20c234SSam Leffler 		int tt = sn->stats[size_bin][x].average_tx_time;
184b2763056SSam Leffler 		if (tt <= 0 || (require_acked_before &&
185b2763056SSam Leffler 				!sn->stats[size_bin][x].packets_acked)) {
186b2763056SSam Leffler 			continue;
187b2763056SSam Leffler 		}
188fa20c234SSam Leffler 		if (!best_rate_tt || best_rate_tt > tt) {
189fa20c234SSam Leffler 			best_rate_tt = tt;
190fa20c234SSam Leffler 			best_rate_ndx = x;
191fa20c234SSam Leffler 		}
192fa20c234SSam Leffler         }
193fa20c234SSam Leffler         return (best_rate_tt) ? best_rate_ndx : -1;
194fa20c234SSam Leffler }
195fa20c234SSam Leffler 
196fa20c234SSam Leffler /*
197fa20c234SSam Leffler  * pick a ndx s.t. the perfect_tx_time
198fa20c234SSam Leffler  * is less than the best bit-rate's average_tx_time
199fa20c234SSam Leffler  * and the ndx has not had four successive failures.
200fa20c234SSam Leffler  */
201fa20c234SSam Leffler static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin)
202fa20c234SSam Leffler {
203fa20c234SSam Leffler 	int x = 0;
204b2763056SSam Leffler 	int current_ndx = 0;
205b2763056SSam Leffler 	unsigned current_tt = 0;
206fa20c234SSam Leffler 
207b2763056SSam Leffler 	current_ndx = sn->current_rate[size_bin];
208b2763056SSam Leffler 	if (current_ndx < 0) {
209fa20c234SSam Leffler 		/* no successes yet, send at the lowest bit-rate */
210fa20c234SSam Leffler 		return 0;
211fa20c234SSam Leffler 	}
212fa20c234SSam Leffler 
213b2763056SSam Leffler 	current_tt = sn->stats[size_bin][current_ndx].average_tx_time;
214fa20c234SSam Leffler 
215b2763056SSam Leffler 	for (x = 0; x < sn->num_rates; x++) {
216b2763056SSam Leffler 		int ndx = (sn->last_sample_ndx[size_bin] + 1 + x) % sn->num_rates;
217fa20c234SSam Leffler 		/*
218b2763056SSam Leffler 		 * clear any stale stuff out.
219fa20c234SSam Leffler 		 */
220b2763056SSam Leffler 		if (ticks - sn->stats[size_bin][ndx].last_tx > ((hz * STALE_FAILURE_TIMEOUT_MS)/1000)) {
221b2763056SSam Leffler 			sn->stats[size_bin][ndx].average_tx_time = sn->stats[size_bin][ndx].perfect_tx_time;
222b2763056SSam Leffler 			sn->stats[size_bin][ndx].successive_failures = 0;
223b2763056SSam Leffler 			sn->stats[size_bin][ndx].tries = 0;
224b2763056SSam Leffler 			sn->stats[size_bin][ndx].total_packets = 0;
225b2763056SSam Leffler 			sn->stats[size_bin][ndx].packets_acked = 0;
226fa20c234SSam Leffler 		}
227fa20c234SSam Leffler 
228b2763056SSam Leffler 		if (ndx != current_ndx &&
229b2763056SSam Leffler 		    sn->stats[size_bin][ndx].perfect_tx_time < current_tt &&
230b2763056SSam Leffler 		    sn->stats[size_bin][ndx].successive_failures < 4) {
231b2763056SSam Leffler 			sn->last_sample_ndx[size_bin] = ndx;
232b2763056SSam Leffler 			return ndx;
233fa20c234SSam Leffler 		}
234fa20c234SSam Leffler 	}
235b2763056SSam Leffler 	return current_ndx;
236fa20c234SSam Leffler }
237fa20c234SSam Leffler 
238fa20c234SSam Leffler void
239fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
240a4d8dd10SSam Leffler 		  int shortPreamble, size_t frameLen,
241fa20c234SSam Leffler 		  u_int8_t *rix, int *try0, u_int8_t *txrate)
242fa20c234SSam Leffler {
243fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
244fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
245b2763056SSam Leffler 	struct ieee80211com *ic = &sc->sc_ic;
246b2763056SSam Leffler 	int ndx, size_bin, mrr, best_ndx;
247b2763056SSam Leffler 	unsigned average_tx_time;
248fa20c234SSam Leffler 
249b2763056SSam Leffler 	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) &&
250b2763056SSam Leffler 		!(frameLen > ic->ic_rtsthreshold);
251b2763056SSam Leffler 	size_bin = size_to_bin(frameLen);
252b2763056SSam Leffler 	best_ndx = best_rate_ndx(sn, size_bin, !mrr);
253fa20c234SSam Leffler 
25443e9cf7cSSam Leffler 	if (best_ndx >= 0) {
255b2763056SSam Leffler 		average_tx_time = sn->stats[size_bin][best_ndx].average_tx_time;
256fa20c234SSam Leffler 	} else {
257b2763056SSam Leffler 		average_tx_time = 0;
258b2763056SSam Leffler 	}
259b2763056SSam Leffler 	if (sn->static_rate_ndx != -1) {
260b2763056SSam Leffler 		ndx = sn->static_rate_ndx;
261b2763056SSam Leffler 		*try0 = ATH_TXMAXTRY;
262b2763056SSam Leffler 	} else {
263b2763056SSam Leffler 		ndx = 0;
264b2763056SSam Leffler 		*try0 = mrr ? 2 : ATH_TXMAXTRY;
265b2763056SSam Leffler 
26643e9cf7cSSam Leffler 		DPRINTF(sc, "%s: %s size %d mrr %d packets_sent %d best_ndx %d "
26743e9cf7cSSam Leffler 			"sample tt %d packets since %d\n"
26843e9cf7cSSam Leffler 			, __func__, ether_sprintf(an->an_node.ni_macaddr)
26943e9cf7cSSam Leffler 			, packet_size_bins[size_bin]
27043e9cf7cSSam Leffler 			, mrr
27143e9cf7cSSam Leffler 			, sn->packets_sent[size_bin]
27243e9cf7cSSam Leffler 			, best_ndx
27343e9cf7cSSam Leffler 			, sn->sample_tt[size_bin]
27443e9cf7cSSam Leffler 			, sn->packets_since_sample[size_bin]
27543e9cf7cSSam Leffler 		);
276b2763056SSam Leffler 		if (!sn->packets_sent[size_bin]) {
277b2763056SSam Leffler 			/* no packets sent */
278b2763056SSam Leffler 			if (best_ndx == -1) {
279b2763056SSam Leffler 				ndx = sn->num_rates - 1;
280b2763056SSam Leffler 				if (sc->sc_curmode != IEEE80211_MODE_11B) {
281b2763056SSam Leffler 					for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--)
282b2763056SSam Leffler 						;
283b2763056SSam Leffler 
284b2763056SSam Leffler 				}
285b2763056SSam Leffler 			} else {
286b2763056SSam Leffler 				ndx = best_ndx;
287b2763056SSam Leffler 			}
288b2763056SSam Leffler 		} else if (best_ndx == -1) {
289b2763056SSam Leffler 			/* no packet has succeeded yet */
290b2763056SSam Leffler 			if (mrr) {
291fa20c234SSam Leffler 				/*
292b2763056SSam Leffler 				 * no packet has succeeded, try the
293b2763056SSam Leffler 				 * highest bitrate that hasn't failed
294fa20c234SSam Leffler 				 */
295fa20c234SSam Leffler 				for (ndx = sn->num_rates-1; ndx >= 0; ndx--) {
296fa20c234SSam Leffler 					if (sn->stats[size_bin][ndx].successive_failures == 0) {
297fa20c234SSam Leffler 						break;
298fa20c234SSam Leffler 					}
299fa20c234SSam Leffler 				}
300fa20c234SSam Leffler 			} else {
30143e9cf7cSSam Leffler 				ndx = sn->num_rates - 1;
30243e9cf7cSSam Leffler 				if (sc->sc_curmode != IEEE80211_MODE_11B) {
30343e9cf7cSSam Leffler 					for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--)
30443e9cf7cSSam Leffler 						;
30543e9cf7cSSam Leffler 
30643e9cf7cSSam Leffler 				}
307b2763056SSam Leffler 			}
308b2763056SSam Leffler 		} else if (sn->sample_tt[size_bin] < (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100) * average_tx_time &&
309b2763056SSam Leffler 			   sn->packets_since_sample[size_bin] > 15) {
310fa20c234SSam Leffler 			/*
311b2763056SSam Leffler 			 * we want to limit the time measuring the performance
312b2763056SSam Leffler 			 * of other bit-rates to ath_sample_rate% of the
313b2763056SSam Leffler 			 * total transmission time.
314fa20c234SSam Leffler 			 */
315fa20c234SSam Leffler 			ndx = pick_sample_ndx(sn, size_bin);
316b2763056SSam Leffler 			if (ndx != sn->current_rate[size_bin]) {
317b2763056SSam Leffler 				DPRINTF(sc, "%s: %s size %d last sample tt %d sampling %d packets since %d\n",
318b2763056SSam Leffler 					__func__,
319b2763056SSam Leffler 					ether_sprintf(an->an_node.ni_macaddr),
320b2763056SSam Leffler 					packet_size_bins[size_bin],
321b2763056SSam Leffler 					sn->sample_tt[size_bin],
322b2763056SSam Leffler 					sn->rates[ndx].rate,
323b2763056SSam Leffler 					sn->packets_since_sample[size_bin]);
324b2763056SSam Leffler 				sn->current_sample_ndx[size_bin] = ndx;
325b2763056SSam Leffler 			} else {
326b2763056SSam Leffler 				sn->current_sample_ndx[size_bin] = -1;
327b2763056SSam Leffler 			}
328b2763056SSam Leffler 			sn->packets_since_sample[size_bin] = 0;
329b2763056SSam Leffler 
330b2763056SSam Leffler 		} else {
331b2763056SSam Leffler 			sn->packets_since_sample[size_bin]++;
332b2763056SSam Leffler 			/*
333b2763056SSam Leffler 			 * don't switch bit-rates every packet.  only
334b2763056SSam Leffler 			 * switch during the first few packets we send
335b2763056SSam Leffler 			 * or after 100 packets, or if the current
336b2763056SSam Leffler 			 * bit-rate begins to perform twice as bad as
337b2763056SSam Leffler 			 * another one.
338b2763056SSam Leffler 			 */
339b2763056SSam Leffler 			if (sn->packets_sent[size_bin] < 20 ||
340b2763056SSam Leffler 			    ticks - ((hz*2000)/1000) > sn->jiffies_since_switch[size_bin] ||
341b2763056SSam Leffler 			    average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time ) {
342b2763056SSam Leffler 				if (sn->packets_sent[size_bin] > 20) {
343b2763056SSam Leffler 					DPRINTF(sc, "%s: %s size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mmr %d\n",
344b2763056SSam Leffler 						__func__,
345b2763056SSam Leffler 						ether_sprintf(an->an_node.ni_macaddr),
346b2763056SSam Leffler 						packet_size_bins[size_bin],
347b2763056SSam Leffler 						sn->rates[sn->current_rate[size_bin]].rate,
348b2763056SSam Leffler 						sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time,
349b2763056SSam Leffler 						sn->stats[size_bin][sn->current_rate[size_bin]].perfect_tx_time,
350b2763056SSam Leffler 						sn->rates[best_ndx].rate,
351b2763056SSam Leffler 						sn->stats[size_bin][best_ndx].average_tx_time,
352b2763056SSam Leffler 						sn->stats[size_bin][best_ndx].perfect_tx_time,
353b2763056SSam Leffler 						sn->packets_since_switch[size_bin],
354b2763056SSam Leffler 						mrr);
355b2763056SSam Leffler 				}
356b2763056SSam Leffler 				sn->packets_since_switch[size_bin] = 0;
357b2763056SSam Leffler 				sn->current_rate[size_bin] = best_ndx;
358b2763056SSam Leffler 				sn->jiffies_since_switch[size_bin] = ticks;
359b2763056SSam Leffler 			}
360b2763056SSam Leffler 			ndx = sn->current_rate[size_bin];
361b2763056SSam Leffler 			sn->packets_since_switch[size_bin]++;
362fa20c234SSam Leffler 		}
363fa20c234SSam Leffler 
364b2763056SSam Leffler 	}
365fa20c234SSam Leffler 
366b2763056SSam Leffler 	if (ndx < 0) {
367b2763056SSam Leffler 		ndx = 0;
368b2763056SSam Leffler 	}
369fa20c234SSam Leffler 	*rix = sn->rates[ndx].rix;
370fa20c234SSam Leffler 	if (shortPreamble) {
371fa20c234SSam Leffler 		*txrate = sn->rates[ndx].shortPreambleRateCode;
372fa20c234SSam Leffler 	} else {
373fa20c234SSam Leffler 		*txrate = sn->rates[ndx].rateCode;
374fa20c234SSam Leffler 	}
375fa20c234SSam Leffler 	sn->packets_sent[size_bin]++;
376b2763056SSam Leffler 	an->an_node.ni_txrate = ndx;
377fa20c234SSam Leffler }
378fa20c234SSam Leffler 
379fa20c234SSam Leffler void
380fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
381a4d8dd10SSam Leffler 		      struct ath_desc *ds, int shortPreamble, u_int8_t rix)
382fa20c234SSam Leffler {
383fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
384fa20c234SSam Leffler 	int rateCode = -1;
385b2763056SSam Leffler 	int frame_size, size_bin, best_ndx, ndx;
386fa20c234SSam Leffler 
387fa20c234SSam Leffler 	frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
388b2763056SSam Leffler 	KASSERT(frame_size != 0, ("no frame size"));
389fa20c234SSam Leffler 	size_bin = size_to_bin(frame_size);
390b2763056SSam Leffler 	best_ndx = best_rate_ndx(sn, size_bin, 0);
391fa20c234SSam Leffler 
392fa20c234SSam Leffler 	if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) {
393fa20c234SSam Leffler 		/*
394b2763056SSam Leffler 		 * no packet has succeeded, so also try at the
395b2763056SSam Leffler 		 * lowest bitate.
396fa20c234SSam Leffler 		 */
397b2763056SSam Leffler 		ndx = 0;
398fa20c234SSam Leffler 	} else {
399fa20c234SSam Leffler 		/*
400fa20c234SSam Leffler 		 * we're trying a different bit-rate, and it could be lossy,
401fa20c234SSam Leffler 		 * so if it fails try at the best bit-rate.
402fa20c234SSam Leffler 		 */
403b2763056SSam Leffler 		ndx = best_ndx;
404b2763056SSam Leffler 	}
405b2763056SSam Leffler 	KASSERT(0 <= ndx && ndx < IEEE80211_RATE_MAXSIZE,
406b2763056SSam Leffler 		("invalid ndx %d", ndx));
407fa20c234SSam Leffler 	if (shortPreamble) {
408b2763056SSam Leffler 		rateCode = sn->rates[ndx].shortPreambleRateCode;
409fa20c234SSam Leffler 	} else {
410b2763056SSam Leffler 		rateCode = sn->rates[ndx].rateCode;
411fa20c234SSam Leffler 	}
412fa20c234SSam Leffler 	ath_hal_setupxtxdesc(sc->sc_ah, ds
413b2763056SSam Leffler 			     , rateCode, 3	        /* series 1 */
414b2763056SSam Leffler 			     , sn->rates[0].rateCode, 3	/* series 2 */
415b2763056SSam Leffler 			     , 0, 0	                /* series 3 */
416fa20c234SSam Leffler 			     );
417fa20c234SSam Leffler }
418fa20c234SSam Leffler 
419b2763056SSam Leffler static void
420b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an,
421b2763056SSam Leffler 		  int frame_size,
422b2763056SSam Leffler 		  int ndx0, int tries0,
423b2763056SSam Leffler 		  int ndx1, int tries1,
424b2763056SSam Leffler 		  int ndx2, int tries2,
425b2763056SSam Leffler 		  int ndx3, int tries3,
426b2763056SSam Leffler 		  int short_tries, int tries, int status)
427fa20c234SSam Leffler {
428fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
429fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
430fa20c234SSam Leffler 	int tt = 0;
431b2763056SSam Leffler 	int tries_so_far = 0;
432b2763056SSam Leffler 	int size_bin = 0;
433b2763056SSam Leffler 	int size = 0;
434b2763056SSam Leffler 	int rate = 0;
435fa20c234SSam Leffler 
436fa20c234SSam Leffler 	size_bin = size_to_bin(frame_size);
437fa20c234SSam Leffler 	size = bin_to_size(size_bin);
438b2763056SSam Leffler 	rate = sn->rates[ndx0].rate;
439fa20c234SSam Leffler 
440b2763056SSam Leffler 	tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix,
441b2763056SSam Leffler 					short_tries-1,
442b2763056SSam Leffler 					MIN(tries0, tries) - 1);
443b2763056SSam Leffler 	tries_so_far += tries0;
444b2763056SSam Leffler 	if (tries1 && tries0 < tries) {
445b2763056SSam Leffler 		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx1].rix,
446b2763056SSam Leffler 						short_tries-1,
447b2763056SSam Leffler 						MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
448b2763056SSam Leffler 	}
449b2763056SSam Leffler 	tries_so_far += tries1;
450fa20c234SSam Leffler 
451b2763056SSam Leffler 	if (tries2 && tries0 + tries1 < tries) {
452b2763056SSam Leffler 		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx2].rix,
453b2763056SSam Leffler 					       short_tries-1,
454b2763056SSam Leffler 						MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
455b2763056SSam Leffler 	}
456b2763056SSam Leffler 
457b2763056SSam Leffler 	tries_so_far += tries2;
458b2763056SSam Leffler 
459b2763056SSam Leffler 	if (tries3 && tries0 + tries1 + tries2 < tries) {
460b2763056SSam Leffler 		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx3].rix,
461b2763056SSam Leffler 						short_tries-1,
462b2763056SSam Leffler 						MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
463b2763056SSam Leffler 	}
46443e9cf7cSSam Leffler #ifdef SAMPLE_DEBUG
46543e9cf7cSSam Leffler 	if (short_tries + tries > 3 || status) {
466b2763056SSam Leffler 		DPRINTF(sc, "%s: %s size %d rate %d ndx %d tries (%d/%d) tries0 %d tt %d avg_tt %d perfect_tt %d status %d\n",
467b2763056SSam Leffler 			__func__, ether_sprintf(an->an_node.ni_macaddr),
468b2763056SSam Leffler 			size,
469b2763056SSam Leffler 			rate, ndx0, short_tries, tries, tries0, tt,
470b2763056SSam Leffler 			sn->stats[size_bin][ndx0].average_tx_time,
471b2763056SSam Leffler 			sn->stats[size_bin][ndx0].perfect_tx_time,
472b2763056SSam Leffler 			status);
473b2763056SSam Leffler 	}
47443e9cf7cSSam Leffler #endif /* SAMPLE_DEBUG */
475b2763056SSam Leffler 	if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) {
476fa20c234SSam Leffler 		/* just average the first few packets */
477b2763056SSam Leffler 		int avg_tx = sn->stats[size_bin][ndx0].average_tx_time;
478b2763056SSam Leffler 		int packets = sn->stats[size_bin][ndx0].total_packets;
479b2763056SSam Leffler 		sn->stats[size_bin][ndx0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
480fa20c234SSam Leffler 	} else {
481fa20c234SSam Leffler 		/* use a ewma */
482b2763056SSam Leffler 		sn->stats[size_bin][ndx0].average_tx_time =
483b2763056SSam Leffler 			((sn->stats[size_bin][ndx0].average_tx_time * ssc->ath_smoothing_rate) +
484fa20c234SSam Leffler 			 (tt * (100 - ssc->ath_smoothing_rate))) / 100;
485fa20c234SSam Leffler 	}
486fa20c234SSam Leffler 
487b2763056SSam Leffler 	if (status) {
488fa20c234SSam Leffler 		/*
489fa20c234SSam Leffler 		 * this packet failed - count this as a failure
490fa20c234SSam Leffler 		 * for larger packets also, since we assume
491fa20c234SSam Leffler 		 * if a small packet fails at a lower bit-rate
492fa20c234SSam Leffler 		 * then a larger one will also.
493fa20c234SSam Leffler 		 */
494fa20c234SSam Leffler 		int y;
495fa20c234SSam Leffler 		for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) {
496b2763056SSam Leffler 			sn->stats[y][ndx0].successive_failures++;
497b2763056SSam Leffler 			sn->stats[y][ndx0].last_tx = ticks;
498fa20c234SSam Leffler 		}
499fa20c234SSam Leffler 	} else {
500b2763056SSam Leffler 		sn->stats[size_bin][ndx0].packets_acked++;
501b2763056SSam Leffler 		sn->stats[size_bin][ndx0].successive_failures = 0;
502fa20c234SSam Leffler 	}
503b2763056SSam Leffler 	sn->stats[size_bin][ndx0].tries += tries;
504b2763056SSam Leffler 	sn->stats[size_bin][ndx0].last_tx = ticks;
505b2763056SSam Leffler 	sn->stats[size_bin][ndx0].total_packets++;
506b2763056SSam Leffler 
507b2763056SSam Leffler 
508b2763056SSam Leffler 	if (ndx0 == sn->current_sample_ndx[size_bin]) {
509b2763056SSam Leffler 		DPRINTF(sc, "%s: %s size %d sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d) status %d\n",
510b2763056SSam Leffler 			__func__, ether_sprintf(an->an_node.ni_macaddr),
511b2763056SSam Leffler 			size, rate, short_tries, tries, tt,
512b2763056SSam Leffler 			sn->stats[size_bin][ndx0].average_tx_time,
513b2763056SSam Leffler 			sn->stats[size_bin][ndx0].perfect_tx_time,
514b2763056SSam Leffler 			status);
515b2763056SSam Leffler 		sn->sample_tt[size_bin] = tt;
516b2763056SSam Leffler 		sn->current_sample_ndx[size_bin] = -1;
517b2763056SSam Leffler 	}
518b2763056SSam Leffler }
519b2763056SSam Leffler 
520b2763056SSam Leffler void
52143e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
52243e9cf7cSSam Leffler 	const struct ath_desc *ds, const struct ath_desc *ds0)
523b2763056SSam Leffler {
524b2763056SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
525eb988356SSam Leffler 	const struct ar5212_desc *ads = (const struct ar5212_desc *)&ds->ds_ctl0;
526b2763056SSam Leffler 	int final_rate, short_tries, long_tries, frame_size;
527b2763056SSam Leffler 	int ndx = -1;
528b2763056SSam Leffler 
529b2763056SSam Leffler 	final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
530b2763056SSam Leffler 	short_tries = ds->ds_txstat.ts_shortretry + 1;
531b2763056SSam Leffler 	long_tries = ds->ds_txstat.ts_longretry + 1;
53243e9cf7cSSam Leffler 	frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
53343e9cf7cSSam Leffler 	if (frame_size == 0)		    /* NB: should not happen */
534b2763056SSam Leffler 		frame_size = 1500;
535b2763056SSam Leffler 
536b2763056SSam Leffler 	if (sn->num_rates <= 0) {
53743e9cf7cSSam Leffler 		DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d "
53843e9cf7cSSam Leffler 			"no rates yet\n",
53943e9cf7cSSam Leffler 			__func__, ether_sprintf(an->an_node.ni_macaddr),
54043e9cf7cSSam Leffler 			bin_to_size(size_to_bin(frame_size)),
54143e9cf7cSSam Leffler 			ds->ds_txstat.ts_status,
54243e9cf7cSSam Leffler 			short_tries, long_tries);
543b2763056SSam Leffler 		return;
544b2763056SSam Leffler 	}
545b2763056SSam Leffler 
546b2763056SSam Leffler 	if (sc->sc_mrretry && ds->ds_txstat.ts_status) {
547b2763056SSam Leffler 		/* this packet failed */
548b2763056SSam Leffler 		DPRINTF(sc, "%s: %s size %d rate/try %d/%d %d/%d %d/%d %d/%d status %s retries (%d/%d)\n",
549b2763056SSam Leffler 			__func__,
550b2763056SSam Leffler 			ether_sprintf(an->an_node.ni_macaddr),
551b2763056SSam Leffler 			bin_to_size(size_to_bin(frame_size)),
552b2763056SSam Leffler 			sc->sc_hwmap[ads->xmit_rate0].ieeerate,
553b2763056SSam Leffler 				ads->xmit_tries0,
554b2763056SSam Leffler 			sc->sc_hwmap[ads->xmit_rate1].ieeerate,
555b2763056SSam Leffler 				ads->xmit_tries1,
556b2763056SSam Leffler 			sc->sc_hwmap[ads->xmit_rate2].ieeerate,
557b2763056SSam Leffler 				ads->xmit_tries2,
558b2763056SSam Leffler 			sc->sc_hwmap[ads->xmit_rate3].ieeerate,
559b2763056SSam Leffler 				ads->xmit_tries3,
560b2763056SSam Leffler 			ds->ds_txstat.ts_status ? "FAIL" : "OK",
561b2763056SSam Leffler 			short_tries,
562b2763056SSam Leffler 			long_tries);
563b2763056SSam Leffler 	}
564b2763056SSam Leffler 
565b2763056SSam Leffler 	if (!(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) {
566b2763056SSam Leffler 		/* only one rate was used */
567b2763056SSam Leffler 		ndx = rate_to_ndx(sn, final_rate);
56843e9cf7cSSam Leffler 		DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d/%d\n",
56943e9cf7cSSam Leffler 			__func__, ether_sprintf(an->an_node.ni_macaddr),
57043e9cf7cSSam Leffler 			bin_to_size(size_to_bin(frame_size)),
57143e9cf7cSSam Leffler 			ds->ds_txstat.ts_status,
57243e9cf7cSSam Leffler 			ndx, short_tries, long_tries);
573b2763056SSam Leffler 		if (ndx >= 0 && ndx < sn->num_rates) {
574b2763056SSam Leffler 			update_stats(sc, an, frame_size,
575b2763056SSam Leffler 				     ndx, long_tries,
576b2763056SSam Leffler 				     0, 0,
577b2763056SSam Leffler 				     0, 0,
578b2763056SSam Leffler 				     0, 0,
579b2763056SSam Leffler 				     short_tries, long_tries, ds->ds_txstat.ts_status);
580b2763056SSam Leffler 		}
581b2763056SSam Leffler 	} else {
582b2763056SSam Leffler 		int rate0, tries0, ndx0;
583b2763056SSam Leffler 		int rate1, tries1, ndx1;
584b2763056SSam Leffler 		int rate2, tries2, ndx2;
585b2763056SSam Leffler 		int rate3, tries3, ndx3;
586b2763056SSam Leffler 		int finalTSIdx = ads->final_ts_index;
587b2763056SSam Leffler 
588b2763056SSam Leffler 		/*
589b2763056SSam Leffler 		 * Process intermediate rates that failed.
590b2763056SSam Leffler 		 */
591b2763056SSam Leffler 
592b2763056SSam Leffler 		rate0 = sc->sc_hwmap[ads->xmit_rate0].ieeerate;
593b2763056SSam Leffler 		tries0 = ads->xmit_tries0;
594b2763056SSam Leffler 		ndx0 = rate_to_ndx(sn, rate0);
595b2763056SSam Leffler 
596b2763056SSam Leffler 		rate1 = sc->sc_hwmap[ads->xmit_rate1].ieeerate;
597b2763056SSam Leffler 		tries1 = ads->xmit_tries1;
598b2763056SSam Leffler 		ndx1 = rate_to_ndx(sn, rate1);
599b2763056SSam Leffler 
600b2763056SSam Leffler 		rate2 = sc->sc_hwmap[ads->xmit_rate2].ieeerate;
601b2763056SSam Leffler 		tries2 = ads->xmit_tries2;
602b2763056SSam Leffler 		ndx2 = rate_to_ndx(sn, rate2);
603b2763056SSam Leffler 
604b2763056SSam Leffler 		rate3 = sc->sc_hwmap[ads->xmit_rate3].ieeerate;
605b2763056SSam Leffler 		tries3 = ads->xmit_tries3;
606b2763056SSam Leffler 		ndx3 = rate_to_ndx(sn, rate3);
607b2763056SSam Leffler 
60843e9cf7cSSam Leffler #if 1
609b2763056SSam Leffler 		DPRINTF(sc, "%s: %s size %d finaltsidx %d tries %d status %d rate/try %d/%d %d/%d %d/%d %d/%d\n",
610b2763056SSam Leffler 			__func__, ether_sprintf(an->an_node.ni_macaddr),
611b2763056SSam Leffler 			bin_to_size(size_to_bin(frame_size)),
612b2763056SSam Leffler 			finalTSIdx,
613b2763056SSam Leffler 			long_tries,
614b2763056SSam Leffler 			ds->ds_txstat.ts_status,
615b2763056SSam Leffler 			rate0, tries0,
616b2763056SSam Leffler 			rate1, tries1,
617b2763056SSam Leffler 			rate2, tries2,
618b2763056SSam Leffler 			rate3, tries3);
619b2763056SSam Leffler #endif
620b2763056SSam Leffler 
621b2763056SSam Leffler 		if (tries0) {
622b2763056SSam Leffler 			update_stats(sc, an, frame_size,
623b2763056SSam Leffler 				     ndx0, tries0,
624b2763056SSam Leffler 				     ndx1, tries1,
625b2763056SSam Leffler 				     ndx2, tries2,
626b2763056SSam Leffler 				     ndx3, tries3,
627b2763056SSam Leffler 				     short_tries, ds->ds_txstat.ts_longretry + 1,
628b2763056SSam Leffler 				     ds->ds_txstat.ts_status);
629b2763056SSam Leffler 		}
630b2763056SSam Leffler 
631b2763056SSam Leffler 		if (tries1 && finalTSIdx > 0) {
632b2763056SSam Leffler 			update_stats(sc, an, frame_size,
633b2763056SSam Leffler 				     ndx1, tries1,
634b2763056SSam Leffler 				     ndx2, tries2,
635b2763056SSam Leffler 				     ndx3, tries3,
636b2763056SSam Leffler 				     0, 0,
637b2763056SSam Leffler 				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0,
638b2763056SSam Leffler 				     ds->ds_txstat.ts_status);
639b2763056SSam Leffler 		}
640b2763056SSam Leffler 
641b2763056SSam Leffler 		if (tries2 && finalTSIdx > 1) {
642b2763056SSam Leffler 			update_stats(sc, an, frame_size,
643b2763056SSam Leffler 				     ndx2, tries2,
644b2763056SSam Leffler 				     ndx3, tries3,
645b2763056SSam Leffler 				     0, 0,
646b2763056SSam Leffler 				     0, 0,
647b2763056SSam Leffler 				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1,
648b2763056SSam Leffler 				     ds->ds_txstat.ts_status);
649b2763056SSam Leffler 		}
650b2763056SSam Leffler 
651b2763056SSam Leffler 		if (tries3 && finalTSIdx > 2) {
652b2763056SSam Leffler 			update_stats(sc, an, frame_size,
653b2763056SSam Leffler 				     ndx3, tries3,
654b2763056SSam Leffler 				     0, 0,
655b2763056SSam Leffler 				     0, 0,
656b2763056SSam Leffler 				     0, 0,
657b2763056SSam Leffler 				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1 - tries2,
658b2763056SSam Leffler 				     ds->ds_txstat.ts_status);
659b2763056SSam Leffler 		}
660b2763056SSam Leffler 	}
661fa20c234SSam Leffler }
662fa20c234SSam Leffler 
663fa20c234SSam Leffler void
664fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
665fa20c234SSam Leffler {
66643e9cf7cSSam Leffler 	DPRINTF(sc, "%s: %s isnew %d\n", __func__,
66743e9cf7cSSam Leffler 		ether_sprintf(an->an_node.ni_macaddr), isnew);
668fa20c234SSam Leffler 	if (isnew)
669b2763056SSam Leffler 		ath_rate_ctl_reset(sc, &an->an_node);
670fa20c234SSam Leffler }
671fa20c234SSam Leffler 
672fa20c234SSam Leffler /*
673fa20c234SSam Leffler  * Initialize the tables for a node.
674fa20c234SSam Leffler  */
675fa20c234SSam Leffler static void
676b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
677fa20c234SSam Leffler {
678fa20c234SSam Leffler #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
679fa20c234SSam Leffler 	struct ieee80211com *ic = &sc->sc_ic;
680fa20c234SSam Leffler 	struct ath_node *an = ATH_NODE(ni);
681fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
682fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
683b2763056SSam Leffler 	int x, y, srate;
684fa20c234SSam Leffler 
685fa20c234SSam Leffler 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
686fa20c234SSam Leffler         sn->static_rate_ndx = -1;
687fa20c234SSam Leffler 	if (ic->ic_fixed_rate != -1) {
688fa20c234SSam Leffler 		/*
689fa20c234SSam Leffler 		 * A fixed rate is to be used; ic_fixed_rate is an
690fa20c234SSam Leffler 		 * index into the supported rate set.  Convert this
691fa20c234SSam Leffler 		 * to the index into the negotiated rate set for
692fa20c234SSam Leffler 		 * the node.  We know the rate is there because the
693fa20c234SSam Leffler 		 * rate set is checked when the station associates.
694fa20c234SSam Leffler 		 */
695fa20c234SSam Leffler 		const struct ieee80211_rateset *rs =
696fa20c234SSam Leffler 			&ic->ic_sup_rates[ic->ic_curmode];
697fa20c234SSam Leffler 		int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
698fa20c234SSam Leffler 		/* NB: the rate set is assumed sorted */
699fa20c234SSam Leffler 		srate = ni->ni_rates.rs_nrates - 1;
700fa20c234SSam Leffler 		for (; srate >= 0 && RATE(srate) != r; srate--)
701fa20c234SSam Leffler 			;
702fa20c234SSam Leffler 		KASSERT(srate >= 0,
703fa20c234SSam Leffler 			("fixed rate %d not in rate set", ic->ic_fixed_rate));
704fa20c234SSam Leffler                 sn->static_rate_ndx = srate;
705fa20c234SSam Leffler 	}
706b2763056SSam Leffler 
707b2763056SSam Leffler         DPRINTF(sc, "%s: %s size 1600 rate/tt", __func__, ether_sprintf(ni->ni_macaddr));
708b2763056SSam Leffler 
709fa20c234SSam Leffler 	sn->num_rates = ni->ni_rates.rs_nrates;
710fa20c234SSam Leffler         for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
711fa20c234SSam Leffler 		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
712fa20c234SSam Leffler 		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
713fa20c234SSam Leffler 		sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
714fa20c234SSam Leffler 		sn->rates[x].shortPreambleRateCode =
715fa20c234SSam Leffler 			rt->info[sn->rates[x].rix].rateCode |
716fa20c234SSam Leffler 			rt->info[sn->rates[x].rix].shortPreamble;
717fa20c234SSam Leffler 
718b2763056SSam Leffler 		DPRINTF(sc, " %d/%d", sn->rates[x].rate,
719b2763056SSam Leffler 			calc_usecs_unicast_packet(sc, 1600, sn->rates[x].rix,
720b2763056SSam Leffler 						  0,0));
721b2763056SSam Leffler 	}
722b2763056SSam Leffler 	DPRINTF(sc, "%s\n", "");
723b2763056SSam Leffler 
724b2763056SSam Leffler 	/* set the visible bit-rate to the lowest one available */
725b2763056SSam Leffler 	ni->ni_txrate = 0;
726b2763056SSam Leffler 	sn->num_rates = ni->ni_rates.rs_nrates;
727b2763056SSam Leffler 
728b2763056SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
729b2763056SSam Leffler 		int size = bin_to_size(y);
730b2763056SSam Leffler 		sn->packets_sent[y] = 0;
731b2763056SSam Leffler 		sn->current_sample_ndx[y] = -1;
732b2763056SSam Leffler 		sn->last_sample_ndx[y] = 0;
733b2763056SSam Leffler 
734b2763056SSam Leffler 		for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
735b2763056SSam Leffler 			sn->stats[y][x].successive_failures = 0;
736b2763056SSam Leffler 			sn->stats[y][x].tries = 0;
737b2763056SSam Leffler 			sn->stats[y][x].total_packets = 0;
738b2763056SSam Leffler 			sn->stats[y][x].packets_acked = 0;
739b2763056SSam Leffler 			sn->stats[y][x].last_tx = 0;
740b2763056SSam Leffler 
741b2763056SSam Leffler 			sn->stats[y][x].perfect_tx_time =
742b2763056SSam Leffler 				calc_usecs_unicast_packet(sc, size,
743b2763056SSam Leffler 							  sn->rates[x].rix,
744b2763056SSam Leffler 							  0, 0);
745b2763056SSam Leffler 			sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time;
746b2763056SSam Leffler 		}
747b2763056SSam Leffler 	}
748fa20c234SSam Leffler #undef RATE
749fa20c234SSam Leffler }
750fa20c234SSam Leffler 
751f0fd5e07SSam Leffler static void
752f0fd5e07SSam Leffler rate_cb(void *arg, struct ieee80211_node *ni)
753f0fd5e07SSam Leffler {
754f0fd5e07SSam Leffler 	struct ath_softc *sc = arg;
755f0fd5e07SSam Leffler 
756f0fd5e07SSam Leffler 	ath_rate_newassoc(sc, ATH_NODE(ni), 1);
757f0fd5e07SSam Leffler }
758f0fd5e07SSam Leffler 
759fa20c234SSam Leffler /*
760fa20c234SSam Leffler  * Reset the rate control state for each 802.11 state transition.
761fa20c234SSam Leffler  */
762fa20c234SSam Leffler void
763fa20c234SSam Leffler ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
764fa20c234SSam Leffler {
765fa20c234SSam Leffler 	struct ieee80211com *ic = &sc->sc_ic;
766fa20c234SSam Leffler 
767f0fd5e07SSam Leffler 	if (state == IEEE80211_S_RUN) {
768f0fd5e07SSam Leffler 		if (ic->ic_opmode != IEEE80211_M_STA) {
769f0fd5e07SSam Leffler 			/*
770f0fd5e07SSam Leffler 			 * Sync rates for associated stations and neighbors.
771f0fd5e07SSam Leffler 			 */
772f0fd5e07SSam Leffler 			ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc);
773f0fd5e07SSam Leffler 		}
774fa20c234SSam Leffler 		ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
775fa20c234SSam Leffler 	}
776f0fd5e07SSam Leffler }
777fa20c234SSam Leffler 
778fa20c234SSam Leffler static void
779fa20c234SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
780fa20c234SSam Leffler {
781fa20c234SSam Leffler 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
782fa20c234SSam Leffler 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
783fa20c234SSam Leffler 
784fa20c234SSam Leffler 	/* XXX bounds check [0..100] */
785fa20c234SSam Leffler 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
786fa20c234SSam Leffler 		"smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0,
787fa20c234SSam Leffler 		"rate control: retry threshold to credit rate raise (%%)");
788fa20c234SSam Leffler 	/* XXX bounds check [2..100] */
789fa20c234SSam Leffler 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
790fa20c234SSam Leffler 		"sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0,
791fa20c234SSam Leffler 		"rate control: # good periods before raising rate");
792fa20c234SSam Leffler }
793fa20c234SSam Leffler 
794fa20c234SSam Leffler struct ath_ratectrl *
795fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc)
796fa20c234SSam Leffler {
797fa20c234SSam Leffler 	struct sample_softc *osc;
798fa20c234SSam Leffler 
799fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
800fa20c234SSam Leffler 	osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
801fa20c234SSam Leffler 	if (osc == NULL)
802fa20c234SSam Leffler 		return NULL;
803fa20c234SSam Leffler 	osc->arc.arc_space = sizeof(struct sample_node);
804fa20c234SSam Leffler 	osc->ath_smoothing_rate = 95;	/* ewma percentage (out of 100) */
805fa20c234SSam Leffler 	osc->ath_sample_rate = 10;	/* send a different bit-rate 1/X packets */
806fa20c234SSam Leffler 	ath_rate_sysctlattach(sc, osc);
807fa20c234SSam Leffler 	return &osc->arc;
808fa20c234SSam Leffler }
809fa20c234SSam Leffler 
810fa20c234SSam Leffler void
811fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc)
812fa20c234SSam Leffler {
813fa20c234SSam Leffler 	struct sample_softc *osc = (struct sample_softc *) arc;
814fa20c234SSam Leffler 
815fa20c234SSam Leffler 	free(osc, M_DEVBUF);
816fa20c234SSam Leffler }
817fa20c234SSam Leffler 
818fa20c234SSam Leffler /*
819fa20c234SSam Leffler  * Module glue.
820fa20c234SSam Leffler  */
821fa20c234SSam Leffler static int
822fa20c234SSam Leffler sample_modevent(module_t mod, int type, void *unused)
823fa20c234SSam Leffler {
824fa20c234SSam Leffler 	switch (type) {
825fa20c234SSam Leffler 	case MOD_LOAD:
826fa20c234SSam Leffler 		if (bootverbose)
82743e9cf7cSSam Leffler 			printf("ath_rate: version 1.2 <SampleRate bit-rate selection algorithm>\n");
828fa20c234SSam Leffler 		return 0;
829fa20c234SSam Leffler 	case MOD_UNLOAD:
830fa20c234SSam Leffler 		return 0;
831fa20c234SSam Leffler 	}
832fa20c234SSam Leffler 	return EINVAL;
833fa20c234SSam Leffler }
834fa20c234SSam Leffler 
835fa20c234SSam Leffler static moduledata_t sample_mod = {
836fa20c234SSam Leffler 	"ath_rate",
837fa20c234SSam Leffler 	sample_modevent,
838fa20c234SSam Leffler 	0
839fa20c234SSam Leffler };
840fa20c234SSam Leffler DECLARE_MODULE(ath_rate, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
841fa20c234SSam Leffler MODULE_VERSION(ath_rate, 1);
8424e860beeSTai-hwa Liang MODULE_DEPEND(ath_rate, ath_hal, 1, 1, 1);	/* Atheros HAL */
843fa20c234SSam Leffler MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
844