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