amrr.c revision 170530
1138569Ssam/*- 2138569Ssam * Copyright (c) 2004 INRIA 3139530Ssam * Copyright (c) 2002-2005 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 170530 2007-06-11 03:36:55Z 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, 117144546Ssam int 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, 132144546Ssam struct ath_desc *ds, int 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 144144347Ssamath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 145165185Ssam const struct ath_buf *bf) 146138569Ssam{ 147138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 148165185Ssam const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; 149165185Ssam int sr = ts->ts_shortretry; 150165185Ssam int lr = ts->ts_longretry; 151138569Ssam int retry_count = sr + lr; 152138569Ssam 153138569Ssam amn->amn_tx_try0_cnt++; 154138569Ssam if (retry_count == 1) { 155138569Ssam amn->amn_tx_try1_cnt++; 156138569Ssam } else if (retry_count == 2) { 157138569Ssam amn->amn_tx_try1_cnt++; 158138569Ssam amn->amn_tx_try2_cnt++; 159138569Ssam } else if (retry_count == 3) { 160138569Ssam amn->amn_tx_try1_cnt++; 161138569Ssam amn->amn_tx_try2_cnt++; 162138569Ssam amn->amn_tx_try3_cnt++; 163138569Ssam } else if (retry_count > 3) { 164138569Ssam amn->amn_tx_try1_cnt++; 165138569Ssam amn->amn_tx_try2_cnt++; 166138569Ssam amn->amn_tx_try3_cnt++; 167138569Ssam amn->amn_tx_failure_cnt++; 168138569Ssam } 169138569Ssam} 170138569Ssam 171138569Ssamvoid 172138569Ssamath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 173138569Ssam{ 174138569Ssam if (isnew) 175138569Ssam ath_rate_ctl_start(sc, &an->an_node); 176138569Ssam} 177138569Ssam 178138569Ssamstatic void 179138569Ssamnode_reset (struct amrr_node *amn) 180138569Ssam{ 181138569Ssam amn->amn_tx_try0_cnt = 0; 182138569Ssam amn->amn_tx_try1_cnt = 0; 183138569Ssam amn->amn_tx_try2_cnt = 0; 184138569Ssam amn->amn_tx_try3_cnt = 0; 185138569Ssam amn->amn_tx_failure_cnt = 0; 186138569Ssam amn->amn_success = 0; 187138569Ssam amn->amn_recovery = 0; 188138569Ssam amn->amn_success_threshold = ath_rate_min_success_threshold; 189138569Ssam} 190138569Ssam 191138569Ssam 192138569Ssam/** 193138569Ssam * The code below assumes that we are dealing with hardware multi rate retry 194138569Ssam * I have no idea what will happen if you try to use this module with another 195138569Ssam * type of hardware. Your machine might catch fire or it might work with 196138569Ssam * horrible performance... 197138569Ssam */ 198138569Ssamstatic void 199138569Ssamath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) 200138569Ssam{ 201138569Ssam struct ath_node *an = ATH_NODE(ni); 202138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 203138569Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 204138569Ssam u_int8_t rix; 205138569Ssam 206138569Ssam KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 207138569Ssam 208138569Ssam DPRINTF(sc, "%s: set xmit rate for %s to %dM\n", 209138569Ssam __func__, ether_sprintf(ni->ni_macaddr), 210138569Ssam ni->ni_rates.rs_nrates > 0 ? 211138569Ssam (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); 212138569Ssam 213138569Ssam ni->ni_txrate = rate; 214138569Ssam /* 215138569Ssam * Before associating a node has no rate set setup 216138569Ssam * so we can't calculate any transmit codes to use. 217138569Ssam * This is ok since we should never be sending anything 218138569Ssam * but management frames and those always go at the 219138569Ssam * lowest hardware rate. 220138569Ssam */ 221138569Ssam if (ni->ni_rates.rs_nrates > 0) { 222138569Ssam amn->amn_tx_rix0 = sc->sc_rixmap[ 223138569Ssam ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL]; 224138569Ssam amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode; 225138569Ssam amn->amn_tx_rate0sp = amn->amn_tx_rate0 | 226138569Ssam rt->info[amn->amn_tx_rix0].shortPreamble; 227138569Ssam if (sc->sc_mrretry) { 228138569Ssam amn->amn_tx_try0 = 1; 229138569Ssam amn->amn_tx_try1 = 1; 230138569Ssam amn->amn_tx_try2 = 1; 231138569Ssam amn->amn_tx_try3 = 1; 232138569Ssam if (--rate >= 0) { 233138569Ssam rix = sc->sc_rixmap[ 234138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 235138569Ssam amn->amn_tx_rate1 = rt->info[rix].rateCode; 236138569Ssam amn->amn_tx_rate1sp = amn->amn_tx_rate1 | 237138569Ssam rt->info[rix].shortPreamble; 238138569Ssam } else { 239138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 240138569Ssam } 241138569Ssam if (--rate >= 0) { 242138569Ssam rix = sc->sc_rixmap[ 243138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 244138569Ssam amn->amn_tx_rate2 = rt->info[rix].rateCode; 245138569Ssam amn->amn_tx_rate2sp = amn->amn_tx_rate2 | 246138569Ssam rt->info[rix].shortPreamble; 247138569Ssam } else { 248138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 249138569Ssam } 250138569Ssam if (rate > 0) { 251138569Ssam /* NB: only do this if we didn't already do it above */ 252138569Ssam amn->amn_tx_rate3 = rt->info[0].rateCode; 253138569Ssam amn->amn_tx_rate3sp = 254155477Ssam amn->amn_tx_rate3 | rt->info[0].shortPreamble; 255138569Ssam } else { 256138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 257138569Ssam } 258138569Ssam } else { 259138569Ssam amn->amn_tx_try0 = ATH_TXMAXTRY; 260138569Ssam /* theorically, these statements are useless because 261138569Ssam * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY 262138569Ssam */ 263138569Ssam amn->amn_tx_try1 = 0; 264138569Ssam amn->amn_tx_try2 = 0; 265138569Ssam amn->amn_tx_try3 = 0; 266138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 267138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 268138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 269138569Ssam } 270138569Ssam } 271138569Ssam node_reset (amn); 272138569Ssam} 273138569Ssam 274138569Ssam/* 275138569Ssam * Set the starting transmit rate for a node. 276138569Ssam */ 277138569Ssamstatic void 278138569Ssamath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) 279138569Ssam{ 280138569Ssam#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 281138569Ssam struct ieee80211com *ic = &sc->sc_ic; 282138569Ssam int srate; 283138569Ssam 284138569Ssam KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); 285148290Ssam if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 286138569Ssam /* 287138569Ssam * No fixed rate is requested. For 11b start with 288138569Ssam * the highest negotiated rate; otherwise, for 11g 289138569Ssam * and 11a, we start "in the middle" at 24Mb or 36Mb. 290138569Ssam */ 291138569Ssam srate = ni->ni_rates.rs_nrates - 1; 292138569Ssam if (sc->sc_curmode != IEEE80211_MODE_11B) { 293138569Ssam /* 294138569Ssam * Scan the negotiated rate set to find the 295138569Ssam * closest rate. 296138569Ssam */ 297138569Ssam /* NB: the rate set is assumed sorted */ 298138569Ssam for (; srate >= 0 && RATE(srate) > 72; srate--) 299138569Ssam ; 300138569Ssam } 301138569Ssam } else { 302138569Ssam /* 303170530Ssam * A fixed rate is to be used; ic_fixed_rate is the 304170530Ssam * IEEE code for this rate (sans basic bit). Convert this 305138569Ssam * to the index into the negotiated rate set for 306138569Ssam * the node. We know the rate is there because the 307138569Ssam * rate set is checked when the station associates. 308138569Ssam */ 309138569Ssam /* NB: the rate set is assumed sorted */ 310138569Ssam srate = ni->ni_rates.rs_nrates - 1; 311170530Ssam for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--) 312138569Ssam ; 313138569Ssam } 314170530Ssam /* 315170530Ssam * The selected rate may not be available due to races 316170530Ssam * and mode settings. Also orphaned nodes created in 317170530Ssam * adhoc mode may not have any rate set so this lookup 318170530Ssam * can fail. This is not fatal. 319170530Ssam */ 320170530Ssam ath_rate_update(sc, ni, srate < 0 ? 0 : srate); 321138569Ssam#undef RATE 322138569Ssam} 323138569Ssam 324138569Ssamstatic void 325138569Ssamath_rate_cb(void *arg, struct ieee80211_node *ni) 326138569Ssam{ 327144306Ssam struct ath_softc *sc = arg; 328144306Ssam 329144306Ssam ath_rate_update(sc, ni, 0); 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 */ 364144306Ssam ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, sc); 365138569Ssam ath_rate_update(sc, ic->ic_bss, 0); 366138569Ssam } 367148290Ssam if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE && 368148290Ssam 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, 378147256Sbrooks ath_ratectl, sc->sc_ifp); 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 465148887Srwatson if (ifp->if_drv_flags & IFF_DRV_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 */ 470140753Ssam else 471140753Ssam ieee80211_iterate_nodes(&ic->ic_sta, 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, 477147256Sbrooks ath_ratectl, sc->sc_ifp); 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