1*d47bcd29Schs /* $NetBSD: athrate-amrr.c,v 1.13 2019/11/10 21:16:35 chs Exp $ */
2fd8cfc5eSxtraeme
3d1f00611Sdyoung /*-
4d1f00611Sdyoung * Copyright (c) 2004 INRIA
5d1f00611Sdyoung * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
6d1f00611Sdyoung * All rights reserved.
7d1f00611Sdyoung *
8d1f00611Sdyoung * Redistribution and use in source and binary forms, with or without
9d1f00611Sdyoung * modification, are permitted provided that the following conditions
10d1f00611Sdyoung * are met:
11d1f00611Sdyoung * 1. Redistributions of source code must retain the above copyright
12d1f00611Sdyoung * notice, this list of conditions and the following disclaimer,
13d1f00611Sdyoung * without modification.
14d1f00611Sdyoung * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15d1f00611Sdyoung * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
16d1f00611Sdyoung * redistribution must be conditioned upon including a substantially
17d1f00611Sdyoung * similar Disclaimer requirement for further binary redistribution.
18d1f00611Sdyoung * 3. Neither the names of the above-listed copyright holders nor the names
19d1f00611Sdyoung * of any contributors may be used to endorse or promote products derived
20d1f00611Sdyoung * from this software without specific prior written permission.
21d1f00611Sdyoung *
22d1f00611Sdyoung * Alternatively, this software may be distributed under the terms of the
23d1f00611Sdyoung * GNU General Public License ("GPL") version 2 as published by the Free
24d1f00611Sdyoung * Software Foundation.
25d1f00611Sdyoung *
26d1f00611Sdyoung * NO WARRANTY
27d1f00611Sdyoung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28d1f00611Sdyoung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29d1f00611Sdyoung * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
30d1f00611Sdyoung * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
31d1f00611Sdyoung * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
32d1f00611Sdyoung * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33d1f00611Sdyoung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34d1f00611Sdyoung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
35d1f00611Sdyoung * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36d1f00611Sdyoung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
37d1f00611Sdyoung * THE POSSIBILITY OF SUCH DAMAGES.
38d1f00611Sdyoung *
39d1f00611Sdyoung */
40d1f00611Sdyoung
41d1f00611Sdyoung #include <sys/cdefs.h>
42fd8cfc5eSxtraeme #ifdef __FreeBSD__
43dc2bd8a8Sskrll __FBSDID("$FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.c,v 1.10 2005/08/09 10:19:43 rwatson Exp $");
44fd8cfc5eSxtraeme #endif
45fd8cfc5eSxtraeme #ifdef __NetBSD__
46*d47bcd29Schs __KERNEL_RCSID(0, "$NetBSD: athrate-amrr.c,v 1.13 2019/11/10 21:16:35 chs Exp $");
47fd8cfc5eSxtraeme #endif
48d1f00611Sdyoung
49d1f00611Sdyoung /*
50d1f00611Sdyoung * AMRR rate control. See:
51d1f00611Sdyoung * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
52d1f00611Sdyoung * "IEEE 802.11 Rate Adaptation: A Practical Approach" by
53d1f00611Sdyoung * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
54d1f00611Sdyoung */
55d1f00611Sdyoung #include "opt_inet.h"
56d1f00611Sdyoung
57d1f00611Sdyoung #include <sys/param.h>
58d1f00611Sdyoung #include <sys/systm.h>
59d1f00611Sdyoung #include <sys/sysctl.h>
60d1f00611Sdyoung #include <sys/kernel.h>
61d1f00611Sdyoung #include <sys/errno.h>
62a2a38285Sad #include <sys/bus.h>
63d1f00611Sdyoung #include <sys/socket.h>
64d1f00611Sdyoung
65d1f00611Sdyoung #include <net/if.h>
66d1f00611Sdyoung #include <net/if_media.h>
67d1f00611Sdyoung #include <net/if_arp.h>
6890634029Sdyoung #include <net/if_ether.h> /* XXX for ether_sprintf */
69d1f00611Sdyoung
70d1f00611Sdyoung #include <net80211/ieee80211_var.h>
71d1f00611Sdyoung
72d1f00611Sdyoung #include <net/bpf.h>
73d1f00611Sdyoung
74d1f00611Sdyoung #ifdef INET
75d1f00611Sdyoung #include <netinet/in.h>
76d1f00611Sdyoung #endif
77d1f00611Sdyoung
7890634029Sdyoung #include <dev/ic/athvar.h>
7990634029Sdyoung #include <dev/ic/athrate-amrr.h>
805d561f94Salc
815d561f94Salc #include <external/isc/atheros_hal/dist/ah.h>
82d1f00611Sdyoung
83d1f00611Sdyoung #define AMRR_DEBUG
84d1f00611Sdyoung #ifdef AMRR_DEBUG
85d1f00611Sdyoung #define DPRINTF(sc, _fmt, ...) do { \
86d1f00611Sdyoung if (sc->sc_debug & 0x10) \
87d1f00611Sdyoung printf(_fmt, __VA_ARGS__); \
88d1f00611Sdyoung } while (0)
89d1f00611Sdyoung #else
90d1f00611Sdyoung #define DPRINTF(sc, _fmt, ...)
91d1f00611Sdyoung #endif
92d1f00611Sdyoung
93d1f00611Sdyoung static int ath_rateinterval = 1000; /* rate ctl interval (ms) */
94d1f00611Sdyoung static int ath_rate_max_success_threshold = 10;
95d1f00611Sdyoung static int ath_rate_min_success_threshold = 1;
96d1f00611Sdyoung
97d1f00611Sdyoung static void ath_ratectl(void *);
98d1f00611Sdyoung static void ath_rate_update(struct ath_softc *, struct ieee80211_node *,
99d1f00611Sdyoung int rate);
100d1f00611Sdyoung static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
101d1f00611Sdyoung static void ath_rate_ctl(void *, struct ieee80211_node *);
102d1f00611Sdyoung
103d1f00611Sdyoung void
ath_rate_node_init(struct ath_softc * sc,struct ath_node * an)104d1f00611Sdyoung ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
105d1f00611Sdyoung {
106d1f00611Sdyoung /* NB: assumed to be zero'd by caller */
107d1f00611Sdyoung ath_rate_update(sc, &an->an_node, 0);
108d1f00611Sdyoung }
109d1f00611Sdyoung
110d1f00611Sdyoung void
ath_rate_node_cleanup(struct ath_softc * sc,struct ath_node * an)111d1f00611Sdyoung ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
112d1f00611Sdyoung {
113d1f00611Sdyoung }
114d1f00611Sdyoung
115d1f00611Sdyoung 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)116d1f00611Sdyoung ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
117d1f00611Sdyoung int shortPreamble, size_t frameLen,
118d1f00611Sdyoung u_int8_t *rix, int *try0, u_int8_t *txrate)
119d1f00611Sdyoung {
120d1f00611Sdyoung struct amrr_node *amn = ATH_NODE_AMRR(an);
121d1f00611Sdyoung
122d1f00611Sdyoung *rix = amn->amn_tx_rix0;
123d1f00611Sdyoung *try0 = amn->amn_tx_try0;
124d1f00611Sdyoung if (shortPreamble)
125d1f00611Sdyoung *txrate = amn->amn_tx_rate0sp;
126d1f00611Sdyoung else
127d1f00611Sdyoung *txrate = amn->amn_tx_rate0;
128d1f00611Sdyoung }
129d1f00611Sdyoung
130d1f00611Sdyoung void
ath_rate_setupxtxdesc(struct ath_softc * sc,struct ath_node * an,struct ath_desc * ds,int shortPreamble,u_int8_t rix)131d1f00611Sdyoung ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
132d1f00611Sdyoung struct ath_desc *ds, int shortPreamble, u_int8_t rix)
133d1f00611Sdyoung {
134d1f00611Sdyoung struct amrr_node *amn = ATH_NODE_AMRR(an);
135d1f00611Sdyoung
136d1f00611Sdyoung ath_hal_setupxtxdesc(sc->sc_ah, ds
137d1f00611Sdyoung , amn->amn_tx_rate1sp, amn->amn_tx_try1 /* series 1 */
138d1f00611Sdyoung , amn->amn_tx_rate2sp, amn->amn_tx_try2 /* series 2 */
139d1f00611Sdyoung , amn->amn_tx_rate3sp, amn->amn_tx_try3 /* series 3 */
140d1f00611Sdyoung );
141d1f00611Sdyoung }
142d1f00611Sdyoung
143d1f00611Sdyoung void
ath_rate_tx_complete(struct ath_softc * sc,struct ath_node * an,const struct ath_desc * ds,const struct ath_desc * ds0)144d1f00611Sdyoung ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
145d1f00611Sdyoung const struct ath_desc *ds, const struct ath_desc *ds0)
146d1f00611Sdyoung {
147d1f00611Sdyoung struct amrr_node *amn = ATH_NODE_AMRR(an);
148d1f00611Sdyoung int sr = ds->ds_txstat.ts_shortretry;
149d1f00611Sdyoung int lr = ds->ds_txstat.ts_longretry;
150d1f00611Sdyoung int retry_count = sr + lr;
151d1f00611Sdyoung
152d1f00611Sdyoung amn->amn_tx_try0_cnt++;
153d1f00611Sdyoung if (retry_count == 1) {
154d1f00611Sdyoung amn->amn_tx_try1_cnt++;
155d1f00611Sdyoung } else if (retry_count == 2) {
156d1f00611Sdyoung amn->amn_tx_try1_cnt++;
157d1f00611Sdyoung amn->amn_tx_try2_cnt++;
158d1f00611Sdyoung } else if (retry_count == 3) {
159d1f00611Sdyoung amn->amn_tx_try1_cnt++;
160d1f00611Sdyoung amn->amn_tx_try2_cnt++;
161d1f00611Sdyoung amn->amn_tx_try3_cnt++;
162d1f00611Sdyoung } else if (retry_count > 3) {
163d1f00611Sdyoung amn->amn_tx_try1_cnt++;
164d1f00611Sdyoung amn->amn_tx_try2_cnt++;
165d1f00611Sdyoung amn->amn_tx_try3_cnt++;
166d1f00611Sdyoung amn->amn_tx_failure_cnt++;
167d1f00611Sdyoung }
168d1f00611Sdyoung }
169d1f00611Sdyoung
170d1f00611Sdyoung void
ath_rate_newassoc(struct ath_softc * sc,struct ath_node * an,int isnew)171d1f00611Sdyoung ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
172d1f00611Sdyoung {
173d1f00611Sdyoung if (isnew)
174d1f00611Sdyoung ath_rate_ctl_start(sc, &an->an_node);
175d1f00611Sdyoung }
176d1f00611Sdyoung
177d1f00611Sdyoung static void
node_reset(struct amrr_node * amn)178d1f00611Sdyoung node_reset (struct amrr_node *amn)
179d1f00611Sdyoung {
180d1f00611Sdyoung amn->amn_tx_try0_cnt = 0;
181d1f00611Sdyoung amn->amn_tx_try1_cnt = 0;
182d1f00611Sdyoung amn->amn_tx_try2_cnt = 0;
183d1f00611Sdyoung amn->amn_tx_try3_cnt = 0;
184d1f00611Sdyoung amn->amn_tx_failure_cnt = 0;
185d1f00611Sdyoung amn->amn_success = 0;
186d1f00611Sdyoung amn->amn_recovery = 0;
187d1f00611Sdyoung amn->amn_success_threshold = ath_rate_min_success_threshold;
188d1f00611Sdyoung }
189d1f00611Sdyoung
190d1f00611Sdyoung
191d1f00611Sdyoung /**
192d1f00611Sdyoung * The code below assumes that we are dealing with hardware multi rate retry
193d1f00611Sdyoung * I have no idea what will happen if you try to use this module with another
194d1f00611Sdyoung * type of hardware. Your machine might catch fire or it might work with
195d1f00611Sdyoung * horrible performance...
196d1f00611Sdyoung */
197d1f00611Sdyoung static void
ath_rate_update(struct ath_softc * sc,struct ieee80211_node * ni,int rate)198d1f00611Sdyoung ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
199d1f00611Sdyoung {
200d1f00611Sdyoung struct ath_node *an = ATH_NODE(ni);
201d1f00611Sdyoung struct amrr_node *amn = ATH_NODE_AMRR(an);
202d1f00611Sdyoung const HAL_RATE_TABLE *rt = sc->sc_currates;
203d1f00611Sdyoung u_int8_t rix;
204d1f00611Sdyoung
205216b022dSdyoung KASSERTMSG(rt != NULL, "no rate table, mode %u", sc->sc_curmode);
206d1f00611Sdyoung
207d1f00611Sdyoung DPRINTF(sc, "%s: set xmit rate for %s to %dM\n",
208d1f00611Sdyoung __func__, ether_sprintf(ni->ni_macaddr),
209d1f00611Sdyoung ni->ni_rates.rs_nrates > 0 ?
210d1f00611Sdyoung (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0);
211d1f00611Sdyoung
212d1f00611Sdyoung ni->ni_txrate = rate;
213d1f00611Sdyoung /*
214d1f00611Sdyoung * Before associating a node has no rate set setup
215d1f00611Sdyoung * so we can't calculate any transmit codes to use.
216d1f00611Sdyoung * This is ok since we should never be sending anything
217d1f00611Sdyoung * but management frames and those always go at the
218d1f00611Sdyoung * lowest hardware rate.
219d1f00611Sdyoung */
220d1f00611Sdyoung if (ni->ni_rates.rs_nrates > 0) {
221d1f00611Sdyoung amn->amn_tx_rix0 = sc->sc_rixmap[
222d1f00611Sdyoung ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL];
223d1f00611Sdyoung amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode;
224d1f00611Sdyoung amn->amn_tx_rate0sp = amn->amn_tx_rate0 |
225d1f00611Sdyoung rt->info[amn->amn_tx_rix0].shortPreamble;
226d1f00611Sdyoung if (sc->sc_mrretry) {
227d1f00611Sdyoung amn->amn_tx_try0 = 1;
228d1f00611Sdyoung amn->amn_tx_try1 = 1;
229d1f00611Sdyoung amn->amn_tx_try2 = 1;
230d1f00611Sdyoung amn->amn_tx_try3 = 1;
231d1f00611Sdyoung if (--rate >= 0) {
232d1f00611Sdyoung rix = sc->sc_rixmap[
233d1f00611Sdyoung ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
234d1f00611Sdyoung amn->amn_tx_rate1 = rt->info[rix].rateCode;
235d1f00611Sdyoung amn->amn_tx_rate1sp = amn->amn_tx_rate1 |
236d1f00611Sdyoung rt->info[rix].shortPreamble;
237d1f00611Sdyoung } else {
238d1f00611Sdyoung amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
239d1f00611Sdyoung }
240d1f00611Sdyoung if (--rate >= 0) {
241d1f00611Sdyoung rix = sc->sc_rixmap[
242d1f00611Sdyoung ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL];
243d1f00611Sdyoung amn->amn_tx_rate2 = rt->info[rix].rateCode;
244d1f00611Sdyoung amn->amn_tx_rate2sp = amn->amn_tx_rate2 |
245d1f00611Sdyoung rt->info[rix].shortPreamble;
246d1f00611Sdyoung } else {
247d1f00611Sdyoung amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
248d1f00611Sdyoung }
249d1f00611Sdyoung if (rate > 0) {
250d1f00611Sdyoung /* NB: only do this if we didn't already do it above */
251d1f00611Sdyoung amn->amn_tx_rate3 = rt->info[0].rateCode;
252d1f00611Sdyoung amn->amn_tx_rate3sp =
25325e9e914Sdyoung an->an_tx_rate3 | rt->info[0].shortPreamble;
254d1f00611Sdyoung } else {
255d1f00611Sdyoung amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
256d1f00611Sdyoung }
257d1f00611Sdyoung } else {
258d1f00611Sdyoung amn->amn_tx_try0 = ATH_TXMAXTRY;
259d1f00611Sdyoung /* theorically, these statements are useless because
260d1f00611Sdyoung * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY
261d1f00611Sdyoung */
262d1f00611Sdyoung amn->amn_tx_try1 = 0;
263d1f00611Sdyoung amn->amn_tx_try2 = 0;
264d1f00611Sdyoung amn->amn_tx_try3 = 0;
265d1f00611Sdyoung amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0;
266d1f00611Sdyoung amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0;
267d1f00611Sdyoung amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0;
268d1f00611Sdyoung }
269d1f00611Sdyoung }
270d1f00611Sdyoung node_reset (amn);
271d1f00611Sdyoung }
272d1f00611Sdyoung
273d1f00611Sdyoung /*
274d1f00611Sdyoung * Set the starting transmit rate for a node.
275d1f00611Sdyoung */
276d1f00611Sdyoung static void
ath_rate_ctl_start(struct ath_softc * sc,struct ieee80211_node * ni)277d1f00611Sdyoung ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
278d1f00611Sdyoung {
279d1f00611Sdyoung #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
280d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
281d1f00611Sdyoung int srate;
282d1f00611Sdyoung
283216b022dSdyoung KASSERTMSG(ni->ni_rates.rs_nrates > 0, "no rates");
284dc2bd8a8Sskrll if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
285d1f00611Sdyoung /*
286d1f00611Sdyoung * No fixed rate is requested. For 11b start with
287d1f00611Sdyoung * the highest negotiated rate; otherwise, for 11g
288d1f00611Sdyoung * and 11a, we start "in the middle" at 24Mb or 36Mb.
289d1f00611Sdyoung */
290d1f00611Sdyoung srate = ni->ni_rates.rs_nrates - 1;
291d1f00611Sdyoung if (sc->sc_curmode != IEEE80211_MODE_11B) {
292d1f00611Sdyoung /*
293d1f00611Sdyoung * Scan the negotiated rate set to find the
294d1f00611Sdyoung * closest rate.
295d1f00611Sdyoung */
296d1f00611Sdyoung /* NB: the rate set is assumed sorted */
297d1f00611Sdyoung for (; srate >= 0 && RATE(srate) > 72; srate--)
298d1f00611Sdyoung ;
299216b022dSdyoung KASSERTMSG(srate >= 0, "bogus rate set");
300d1f00611Sdyoung }
301d1f00611Sdyoung } else {
302d1f00611Sdyoung /*
303d1f00611Sdyoung * A fixed rate is to be used; ic_fixed_rate is an
304d1f00611Sdyoung * index into the supported rate set. Convert this
305d1f00611Sdyoung * to the index into the negotiated rate set for
306d1f00611Sdyoung * the node. We know the rate is there because the
307d1f00611Sdyoung * rate set is checked when the station associates.
308d1f00611Sdyoung */
309d1f00611Sdyoung const struct ieee80211_rateset *rs =
310d1f00611Sdyoung &ic->ic_sup_rates[ic->ic_curmode];
311d1f00611Sdyoung int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
312d1f00611Sdyoung /* NB: the rate set is assumed sorted */
313d1f00611Sdyoung srate = ni->ni_rates.rs_nrates - 1;
314d1f00611Sdyoung for (; srate >= 0 && RATE(srate) != r; srate--)
315d1f00611Sdyoung ;
316216b022dSdyoung KASSERTMSG(srate >= 0,
317216b022dSdyoung "fixed rate %d not in rate set", ic->ic_fixed_rate);
318d1f00611Sdyoung }
319d1f00611Sdyoung ath_rate_update(sc, ni, srate);
320d1f00611Sdyoung #undef RATE
321d1f00611Sdyoung }
322d1f00611Sdyoung
323d1f00611Sdyoung static void
ath_rate_cb(void * arg,struct ieee80211_node * ni)324d1f00611Sdyoung ath_rate_cb(void *arg, struct ieee80211_node *ni)
325d1f00611Sdyoung {
326d1f00611Sdyoung struct ath_softc *sc = arg;
327d1f00611Sdyoung
328d1f00611Sdyoung ath_rate_update(sc, ni, 0);
329d1f00611Sdyoung }
330d1f00611Sdyoung
331d1f00611Sdyoung /*
332d1f00611Sdyoung * Reset the rate control state for each 802.11 state transition.
333d1f00611Sdyoung */
334d1f00611Sdyoung void
ath_rate_newstate(struct ath_softc * sc,enum ieee80211_state state)335d1f00611Sdyoung ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
336d1f00611Sdyoung {
337d1f00611Sdyoung struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc;
338d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
339d1f00611Sdyoung struct ieee80211_node *ni;
340d1f00611Sdyoung
341d1f00611Sdyoung if (state == IEEE80211_S_INIT) {
342d1f00611Sdyoung callout_stop(&asc->timer);
343d1f00611Sdyoung return;
344d1f00611Sdyoung }
345d1f00611Sdyoung if (ic->ic_opmode == IEEE80211_M_STA) {
346d1f00611Sdyoung /*
347d1f00611Sdyoung * Reset local xmit state; this is really only
348d1f00611Sdyoung * meaningful when operating in station mode.
349d1f00611Sdyoung */
350d1f00611Sdyoung ni = ic->ic_bss;
351d1f00611Sdyoung if (state == IEEE80211_S_RUN) {
352d1f00611Sdyoung ath_rate_ctl_start(sc, ni);
353d1f00611Sdyoung } else {
354d1f00611Sdyoung ath_rate_update(sc, ni, 0);
355d1f00611Sdyoung }
356d1f00611Sdyoung } else {
357d1f00611Sdyoung /*
358d1f00611Sdyoung * When operating as a station the node table holds
359d1f00611Sdyoung * the AP's that were discovered during scanning.
360d1f00611Sdyoung * For any other operating mode we want to reset the
361d1f00611Sdyoung * tx rate state of each node.
362d1f00611Sdyoung */
363d1f00611Sdyoung ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, sc);
364d1f00611Sdyoung ath_rate_update(sc, ic->ic_bss, 0);
365d1f00611Sdyoung }
366dc2bd8a8Sskrll if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE &&
367dc2bd8a8Sskrll state == IEEE80211_S_RUN) {
368d1f00611Sdyoung int interval;
369d1f00611Sdyoung /*
370d1f00611Sdyoung * Start the background rate control thread if we
371d1f00611Sdyoung * are not configured to use a fixed xmit rate.
372d1f00611Sdyoung */
373d1f00611Sdyoung interval = ath_rateinterval;
374d1f00611Sdyoung if (ic->ic_opmode == IEEE80211_M_STA)
375d1f00611Sdyoung interval /= 2;
376d1f00611Sdyoung callout_reset(&asc->timer, (interval * hz) / 1000,
377d1f00611Sdyoung ath_ratectl, &sc->sc_if);
378d1f00611Sdyoung }
379d1f00611Sdyoung }
380d1f00611Sdyoung
381d1f00611Sdyoung /*
382d1f00611Sdyoung * Examine and potentially adjust the transmit rate.
383d1f00611Sdyoung */
384d1f00611Sdyoung static void
ath_rate_ctl(void * arg,struct ieee80211_node * ni)385d1f00611Sdyoung ath_rate_ctl(void *arg, struct ieee80211_node *ni)
386d1f00611Sdyoung {
387d1f00611Sdyoung struct ath_softc *sc = arg;
388d1f00611Sdyoung struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni));
389d1f00611Sdyoung int old_rate;
390d1f00611Sdyoung
391d1f00611Sdyoung #define is_success(amn) \
392d1f00611Sdyoung (amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10))
393d1f00611Sdyoung #define is_enough(amn) \
394d1f00611Sdyoung (amn->amn_tx_try0_cnt > 10)
395d1f00611Sdyoung #define is_failure(amn) \
396d1f00611Sdyoung (amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3))
397d1f00611Sdyoung #define is_max_rate(ni) \
398d1f00611Sdyoung ((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates)
399d1f00611Sdyoung #define is_min_rate(ni) \
400d1f00611Sdyoung (ni->ni_txrate == 0)
401d1f00611Sdyoung
402d1f00611Sdyoung old_rate = ni->ni_txrate;
403d1f00611Sdyoung
404d1f00611Sdyoung DPRINTF (sc, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n",
405d1f00611Sdyoung amn->amn_tx_try0_cnt,
406d1f00611Sdyoung amn->amn_tx_try1_cnt,
407d1f00611Sdyoung amn->amn_tx_try2_cnt,
408d1f00611Sdyoung amn->amn_tx_try3_cnt,
409d1f00611Sdyoung amn->amn_success_threshold);
410d1f00611Sdyoung if (is_success (amn) && is_enough (amn)) {
411d1f00611Sdyoung amn->amn_success++;
412d1f00611Sdyoung if (amn->amn_success == amn->amn_success_threshold &&
413d1f00611Sdyoung !is_max_rate (ni)) {
414d1f00611Sdyoung amn->amn_recovery = 1;
415d1f00611Sdyoung amn->amn_success = 0;
416d1f00611Sdyoung ni->ni_txrate++;
417d1f00611Sdyoung DPRINTF (sc, "increase rate to %d\n", ni->ni_txrate);
418d1f00611Sdyoung } else {
419d1f00611Sdyoung amn->amn_recovery = 0;
420d1f00611Sdyoung }
421d1f00611Sdyoung } else if (is_failure (amn)) {
422d1f00611Sdyoung amn->amn_success = 0;
423d1f00611Sdyoung if (!is_min_rate (ni)) {
424d1f00611Sdyoung if (amn->amn_recovery) {
425d1f00611Sdyoung /* recovery failure. */
426d1f00611Sdyoung amn->amn_success_threshold *= 2;
427d1f00611Sdyoung amn->amn_success_threshold = min (amn->amn_success_threshold,
428d1f00611Sdyoung (u_int)ath_rate_max_success_threshold);
429d1f00611Sdyoung DPRINTF (sc, "decrease rate recovery thr: %d\n", amn->amn_success_threshold);
430d1f00611Sdyoung } else {
431d1f00611Sdyoung /* simple failure. */
432d1f00611Sdyoung amn->amn_success_threshold = ath_rate_min_success_threshold;
433d1f00611Sdyoung DPRINTF (sc, "decrease rate normal thr: %d\n", amn->amn_success_threshold);
434d1f00611Sdyoung }
435d1f00611Sdyoung amn->amn_recovery = 0;
436d1f00611Sdyoung ni->ni_txrate--;
437d1f00611Sdyoung } else {
438d1f00611Sdyoung amn->amn_recovery = 0;
439d1f00611Sdyoung }
440d1f00611Sdyoung
441d1f00611Sdyoung }
442d1f00611Sdyoung if (is_enough (amn) || old_rate != ni->ni_txrate) {
443d1f00611Sdyoung /* reset counters. */
444d1f00611Sdyoung amn->amn_tx_try0_cnt = 0;
445d1f00611Sdyoung amn->amn_tx_try1_cnt = 0;
446d1f00611Sdyoung amn->amn_tx_try2_cnt = 0;
447d1f00611Sdyoung amn->amn_tx_try3_cnt = 0;
448d1f00611Sdyoung amn->amn_tx_failure_cnt = 0;
449d1f00611Sdyoung }
450d1f00611Sdyoung if (old_rate != ni->ni_txrate) {
451d1f00611Sdyoung ath_rate_update(sc, ni, ni->ni_txrate);
452d1f00611Sdyoung }
453d1f00611Sdyoung }
454d1f00611Sdyoung
455d1f00611Sdyoung static void
ath_ratectl(void * arg)456d1f00611Sdyoung ath_ratectl(void *arg)
457d1f00611Sdyoung {
458d1f00611Sdyoung struct ifnet *ifp = arg;
459d1f00611Sdyoung struct ath_softc *sc = ifp->if_softc;
460d1f00611Sdyoung struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc;
461d1f00611Sdyoung struct ieee80211com *ic = &sc->sc_ic;
462d1f00611Sdyoung int interval;
463d1f00611Sdyoung
464dc2bd8a8Sskrll if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
465d1f00611Sdyoung sc->sc_stats.ast_rate_calls++;
466d1f00611Sdyoung
467d1f00611Sdyoung if (ic->ic_opmode == IEEE80211_M_STA)
468d1f00611Sdyoung ath_rate_ctl(sc, ic->ic_bss); /* NB: no reference */
469d1f00611Sdyoung else
470d1f00611Sdyoung ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_ctl, sc);
471d1f00611Sdyoung }
472d1f00611Sdyoung interval = ath_rateinterval;
473d1f00611Sdyoung if (ic->ic_opmode == IEEE80211_M_STA)
474d1f00611Sdyoung interval /= 2;
475d1f00611Sdyoung callout_reset(&asc->timer, (interval * hz) / 1000,
476d1f00611Sdyoung ath_ratectl, &sc->sc_if);
477d1f00611Sdyoung }
478d1f00611Sdyoung
479d1f00611Sdyoung static void
ath_rate_sysctlattach(struct ath_softc * sc)480d1f00611Sdyoung ath_rate_sysctlattach(struct ath_softc *sc)
481d1f00611Sdyoung {
482d1f00611Sdyoung struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
483d1f00611Sdyoung struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
484d1f00611Sdyoung
485d1f00611Sdyoung SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
486d1f00611Sdyoung "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0,
487d1f00611Sdyoung "rate control: operation interval (ms)");
488d1f00611Sdyoung /* XXX bounds check values */
489d1f00611Sdyoung SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
490d1f00611Sdyoung "max_sucess_threshold", CTLFLAG_RW,
491d1f00611Sdyoung &ath_rate_max_success_threshold, 0, "");
492d1f00611Sdyoung SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
493d1f00611Sdyoung "min_sucess_threshold", CTLFLAG_RW,
494d1f00611Sdyoung &ath_rate_min_success_threshold, 0, "");
495d1f00611Sdyoung }
496d1f00611Sdyoung
497d1f00611Sdyoung struct ath_ratectrl *
ath_rate_attach(struct ath_softc * sc)498d1f00611Sdyoung ath_rate_attach(struct ath_softc *sc)
499d1f00611Sdyoung {
500d1f00611Sdyoung struct amrr_softc *asc;
501d1f00611Sdyoung
502*d47bcd29Schs asc = malloc(sizeof(struct amrr_softc), M_DEVBUF, M_WAITOK|M_ZERO);
503d1f00611Sdyoung asc->arc.arc_space = sizeof(struct amrr_node);
504d1f00611Sdyoung callout_init(&asc->timer, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
505d1f00611Sdyoung ath_rate_sysctlattach(sc);
506d1f00611Sdyoung
507d1f00611Sdyoung return &asc->arc;
508d1f00611Sdyoung }
509d1f00611Sdyoung
510d1f00611Sdyoung void
ath_rate_detach(struct ath_ratectrl * arc)511d1f00611Sdyoung ath_rate_detach(struct ath_ratectrl *arc)
512d1f00611Sdyoung {
513d1f00611Sdyoung struct amrr_softc *asc = (struct amrr_softc *) arc;
514d1f00611Sdyoung
515d1f00611Sdyoung callout_drain(&asc->timer);
516d1f00611Sdyoung free(asc, M_DEVBUF);
517d1f00611Sdyoung }
518