amrr.c revision 178354
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 178354 2008-04-20 20:35:46Z 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" 49178354Ssam#include "opt_wlan.h" 50138569Ssam 51138569Ssam#include <sys/param.h> 52138569Ssam#include <sys/systm.h> 53138569Ssam#include <sys/sysctl.h> 54138569Ssam#include <sys/module.h> 55138569Ssam#include <sys/kernel.h> 56138569Ssam#include <sys/lock.h> 57138569Ssam#include <sys/mutex.h> 58138569Ssam#include <sys/errno.h> 59138569Ssam 60138569Ssam#include <machine/bus.h> 61138569Ssam#include <machine/resource.h> 62138569Ssam#include <sys/bus.h> 63138569Ssam 64138569Ssam#include <sys/socket.h> 65138569Ssam 66138569Ssam#include <net/if.h> 67138569Ssam#include <net/if_media.h> 68138569Ssam#include <net/if_arp.h> 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 83138569Ssamstatic int ath_rateinterval = 1000; /* rate ctl interval (ms) */ 84138569Ssamstatic int ath_rate_max_success_threshold = 10; 85138569Ssamstatic int ath_rate_min_success_threshold = 1; 86138569Ssam 87138569Ssamstatic void ath_rate_update(struct ath_softc *, struct ieee80211_node *, 88138569Ssam int rate); 89138569Ssamstatic void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *); 90138569Ssamstatic void ath_rate_ctl(void *, struct ieee80211_node *); 91138569Ssam 92138569Ssamvoid 93138569Ssamath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 94138569Ssam{ 95138569Ssam /* NB: assumed to be zero'd by caller */ 96138569Ssam} 97138569Ssam 98138569Ssamvoid 99138569Ssamath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 100138569Ssam{ 101138569Ssam} 102138569Ssam 103138569Ssamvoid 104138569Ssamath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 105144546Ssam int shortPreamble, size_t frameLen, 106138569Ssam u_int8_t *rix, int *try0, u_int8_t *txrate) 107138569Ssam{ 108138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 109138569Ssam 110138569Ssam *rix = amn->amn_tx_rix0; 111138569Ssam *try0 = amn->amn_tx_try0; 112138569Ssam if (shortPreamble) 113138569Ssam *txrate = amn->amn_tx_rate0sp; 114138569Ssam else 115138569Ssam *txrate = amn->amn_tx_rate0; 116138569Ssam} 117138569Ssam 118138569Ssamvoid 119138569Ssamath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 120144546Ssam struct ath_desc *ds, int shortPreamble, u_int8_t rix) 121138569Ssam{ 122138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 123138569Ssam 124138569Ssam ath_hal_setupxtxdesc(sc->sc_ah, ds 125138569Ssam , amn->amn_tx_rate1sp, amn->amn_tx_try1 /* series 1 */ 126138569Ssam , amn->amn_tx_rate2sp, amn->amn_tx_try2 /* series 2 */ 127138569Ssam , amn->amn_tx_rate3sp, amn->amn_tx_try3 /* series 3 */ 128138569Ssam ); 129138569Ssam} 130138569Ssam 131138569Ssamvoid 132144347Ssamath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 133165185Ssam const struct ath_buf *bf) 134138569Ssam{ 135138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 136165185Ssam const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; 137165185Ssam int sr = ts->ts_shortretry; 138165185Ssam int lr = ts->ts_longretry; 139138569Ssam int retry_count = sr + lr; 140138569Ssam 141138569Ssam amn->amn_tx_try0_cnt++; 142138569Ssam if (retry_count == 1) { 143138569Ssam amn->amn_tx_try1_cnt++; 144138569Ssam } else if (retry_count == 2) { 145138569Ssam amn->amn_tx_try1_cnt++; 146138569Ssam amn->amn_tx_try2_cnt++; 147138569Ssam } else if (retry_count == 3) { 148138569Ssam amn->amn_tx_try1_cnt++; 149138569Ssam amn->amn_tx_try2_cnt++; 150138569Ssam amn->amn_tx_try3_cnt++; 151138569Ssam } else if (retry_count > 3) { 152138569Ssam amn->amn_tx_try1_cnt++; 153138569Ssam amn->amn_tx_try2_cnt++; 154138569Ssam amn->amn_tx_try3_cnt++; 155138569Ssam amn->amn_tx_failure_cnt++; 156138569Ssam } 157178354Ssam if (amn->amn_interval != 0 && 158178354Ssam ticks - amn->amn_ticks > amn->amn_interval) { 159178354Ssam ath_rate_ctl(sc, &an->an_node); 160178354Ssam amn->amn_ticks = ticks; 161178354Ssam } 162138569Ssam} 163138569Ssam 164138569Ssamvoid 165138569Ssamath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 166138569Ssam{ 167138569Ssam if (isnew) 168138569Ssam ath_rate_ctl_start(sc, &an->an_node); 169138569Ssam} 170138569Ssam 171138569Ssamstatic void 172178354Ssamnode_reset(struct amrr_node *amn) 173138569Ssam{ 174138569Ssam amn->amn_tx_try0_cnt = 0; 175138569Ssam amn->amn_tx_try1_cnt = 0; 176138569Ssam amn->amn_tx_try2_cnt = 0; 177138569Ssam amn->amn_tx_try3_cnt = 0; 178138569Ssam amn->amn_tx_failure_cnt = 0; 179138569Ssam amn->amn_success = 0; 180138569Ssam amn->amn_recovery = 0; 181138569Ssam amn->amn_success_threshold = ath_rate_min_success_threshold; 182138569Ssam} 183138569Ssam 184138569Ssam 185138569Ssam/** 186138569Ssam * The code below assumes that we are dealing with hardware multi rate retry 187138569Ssam * I have no idea what will happen if you try to use this module with another 188138569Ssam * type of hardware. Your machine might catch fire or it might work with 189138569Ssam * horrible performance... 190138569Ssam */ 191138569Ssamstatic void 192138569Ssamath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) 193138569Ssam{ 194138569Ssam struct ath_node *an = ATH_NODE(ni); 195138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(an); 196178354Ssam struct ieee80211vap *vap = ni->ni_vap; 197138569Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 198138569Ssam u_int8_t rix; 199138569Ssam 200138569Ssam KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 201138569Ssam 202178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL, ni, 203178354Ssam "%s: set xmit rate to %dM", __func__, 204138569Ssam ni->ni_rates.rs_nrates > 0 ? 205138569Ssam (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); 206138569Ssam 207178354Ssam amn->amn_rix = rate; 208138569Ssam /* 209138569Ssam * Before associating a node has no rate set setup 210138569Ssam * so we can't calculate any transmit codes to use. 211138569Ssam * This is ok since we should never be sending anything 212138569Ssam * but management frames and those always go at the 213138569Ssam * lowest hardware rate. 214138569Ssam */ 215138569Ssam if (ni->ni_rates.rs_nrates > 0) { 216178354Ssam ni->ni_txrate = ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL; 217178354Ssam amn->amn_tx_rix0 = sc->sc_rixmap[ni->ni_txrate]; 218138569Ssam amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode; 219138569Ssam amn->amn_tx_rate0sp = amn->amn_tx_rate0 | 220138569Ssam rt->info[amn->amn_tx_rix0].shortPreamble; 221138569Ssam if (sc->sc_mrretry) { 222138569Ssam amn->amn_tx_try0 = 1; 223138569Ssam amn->amn_tx_try1 = 1; 224138569Ssam amn->amn_tx_try2 = 1; 225138569Ssam amn->amn_tx_try3 = 1; 226138569Ssam if (--rate >= 0) { 227138569Ssam rix = sc->sc_rixmap[ 228138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 229138569Ssam amn->amn_tx_rate1 = rt->info[rix].rateCode; 230138569Ssam amn->amn_tx_rate1sp = amn->amn_tx_rate1 | 231138569Ssam rt->info[rix].shortPreamble; 232138569Ssam } else { 233138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 234138569Ssam } 235138569Ssam if (--rate >= 0) { 236138569Ssam rix = sc->sc_rixmap[ 237138569Ssam ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; 238138569Ssam amn->amn_tx_rate2 = rt->info[rix].rateCode; 239138569Ssam amn->amn_tx_rate2sp = amn->amn_tx_rate2 | 240138569Ssam rt->info[rix].shortPreamble; 241138569Ssam } else { 242138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 243138569Ssam } 244138569Ssam if (rate > 0) { 245138569Ssam /* NB: only do this if we didn't already do it above */ 246138569Ssam amn->amn_tx_rate3 = rt->info[0].rateCode; 247138569Ssam amn->amn_tx_rate3sp = 248155477Ssam amn->amn_tx_rate3 | rt->info[0].shortPreamble; 249138569Ssam } else { 250138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 251138569Ssam } 252138569Ssam } else { 253138569Ssam amn->amn_tx_try0 = ATH_TXMAXTRY; 254138569Ssam /* theorically, these statements are useless because 255138569Ssam * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY 256138569Ssam */ 257138569Ssam amn->amn_tx_try1 = 0; 258138569Ssam amn->amn_tx_try2 = 0; 259138569Ssam amn->amn_tx_try3 = 0; 260138569Ssam amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; 261138569Ssam amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; 262138569Ssam amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; 263138569Ssam } 264138569Ssam } 265178354Ssam node_reset(amn); 266178354Ssam 267178354Ssam amn->amn_interval = ath_rateinterval; 268178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) 269178354Ssam amn->amn_interval /= 2; 270178354Ssam amn->amn_interval = (amn->amn_interval * hz) / 1000; 271138569Ssam} 272138569Ssam 273138569Ssam/* 274138569Ssam * Set the starting transmit rate for a node. 275138569Ssam */ 276138569Ssamstatic void 277138569Ssamath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) 278138569Ssam{ 279138569Ssam#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 280178354Ssam struct ath_node *an = ATH_NODE(ni); 281178354Ssam const struct ieee80211_txparam *tp = an->an_tp; 282138569Ssam int srate; 283138569Ssam 284138569Ssam KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); 285178354Ssam if (tp == NULL || tp->ucastrate == 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; 311178354Ssam for (; srate >= 0 && RATE(srate) != tp->ucastrate; 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 336178354Ssamath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state) 337138569Ssam{ 338178354Ssam struct ieee80211com *ic = vap->iv_ic; 339178354Ssam struct ath_softc *sc = ic->ic_ifp->if_softc; 340138569Ssam struct ieee80211_node *ni; 341138569Ssam 342178354Ssam if (state == IEEE80211_S_INIT) 343138569Ssam return; 344178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 345138569Ssam /* 346138569Ssam * Reset local xmit state; this is really only 347138569Ssam * meaningful when operating in station mode. 348138569Ssam */ 349178354Ssam ni = vap->iv_bss; 350138569Ssam if (state == IEEE80211_S_RUN) { 351138569Ssam ath_rate_ctl_start(sc, ni); 352138569Ssam } else { 353138569Ssam ath_rate_update(sc, ni, 0); 354138569Ssam } 355138569Ssam } else { 356138569Ssam /* 357138569Ssam * When operating as a station the node table holds 358138569Ssam * the AP's that were discovered during scanning. 359138569Ssam * For any other operating mode we want to reset the 360138569Ssam * tx rate state of each node. 361138569Ssam */ 362144306Ssam ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, sc); 363178354Ssam ath_rate_update(sc, vap->iv_bss, 0); 364138569Ssam } 365138569Ssam} 366138569Ssam 367138569Ssam/* 368138569Ssam * Examine and potentially adjust the transmit rate. 369138569Ssam */ 370138569Ssamstatic void 371138569Ssamath_rate_ctl(void *arg, struct ieee80211_node *ni) 372138569Ssam{ 373138569Ssam struct ath_softc *sc = arg; 374138569Ssam struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni)); 375178354Ssam int rix; 376138569Ssam 377138569Ssam#define is_success(amn) \ 378138569Ssam(amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10)) 379138569Ssam#define is_enough(amn) \ 380138569Ssam(amn->amn_tx_try0_cnt > 10) 381138569Ssam#define is_failure(amn) \ 382138569Ssam(amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3)) 383138569Ssam 384178354Ssam rix = amn->amn_rix; 385138569Ssam 386178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 387178354Ssam "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d", 388178354Ssam amn->amn_tx_try0_cnt, amn->amn_tx_try1_cnt, amn->amn_tx_try2_cnt, 389178354Ssam amn->amn_tx_try3_cnt, amn->amn_success_threshold); 390138569Ssam if (is_success (amn) && is_enough (amn)) { 391138569Ssam amn->amn_success++; 392138569Ssam if (amn->amn_success == amn->amn_success_threshold && 393178354Ssam rix + 1 < ni->ni_rates.rs_nrates) { 394138569Ssam amn->amn_recovery = 1; 395138569Ssam amn->amn_success = 0; 396178354Ssam rix++; 397178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 398178354Ssam "increase rate to %d", rix); 399138569Ssam } else { 400138569Ssam amn->amn_recovery = 0; 401138569Ssam } 402138569Ssam } else if (is_failure (amn)) { 403138569Ssam amn->amn_success = 0; 404178354Ssam if (rix > 0) { 405138569Ssam if (amn->amn_recovery) { 406138569Ssam /* recovery failure. */ 407138569Ssam amn->amn_success_threshold *= 2; 408138569Ssam amn->amn_success_threshold = min (amn->amn_success_threshold, 409138569Ssam (u_int)ath_rate_max_success_threshold); 410178354Ssam IEEE80211_NOTE(ni->ni_vap, 411178354Ssam IEEE80211_MSG_RATECTL, ni, 412178354Ssam "decrease rate recovery thr: %d", 413178354Ssam amn->amn_success_threshold); 414138569Ssam } else { 415138569Ssam /* simple failure. */ 416138569Ssam amn->amn_success_threshold = ath_rate_min_success_threshold; 417178354Ssam IEEE80211_NOTE(ni->ni_vap, 418178354Ssam IEEE80211_MSG_RATECTL, ni, 419178354Ssam "decrease rate normal thr: %d", 420178354Ssam amn->amn_success_threshold); 421138569Ssam } 422138569Ssam amn->amn_recovery = 0; 423178354Ssam rix--; 424138569Ssam } else { 425138569Ssam amn->amn_recovery = 0; 426138569Ssam } 427138569Ssam 428138569Ssam } 429178354Ssam if (is_enough (amn) || rix != amn->amn_rix) { 430138569Ssam /* reset counters. */ 431138569Ssam amn->amn_tx_try0_cnt = 0; 432138569Ssam amn->amn_tx_try1_cnt = 0; 433138569Ssam amn->amn_tx_try2_cnt = 0; 434138569Ssam amn->amn_tx_try3_cnt = 0; 435138569Ssam amn->amn_tx_failure_cnt = 0; 436138569Ssam } 437178354Ssam if (rix != amn->amn_rix) { 438178354Ssam ath_rate_update(sc, ni, rix); 439138569Ssam } 440138569Ssam} 441138569Ssam 442138569Ssamstatic void 443138569Ssamath_rate_sysctlattach(struct ath_softc *sc) 444138569Ssam{ 445138569Ssam struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 446138569Ssam struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 447138569Ssam 448138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 449138569Ssam "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0, 450138569Ssam "rate control: operation interval (ms)"); 451138569Ssam /* XXX bounds check values */ 452138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 453138569Ssam "max_sucess_threshold", CTLFLAG_RW, 454138569Ssam &ath_rate_max_success_threshold, 0, ""); 455138569Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 456138569Ssam "min_sucess_threshold", CTLFLAG_RW, 457138569Ssam &ath_rate_min_success_threshold, 0, ""); 458138569Ssam} 459138569Ssam 460138569Ssamstruct ath_ratectrl * 461138569Ssamath_rate_attach(struct ath_softc *sc) 462138569Ssam{ 463138569Ssam struct amrr_softc *asc; 464138569Ssam 465138569Ssam asc = malloc(sizeof(struct amrr_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 466138569Ssam if (asc == NULL) 467138569Ssam return NULL; 468138569Ssam asc->arc.arc_space = sizeof(struct amrr_node); 469138569Ssam ath_rate_sysctlattach(sc); 470138569Ssam 471138569Ssam return &asc->arc; 472138569Ssam} 473138569Ssam 474138569Ssamvoid 475138569Ssamath_rate_detach(struct ath_ratectrl *arc) 476138569Ssam{ 477138569Ssam struct amrr_softc *asc = (struct amrr_softc *) arc; 478138569Ssam 479138569Ssam free(asc, M_DEVBUF); 480138569Ssam} 481138569Ssam 482138569Ssam/* 483138569Ssam * Module glue. 484138569Ssam */ 485138569Ssamstatic int 486138569Ssamamrr_modevent(module_t mod, int type, void *unused) 487138569Ssam{ 488138569Ssam switch (type) { 489138569Ssam case MOD_LOAD: 490138569Ssam if (bootverbose) 491138569Ssam printf("ath_rate: <AMRR rate control algorithm> version 0.1\n"); 492138569Ssam return 0; 493138569Ssam case MOD_UNLOAD: 494138569Ssam return 0; 495138569Ssam } 496138569Ssam return EINVAL; 497138569Ssam} 498138569Ssam 499138569Ssamstatic moduledata_t amrr_mod = { 500138569Ssam "ath_rate", 501138569Ssam amrr_modevent, 502138569Ssam 0 503138569Ssam}; 504138569SsamDECLARE_MODULE(ath_rate, amrr_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 505138569SsamMODULE_VERSION(ath_rate, 1); 506138569SsamMODULE_DEPEND(ath_rate, wlan, 1, 1, 1); 507