1*8c146276Sandvar /* $NetBSD: athrate-sample.c,v 1.21 2021/08/09 21:20:50 andvar Exp $ */
2fd8cfc5eSxtraeme
3d1f00611Sdyoung /*-
4d1f00611Sdyoung * Copyright (c) 2005 John Bicket
5d1f00611Sdyoung * All rights reserved.
6d1f00611Sdyoung *
7d1f00611Sdyoung * Redistribution and use in source and binary forms, with or without
8d1f00611Sdyoung * modification, are permitted provided that the following conditions
9d1f00611Sdyoung * are met:
10d1f00611Sdyoung * 1. Redistributions of source code must retain the above copyright
11d1f00611Sdyoung * notice, this list of conditions and the following disclaimer,
12d1f00611Sdyoung * without modification.
13d1f00611Sdyoung * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14d1f00611Sdyoung * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15d1f00611Sdyoung * redistribution must be conditioned upon including a substantially
16d1f00611Sdyoung * similar Disclaimer requirement for further binary redistribution.
17d1f00611Sdyoung * 3. Neither the names of the above-listed copyright holders nor the names
18d1f00611Sdyoung * of any contributors may be used to endorse or promote products derived
19d1f00611Sdyoung * from this software without specific prior written permission.
20d1f00611Sdyoung *
21d1f00611Sdyoung * Alternatively, this software may be distributed under the terms of the
22d1f00611Sdyoung * GNU General Public License ("GPL") version 2 as published by the Free
23d1f00611Sdyoung * Software Foundation.
24d1f00611Sdyoung *
25d1f00611Sdyoung * NO WARRANTY
26d1f00611Sdyoung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27d1f00611Sdyoung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28d1f00611Sdyoung * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
29d1f00611Sdyoung * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
30d1f00611Sdyoung * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
31d1f00611Sdyoung * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32d1f00611Sdyoung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33d1f00611Sdyoung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34d1f00611Sdyoung * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35d1f00611Sdyoung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36d1f00611Sdyoung * THE POSSIBILITY OF SUCH DAMAGES.
37d1f00611Sdyoung */
38d1f00611Sdyoung
39d1f00611Sdyoung #include <sys/cdefs.h>
4081071408Sdyoung #ifdef __FreeBSD__
41dc2bd8a8Sskrll __FBSDID("$FreeBSD: src/sys/dev/ath/ath_rate/sample/sample.c,v 1.9 2005/07/22 16:50:17 sam Exp $");
4281071408Sdyoung #endif
4381071408Sdyoung #ifdef __NetBSD__
44*8c146276Sandvar __KERNEL_RCSID(0, "$NetBSD: athrate-sample.c,v 1.21 2021/08/09 21:20:50 andvar Exp $");
4581071408Sdyoung #endif
4681071408Sdyoung
47d1f00611Sdyoung
48d1f00611Sdyoung /*
49d1f00611Sdyoung * John Bicket's SampleRate control algorithm.
50d1f00611Sdyoung */
5180da4313Sjmcneill #ifdef _KERNEL_OPT
52d1f00611Sdyoung #include "opt_inet.h"
5380da4313Sjmcneill #endif
54d1f00611Sdyoung
55d1f00611Sdyoung #include <sys/param.h>
56d1f00611Sdyoung #include <sys/systm.h>
57d1f00611Sdyoung #include <sys/sysctl.h>
58d1f00611Sdyoung #include <sys/kernel.h>
59d1f00611Sdyoung #include <sys/errno.h>
603e4f7c87Smartin #include <sys/device.h>
61d1f00611Sdyoung
62a2a38285Sad #include <sys/bus.h>
63d1f00611Sdyoung
64d1f00611Sdyoung #include <sys/socket.h>
65d1f00611Sdyoung
66d1f00611Sdyoung #include <net/if.h>
67d1f00611Sdyoung #include <net/if_media.h>
68d1f00611Sdyoung #include <net/if_arp.h>
6981071408Sdyoung #include <net/if_ether.h> /* XXX for ether_sprintf */
70d1f00611Sdyoung
71d1f00611Sdyoung #include <net80211/ieee80211_var.h>
72d1f00611Sdyoung
73d1f00611Sdyoung #include <net/bpf.h>
74d1f00611Sdyoung
75d1f00611Sdyoung #ifdef INET
76d1f00611Sdyoung #include <netinet/in.h>
77d1f00611Sdyoung #endif
78d1f00611Sdyoung
795d561f94Salc #include "ah_desc.h"
8090634029Sdyoung #include <dev/ic/athvar.h>
8190634029Sdyoung #include <dev/ic/athrate-sample.h>
82d1f00611Sdyoung
83d1f00611Sdyoung #define SAMPLE_DEBUG
84d1f00611Sdyoung #ifdef SAMPLE_DEBUG
85d1f00611Sdyoung enum {
8625e9e914Sdyoung ATH_DEBUG_RATE = 0x00000010 /* rate control */
87d1f00611Sdyoung };
88d1f00611Sdyoung #define DPRINTF(sc, _fmt, ...) do { \
89d1f00611Sdyoung if (sc->sc_debug & ATH_DEBUG_RATE) \
90d1f00611Sdyoung printf(_fmt, __VA_ARGS__); \
91d1f00611Sdyoung } while (0)
92d1f00611Sdyoung #else
93d1f00611Sdyoung #define DPRINTF(sc, _fmt, ...)
94d1f00611Sdyoung #endif
95d1f00611Sdyoung
96d1f00611Sdyoung /*
97d1f00611Sdyoung * This file is an implementation of the SampleRate algorithm
98d1f00611Sdyoung * in "Bit-rate Selection in Wireless Networks"
99d1f00611Sdyoung * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
100d1f00611Sdyoung *
101d1f00611Sdyoung * SampleRate chooses the bit-rate it predicts will provide the most
102d1f00611Sdyoung * throughput based on estimates of the expected per-packet
103d1f00611Sdyoung * transmission time for each bit-rate. SampleRate periodically sends
104d1f00611Sdyoung * packets at bit-rates other than the current one to estimate when
105d1f00611Sdyoung * another bit-rate will provide better performance. SampleRate
106d1f00611Sdyoung * switches to another bit-rate when its estimated per-packet
107d1f00611Sdyoung * transmission time becomes smaller than the current bit-rate's.
108d1f00611Sdyoung * SampleRate reduces the number of bit-rates it must sample by
109d1f00611Sdyoung * eliminating those that could not perform better than the one
110d1f00611Sdyoung * currently being used. SampleRate also stops probing at a bit-rate
111d1f00611Sdyoung * if it experiences several successive losses.
112d1f00611Sdyoung *
113d1f00611Sdyoung * The difference between the algorithm in the thesis and the one in this
114d1f00611Sdyoung * file is that the one in this file uses a ewma instead of a window.
115d1f00611Sdyoung *
11625e9e914Sdyoung * Also, this implementation tracks the average transmission time for
11725e9e914Sdyoung * a few different packet sizes independently for each link.
118d1f00611Sdyoung */
119d1f00611Sdyoung
120d1f00611Sdyoung #define STALE_FAILURE_TIMEOUT_MS 10000
12125e9e914Sdyoung #define MIN_SWITCH_MS 1000
122d1f00611Sdyoung
123d1f00611Sdyoung static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
124d1f00611Sdyoung
12525e9e914Sdyoung static inline int
size_to_bin(int size)12625e9e914Sdyoung size_to_bin(int size)
127d1f00611Sdyoung {
128d1f00611Sdyoung int x = 0;
129d1f00611Sdyoung for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
130d1f00611Sdyoung if (size <= packet_size_bins[x]) {
131d1f00611Sdyoung return x;
132d1f00611Sdyoung }
133d1f00611Sdyoung }
134d1f00611Sdyoung return NUM_PACKET_SIZE_BINS-1;
135d1f00611Sdyoung }
bin_to_size(int index)13693124077Sperry static inline int bin_to_size(int index) {
137d1f00611Sdyoung return packet_size_bins[index];
138d1f00611Sdyoung }
139d1f00611Sdyoung
14025e9e914Sdyoung static inline int
rate_to_ndx(struct sample_node * sn,int rate)14125e9e914Sdyoung rate_to_ndx(struct sample_node *sn, int rate) {
142d1f00611Sdyoung int x = 0;
143d1f00611Sdyoung for (x = 0; x < sn->num_rates; x++) {
144d1f00611Sdyoung if (sn->rates[x].rate == rate) {
145d1f00611Sdyoung return x;
146d1f00611Sdyoung }
147d1f00611Sdyoung }
148d1f00611Sdyoung return -1;
149d1f00611Sdyoung }
150d1f00611Sdyoung
151d1f00611Sdyoung void
ath_rate_node_init(struct ath_softc * sc,struct ath_node * an)152168cd830Schristos ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
153d1f00611Sdyoung {
154d1f00611Sdyoung DPRINTF(sc, "%s:\n", __func__);
155d1f00611Sdyoung /* NB: assumed to be zero'd by caller */
156d1f00611Sdyoung }
157d1f00611Sdyoung
158d1f00611Sdyoung void
ath_rate_node_cleanup(struct ath_softc * sc,struct ath_node * an)159168cd830Schristos ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
160d1f00611Sdyoung {
161d1f00611Sdyoung DPRINTF(sc, "%s:\n", __func__);
162d1f00611Sdyoung }
163d1f00611Sdyoung
164d1f00611Sdyoung
165d1f00611Sdyoung /*
166d1f00611Sdyoung * returns the ndx with the lowest average_tx_time,
167d1f00611Sdyoung * or -1 if all the average_tx_times are 0.
168d1f00611Sdyoung */
best_rate_ndx(struct sample_node * sn,int size_bin,int require_acked_before)16993124077Sperry static inline int best_rate_ndx(struct sample_node *sn, int size_bin,
170d1f00611Sdyoung int require_acked_before)
171d1f00611Sdyoung {
172d1f00611Sdyoung int x = 0;
17381071408Sdyoung int best_ndx = 0;
174d1f00611Sdyoung int best_rate_tt = 0;
175d1f00611Sdyoung for (x = 0; x < sn->num_rates; x++) {
176d1f00611Sdyoung int tt = sn->stats[size_bin][x].average_tx_time;
177d1f00611Sdyoung if (tt <= 0 || (require_acked_before &&
178d1f00611Sdyoung !sn->stats[size_bin][x].packets_acked)) {
179d1f00611Sdyoung continue;
180d1f00611Sdyoung }
18125e9e914Sdyoung
18225e9e914Sdyoung /* 9 megabits never works better than 12 */
18325e9e914Sdyoung if (sn->rates[x].rate == 18)
18425e9e914Sdyoung continue;
18525e9e914Sdyoung
18625e9e914Sdyoung /* don't use a bit-rate that has been failing */
18725e9e914Sdyoung if (sn->stats[size_bin][x].successive_failures > 3)
18825e9e914Sdyoung continue;
18925e9e914Sdyoung
190d1f00611Sdyoung if (!best_rate_tt || best_rate_tt > tt) {
191d1f00611Sdyoung best_rate_tt = tt;
19281071408Sdyoung best_ndx = x;
193d1f00611Sdyoung }
194d1f00611Sdyoung }
19581071408Sdyoung return (best_rate_tt) ? best_ndx : -1;
196d1f00611Sdyoung }
197d1f00611Sdyoung
198d1f00611Sdyoung /*
19925e9e914Sdyoung * pick a good "random" bit-rate to sample other than the current one
200d1f00611Sdyoung */
20125e9e914Sdyoung static inline int
pick_sample_ndx(struct sample_node * sn,int size_bin)20225e9e914Sdyoung pick_sample_ndx(struct sample_node *sn, int size_bin)
203d1f00611Sdyoung {
204d1f00611Sdyoung int x = 0;
205d1f00611Sdyoung int current_ndx = 0;
206d1f00611Sdyoung unsigned current_tt = 0;
207d1f00611Sdyoung
208d1f00611Sdyoung current_ndx = sn->current_rate[size_bin];
209d1f00611Sdyoung if (current_ndx < 0) {
210d1f00611Sdyoung /* no successes yet, send at the lowest bit-rate */
211d1f00611Sdyoung return 0;
212d1f00611Sdyoung }
213d1f00611Sdyoung
214d1f00611Sdyoung current_tt = sn->stats[size_bin][current_ndx].average_tx_time;
215d1f00611Sdyoung
216d1f00611Sdyoung for (x = 0; x < sn->num_rates; x++) {
217d1f00611Sdyoung int ndx = (sn->last_sample_ndx[size_bin]+1+x) % sn->num_rates;
218d1f00611Sdyoung
21925e9e914Sdyoung /* don't sample the current bit-rate */
22025e9e914Sdyoung if (ndx == current_ndx)
22125e9e914Sdyoung continue;
22225e9e914Sdyoung
22325e9e914Sdyoung /* this bit-rate is always worse than the current one */
22425e9e914Sdyoung if (sn->stats[size_bin][ndx].perfect_tx_time > current_tt)
22525e9e914Sdyoung continue;
22625e9e914Sdyoung
22725e9e914Sdyoung /* rarely sample bit-rates that fail a lot */
22825e9e914Sdyoung if (ticks - sn->stats[size_bin][ndx].last_tx < ((hz * STALE_FAILURE_TIMEOUT_MS)/1000) &&
22925e9e914Sdyoung sn->stats[size_bin][ndx].successive_failures > 3)
23025e9e914Sdyoung continue;
23125e9e914Sdyoung
23225e9e914Sdyoung /* don't sample more than 2 indexes higher
23325e9e914Sdyoung * for rates higher than 11 megabits
23425e9e914Sdyoung */
23525e9e914Sdyoung if (sn->rates[ndx].rate > 22 && ndx > current_ndx + 2)
23625e9e914Sdyoung continue;
23725e9e914Sdyoung
23825e9e914Sdyoung /* 9 megabits never works better than 12 */
23925e9e914Sdyoung if (sn->rates[ndx].rate == 18)
24025e9e914Sdyoung continue;
24125e9e914Sdyoung
24225e9e914Sdyoung /* if we're using 11 megabits, only sample up to 12 megabits
24325e9e914Sdyoung */
24425e9e914Sdyoung if (sn->rates[current_ndx].rate == 22 && ndx > current_ndx + 1)
24525e9e914Sdyoung continue;
24625e9e914Sdyoung
247d1f00611Sdyoung sn->last_sample_ndx[size_bin] = ndx;
248d1f00611Sdyoung return ndx;
249d1f00611Sdyoung }
250d1f00611Sdyoung return current_ndx;
251d1f00611Sdyoung }
252d1f00611Sdyoung
253d1f00611Sdyoung void
ath_rate_findrate(struct ath_softc * sc,struct ath_node * an,int shortPreamble,size_t frameLen,u_int8_t * rix,int * try0,u_int8_t * txrate)254d1f00611Sdyoung ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
255d1f00611Sdyoung int shortPreamble, size_t frameLen,
256d1f00611Sdyoung u_int8_t *rix, int *try0, u_int8_t *txrate)
257d1f00611Sdyoung {
258d1f00611Sdyoung struct sample_node *sn = ATH_NODE_SAMPLE(an);
259d1f00611Sdyoung struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
260d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
26125e9e914Sdyoung int ndx, size_bin, mrr, best_ndx, change_rates;
262d1f00611Sdyoung unsigned average_tx_time;
263d1f00611Sdyoung
26425e9e914Sdyoung mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
265d1f00611Sdyoung size_bin = size_to_bin(frameLen);
266d1f00611Sdyoung best_ndx = best_rate_ndx(sn, size_bin, !mrr);
267d1f00611Sdyoung
268d1f00611Sdyoung if (best_ndx >= 0) {
269d1f00611Sdyoung average_tx_time = sn->stats[size_bin][best_ndx].average_tx_time;
270d1f00611Sdyoung } else {
271d1f00611Sdyoung average_tx_time = 0;
272d1f00611Sdyoung }
27325e9e914Sdyoung
274d1f00611Sdyoung if (sn->static_rate_ndx != -1) {
275d1f00611Sdyoung ndx = sn->static_rate_ndx;
276d1f00611Sdyoung *try0 = ATH_TXMAXTRY;
277d1f00611Sdyoung } else {
278d1f00611Sdyoung *try0 = mrr ? 2 : ATH_TXMAXTRY;
279d1f00611Sdyoung
28025e9e914Sdyoung if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100)) {
281d1f00611Sdyoung /*
282d1f00611Sdyoung * we want to limit the time measuring the performance
283d1f00611Sdyoung * of other bit-rates to ath_sample_rate% of the
284d1f00611Sdyoung * total transmission time.
285d1f00611Sdyoung */
286d1f00611Sdyoung ndx = pick_sample_ndx(sn, size_bin);
287d1f00611Sdyoung if (ndx != sn->current_rate[size_bin]) {
288d1f00611Sdyoung sn->current_sample_ndx[size_bin] = ndx;
289d1f00611Sdyoung } else {
290d1f00611Sdyoung sn->current_sample_ndx[size_bin] = -1;
291d1f00611Sdyoung }
292d1f00611Sdyoung sn->packets_since_sample[size_bin] = 0;
293d1f00611Sdyoung
294d1f00611Sdyoung } else {
29525e9e914Sdyoung change_rates = 0;
29625e9e914Sdyoung if (!sn->packets_sent[size_bin] || best_ndx == -1) {
29725e9e914Sdyoung /* no packet has been sent successfully yet */
29825e9e914Sdyoung for (ndx = sn->num_rates-1; ndx > 0; ndx--) {
299d1f00611Sdyoung /*
30025e9e914Sdyoung * pick the highest rate <= 36 Mbps
30125e9e914Sdyoung * that hasn't failed.
302d1f00611Sdyoung */
30325e9e914Sdyoung if (sn->rates[ndx].rate <= 72 &&
30425e9e914Sdyoung sn->stats[size_bin][ndx].successive_failures == 0) {
30525e9e914Sdyoung break;
30625e9e914Sdyoung }
30725e9e914Sdyoung }
30825e9e914Sdyoung change_rates = 1;
30925e9e914Sdyoung best_ndx = ndx;
31025e9e914Sdyoung } else if (sn->packets_sent[size_bin] < 20) {
31125e9e914Sdyoung /* let the bit-rate switch quickly during the first few packets */
31225e9e914Sdyoung change_rates = 1;
31325e9e914Sdyoung } else if (ticks - ((hz*MIN_SWITCH_MS)/1000) > sn->ticks_since_switch[size_bin]) {
31425e9e914Sdyoung /* 2 seconds have gone by */
31525e9e914Sdyoung change_rates = 1;
31625e9e914Sdyoung } else if (average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time) {
31725e9e914Sdyoung /* the current bit-rate is twice as slow as the best one */
31825e9e914Sdyoung change_rates = 1;
31925e9e914Sdyoung }
32025e9e914Sdyoung
32125e9e914Sdyoung sn->packets_since_sample[size_bin]++;
32225e9e914Sdyoung
32325e9e914Sdyoung if (change_rates) {
32425e9e914Sdyoung if (best_ndx != sn->current_rate[size_bin]) {
32525e9e914Sdyoung DPRINTF(sc, "%s: %s size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d\n",
326d1f00611Sdyoung __func__,
327d1f00611Sdyoung ether_sprintf(an->an_node.ni_macaddr),
328d1f00611Sdyoung packet_size_bins[size_bin],
329d1f00611Sdyoung sn->rates[sn->current_rate[size_bin]].rate,
330d1f00611Sdyoung sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time,
331d1f00611Sdyoung sn->stats[size_bin][sn->current_rate[size_bin]].perfect_tx_time,
332d1f00611Sdyoung sn->rates[best_ndx].rate,
333d1f00611Sdyoung sn->stats[size_bin][best_ndx].average_tx_time,
334d1f00611Sdyoung sn->stats[size_bin][best_ndx].perfect_tx_time,
335d1f00611Sdyoung sn->packets_since_switch[size_bin],
336d1f00611Sdyoung mrr);
337d1f00611Sdyoung }
338d1f00611Sdyoung sn->packets_since_switch[size_bin] = 0;
339d1f00611Sdyoung sn->current_rate[size_bin] = best_ndx;
34025e9e914Sdyoung sn->ticks_since_switch[size_bin] = ticks;
341d1f00611Sdyoung }
342d1f00611Sdyoung ndx = sn->current_rate[size_bin];
343d1f00611Sdyoung sn->packets_since_switch[size_bin]++;
34425e9e914Sdyoung if (size_bin == 0) {
34525e9e914Sdyoung /*
34625e9e914Sdyoung * set the visible txrate for this node
34725e9e914Sdyoung * to the rate of small packets
34825e9e914Sdyoung */
34925e9e914Sdyoung an->an_node.ni_txrate = ndx;
35025e9e914Sdyoung }
35125e9e914Sdyoung }
352d1f00611Sdyoung }
353d1f00611Sdyoung
354216b022dSdyoung KASSERTMSG(ndx >= 0 && ndx < sn->num_rates, "ndx is %d", ndx);
355d1f00611Sdyoung
356d1f00611Sdyoung *rix = sn->rates[ndx].rix;
357d1f00611Sdyoung if (shortPreamble) {
358d1f00611Sdyoung *txrate = sn->rates[ndx].shortPreambleRateCode;
359d1f00611Sdyoung } else {
360d1f00611Sdyoung *txrate = sn->rates[ndx].rateCode;
361d1f00611Sdyoung }
362d1f00611Sdyoung sn->packets_sent[size_bin]++;
363d1f00611Sdyoung }
364d1f00611Sdyoung
365d1f00611Sdyoung void
ath_rate_setupxtxdesc(struct ath_softc * sc,struct ath_node * an,struct ath_desc * ds,int shortPreamble,u_int8_t rix)366d1f00611Sdyoung ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
367168cd830Schristos struct ath_desc *ds, int shortPreamble, u_int8_t rix)
368d1f00611Sdyoung {
369d1f00611Sdyoung struct sample_node *sn = ATH_NODE_SAMPLE(an);
370d1f00611Sdyoung int rateCode = -1;
37125e9e914Sdyoung int frame_size = 0;
37225e9e914Sdyoung int size_bin = 0;
37325e9e914Sdyoung int ndx = 0;
374d1f00611Sdyoung
375*8c146276Sandvar size_bin = size_to_bin(frame_size); // TODO: it's correct that frame_size always 0 ?
37625e9e914Sdyoung ndx = sn->current_rate[size_bin]; /* retry at the current bit-rate */
377d1f00611Sdyoung
37825e9e914Sdyoung if (!sn->stats[size_bin][ndx].packets_acked) {
37925e9e914Sdyoung ndx = 0; /* use the lowest bit-rate */
380d1f00611Sdyoung }
38125e9e914Sdyoung
382d1f00611Sdyoung if (shortPreamble) {
383d1f00611Sdyoung rateCode = sn->rates[ndx].shortPreambleRateCode;
384d1f00611Sdyoung } else {
385d1f00611Sdyoung rateCode = sn->rates[ndx].rateCode;
386d1f00611Sdyoung }
387d1f00611Sdyoung ath_hal_setupxtxdesc(sc->sc_ah, ds
388d1f00611Sdyoung , rateCode, 3 /* series 1 */
389d1f00611Sdyoung , sn->rates[0].rateCode, 3 /* series 2 */
390d1f00611Sdyoung , 0, 0 /* series 3 */
391d1f00611Sdyoung );
392d1f00611Sdyoung }
393d1f00611Sdyoung
394d1f00611Sdyoung static void
update_stats(struct ath_softc * sc,struct ath_node * an,int frame_size,int ndx0,int tries0,int ndx1,int tries1,int ndx2,int tries2,int ndx3,int tries3,int short_tries,int tries,int status)395d1f00611Sdyoung update_stats(struct ath_softc *sc, struct ath_node *an,
396d1f00611Sdyoung int frame_size,
397d1f00611Sdyoung int ndx0, int tries0,
398d1f00611Sdyoung int ndx1, int tries1,
399d1f00611Sdyoung int ndx2, int tries2,
400d1f00611Sdyoung int ndx3, int tries3,
401d1f00611Sdyoung int short_tries, int tries, int status)
402d1f00611Sdyoung {
403d1f00611Sdyoung struct sample_node *sn = ATH_NODE_SAMPLE(an);
404d1f00611Sdyoung struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
405d1f00611Sdyoung int tt = 0;
406d1f00611Sdyoung int tries_so_far = 0;
407838d9e68Schristos int size_bin;
408838d9e68Schristos int size;
409838d9e68Schristos int rate;
410838d9e68Schristos
411838d9e68Schristos if (ndx0 == -1)
412838d9e68Schristos return;
413d1f00611Sdyoung
414d1f00611Sdyoung size_bin = size_to_bin(frame_size);
415d1f00611Sdyoung size = bin_to_size(size_bin);
416d1f00611Sdyoung rate = sn->rates[ndx0].rate;
417d1f00611Sdyoung
418d1f00611Sdyoung tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix,
419838d9e68Schristos short_tries - 1, MIN(tries0, tries) - 1);
420d1f00611Sdyoung tries_so_far += tries0;
421d1f00611Sdyoung if (tries1 && tries0 < tries) {
422838d9e68Schristos tt += calc_usecs_unicast_packet(sc, size,
423838d9e68Schristos ndx1 == -1 ? 0 : sn->rates[ndx1].rix, short_tries - 1,
424d1f00611Sdyoung MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
425d1f00611Sdyoung }
426d1f00611Sdyoung tries_so_far += tries1;
427d1f00611Sdyoung
428d1f00611Sdyoung if (tries2 && tries0 + tries1 < tries) {
429838d9e68Schristos tt += calc_usecs_unicast_packet(sc, size,
430838d9e68Schristos ndx2 == -1 ? 0 : sn->rates[ndx2].rix, short_tries - 1,
431d1f00611Sdyoung MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
432d1f00611Sdyoung }
433d1f00611Sdyoung
434d1f00611Sdyoung tries_so_far += tries2;
435d1f00611Sdyoung
436d1f00611Sdyoung if (tries3 && tries0 + tries1 + tries2 < tries) {
437838d9e68Schristos tt += calc_usecs_unicast_packet(sc, size,
438838d9e68Schristos ndx3 == -1 ? 0 : sn->rates[ndx3].rix, short_tries - 1,
439d1f00611Sdyoung MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
440d1f00611Sdyoung }
441838d9e68Schristos
442d1f00611Sdyoung if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) {
443d1f00611Sdyoung /* just average the first few packets */
444d1f00611Sdyoung int avg_tx = sn->stats[size_bin][ndx0].average_tx_time;
445d1f00611Sdyoung int packets = sn->stats[size_bin][ndx0].total_packets;
446d1f00611Sdyoung sn->stats[size_bin][ndx0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
447d1f00611Sdyoung } else {
448d1f00611Sdyoung /* use a ewma */
449d1f00611Sdyoung sn->stats[size_bin][ndx0].average_tx_time =
450d1f00611Sdyoung ((sn->stats[size_bin][ndx0].average_tx_time * ssc->ath_smoothing_rate) +
451d1f00611Sdyoung (tt * (100 - ssc->ath_smoothing_rate))) / 100;
452d1f00611Sdyoung }
453d1f00611Sdyoung
454d1f00611Sdyoung if (status) {
455d1f00611Sdyoung int y;
45625e9e914Sdyoung sn->stats[size_bin][ndx0].successive_failures++;
45725e9e914Sdyoung for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
45825e9e914Sdyoung /* also say larger packets failed since we
45925e9e914Sdyoung * assume if a small packet fails at a lower
46025e9e914Sdyoung * bit-rate then a larger one will also.
46125e9e914Sdyoung */
462d1f00611Sdyoung sn->stats[y][ndx0].successive_failures++;
463d1f00611Sdyoung sn->stats[y][ndx0].last_tx = ticks;
46425e9e914Sdyoung sn->stats[y][ndx0].tries += tries;
46525e9e914Sdyoung sn->stats[y][ndx0].total_packets++;
466d1f00611Sdyoung }
467d1f00611Sdyoung } else {
468d1f00611Sdyoung sn->stats[size_bin][ndx0].packets_acked++;
469d1f00611Sdyoung sn->stats[size_bin][ndx0].successive_failures = 0;
470d1f00611Sdyoung }
471d1f00611Sdyoung sn->stats[size_bin][ndx0].tries += tries;
472d1f00611Sdyoung sn->stats[size_bin][ndx0].last_tx = ticks;
473d1f00611Sdyoung sn->stats[size_bin][ndx0].total_packets++;
474d1f00611Sdyoung
475d1f00611Sdyoung
476d1f00611Sdyoung if (ndx0 == sn->current_sample_ndx[size_bin]) {
477d1f00611Sdyoung DPRINTF(sc, "%s: %s size %d sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d) status %d\n",
478d1f00611Sdyoung __func__, ether_sprintf(an->an_node.ni_macaddr),
479d1f00611Sdyoung size, rate, short_tries, tries, tt,
480d1f00611Sdyoung sn->stats[size_bin][ndx0].average_tx_time,
481d1f00611Sdyoung sn->stats[size_bin][ndx0].perfect_tx_time,
482d1f00611Sdyoung status);
483d1f00611Sdyoung sn->sample_tt[size_bin] = tt;
484d1f00611Sdyoung sn->current_sample_ndx[size_bin] = -1;
485d1f00611Sdyoung }
486d1f00611Sdyoung }
487d1f00611Sdyoung
488d1f00611Sdyoung void
ath_rate_tx_complete(struct ath_softc * sc,struct ath_node * an,const struct ath_desc * ds,const struct ath_desc * ds0)489d1f00611Sdyoung ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
490d1f00611Sdyoung const struct ath_desc *ds, const struct ath_desc *ds0)
491d1f00611Sdyoung {
49225e9e914Sdyoung struct ieee80211com *ic = &sc->sc_ic;
493d1f00611Sdyoung struct sample_node *sn = ATH_NODE_SAMPLE(an);
494d1f00611Sdyoung const struct ar5212_desc *ads = (const struct ar5212_desc *)&ds->ds_ctl0;
495d1f00611Sdyoung int final_rate, short_tries, long_tries, frame_size;
496d1f00611Sdyoung int ndx = -1;
49725e9e914Sdyoung int mrr;
498d1f00611Sdyoung
499d1f00611Sdyoung final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
500d1f00611Sdyoung short_tries = ds->ds_txstat.ts_shortretry + 1;
501d1f00611Sdyoung long_tries = ds->ds_txstat.ts_longretry + 1;
502d1f00611Sdyoung frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
503d1f00611Sdyoung if (frame_size == 0) /* NB: should not happen */
504d1f00611Sdyoung frame_size = 1500;
505d1f00611Sdyoung
506d1f00611Sdyoung if (sn->num_rates <= 0) {
507d1f00611Sdyoung DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d "
508d1f00611Sdyoung "no rates yet\n",
509d1f00611Sdyoung __func__, ether_sprintf(an->an_node.ni_macaddr),
510d1f00611Sdyoung bin_to_size(size_to_bin(frame_size)),
511d1f00611Sdyoung ds->ds_txstat.ts_status,
512d1f00611Sdyoung short_tries, long_tries);
513d1f00611Sdyoung return;
514d1f00611Sdyoung }
515d1f00611Sdyoung
51625e9e914Sdyoung mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
51725e9e914Sdyoung
518d1f00611Sdyoung if (sc->sc_mrretry && ds->ds_txstat.ts_status) {
519d1f00611Sdyoung /* this packet failed */
520d1f00611Sdyoung DPRINTF(sc, "%s: %s size %d rate/try %d/%d %d/%d %d/%d %d/%d status %s retries (%d/%d)\n",
521d1f00611Sdyoung __func__,
522d1f00611Sdyoung ether_sprintf(an->an_node.ni_macaddr),
523d1f00611Sdyoung bin_to_size(size_to_bin(frame_size)),
524d1f00611Sdyoung sc->sc_hwmap[ads->xmit_rate0].ieeerate,
525d1f00611Sdyoung ads->xmit_tries0,
526d1f00611Sdyoung sc->sc_hwmap[ads->xmit_rate1].ieeerate,
527d1f00611Sdyoung ads->xmit_tries1,
528d1f00611Sdyoung sc->sc_hwmap[ads->xmit_rate2].ieeerate,
529d1f00611Sdyoung ads->xmit_tries2,
530d1f00611Sdyoung sc->sc_hwmap[ads->xmit_rate3].ieeerate,
531d1f00611Sdyoung ads->xmit_tries3,
532d1f00611Sdyoung ds->ds_txstat.ts_status ? "FAIL" : "OK",
533d1f00611Sdyoung short_tries,
534d1f00611Sdyoung long_tries);
535d1f00611Sdyoung }
536d1f00611Sdyoung
53725e9e914Sdyoung if (!mrr || !(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) {
538d1f00611Sdyoung /* only one rate was used */
539d1f00611Sdyoung ndx = rate_to_ndx(sn, final_rate);
540d1f00611Sdyoung DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d/%d\n",
541d1f00611Sdyoung __func__, ether_sprintf(an->an_node.ni_macaddr),
542d1f00611Sdyoung bin_to_size(size_to_bin(frame_size)),
543d1f00611Sdyoung ds->ds_txstat.ts_status,
544d1f00611Sdyoung ndx, short_tries, long_tries);
545d1f00611Sdyoung if (ndx >= 0 && ndx < sn->num_rates) {
546d1f00611Sdyoung update_stats(sc, an, frame_size,
547d1f00611Sdyoung ndx, long_tries,
548d1f00611Sdyoung 0, 0,
549d1f00611Sdyoung 0, 0,
550d1f00611Sdyoung 0, 0,
551d1f00611Sdyoung short_tries, long_tries, ds->ds_txstat.ts_status);
552d1f00611Sdyoung }
553d1f00611Sdyoung } else {
554d1f00611Sdyoung int rate0, tries0, ndx0;
555d1f00611Sdyoung int rate1, tries1, ndx1;
556d1f00611Sdyoung int rate2, tries2, ndx2;
557d1f00611Sdyoung int rate3, tries3, ndx3;
558d1f00611Sdyoung int finalTSIdx = ads->final_ts_index;
559d1f00611Sdyoung
560d1f00611Sdyoung /*
561d1f00611Sdyoung * Process intermediate rates that failed.
562d1f00611Sdyoung */
563d1f00611Sdyoung
564d1f00611Sdyoung rate0 = sc->sc_hwmap[ads->xmit_rate0].ieeerate;
565d1f00611Sdyoung tries0 = ads->xmit_tries0;
566d1f00611Sdyoung ndx0 = rate_to_ndx(sn, rate0);
567d1f00611Sdyoung
568d1f00611Sdyoung rate1 = sc->sc_hwmap[ads->xmit_rate1].ieeerate;
569d1f00611Sdyoung tries1 = ads->xmit_tries1;
570d1f00611Sdyoung ndx1 = rate_to_ndx(sn, rate1);
571d1f00611Sdyoung
572d1f00611Sdyoung rate2 = sc->sc_hwmap[ads->xmit_rate2].ieeerate;
573d1f00611Sdyoung tries2 = ads->xmit_tries2;
574d1f00611Sdyoung ndx2 = rate_to_ndx(sn, rate2);
575d1f00611Sdyoung
576d1f00611Sdyoung rate3 = sc->sc_hwmap[ads->xmit_rate3].ieeerate;
577d1f00611Sdyoung tries3 = ads->xmit_tries3;
578d1f00611Sdyoung ndx3 = rate_to_ndx(sn, rate3);
579d1f00611Sdyoung
580d1f00611Sdyoung #if 1
581d1f00611Sdyoung DPRINTF(sc, "%s: %s size %d finaltsidx %d tries %d status %d rate/try %d/%d %d/%d %d/%d %d/%d\n",
582d1f00611Sdyoung __func__, ether_sprintf(an->an_node.ni_macaddr),
583d1f00611Sdyoung bin_to_size(size_to_bin(frame_size)),
584d1f00611Sdyoung finalTSIdx,
585d1f00611Sdyoung long_tries,
586d1f00611Sdyoung ds->ds_txstat.ts_status,
587d1f00611Sdyoung rate0, tries0,
588d1f00611Sdyoung rate1, tries1,
589d1f00611Sdyoung rate2, tries2,
590d1f00611Sdyoung rate3, tries3);
591d1f00611Sdyoung #endif
592d1f00611Sdyoung
593d1f00611Sdyoung if (tries0) {
594d1f00611Sdyoung update_stats(sc, an, frame_size,
595d1f00611Sdyoung ndx0, tries0,
596d1f00611Sdyoung ndx1, tries1,
597d1f00611Sdyoung ndx2, tries2,
598d1f00611Sdyoung ndx3, tries3,
599d1f00611Sdyoung short_tries, ds->ds_txstat.ts_longretry + 1,
60025e9e914Sdyoung long_tries > tries0);
601d1f00611Sdyoung }
602d1f00611Sdyoung
603d1f00611Sdyoung if (tries1 && finalTSIdx > 0) {
604d1f00611Sdyoung update_stats(sc, an, frame_size,
605d1f00611Sdyoung ndx1, tries1,
606d1f00611Sdyoung ndx2, tries2,
607d1f00611Sdyoung ndx3, tries3,
608d1f00611Sdyoung 0, 0,
609d1f00611Sdyoung short_tries, ds->ds_txstat.ts_longretry + 1 - tries0,
610d1f00611Sdyoung ds->ds_txstat.ts_status);
611d1f00611Sdyoung }
612d1f00611Sdyoung
613d1f00611Sdyoung if (tries2 && finalTSIdx > 1) {
614d1f00611Sdyoung update_stats(sc, an, frame_size,
615d1f00611Sdyoung ndx2, tries2,
616d1f00611Sdyoung ndx3, tries3,
617d1f00611Sdyoung 0, 0,
618d1f00611Sdyoung 0, 0,
619d1f00611Sdyoung short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1,
620d1f00611Sdyoung ds->ds_txstat.ts_status);
621d1f00611Sdyoung }
622d1f00611Sdyoung
623d1f00611Sdyoung if (tries3 && finalTSIdx > 2) {
624d1f00611Sdyoung update_stats(sc, an, frame_size,
625d1f00611Sdyoung ndx3, tries3,
626d1f00611Sdyoung 0, 0,
627d1f00611Sdyoung 0, 0,
628d1f00611Sdyoung 0, 0,
629d1f00611Sdyoung short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1 - tries2,
630d1f00611Sdyoung ds->ds_txstat.ts_status);
631d1f00611Sdyoung }
632d1f00611Sdyoung }
633d1f00611Sdyoung }
634d1f00611Sdyoung
635d1f00611Sdyoung void
ath_rate_newassoc(struct ath_softc * sc,struct ath_node * an,int isnew)636d1f00611Sdyoung ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
637d1f00611Sdyoung {
638d1f00611Sdyoung DPRINTF(sc, "%s: %s isnew %d\n", __func__,
639d1f00611Sdyoung ether_sprintf(an->an_node.ni_macaddr), isnew);
640d1f00611Sdyoung if (isnew)
641d1f00611Sdyoung ath_rate_ctl_reset(sc, &an->an_node);
642d1f00611Sdyoung }
643d1f00611Sdyoung
644d1f00611Sdyoung /*
645d1f00611Sdyoung * Initialize the tables for a node.
646d1f00611Sdyoung */
647d1f00611Sdyoung static void
ath_rate_ctl_reset(struct ath_softc * sc,struct ieee80211_node * ni)648d1f00611Sdyoung ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
649d1f00611Sdyoung {
650d1f00611Sdyoung #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
651d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
652d1f00611Sdyoung struct ath_node *an = ATH_NODE(ni);
653d1f00611Sdyoung struct sample_node *sn = ATH_NODE_SAMPLE(an);
654d1f00611Sdyoung const HAL_RATE_TABLE *rt = sc->sc_currates;
655d1f00611Sdyoung int x, y, srate;
656d1f00611Sdyoung
657216b022dSdyoung KASSERTMSG(rt != NULL, "no rate table, mode %u", sc->sc_curmode);
658d1f00611Sdyoung sn->static_rate_ndx = -1;
659dc2bd8a8Sskrll if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
660d1f00611Sdyoung /*
661d1f00611Sdyoung * A fixed rate is to be used; ic_fixed_rate is an
662d1f00611Sdyoung * index into the supported rate set. Convert this
663d1f00611Sdyoung * to the index into the negotiated rate set for
664d1f00611Sdyoung * the node. We know the rate is there because the
665d1f00611Sdyoung * rate set is checked when the station associates.
666d1f00611Sdyoung */
667d1f00611Sdyoung const struct ieee80211_rateset *rs =
668d1f00611Sdyoung &ic->ic_sup_rates[ic->ic_curmode];
669d1f00611Sdyoung int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
670d1f00611Sdyoung /* NB: the rate set is assumed sorted */
671d1f00611Sdyoung srate = ni->ni_rates.rs_nrates - 1;
672d1f00611Sdyoung for (; srate >= 0 && RATE(srate) != r; srate--)
673d1f00611Sdyoung ;
674216b022dSdyoung KASSERTMSG(srate >= 0,
675216b022dSdyoung "fixed rate %d not in rate set", ic->ic_fixed_rate);
676d1f00611Sdyoung sn->static_rate_ndx = srate;
677d1f00611Sdyoung }
678d1f00611Sdyoung
679d1f00611Sdyoung DPRINTF(sc, "%s: %s size 1600 rate/tt", __func__, ether_sprintf(ni->ni_macaddr));
680d1f00611Sdyoung
681d1f00611Sdyoung sn->num_rates = ni->ni_rates.rs_nrates;
682d1f00611Sdyoung for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
683d1f00611Sdyoung sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
684d1f00611Sdyoung sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
685d1f00611Sdyoung sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
686d1f00611Sdyoung sn->rates[x].shortPreambleRateCode =
687d1f00611Sdyoung rt->info[sn->rates[x].rix].rateCode |
688d1f00611Sdyoung rt->info[sn->rates[x].rix].shortPreamble;
689d1f00611Sdyoung
690d1f00611Sdyoung DPRINTF(sc, " %d/%d", sn->rates[x].rate,
691d1f00611Sdyoung calc_usecs_unicast_packet(sc, 1600, sn->rates[x].rix,
692d1f00611Sdyoung 0,0));
693d1f00611Sdyoung }
694d1f00611Sdyoung DPRINTF(sc, "%s\n", "");
695d1f00611Sdyoung
696d1f00611Sdyoung /* set the visible bit-rate to the lowest one available */
697d1f00611Sdyoung ni->ni_txrate = 0;
698d1f00611Sdyoung sn->num_rates = ni->ni_rates.rs_nrates;
699d1f00611Sdyoung
700d1f00611Sdyoung for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
701d1f00611Sdyoung int size = bin_to_size(y);
70225e9e914Sdyoung int ndx = 0;
703d1f00611Sdyoung sn->packets_sent[y] = 0;
704d1f00611Sdyoung sn->current_sample_ndx[y] = -1;
705d1f00611Sdyoung sn->last_sample_ndx[y] = 0;
706d1f00611Sdyoung
707d1f00611Sdyoung for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
708d1f00611Sdyoung sn->stats[y][x].successive_failures = 0;
709d1f00611Sdyoung sn->stats[y][x].tries = 0;
710d1f00611Sdyoung sn->stats[y][x].total_packets = 0;
711d1f00611Sdyoung sn->stats[y][x].packets_acked = 0;
712d1f00611Sdyoung sn->stats[y][x].last_tx = 0;
713d1f00611Sdyoung
714d1f00611Sdyoung sn->stats[y][x].perfect_tx_time =
715d1f00611Sdyoung calc_usecs_unicast_packet(sc, size,
716d1f00611Sdyoung sn->rates[x].rix,
717d1f00611Sdyoung 0, 0);
718d1f00611Sdyoung sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time;
719d1f00611Sdyoung }
72025e9e914Sdyoung
72125e9e914Sdyoung /* set the initial rate */
72225e9e914Sdyoung for (ndx = sn->num_rates-1; ndx > 0; ndx--) {
72325e9e914Sdyoung if (sn->rates[ndx].rate <= 72) {
72425e9e914Sdyoung break;
725d1f00611Sdyoung }
72625e9e914Sdyoung }
72725e9e914Sdyoung sn->current_rate[y] = ndx;
72825e9e914Sdyoung }
72925e9e914Sdyoung
73025e9e914Sdyoung DPRINTF(sc, "%s: %s %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n",
73125e9e914Sdyoung __func__, ether_sprintf(ni->ni_macaddr),
73225e9e914Sdyoung sn->num_rates,
73325e9e914Sdyoung sn->rates[0].rate/2, sn->rates[0].rate % 0x1 ? ".5" : "",
73425e9e914Sdyoung sn->stats[1][0].perfect_tx_time,
73525e9e914Sdyoung sn->rates[sn->num_rates-1].rate/2,
73625e9e914Sdyoung sn->rates[sn->num_rates-1].rate % 0x1 ? ".5" : "",
73725e9e914Sdyoung sn->stats[1][sn->num_rates-1].perfect_tx_time
73825e9e914Sdyoung );
73925e9e914Sdyoung
74025e9e914Sdyoung ni->ni_txrate = sn->current_rate[0];
741d1f00611Sdyoung #undef RATE
742d1f00611Sdyoung }
743d1f00611Sdyoung
744d1f00611Sdyoung static void
rate_cb(void * arg,struct ieee80211_node * ni)745d1f00611Sdyoung rate_cb(void *arg, struct ieee80211_node *ni)
746d1f00611Sdyoung {
747d1f00611Sdyoung struct ath_softc *sc = arg;
748d1f00611Sdyoung
749d1f00611Sdyoung ath_rate_newassoc(sc, ATH_NODE(ni), 1);
750d1f00611Sdyoung }
751d1f00611Sdyoung
752d1f00611Sdyoung /*
753d1f00611Sdyoung * Reset the rate control state for each 802.11 state transition.
754d1f00611Sdyoung */
755d1f00611Sdyoung void
ath_rate_newstate(struct ath_softc * sc,enum ieee80211_state state)756d1f00611Sdyoung ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
757d1f00611Sdyoung {
758d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
759d1f00611Sdyoung
760d1f00611Sdyoung if (state == IEEE80211_S_RUN) {
761d1f00611Sdyoung if (ic->ic_opmode != IEEE80211_M_STA) {
762d1f00611Sdyoung /*
763d1f00611Sdyoung * Sync rates for associated stations and neighbors.
764d1f00611Sdyoung */
765d1f00611Sdyoung ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc);
766d1f00611Sdyoung }
767d1f00611Sdyoung ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
768d1f00611Sdyoung }
769d1f00611Sdyoung }
770d1f00611Sdyoung
771d1f00611Sdyoung static void
ath_rate_sysctlattach(struct ath_softc * sc,struct sample_softc * osc)772d1f00611Sdyoung ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
773d1f00611Sdyoung {
77481071408Sdyoung int rc;
77581071408Sdyoung struct sysctllog **log = &sc->sc_sysctllog;
77681071408Sdyoung const struct sysctlnode *cnode, *rnode;
77781071408Sdyoung
77852c17c89Sjoerg if ((rnode = ath_sysctl_instance(device_xname(sc->sc_dev), log)) == NULL)
77981071408Sdyoung return;
780d1f00611Sdyoung
781d1f00611Sdyoung /* XXX bounds check [0..100] */
78281071408Sdyoung if ((rc = SYSCTL_PFX_INT(osc->ath_, CTLFLAG_READWRITE, smoothing_rate,
78381071408Sdyoung "rate control: retry threshold to credit rate raise (%%)")) != 0)
78481071408Sdyoung goto err;
78581071408Sdyoung
786d1f00611Sdyoung /* XXX bounds check [2..100] */
78781071408Sdyoung if ((rc = SYSCTL_PFX_INT(osc->ath_, CTLFLAG_READWRITE, sample_rate,
78881071408Sdyoung "rate control: # good periods before raising rate")) != 0)
78981071408Sdyoung goto err;
79081071408Sdyoung
79181071408Sdyoung return;
79281071408Sdyoung err:
79381071408Sdyoung printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
794d1f00611Sdyoung }
795d1f00611Sdyoung
796d1f00611Sdyoung struct ath_ratectrl *
ath_rate_attach(struct ath_softc * sc)797d1f00611Sdyoung ath_rate_attach(struct ath_softc *sc)
798d1f00611Sdyoung {
799d1f00611Sdyoung struct sample_softc *osc;
800d1f00611Sdyoung
801d1f00611Sdyoung DPRINTF(sc, "%s:\n", __func__);
802d47bcd29Schs osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_WAITOK|M_ZERO);
803d1f00611Sdyoung osc->arc.arc_space = sizeof(struct sample_node);
804d1f00611Sdyoung osc->ath_smoothing_rate = 95; /* ewma percentage (out of 100) */
805d1f00611Sdyoung osc->ath_sample_rate = 10; /* send a different bit-rate 1/X packets */
806d1f00611Sdyoung ath_rate_sysctlattach(sc, osc);
807d1f00611Sdyoung return &osc->arc;
808d1f00611Sdyoung }
809d1f00611Sdyoung
810d1f00611Sdyoung void
ath_rate_detach(struct ath_ratectrl * arc)811d1f00611Sdyoung ath_rate_detach(struct ath_ratectrl *arc)
812d1f00611Sdyoung {
813d1f00611Sdyoung struct sample_softc *osc = (struct sample_softc *) arc;
814d1f00611Sdyoung
815d1f00611Sdyoung free(osc, M_DEVBUF);
816d1f00611Sdyoung }
817