amrr.c revision 138569
1138569Ssam/*- 2138569Ssam * Copyright (c) 2004 INRIA 3138569Ssam * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting 4138569Ssam * All rights reserved. 5138569Ssam * 6138569Ssam * Redistribution and use in source and binary forms, with or without 7138569Ssam * modification, are permitted provided that the following conditions 8138569Ssam * are met: 9138569Ssam * 1. Redistributions of source code must retain the above copyright 10138569Ssam * notice, this list of conditions and the following disclaimer, 11138569Ssam * without modification. 12138569Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13138569Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14138569Ssam * redistribution must be conditioned upon including a substantially 15138569Ssam * similar Disclaimer requirement for further binary redistribution. 16138569Ssam * 3. Neither the names of the above-listed copyright holders nor the names 17138569Ssam * of any contributors may be used to endorse or promote products derived 18138569Ssam * from this software without specific prior written permission. 19138569Ssam * 20138569Ssam * Alternatively, this software may be distributed under the terms of the 21138569Ssam * GNU General Public License ("GPL") version 2 as published by the Free 22138569Ssam * Software Foundation. 23138569Ssam * 24138569Ssam * NO WARRANTY 25138569Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26138569Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27138569Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 28138569Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 29138569Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 30138569Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31138569Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32138569Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 33138569Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34138569Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35138569Ssam * THE POSSIBILITY OF SUCH DAMAGES. 36138569Ssam * 37138569Ssam */ 38138569Ssam 39138569Ssam#include <sys/cdefs.h> 40138569Ssam__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/amrr/amrr.c 138569 2004-12-08 17:32:02Z sam $"); 41138569Ssam 42138569Ssam/* 43138569Ssam * AMRR rate control. See: 44138569Ssam * http://www-sop.inria.fr/rapports/sophia/RR-5208.html 45138569Ssam * "IEEE 802.11 Rate Adaptation: A Practical Approach" by 46138569Ssam * Mathieu Lacage, Hossein Manshaei, Thierry Turletti 47138569Ssam */ 48138569Ssam#include "opt_inet.h" 49138569Ssam 50138569Ssam#include <sys/param.h> 51138569Ssam#include <sys/systm.h> 52138569Ssam#include <sys/sysctl.h> 53138569Ssam#include <sys/module.h> 54138569Ssam#include <sys/kernel.h> 55138569Ssam#include <sys/lock.h> 56138569Ssam#include <sys/mutex.h> 57138569Ssam#include <sys/errno.h> 58138569Ssam 59138569Ssam#include <machine/bus.h> 60138569Ssam#include <machine/resource.h> 61138569Ssam#include <sys/bus.h> 62138569Ssam 63138569Ssam#include <sys/socket.h> 64138569Ssam 65138569Ssam#include <net/if.h> 66138569Ssam#include <net/if_media.h> 67138569Ssam#include <net/if_arp.h> 68138569Ssam#include <net/ethernet.h> /* XXX for ether_sprintf */ 69138569Ssam 70138569Ssam#include <net80211/ieee80211_var.h> 71138569Ssam 72138569Ssam#include <net/bpf.h> 73138569Ssam 74138569Ssam#ifdef INET 75138569Ssam#include <netinet/in.h> 76138569Ssam#include <netinet/if_ether.h> 77138569Ssam#endif 78138569Ssam 79138569Ssam#include <dev/ath/if_athvar.h> 80138569Ssam#include <dev/ath/ath_rate/amrr/amrr.h> 81138569Ssam#include <contrib/dev/ath/ah_desc.h> 82138569Ssam 83138569Ssam#define AMRR_DEBUG 84138569Ssam#ifdef AMRR_DEBUG 85138569Ssam#define DPRINTF(sc, _fmt, ...) do { \ 86138569Ssam if (sc->sc_debug & 0x10) \ 87138569Ssam printf(_fmt, __VA_ARGS__); \ 88138569Ssam} while (0) 89138569Ssam#else 90138569Ssam#define DPRINTF(sc, _fmt, ...) 91138569Ssam#endif 92138569Ssam 93138569Ssamstatic int ath_rateinterval = 1000; /* rate ctl interval (ms) */ 94138569Ssamstatic int ath_rate_max_success_threshold = 10; 95138569Ssamstatic int ath_rate_min_success_threshold = 1; 96138569Ssam 97138569Ssamstatic void ath_ratectl(void *); 98138569Ssamstatic void ath_rate_update(struct ath_softc *, struct ieee80211_node *, 99138569Ssam int rate); 100138569Ssamstatic void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *); 101138569Ssamstatic void ath_rate_ctl(void *, struct ieee80211_node *); 102138569Ssam 103138569Ssamvoid 104138569Ssamath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 105138569Ssam{ 106138569Ssam /* NB: assumed to be zero'd by caller */ 107138569Ssam ath_rate_update(sc, &an->an_node, 0); 108138569Ssam} 109138569Ssam 110138569Ssamvoid 111138569Ssamath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 112138569Ssam{ 113138569Ssam} 114138569Ssam 115138569Ssamvoid 116138569Ssamath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 117138569Ssam HAL_BOOL shortPreamble, size_t frameLen, 118138569Ssam u_int8_t *rix, int *try0, u_int8_t *txrate) 119138569Ssam{ 120138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 121138569Ssam 122138569Ssam *rix = amn->amn_tx_rix0; 123138569Ssam *try0 = amn->amn_tx_try0; 124138569Ssam if (shortPreamble) 125138569Ssam *txrate = amn->amn_tx_rate0sp; 126138569Ssam else 127138569Ssam *txrate = amn->amn_tx_rate0; 128138569Ssam} 129138569Ssam 130138569Ssamvoid 131138569Ssamath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 132138569Ssam struct ath_desc *ds, HAL_BOOL shortPreamble, u_int8_t rix) 133138569Ssam{ 134138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 135138569Ssam 136138569Ssam ath_hal_setupxtxdesc(sc->sc_ah, ds 137138569Ssam , amn->amn_tx_rate1sp, amn->amn_tx_try1 /* series 1 */ 138138569Ssam , amn->amn_tx_rate2sp, amn->amn_tx_try2 /* series 2 */ 139138569Ssam , amn->amn_tx_rate3sp, amn->amn_tx_try3 /* series 3 */ 140138569Ssam ); 141138569Ssam} 142138569Ssam 143138569Ssamvoid 144138569Ssamath_rate_tx_complete(struct ath_softc *sc, 145138569Ssam struct ath_node *an, const struct ath_desc *ds) 146138569Ssam{ 147138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 148138569Ssam int sr = ds->ds_txstat.ts_shortretry; 149138569Ssam int lr = ds->ds_txstat.ts_longretry; 150138569Ssam int retry_count = sr + lr; 151138569Ssam 152138569Ssam amn->amn_tx_try0_cnt++; 153138569Ssam if (retry_count == 1) { 154138569Ssam amn->amn_tx_try1_cnt++; 155138569Ssam } else if (retry_count == 2) { 156138569Ssam amn->amn_tx_try1_cnt++; 157138569Ssam amn->amn_tx_try2_cnt++; 158138569Ssam } else if (retry_count == 3) { 159138569Ssam amn->amn_tx_try1_cnt++; 160138569Ssam amn->amn_tx_try2_cnt++; 161138569Ssam amn->amn_tx_try3_cnt++; 162138569Ssam } else if (retry_count > 3) { 163138569Ssam amn->amn_tx_try1_cnt++; 164138569Ssam amn->amn_tx_try2_cnt++; 165138569Ssam amn->amn_tx_try3_cnt++; 166138569Ssam amn->amn_tx_failure_cnt++; 167138569Ssam } 168138569Ssam} 169138569Ssam 170138569Ssamvoid 171138569Ssamath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 172138569Ssam{ 173138569Ssam if (isnew) 174138569Ssam ath_rate_ctl_start(sc, &an->an_node); 175138569Ssam} 176138569Ssam 177138569Ssamstatic void 178138569Ssamnode_reset (struct amrr_node *amn) 179138569Ssam{ 180138569Ssam amn->amn_tx_try0_cnt = 0; 181138569Ssam amn->amn_tx_try1_cnt = 0; 182138569Ssam amn->amn_tx_try2_cnt = 0; 183138569Ssam amn->amn_tx_try3_cnt = 0; 184138569Ssam amn->amn_tx_failure_cnt = 0; 185138569Ssam amn->amn_success = 0; 186138569Ssam amn->amn_recovery = 0; 187138569Ssam amn->amn_success_threshold = ath_rate_min_success_threshold; 188138569Ssam} 189138569Ssam 190138569Ssam 191138569Ssam/** 192138569Ssam * The code below assumes that we are dealing with hardware multi rate retry 193138569Ssam * I have no idea what will happen if you try to use this module with another 194138569Ssam * type of hardware. Your machine might catch fire or it might work with 195138569Ssam * horrible performance... 196138569Ssam */ 197138569Ssamstatic void 198138569Ssamath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) 199138569Ssam{ 200138569Ssam struct ath_node *an = ATH_NODE(ni); 201138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 202138569Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 203138569Ssam u_int8_t rix; 204138569Ssam 205138569Ssam KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 206138569Ssam 207138569Ssam DPRINTF(sc, "%s: set xmit rate for %s to %dM\n", 208138569Ssam __func__, ether_sprintf(ni->ni_macaddr), 209138569Ssam ni->ni_rates.rs_nrates > 0 ? 210138569Ssam (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); 211138569Ssam 212138569Ssam ni->ni_txrate = rate; 213138569Ssam /* XXX management/control frames always go at the lowest speed */ 214138569Ssam an->an_tx_mgtrate = rt->info[0].rateCode; 215138569Ssam an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; 216138569Ssam /* 217138569Ssam * Before associating a node has no rate set setup 218138569Ssam * so we can't calculate any transmit codes to use. 219138569Ssam * This is ok since we should never be sending anything 220138569Ssam * but management frames and those always go at the 221138569Ssam * lowest hardware rate. 222138569Ssam */ 223138569Ssam if (ni->ni_rates.rs_nrates > 0) { 224138569Ssam amn->amn_tx_rix0 = sc->sc_rixmap[ 225138569Ssam ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL]; 226138569Ssam amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode; 227138569Ssam amn->amn_tx_rate0sp = amn->amn_tx_rate0 | 228138569Ssam rt->info[amn->amn_tx_rix0].shortPreamble; 229138569Ssam if (sc->sc_mrretry) { 230138569Ssam amn->amn_tx_try0 = 1; 231138569Ssam amn->amn_tx_try1 = 1; 232138569Ssam amn->amn_tx_try2 = 1; 233138569Ssam amn->amn_tx_try3 = 1; 234138569Ssam if (--rate >= 0) { 235138569Ssam rix = sc->sc_rixmap[ 236138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 237138569Ssam amn->amn_tx_rate1 = rt->info[rix].rateCode; 238138569Ssam amn->amn_tx_rate1sp = amn->amn_tx_rate1 | 239138569Ssam rt->info[rix].shortPreamble; 240138569Ssam } else { 241138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 242138569Ssam } 243138569Ssam if (--rate >= 0) { 244138569Ssam rix = sc->sc_rixmap[ 245138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 246138569Ssam amn->amn_tx_rate2 = rt->info[rix].rateCode; 247138569Ssam amn->amn_tx_rate2sp = amn->amn_tx_rate2 | 248138569Ssam rt->info[rix].shortPreamble; 249138569Ssam } else { 250138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 251138569Ssam } 252138569Ssam if (rate > 0) { 253138569Ssam /* NB: only do this if we didn't already do it above */ 254138569Ssam amn->amn_tx_rate3 = rt->info[0].rateCode; 255138569Ssam amn->amn_tx_rate3sp = 256138569Ssam an->an_tx_mgtrate | rt->info[0].shortPreamble; 257138569Ssam } else { 258138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 259138569Ssam } 260138569Ssam } else { 261138569Ssam amn->amn_tx_try0 = ATH_TXMAXTRY; 262138569Ssam /* theorically, these statements are useless because 263138569Ssam * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY 264138569Ssam */ 265138569Ssam amn->amn_tx_try1 = 0; 266138569Ssam amn->amn_tx_try2 = 0; 267138569Ssam amn->amn_tx_try3 = 0; 268138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 269138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 270138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 271138569Ssam } 272138569Ssam } 273138569Ssam node_reset (amn); 274138569Ssam} 275138569Ssam 276138569Ssam/* 277138569Ssam * Set the starting transmit rate for a node. 278138569Ssam */ 279138569Ssamstatic void 280138569Ssamath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) 281138569Ssam{ 282138569Ssam#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 283138569Ssam struct ieee80211com *ic = &sc->sc_ic; 284138569Ssam int srate; 285138569Ssam 286138569Ssam KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); 287138569Ssam if (ic->ic_fixed_rate == -1) { 288138569Ssam /* 289138569Ssam * No fixed rate is requested. For 11b start with 290138569Ssam * the highest negotiated rate; otherwise, for 11g 291138569Ssam * and 11a, we start "in the middle" at 24Mb or 36Mb. 292138569Ssam */ 293138569Ssam srate = ni->ni_rates.rs_nrates - 1; 294138569Ssam if (sc->sc_curmode != IEEE80211_MODE_11B) { 295138569Ssam /* 296138569Ssam * Scan the negotiated rate set to find the 297138569Ssam * closest rate. 298138569Ssam */ 299138569Ssam /* NB: the rate set is assumed sorted */ 300138569Ssam for (; srate >= 0 && RATE(srate) > 72; srate--) 301138569Ssam ; 302138569Ssam KASSERT(srate >= 0, ("bogus rate set")); 303138569Ssam } 304138569Ssam } else { 305138569Ssam /* 306138569Ssam * A fixed rate is to be used; ic_fixed_rate is an 307138569Ssam * index into the supported rate set. Convert this 308138569Ssam * to the index into the negotiated rate set for 309138569Ssam * the node. We know the rate is there because the 310138569Ssam * rate set is checked when the station associates. 311138569Ssam */ 312138569Ssam const struct ieee80211_rateset *rs = 313138569Ssam &ic->ic_sup_rates[ic->ic_curmode]; 314138569Ssam int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; 315138569Ssam /* NB: the rate set is assumed sorted */ 316138569Ssam srate = ni->ni_rates.rs_nrates - 1; 317138569Ssam for (; srate >= 0 && RATE(srate) != r; srate--) 318138569Ssam ; 319138569Ssam KASSERT(srate >= 0, 320138569Ssam ("fixed rate %d not in rate set", ic->ic_fixed_rate)); 321138569Ssam } 322138569Ssam ath_rate_update(sc, ni, srate); 323138569Ssam#undef RATE 324138569Ssam} 325138569Ssam 326138569Ssamstatic void 327138569Ssamath_rate_cb(void *arg, struct ieee80211_node *ni) 328138569Ssam{ 329138569Ssam ath_rate_update(ni->ni_ic->ic_ifp->if_softc, ni, (int) arg); 330138569Ssam} 331138569Ssam 332138569Ssam/* 333138569Ssam * Reset the rate control state for each 802.11 state transition. 334138569Ssam */ 335138569Ssamvoid 336138569Ssamath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state) 337138569Ssam{ 338138569Ssam struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc; 339138569Ssam struct ieee80211com *ic = &sc->sc_ic; 340138569Ssam struct ieee80211_node *ni; 341138569Ssam 342138569Ssam if (state == IEEE80211_S_INIT) { 343138569Ssam callout_stop(&asc->timer); 344138569Ssam return; 345138569Ssam } 346138569Ssam if (ic->ic_opmode == IEEE80211_M_STA) { 347138569Ssam /* 348138569Ssam * Reset local xmit state; this is really only 349138569Ssam * meaningful when operating in station mode. 350138569Ssam */ 351138569Ssam ni = ic->ic_bss; 352138569Ssam if (state == IEEE80211_S_RUN) { 353138569Ssam ath_rate_ctl_start(sc, ni); 354138569Ssam } else { 355138569Ssam ath_rate_update(sc, ni, 0); 356138569Ssam } 357138569Ssam } else { 358138569Ssam /* 359138569Ssam * When operating as a station the node table holds 360138569Ssam * the AP's that were discovered during scanning. 361138569Ssam * For any other operating mode we want to reset the 362138569Ssam * tx rate state of each node. 363138569Ssam */ 364138569Ssam if (ic->ic_sta != NULL) 365138569Ssam ieee80211_iterate_nodes(ic->ic_sta, ath_rate_cb, 0); 366138569Ssam ath_rate_update(sc, ic->ic_bss, 0); 367138569Ssam } 368138569Ssam if (ic->ic_fixed_rate == -1 && state == IEEE80211_S_RUN) { 369138569Ssam int interval; 370138569Ssam /* 371138569Ssam * Start the background rate control thread if we 372138569Ssam * are not configured to use a fixed xmit rate. 373138569Ssam */ 374138569Ssam interval = ath_rateinterval; 375138569Ssam if (ic->ic_opmode == IEEE80211_M_STA) 376138569Ssam interval /= 2; 377138569Ssam callout_reset(&asc->timer, (interval * hz) / 1000, 378138569Ssam ath_ratectl, &sc->sc_if); 379138569Ssam } 380138569Ssam} 381138569Ssam 382138569Ssam/* 383138569Ssam * Examine and potentially adjust the transmit rate. 384138569Ssam */ 385138569Ssamstatic void 386138569Ssamath_rate_ctl(void *arg, struct ieee80211_node *ni) 387138569Ssam{ 388138569Ssam struct ath_softc *sc = arg; 389138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni)); 390138569Ssam int old_rate; 391138569Ssam 392138569Ssam#define is_success(amn) \ 393138569Ssam(amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10)) 394138569Ssam#define is_enough(amn) \ 395138569Ssam(amn->amn_tx_try0_cnt > 10) 396138569Ssam#define is_failure(amn) \ 397138569Ssam(amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3)) 398138569Ssam#define is_max_rate(ni) \ 399138569Ssam((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates) 400138569Ssam#define is_min_rate(ni) \ 401138569Ssam(ni->ni_txrate == 0) 402138569Ssam 403138569Ssam old_rate = ni->ni_txrate; 404138569Ssam 405138569Ssam DPRINTF (sc, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n", 406138569Ssam amn->amn_tx_try0_cnt, 407138569Ssam amn->amn_tx_try1_cnt, 408138569Ssam amn->amn_tx_try2_cnt, 409138569Ssam amn->amn_tx_try3_cnt, 410138569Ssam amn->amn_success_threshold); 411138569Ssam if (is_success (amn) && is_enough (amn)) { 412138569Ssam amn->amn_success++; 413138569Ssam if (amn->amn_success == amn->amn_success_threshold && 414138569Ssam !is_max_rate (ni)) { 415138569Ssam amn->amn_recovery = 1; 416138569Ssam amn->amn_success = 0; 417138569Ssam ni->ni_txrate++; 418138569Ssam DPRINTF (sc, "increase rate to %d\n", ni->ni_txrate); 419138569Ssam } else { 420138569Ssam amn->amn_recovery = 0; 421138569Ssam } 422138569Ssam } else if (is_failure (amn)) { 423138569Ssam amn->amn_success = 0; 424138569Ssam if (!is_min_rate (ni)) { 425138569Ssam if (amn->amn_recovery) { 426138569Ssam /* recovery failure. */ 427138569Ssam amn->amn_success_threshold *= 2; 428138569Ssam amn->amn_success_threshold = min (amn->amn_success_threshold, 429138569Ssam (u_int)ath_rate_max_success_threshold); 430138569Ssam DPRINTF (sc, "decrease rate recovery thr: %d\n", amn->amn_success_threshold); 431138569Ssam } else { 432138569Ssam /* simple failure. */ 433138569Ssam amn->amn_success_threshold = ath_rate_min_success_threshold; 434138569Ssam DPRINTF (sc, "decrease rate normal thr: %d\n", amn->amn_success_threshold); 435138569Ssam } 436138569Ssam amn->amn_recovery = 0; 437138569Ssam ni->ni_txrate--; 438138569Ssam } else { 439138569Ssam amn->amn_recovery = 0; 440138569Ssam } 441138569Ssam 442138569Ssam } 443138569Ssam if (is_enough (amn) || old_rate != ni->ni_txrate) { 444138569Ssam /* reset counters. */ 445138569Ssam amn->amn_tx_try0_cnt = 0; 446138569Ssam amn->amn_tx_try1_cnt = 0; 447138569Ssam amn->amn_tx_try2_cnt = 0; 448138569Ssam amn->amn_tx_try3_cnt = 0; 449138569Ssam amn->amn_tx_failure_cnt = 0; 450138569Ssam } 451138569Ssam if (old_rate != ni->ni_txrate) { 452138569Ssam ath_rate_update(sc, ni, ni->ni_txrate); 453138569Ssam } 454138569Ssam} 455138569Ssam 456138569Ssamstatic void 457138569Ssamath_ratectl(void *arg) 458138569Ssam{ 459138569Ssam struct ifnet *ifp = arg; 460138569Ssam struct ath_softc *sc = ifp->if_softc; 461138569Ssam struct amrr_softc *asc = (struct amrr_softc *) sc->sc_rc; 462138569Ssam struct ieee80211com *ic = &sc->sc_ic; 463138569Ssam int interval; 464138569Ssam 465138569Ssam if (ifp->if_flags & IFF_RUNNING) { 466138569Ssam sc->sc_stats.ast_rate_calls++; 467138569Ssam 468138569Ssam if (ic->ic_opmode == IEEE80211_M_STA) 469138569Ssam ath_rate_ctl(sc, ic->ic_bss); /* NB: no reference */ 470138569Ssam else if (ic->ic_sta != NULL) 471138569Ssam ieee80211_iterate_nodes(ic, ath_rate_ctl, sc); 472138569Ssam } 473138569Ssam interval = ath_rateinterval; 474138569Ssam if (ic->ic_opmode == IEEE80211_M_STA) 475138569Ssam interval /= 2; 476138569Ssam callout_reset(&asc->timer, (interval * hz) / 1000, 477138569Ssam ath_ratectl, &sc->sc_if); 478138569Ssam} 479138569Ssam 480138569Ssamstatic void 481138569Ssamath_rate_sysctlattach(struct ath_softc *sc) 482138569Ssam{ 483138569Ssam struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 484138569Ssam struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 485138569Ssam 486138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 487138569Ssam "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0, 488138569Ssam "rate control: operation interval (ms)"); 489138569Ssam /* XXX bounds check values */ 490138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 491138569Ssam "max_sucess_threshold", CTLFLAG_RW, 492138569Ssam &ath_rate_max_success_threshold, 0, ""); 493138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 494138569Ssam "min_sucess_threshold", CTLFLAG_RW, 495138569Ssam &ath_rate_min_success_threshold, 0, ""); 496138569Ssam} 497138569Ssam 498138569Ssamstruct ath_ratectrl * 499138569Ssamath_rate_attach(struct ath_softc *sc) 500138569Ssam{ 501138569Ssam struct amrr_softc *asc; 502138569Ssam 503138569Ssam asc = malloc(sizeof(struct amrr_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 504138569Ssam if (asc == NULL) 505138569Ssam return NULL; 506138569Ssam asc->arc.arc_space = sizeof(struct amrr_node); 507138569Ssam callout_init(&asc->timer, debug_mpsafenet ? CALLOUT_MPSAFE : 0); 508138569Ssam ath_rate_sysctlattach(sc); 509138569Ssam 510138569Ssam return &asc->arc; 511138569Ssam} 512138569Ssam 513138569Ssamvoid 514138569Ssamath_rate_detach(struct ath_ratectrl *arc) 515138569Ssam{ 516138569Ssam struct amrr_softc *asc = (struct amrr_softc *) arc; 517138569Ssam 518138569Ssam callout_drain(&asc->timer); 519138569Ssam free(asc, M_DEVBUF); 520138569Ssam} 521138569Ssam 522138569Ssam/* 523138569Ssam * Module glue. 524138569Ssam */ 525138569Ssamstatic int 526138569Ssamamrr_modevent(module_t mod, int type, void *unused) 527138569Ssam{ 528138569Ssam switch (type) { 529138569Ssam case MOD_LOAD: 530138569Ssam if (bootverbose) 531138569Ssam printf("ath_rate: <AMRR rate control algorithm> version 0.1\n"); 532138569Ssam return 0; 533138569Ssam case MOD_UNLOAD: 534138569Ssam return 0; 535138569Ssam } 536138569Ssam return EINVAL; 537138569Ssam} 538138569Ssam 539138569Ssamstatic moduledata_t amrr_mod = { 540138569Ssam "ath_rate", 541138569Ssam amrr_modevent, 542138569Ssam 0 543138569Ssam}; 544138569SsamDECLARE_MODULE(ath_rate, amrr_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 545138569SsamMODULE_VERSION(ath_rate, 1); 546138569SsamMODULE_DEPEND(ath_rate, wlan, 1, 1, 1); 547