xref: /freebsd/sys/dev/ath/ath_rate/sample/sample.c (revision fa20c234019ae7105ae5c4ae975e96ea8d66d7f3)
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 
113fa20c234SSam Leffler static void	ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
114fa20c234SSam Leffler 
115fa20c234SSam Leffler static __inline int size_to_bin(int size)
116fa20c234SSam Leffler {
117fa20c234SSam Leffler 	int x = 0;
118fa20c234SSam Leffler 	for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
119fa20c234SSam Leffler 		if (size < packet_size_bins[x]) {
120fa20c234SSam Leffler 			return x;
121fa20c234SSam Leffler 		}
122fa20c234SSam Leffler 	}
123fa20c234SSam Leffler 	return NUM_PACKET_SIZE_BINS-1;
124fa20c234SSam Leffler }
125fa20c234SSam Leffler static __inline int bin_to_size(int index) {
126fa20c234SSam Leffler 	return packet_size_bins[index];
127fa20c234SSam Leffler }
128fa20c234SSam Leffler 
129fa20c234SSam Leffler /*
130fa20c234SSam Leffler  * Setup rate codes for management/control frames.  We force
131fa20c234SSam Leffler  * all such frames to the lowest rate.
132fa20c234SSam Leffler  */
133fa20c234SSam Leffler static void
134fa20c234SSam Leffler ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an)
135fa20c234SSam Leffler {
136fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
137fa20c234SSam Leffler 
138fa20c234SSam Leffler 	/* setup rates for management frames */
139fa20c234SSam Leffler 	/* XXX management/control frames always go at lowest speed */
140fa20c234SSam Leffler 	an->an_tx_mgtrate = rt->info[0].rateCode;
141fa20c234SSam Leffler 	an->an_tx_mgtratesp = an->an_tx_mgtrate
142fa20c234SSam Leffler 			    | rt->info[0].shortPreamble;
143fa20c234SSam Leffler }
144fa20c234SSam Leffler 
145fa20c234SSam Leffler void
146fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
147fa20c234SSam Leffler {
148fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
149fa20c234SSam Leffler 	/* NB: assumed to be zero'd by caller */
150fa20c234SSam Leffler 	ath_rate_setmgtrates(sc, an);
151fa20c234SSam Leffler }
152fa20c234SSam Leffler 
153fa20c234SSam Leffler void
154fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
155fa20c234SSam Leffler {
156fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
157fa20c234SSam Leffler }
158fa20c234SSam Leffler 
159fa20c234SSam Leffler 
160fa20c234SSam Leffler /*
161fa20c234SSam Leffler  * returns the ndx with the lowest average_tx_time,
162fa20c234SSam Leffler  * or -1 if all the average_tx_times are 0.
163fa20c234SSam Leffler  */
164fa20c234SSam Leffler static __inline int best_rate_ndx(struct sample_node *sn, int size_bin)
165fa20c234SSam Leffler {
166fa20c234SSam Leffler 	int x = 0;
167fa20c234SSam Leffler         int best_rate_ndx = 0;
168fa20c234SSam Leffler         int best_rate_tt = 0;
169fa20c234SSam Leffler         for (x = 0; x < sn->num_rates; x++) {
170fa20c234SSam Leffler 		int tt = sn->stats[size_bin][x].average_tx_time;
171fa20c234SSam Leffler 		if (tt > 0) {
172fa20c234SSam Leffler 			if (!best_rate_tt || best_rate_tt > tt) {
173fa20c234SSam Leffler 				best_rate_tt = tt;
174fa20c234SSam Leffler 				best_rate_ndx = x;
175fa20c234SSam Leffler 			}
176fa20c234SSam Leffler 		}
177fa20c234SSam Leffler         }
178fa20c234SSam Leffler         return (best_rate_tt) ? best_rate_ndx : -1;
179fa20c234SSam Leffler }
180fa20c234SSam Leffler 
181fa20c234SSam Leffler /*
182fa20c234SSam Leffler  * pick a ndx s.t. the perfect_tx_time
183fa20c234SSam Leffler  * is less than the best bit-rate's average_tx_time
184fa20c234SSam Leffler  * and the ndx has not had four successive failures.
185fa20c234SSam Leffler  */
186fa20c234SSam Leffler static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin)
187fa20c234SSam Leffler {
188fa20c234SSam Leffler 	int x = 0;
189fa20c234SSam Leffler 	int best_ndx = best_rate_ndx(sn, size_bin);
190fa20c234SSam Leffler 	int best_tt = 0;
191fa20c234SSam Leffler 	int num_eligible = 0;
192fa20c234SSam Leffler 
193fa20c234SSam Leffler 	if (best_ndx < 0) {
194fa20c234SSam Leffler 		/* no successes yet, send at the lowest bit-rate */
195fa20c234SSam Leffler 		return 0;
196fa20c234SSam Leffler 	}
197fa20c234SSam Leffler 
198fa20c234SSam Leffler 	best_tt = sn->stats[size_bin][best_ndx].average_tx_time;
199fa20c234SSam Leffler 	sn->sample_num[size_bin]++;
200fa20c234SSam Leffler 
201fa20c234SSam Leffler 	/*
202fa20c234SSam Leffler 	 * first, find the number of bit-rates we could potentially
203fa20c234SSam Leffler 	 * sample. we assume this list doesn't change a lot, so
204fa20c234SSam Leffler 	 * we will just cycle through them.
205fa20c234SSam Leffler 	 */
206fa20c234SSam Leffler 	for (x = 0; x < sn->num_rates; x++) {
207fa20c234SSam Leffler 		if (x != best_ndx &&
208fa20c234SSam Leffler 		    sn->stats[size_bin][x].perfect_tx_time < best_tt &&
209fa20c234SSam Leffler 		    sn->stats[size_bin][x].successive_failures < 4) {
210fa20c234SSam Leffler 			num_eligible++;
211fa20c234SSam Leffler 		}
212fa20c234SSam Leffler 	}
213fa20c234SSam Leffler 
214fa20c234SSam Leffler 	if (num_eligible > 0) {
215fa20c234SSam Leffler 		int pick = sn->sample_num[size_bin] % num_eligible;
216fa20c234SSam Leffler 		for (x = 0; x < sn->num_rates; x++) {
217fa20c234SSam Leffler 			if (x != best_ndx &&
218fa20c234SSam Leffler 			    sn->stats[size_bin][x].perfect_tx_time < best_tt &&
219fa20c234SSam Leffler 			    sn->stats[size_bin][x].successive_failures < 4) {
220fa20c234SSam Leffler 				if (pick == 0) {
221fa20c234SSam Leffler 					return x;
222fa20c234SSam Leffler 				}
223fa20c234SSam Leffler 				pick--;
224fa20c234SSam Leffler 			}
225fa20c234SSam Leffler 		}
226fa20c234SSam Leffler 	}
227fa20c234SSam Leffler 	return best_ndx;
228fa20c234SSam Leffler }
229fa20c234SSam Leffler 
230fa20c234SSam Leffler void
231fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
232fa20c234SSam Leffler 		  HAL_BOOL shortPreamble, size_t frameLen,
233fa20c234SSam Leffler 		  u_int8_t *rix, int *try0, u_int8_t *txrate)
234fa20c234SSam Leffler {
235fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
236fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
237fa20c234SSam Leffler 	int x;
238fa20c234SSam Leffler 	int ndx = 0;
239fa20c234SSam Leffler 	int size_bin = size_to_bin(frameLen);
240fa20c234SSam Leffler 	int best_ndx = best_rate_ndx(sn, size_bin);
241fa20c234SSam Leffler 
242fa20c234SSam Leffler 	if (sn->static_rate_ndx != -1) {
243fa20c234SSam Leffler 		*try0 = 4;
244fa20c234SSam Leffler 		*rix = sn->rates[sn->static_rate_ndx].rix;
245fa20c234SSam Leffler 		*txrate = sn->rates[sn->static_rate_ndx].rateCode;
246fa20c234SSam Leffler 		return;
247fa20c234SSam Leffler 	}
248fa20c234SSam Leffler 
249fa20c234SSam Leffler 	*try0 = 2;
250fa20c234SSam Leffler 
251fa20c234SSam Leffler 	best_ndx = best_rate_ndx(sn, size_bin);
252fa20c234SSam Leffler 	if (!sn->packets_sent[size_bin] ||
253fa20c234SSam Leffler 	    sn->packets_sent[size_bin] % ssc->ath_sample_rate > 0) {
254fa20c234SSam Leffler 		/*
255fa20c234SSam Leffler 		 * for most packets, send the packet at the bit-rate with
256fa20c234SSam Leffler 		 * the lowest estimated transmission time.
257fa20c234SSam Leffler 		 */
258fa20c234SSam Leffler 		if (best_ndx != -1) {
259fa20c234SSam Leffler 			ndx = best_ndx;
260fa20c234SSam Leffler 		} else {
261fa20c234SSam Leffler 			/*
262fa20c234SSam Leffler 			 * no packet has succeeded, try the highest bitrate
263fa20c234SSam Leffler 			 * that hasn't failed.
264fa20c234SSam Leffler 			 */
265fa20c234SSam Leffler 			for (ndx = sn->num_rates-1; ndx >= 0; ndx--) {
266fa20c234SSam Leffler 				if (sn->stats[size_bin][ndx].successive_failures == 0) {
267fa20c234SSam Leffler 					break;
268fa20c234SSam Leffler 				}
269fa20c234SSam Leffler 			}
270fa20c234SSam Leffler 		}
271fa20c234SSam Leffler 		if (size_bin == 0) {
272fa20c234SSam Leffler 			/* update the visible txrate for this node */
273fa20c234SSam Leffler 			an->an_node.ni_txrate = ndx;
274fa20c234SSam Leffler 		}
275fa20c234SSam Leffler 	} else {
276fa20c234SSam Leffler 		/*
277fa20c234SSam Leffler 		 * before we pick a bit-rate to "sample", clear any
278fa20c234SSam Leffler 		 * stale stuff out.
279fa20c234SSam Leffler 		 */
280fa20c234SSam Leffler 		for (x = 0; x < sn->num_rates; x++) {
281fa20c234SSam Leffler 			if (ticks - sn->stats[size_bin][x].last_tx > ((hz * 10000)/1000)) {
282fa20c234SSam Leffler 				sn->stats[size_bin][x].average_tx_time = sn->stats[size_bin][x].perfect_tx_time;
283fa20c234SSam Leffler 				sn->stats[size_bin][x].successive_failures = 0;
284fa20c234SSam Leffler 				sn->stats[size_bin][x].tries = 0;
285fa20c234SSam Leffler 				sn->stats[size_bin][x].total_packets = 0;
286fa20c234SSam Leffler 				sn->stats[size_bin][x].packets_acked = 0;
287fa20c234SSam Leffler 			}
288fa20c234SSam Leffler 		}
289fa20c234SSam Leffler 
290fa20c234SSam Leffler 		/* send the packet at a different bit-rate */
291fa20c234SSam Leffler 		ndx = pick_sample_ndx(sn, size_bin);
292fa20c234SSam Leffler 	}
293fa20c234SSam Leffler 
294fa20c234SSam Leffler 
295fa20c234SSam Leffler 	*rix = sn->rates[ndx].rix;
296fa20c234SSam Leffler 	if (shortPreamble) {
297fa20c234SSam Leffler 		*txrate = sn->rates[ndx].shortPreambleRateCode;
298fa20c234SSam Leffler 	} else {
299fa20c234SSam Leffler 
300fa20c234SSam Leffler 		*txrate = sn->rates[ndx].rateCode;
301fa20c234SSam Leffler 	}
302fa20c234SSam Leffler 
303fa20c234SSam Leffler 	sn->packets_sent[size_bin]++;
304fa20c234SSam Leffler }
305fa20c234SSam Leffler 
306fa20c234SSam Leffler void
307fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
308fa20c234SSam Leffler 		      struct ath_desc *ds, HAL_BOOL shortPreamble, u_int8_t rix)
309fa20c234SSam Leffler {
310fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
311fa20c234SSam Leffler 	int rateCode = -1;
312fa20c234SSam Leffler 	int frame_size;
313fa20c234SSam Leffler 	int size_bin;
314fa20c234SSam Leffler 	int best_ndx;
315fa20c234SSam Leffler 
316fa20c234SSam Leffler 	frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
317fa20c234SSam Leffler 	if (frame_size == 0)
318fa20c234SSam Leffler 		frame_size = 1500;
319fa20c234SSam Leffler 	size_bin = size_to_bin(frame_size);
320fa20c234SSam Leffler 	best_ndx = best_rate_ndx(sn, size_bin);
321fa20c234SSam Leffler 
322fa20c234SSam Leffler 	if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) {
323fa20c234SSam Leffler 		/*
324fa20c234SSam Leffler 		 * no packet has succeeded, so also try twice at the lowest bitate.
325fa20c234SSam Leffler 		 */
326fa20c234SSam Leffler 		if (shortPreamble) {
327fa20c234SSam Leffler 			rateCode = sn->rates[0].shortPreambleRateCode;
328fa20c234SSam Leffler 		} else {
329fa20c234SSam Leffler 			rateCode = sn->rates[0].rateCode;
330fa20c234SSam Leffler 		}
331fa20c234SSam Leffler 	} else if (sn->rates[best_ndx].rix != rix) {
332fa20c234SSam Leffler 		/*
333fa20c234SSam Leffler 		 * we're trying a different bit-rate, and it could be lossy,
334fa20c234SSam Leffler 		 * so if it fails try at the best bit-rate.
335fa20c234SSam Leffler 		 */
336fa20c234SSam Leffler 		if (shortPreamble) {
337fa20c234SSam Leffler 			rateCode = sn->rates[MAX(0,best_ndx-1)].shortPreambleRateCode;
338fa20c234SSam Leffler 		} else {
339fa20c234SSam Leffler 			rateCode = sn->rates[MAX(0,best_ndx-1)].rateCode;
340fa20c234SSam Leffler 		}
341fa20c234SSam Leffler 	}
342fa20c234SSam Leffler 	if (rateCode != -1) {
343fa20c234SSam Leffler 		ath_hal_setupxtxdesc(sc->sc_ah, ds
344fa20c234SSam Leffler 				     , rateCode, 1	/* series 1 */
345fa20c234SSam Leffler 				     , rateCode, 1	        /* series 2 */
346fa20c234SSam Leffler 				     , rateCode, 1	        /* series 3 */
347fa20c234SSam Leffler 				     );
348fa20c234SSam Leffler 	}
349fa20c234SSam Leffler 
350fa20c234SSam Leffler }
351fa20c234SSam Leffler 
352fa20c234SSam Leffler void
353fa20c234SSam Leffler ath_rate_tx_complete(struct ath_softc *sc,
354fa20c234SSam Leffler 		     struct ath_node *an, const struct ath_desc *ds)
355fa20c234SSam Leffler {
356fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
357fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
358fa20c234SSam Leffler 	int rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
359fa20c234SSam Leffler 	int retries = ds->ds_txstat.ts_longretry;
360fa20c234SSam Leffler 	int initial_rate_failed = ((ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)
361fa20c234SSam Leffler 				   || ds->ds_txstat.ts_status != 0 ||
362fa20c234SSam Leffler 				   retries > 3);
363fa20c234SSam Leffler 	int tt = 0;
364fa20c234SSam Leffler 	int rix = -1;
365fa20c234SSam Leffler 	int x = 0;
366fa20c234SSam Leffler 	int frame_size; /* low-order 12 bits of ds_ctl0 */
367fa20c234SSam Leffler 	int size_bin;
368fa20c234SSam Leffler 	int size;
369fa20c234SSam Leffler 
370fa20c234SSam Leffler 	if (!sn->num_rates) {
371fa20c234SSam Leffler 		DPRINTF(sc, "%s: no rates yet\n", __func__);
372fa20c234SSam Leffler 		return;
373fa20c234SSam Leffler 	}
374fa20c234SSam Leffler 	for (x = 0; x < sn->num_rates; x++) {
375fa20c234SSam Leffler 		if (sn->rates[x].rate == rate) {
376fa20c234SSam Leffler 			rix = x;
377fa20c234SSam Leffler 			break;
378fa20c234SSam Leffler 		}
379fa20c234SSam Leffler 	}
380fa20c234SSam Leffler 
381fa20c234SSam Leffler 	if (rix < 0 || rix > sn->num_rates) {
382fa20c234SSam Leffler 		/* maybe a management packet */
383fa20c234SSam Leffler 		return;
384fa20c234SSam Leffler 	}
385fa20c234SSam Leffler 
386fa20c234SSam Leffler 	frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
387fa20c234SSam Leffler 	if (frame_size == 0)
388fa20c234SSam Leffler 		frame_size = 1500;
389fa20c234SSam Leffler 	size_bin = size_to_bin(frame_size);
390fa20c234SSam Leffler 	size = bin_to_size(size_bin);
391fa20c234SSam Leffler 	tt = calc_usecs_unicast_packet(sc, size, sn->rates[rix].rix,
392fa20c234SSam Leffler 				       retries);
393fa20c234SSam Leffler 
394fa20c234SSam Leffler 	DPRINTF(sc, "%s: rate %d rix %d frame_size %d (%d) retries %d status %d tt %d avg_tt %d perfect_tt %d ts-rate %d\n",
395fa20c234SSam Leffler 		__func__, rate, rix, frame_size, size, retries, initial_rate_failed, tt,
396fa20c234SSam Leffler 		sn->stats[size_bin][rix].average_tx_time,
397fa20c234SSam Leffler 		sn->stats[size_bin][rix].perfect_tx_time,
398fa20c234SSam Leffler 		ds->ds_txstat.ts_rate);
399fa20c234SSam Leffler 
400fa20c234SSam Leffler 	if (sn->stats[size_bin][rix].total_packets < 7) {
401fa20c234SSam Leffler 		/* just average the first few packets */
402fa20c234SSam Leffler 		int avg_tx = sn->stats[size_bin][rix].average_tx_time;
403fa20c234SSam Leffler 		int packets = sn->stats[size_bin][rix].total_packets;
404fa20c234SSam Leffler 		sn->stats[size_bin][rix].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
405fa20c234SSam Leffler 	} else {
406fa20c234SSam Leffler 		/* use a ewma */
407fa20c234SSam Leffler 		sn->stats[size_bin][rix].average_tx_time =
408fa20c234SSam Leffler 			((sn->stats[size_bin][rix].average_tx_time * ssc->ath_smoothing_rate) +
409fa20c234SSam Leffler 			 (tt * (100 - ssc->ath_smoothing_rate))) / 100;
410fa20c234SSam Leffler 	}
411fa20c234SSam Leffler 
412fa20c234SSam Leffler 	if (initial_rate_failed) {
413fa20c234SSam Leffler 		/*
414fa20c234SSam Leffler 		 * this packet failed - count this as a failure
415fa20c234SSam Leffler 		 * for larger packets also, since we assume
416fa20c234SSam Leffler 		 * if a small packet fails at a lower bit-rate
417fa20c234SSam Leffler 		 * then a larger one will also.
418fa20c234SSam Leffler 		 */
419fa20c234SSam Leffler 		int y;
420fa20c234SSam Leffler 		for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) {
421fa20c234SSam Leffler 			sn->stats[y][rix].successive_failures++;
422fa20c234SSam Leffler 			sn->stats[y][rix].last_tx = ticks;
423fa20c234SSam Leffler 		}
424fa20c234SSam Leffler 	} else {
425fa20c234SSam Leffler 		sn->stats[size_bin][rix].packets_acked++;
426fa20c234SSam Leffler 		sn->stats[size_bin][rix].successive_failures = 0;
427fa20c234SSam Leffler 	}
428fa20c234SSam Leffler 	sn->stats[size_bin][rix].tries += (1+retries);
429fa20c234SSam Leffler 	sn->stats[size_bin][rix].last_tx = ticks;
430fa20c234SSam Leffler 	sn->stats[size_bin][rix].total_packets++;
431fa20c234SSam Leffler }
432fa20c234SSam Leffler 
433fa20c234SSam Leffler void
434fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
435fa20c234SSam Leffler {
436fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
437fa20c234SSam Leffler 	if (isnew)
438fa20c234SSam Leffler 		ath_rate_ctl_start(sc, &an->an_node);
439fa20c234SSam Leffler }
440fa20c234SSam Leffler 
441fa20c234SSam Leffler static void
442fa20c234SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
443fa20c234SSam Leffler {
444fa20c234SSam Leffler 	struct ath_node *an = ATH_NODE(ni);
445fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
446fa20c234SSam Leffler 	int x = 0;
447fa20c234SSam Leffler 	int y = 0;
448fa20c234SSam Leffler 
449fa20c234SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
450fa20c234SSam Leffler 		int size = bin_to_size(y);
451fa20c234SSam Leffler 		sn->packets_sent[y] = 0;
452fa20c234SSam Leffler 		sn->sample_num[y] = 0;
453fa20c234SSam Leffler 
454fa20c234SSam Leffler 		for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
455fa20c234SSam Leffler 			sn->stats[y][x].successive_failures = 0;
456fa20c234SSam Leffler 			sn->stats[y][x].tries = 0;
457fa20c234SSam Leffler 			sn->stats[y][x].total_packets = 0;
458fa20c234SSam Leffler 			sn->stats[y][x].packets_acked = 0;
459fa20c234SSam Leffler 			sn->stats[y][x].last_tx = 0;
460fa20c234SSam Leffler 			sn->stats[y][x].perfect_tx_time = calc_usecs_unicast_packet(sc, size,
461fa20c234SSam Leffler 									      sn->rates[x].rix,
462fa20c234SSam Leffler 									      0);
463fa20c234SSam Leffler 			sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time;
464fa20c234SSam Leffler 
465fa20c234SSam Leffler 
466fa20c234SSam Leffler 			DPRINTF(sc, "%s: %d rate %d rix %d rateCode %d perfect_tx_time %d \n", __func__,
467fa20c234SSam Leffler 				x, sn->rates[x].rate,
468fa20c234SSam Leffler 				sn->rates[x].rix, sn->rates[x].rateCode,
469fa20c234SSam Leffler 				sn->stats[0][x].perfect_tx_time);
470fa20c234SSam Leffler 		}
471fa20c234SSam Leffler 
472fa20c234SSam Leffler 	}
473fa20c234SSam Leffler 
474fa20c234SSam Leffler 	/* set the visible bit-rate to the lowest one available */
475fa20c234SSam Leffler 	ni->ni_txrate = 0;
476fa20c234SSam Leffler 
477fa20c234SSam Leffler }
478fa20c234SSam Leffler 
479fa20c234SSam Leffler /*
480fa20c234SSam Leffler  * Initialize the tables for a node.
481fa20c234SSam Leffler  */
482fa20c234SSam Leffler static void
483fa20c234SSam Leffler ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
484fa20c234SSam Leffler {
485fa20c234SSam Leffler #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
486fa20c234SSam Leffler 	struct ieee80211com *ic = &sc->sc_ic;
487fa20c234SSam Leffler 	struct ath_node *an = ATH_NODE(ni);
488fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
489fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
490fa20c234SSam Leffler 
491fa20c234SSam Leffler 	int x;
492fa20c234SSam Leffler 	int srate;
493fa20c234SSam Leffler 
494fa20c234SSam Leffler         DPRINTF(sc, "%s:\n", __func__);
495fa20c234SSam Leffler 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
496fa20c234SSam Leffler 	KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
497fa20c234SSam Leffler         sn->static_rate_ndx = -1;
498fa20c234SSam Leffler 	if (ic->ic_fixed_rate != -1) {
499fa20c234SSam Leffler 		/*
500fa20c234SSam Leffler 		 * A fixed rate is to be used; ic_fixed_rate is an
501fa20c234SSam Leffler 		 * index into the supported rate set.  Convert this
502fa20c234SSam Leffler 		 * to the index into the negotiated rate set for
503fa20c234SSam Leffler 		 * the node.  We know the rate is there because the
504fa20c234SSam Leffler 		 * rate set is checked when the station associates.
505fa20c234SSam Leffler 		 */
506fa20c234SSam Leffler 		const struct ieee80211_rateset *rs =
507fa20c234SSam Leffler 			&ic->ic_sup_rates[ic->ic_curmode];
508fa20c234SSam Leffler 		int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
509fa20c234SSam Leffler 		/* NB: the rate set is assumed sorted */
510fa20c234SSam Leffler 		srate = ni->ni_rates.rs_nrates - 1;
511fa20c234SSam Leffler 		for (; srate >= 0 && RATE(srate) != r; srate--)
512fa20c234SSam Leffler 			;
513fa20c234SSam Leffler 		KASSERT(srate >= 0,
514fa20c234SSam Leffler 			("fixed rate %d not in rate set", ic->ic_fixed_rate));
515fa20c234SSam Leffler                 sn->static_rate_ndx = srate;
516fa20c234SSam Leffler 
517fa20c234SSam Leffler 	}
518fa20c234SSam Leffler 	sn->num_rates = ni->ni_rates.rs_nrates;
519fa20c234SSam Leffler         for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
520fa20c234SSam Leffler           sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
521fa20c234SSam Leffler           sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
522fa20c234SSam Leffler           sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
523fa20c234SSam Leffler           sn->rates[x].shortPreambleRateCode =
524fa20c234SSam Leffler 		  rt->info[sn->rates[x].rix].rateCode |
525fa20c234SSam Leffler 		  rt->info[sn->rates[x].rix].shortPreamble;
526fa20c234SSam Leffler 	}
527fa20c234SSam Leffler 	ath_rate_ctl_reset(sc, ni);
528fa20c234SSam Leffler 
529fa20c234SSam Leffler #undef RATE
530fa20c234SSam Leffler }
531fa20c234SSam Leffler 
532fa20c234SSam Leffler /*
533fa20c234SSam Leffler  * Reset the rate control state for each 802.11 state transition.
534fa20c234SSam Leffler  */
535fa20c234SSam Leffler void
536fa20c234SSam Leffler ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
537fa20c234SSam Leffler {
538fa20c234SSam Leffler 	struct ieee80211com *ic = &sc->sc_ic;
539fa20c234SSam Leffler 
540fa20c234SSam Leffler 	if (state == IEEE80211_S_RUN)
541fa20c234SSam Leffler 		ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
542fa20c234SSam Leffler }
543fa20c234SSam Leffler 
544fa20c234SSam Leffler static void
545fa20c234SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
546fa20c234SSam Leffler {
547fa20c234SSam Leffler 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
548fa20c234SSam Leffler 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
549fa20c234SSam Leffler 
550fa20c234SSam Leffler 	/* XXX bounds check [0..100] */
551fa20c234SSam Leffler 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
552fa20c234SSam Leffler 		"smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0,
553fa20c234SSam Leffler 		"rate control: retry threshold to credit rate raise (%%)");
554fa20c234SSam Leffler 	/* XXX bounds check [2..100] */
555fa20c234SSam Leffler 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
556fa20c234SSam Leffler 		"sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0,
557fa20c234SSam Leffler 		"rate control: # good periods before raising rate");
558fa20c234SSam Leffler }
559fa20c234SSam Leffler 
560fa20c234SSam Leffler struct ath_ratectrl *
561fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc)
562fa20c234SSam Leffler {
563fa20c234SSam Leffler 	struct sample_softc *osc;
564fa20c234SSam Leffler 
565fa20c234SSam Leffler 	DPRINTF(sc, "%s:\n", __func__);
566fa20c234SSam Leffler 	osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
567fa20c234SSam Leffler 	if (osc == NULL)
568fa20c234SSam Leffler 		return NULL;
569fa20c234SSam Leffler 	osc->arc.arc_space = sizeof(struct sample_node);
570fa20c234SSam Leffler 	osc->ath_smoothing_rate = 95;	/* ewma percentage (out of 100) */
571fa20c234SSam Leffler 	osc->ath_sample_rate = 10;	/* send a different bit-rate 1/X packets */
572fa20c234SSam Leffler 	ath_rate_sysctlattach(sc, osc);
573fa20c234SSam Leffler 	return &osc->arc;
574fa20c234SSam Leffler }
575fa20c234SSam Leffler 
576fa20c234SSam Leffler void
577fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc)
578fa20c234SSam Leffler {
579fa20c234SSam Leffler 	struct sample_softc *osc = (struct sample_softc *) arc;
580fa20c234SSam Leffler 
581fa20c234SSam Leffler 	free(osc, M_DEVBUF);
582fa20c234SSam Leffler }
583fa20c234SSam Leffler 
584fa20c234SSam Leffler /*
585fa20c234SSam Leffler  * Module glue.
586fa20c234SSam Leffler  */
587fa20c234SSam Leffler static int
588fa20c234SSam Leffler sample_modevent(module_t mod, int type, void *unused)
589fa20c234SSam Leffler {
590fa20c234SSam Leffler 	switch (type) {
591fa20c234SSam Leffler 	case MOD_LOAD:
592fa20c234SSam Leffler 		if (bootverbose)
593fa20c234SSam Leffler 			printf("ath_rate: <SampleRate bit-rate selection algorithm>\n");
594fa20c234SSam Leffler 		return 0;
595fa20c234SSam Leffler 	case MOD_UNLOAD:
596fa20c234SSam Leffler 		return 0;
597fa20c234SSam Leffler 	}
598fa20c234SSam Leffler 	return EINVAL;
599fa20c234SSam Leffler }
600fa20c234SSam Leffler 
601fa20c234SSam Leffler static moduledata_t sample_mod = {
602fa20c234SSam Leffler 	"ath_rate",
603fa20c234SSam Leffler 	sample_modevent,
604fa20c234SSam Leffler 	0
605fa20c234SSam Leffler };
606fa20c234SSam Leffler DECLARE_MODULE(ath_rate, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
607fa20c234SSam Leffler MODULE_VERSION(ath_rate, 1);
608fa20c234SSam Leffler MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
609