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