| Commit | Line | Data |
|---|---|---|
| 193b341d SZ |
1 | /* |
| 2 | * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer, | |
| 10 | * without modification. | |
| 11 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
| 12 | * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any | |
| 13 | * redistribution must be conditioned upon including a substantially | |
| 14 | * similar Disclaimer requirement for further binary redistribution. | |
| 15 | * 3. Neither the names of the above-listed copyright holders nor the names | |
| 16 | * of any contributors may be used to endorse or promote products derived | |
| 17 | * from this software without specific prior written permission. | |
| 18 | * | |
| 19 | * Alternatively, this software may be distributed under the terms of the | |
| 20 | * GNU General Public License ("GPL") version 2 as published by the Free | |
| 21 | * Software Foundation. | |
| 22 | * | |
| 23 | * NO WARRANTY | |
| 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY | |
| 27 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
| 28 | * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, | |
| 29 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
| 32 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
| 34 | * THE POSSIBILITY OF SUCH DAMAGES. | |
| 35 | * | |
| 8982d733 SZ |
36 | * $FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.c,v 1.12 2006/12/13 19:34:35 sam Exp $ |
| 37 | * $DragonFly: src/sys/dev/netif/ath/rate_onoe/onoe.c,v 1.5 2007/02/22 05:17:09 sephe Exp $ | |
| 193b341d SZ |
38 | */ |
| 39 | ||
| 40 | /* | |
| 41 | * Atsushi Onoe's rate control algorithm. | |
| 42 | */ | |
| 43 | ||
| 44 | #include <sys/param.h> | |
| 45 | #include <sys/systm.h> | |
| 46 | #include <sys/sysctl.h> | |
| 47 | #include <sys/module.h> | |
| 48 | #include <sys/kernel.h> | |
| 49 | #include <sys/lock.h> | |
| 50 | #include <sys/errno.h> | |
| 51 | #include <sys/serialize.h> | |
| 193b341d SZ |
52 | #include <sys/bus.h> |
| 53 | ||
| 54 | #include <sys/socket.h> | |
| 55 | ||
| 56 | #include <net/if.h> | |
| 57 | #include <net/if_media.h> | |
| 58 | #include <net/if_arp.h> | |
| 59 | #include <net/ethernet.h> /* XXX for ether_sprintf */ | |
| 60 | ||
| 61 | #include <netproto/802_11/ieee80211_var.h> | |
| 62 | ||
| 63 | #include <net/bpf.h> | |
| 64 | ||
| 65 | #include <dev/netif/ath/ath/if_athvar.h> | |
| 66 | #include <dev/netif/ath/rate_onoe/onoe.h> | |
| 3f720b20 | 67 | #include <dev/netif/ath/hal/ath_hal/ah_desc.h> |
| 193b341d SZ |
68 | |
| 69 | #define ONOE_DEBUG | |
| 70 | #ifdef ONOE_DEBUG | |
| 71 | enum { | |
| 72 | ATH_DEBUG_RATE = 0x00000010, /* rate control */ | |
| 73 | }; | |
| 74 | #define DPRINTF(sc, _fmt, ...) do { \ | |
| 75 | if (sc->sc_debug & ATH_DEBUG_RATE) \ | |
| e3869ec7 | 76 | kprintf(_fmt, __VA_ARGS__); \ |
| 193b341d SZ |
77 | } while (0) |
| 78 | #else | |
| 79 | #define DPRINTF(sc, _fmt, ...) | |
| 80 | #endif | |
| 81 | ||
| 82 | /* | |
| 83 | * Default parameters for the rate control algorithm. These are | |
| 84 | * all tunable with sysctls. The rate controller runs periodically | |
| 85 | * (each ath_rateinterval ms) analyzing transmit statistics for each | |
| 86 | * neighbor/station (when operating in station mode this is only the AP). | |
| 87 | * If transmits look to be working well over a sampling period then | |
| 88 | * it gives a "raise rate credit". If transmits look to not be working | |
| 89 | * well than it deducts a credit. If the credits cross a threshold then | |
| 90 | * the transmit rate is raised. Various error conditions force the | |
| 91 | * the transmit rate to be dropped. | |
| 92 | * | |
| 93 | * The decision to issue/deduct a credit is based on the errors and | |
| 94 | * retries accumulated over the sampling period. ath_rate_raise defines | |
| 95 | * the percent of retransmits for which a credit is issued/deducted. | |
| 96 | * ath_rate_raise_threshold defines the threshold on credits at which | |
| 97 | * the transmit rate is increased. | |
| 98 | * | |
| 99 | * XXX this algorithm is flawed. | |
| 100 | */ | |
| 101 | static int ath_rateinterval = 1000; /* rate ctl interval (ms) */ | |
| 102 | static int ath_rate_raise = 10; /* add credit threshold */ | |
| 103 | static int ath_rate_raise_threshold = 10; /* rate ctl raise threshold */ | |
| 104 | ||
| 105 | static void ath_ratectl(void *); | |
| 106 | static void ath_rate_update(struct ath_softc *, struct ieee80211_node *, | |
| 107 | int rate); | |
| 108 | static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *); | |
| 109 | static void ath_rate_ctl(void *, struct ieee80211_node *); | |
| 110 | ||
| 111 | void | |
| 112 | ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) | |
| 113 | { | |
| 114 | /* NB: assumed to be zero'd by caller */ | |
| 115 | ath_rate_update(sc, &an->an_node, 0); | |
| 116 | } | |
| 117 | ||
| 118 | void | |
| 119 | ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) | |
| 120 | { | |
| 121 | } | |
| 122 | ||
| 123 | void | |
| 124 | ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, | |
| 125 | int shortPreamble, size_t frameLen, | |
| 126 | uint8_t *rix, int *try0, uint8_t *txrate) | |
| 127 | { | |
| 128 | struct onoe_node *on = ATH_NODE_ONOE(an); | |
| 129 | ||
| 130 | *rix = on->on_tx_rix0; | |
| 131 | *try0 = on->on_tx_try0; | |
| 132 | if (shortPreamble) | |
| 133 | *txrate = on->on_tx_rate0sp; | |
| 134 | else | |
| 135 | *txrate = on->on_tx_rate0; | |
| 136 | } | |
| 137 | ||
| 138 | void | |
| 139 | ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, | |
| 140 | struct ath_desc *ds, int shortPreamble, uint8_t rix) | |
| 141 | { | |
| 142 | struct onoe_node *on = ATH_NODE_ONOE(an); | |
| 143 | ||
| 144 | ath_hal_setupxtxdesc(sc->sc_ah, ds | |
| 145 | , on->on_tx_rate1sp, 2 /* series 1 */ | |
| 146 | , on->on_tx_rate2sp, 2 /* series 2 */ | |
| 147 | , on->on_tx_rate3sp, 2 /* series 3 */ | |
| 148 | ); | |
| 149 | } | |
| 150 | ||
| 151 | void | |
| 152 | ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, | |
| 8982d733 | 153 | const struct ath_buf *bf) |
| 193b341d SZ |
154 | { |
| 155 | struct onoe_node *on = ATH_NODE_ONOE(an); | |
| 8982d733 | 156 | const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; |
| 193b341d | 157 | |
| 8982d733 | 158 | if (ts->ts_status == 0) |
| 193b341d SZ |
159 | on->on_tx_ok++; |
| 160 | else | |
| 161 | on->on_tx_err++; | |
| 8982d733 | 162 | on->on_tx_retr += ts->ts_shortretry + ts->ts_longretry; |
| 193b341d SZ |
163 | } |
| 164 | ||
| 165 | void | |
| 166 | ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) | |
| 167 | { | |
| 168 | if (isnew) | |
| 169 | ath_rate_ctl_start(sc, &an->an_node); | |
| 170 | } | |
| 171 | ||
| 172 | static void | |
| 173 | ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) | |
| 174 | { | |
| 175 | struct ath_node *an = ATH_NODE(ni); | |
| 176 | struct onoe_node *on = ATH_NODE_ONOE(an); | |
| 177 | const HAL_RATE_TABLE *rt = sc->sc_currates; | |
| 178 | uint8_t rix; | |
| 179 | ||
| 180 | KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); | |
| 181 | ||
| 182 | DPRINTF(sc, "%s: set xmit rate for %6D to %dM\n", | |
| 183 | __func__, ni->ni_macaddr, ":", | |
| 184 | ni->ni_rates.rs_nrates > 0 ? | |
| 185 | (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); | |
| 186 | ||
| 187 | ni->ni_txrate = rate; | |
| 188 | /* | |
| 189 | * Before associating a node has no rate set setup | |
| 190 | * so we can't calculate any transmit codes to use. | |
| 191 | * This is ok since we should never be sending anything | |
| 192 | * but management frames and those always go at the | |
| 193 | * lowest hardware rate. | |
| 194 | */ | |
| 195 | if (ni->ni_rates.rs_nrates == 0) | |
| 196 | goto done; | |
| 197 | on->on_tx_rix0 = sc->sc_rixmap[ | |
| 198 | ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL]; | |
| 199 | on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode; | |
| 200 | ||
| 201 | on->on_tx_rate0sp = on->on_tx_rate0 | | |
| 202 | rt->info[on->on_tx_rix0].shortPreamble; | |
| 203 | if (sc->sc_mrretry) { | |
| 204 | /* | |
| 205 | * Hardware supports multi-rate retry; setup two | |
| 206 | * step-down retry rates and make the lowest rate | |
| 207 | * be the ``last chance''. We use 4, 2, 2, 2 tries | |
| 208 | * respectively (4 is set here, the rest are fixed | |
| 209 | * in the xmit routine). | |
| 210 | */ | |
| 211 | on->on_tx_try0 = 1 + 3; /* 4 tries at rate 0 */ | |
| 212 | if (--rate >= 0) { | |
| 213 | rix = sc->sc_rixmap[ | |
| 214 | ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; | |
| 215 | on->on_tx_rate1 = rt->info[rix].rateCode; | |
| 216 | on->on_tx_rate1sp = on->on_tx_rate1 | | |
| 217 | rt->info[rix].shortPreamble; | |
| 218 | } else { | |
| 219 | on->on_tx_rate1 = on->on_tx_rate1sp = 0; | |
| 220 | } | |
| 221 | if (--rate >= 0) { | |
| 222 | rix = sc->sc_rixmap[ | |
| 223 | ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; | |
| 224 | on->on_tx_rate2 = rt->info[rix].rateCode; | |
| 225 | on->on_tx_rate2sp = on->on_tx_rate2 | | |
| 226 | rt->info[rix].shortPreamble; | |
| 227 | } else { | |
| 228 | on->on_tx_rate2 = on->on_tx_rate2sp = 0; | |
| 229 | } | |
| 230 | if (rate > 0) { | |
| 231 | /* NB: only do this if we didn't already do it above */ | |
| 232 | on->on_tx_rate3 = rt->info[0].rateCode; | |
| 233 | on->on_tx_rate3sp = | |
| 234 | on->on_tx_rate3 | rt->info[0].shortPreamble; | |
| 235 | } else { | |
| 236 | on->on_tx_rate3 = on->on_tx_rate3sp = 0; | |
| 237 | } | |
| 238 | } else { | |
| 239 | on->on_tx_try0 = ATH_TXMAXTRY; /* max tries at rate 0 */ | |
| 240 | on->on_tx_rate1 = on->on_tx_rate1sp = 0; | |
| 241 | on->on_tx_rate2 = on->on_tx_rate2sp = 0; | |
| 242 | on->on_tx_rate3 = on->on_tx_rate3sp = 0; | |
| 243 | } | |
| 244 | done: | |
| 245 | on->on_tx_ok = on->on_tx_err = on->on_tx_retr = on->on_tx_upper = 0; | |
| 246 | } | |
| 247 | ||
| 248 | /* | |
| 249 | * Set the starting transmit rate for a node. | |
| 250 | */ | |
| 251 | static void | |
| 252 | ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) | |
| 253 | { | |
| 254 | #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) | |
| 255 | struct ieee80211com *ic = &sc->sc_ic; | |
| 256 | int srate; | |
| 257 | ||
| 258 | KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); | |
| 259 | if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { | |
| 260 | /* | |
| 261 | * No fixed rate is requested. For 11b start with | |
| 262 | * the highest negotiated rate; otherwise, for 11g | |
| 263 | * and 11a, we start "in the middle" at 24Mb or 36Mb. | |
| 264 | */ | |
| 265 | srate = ni->ni_rates.rs_nrates - 1; | |
| 266 | if (sc->sc_curmode != IEEE80211_MODE_11B) { | |
| 267 | /* | |
| 268 | * Scan the negotiated rate set to find the | |
| 269 | * closest rate. | |
| 270 | */ | |
| 271 | /* NB: the rate set is assumed sorted */ | |
| 272 | for (; srate >= 0 && RATE(srate) > 72; srate--) | |
| 273 | ; | |
| 274 | KASSERT(srate >= 0, ("bogus rate set")); | |
| 275 | } | |
| 276 | } else { | |
| 277 | /* | |
| 278 | * A fixed rate is to be used; ic_fixed_rate is an | |
| 279 | * index into the supported rate set. Convert this | |
| 280 | * to the index into the negotiated rate set for | |
| 281 | * the node. We know the rate is there because the | |
| 282 | * rate set is checked when the station associates. | |
| 283 | */ | |
| 284 | const struct ieee80211_rateset *rs = | |
| 285 | &ic->ic_sup_rates[ic->ic_curmode]; | |
| 286 | int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; | |
| 287 | /* NB: the rate set is assumed sorted */ | |
| 288 | srate = ni->ni_rates.rs_nrates - 1; | |
| 289 | for (; srate >= 0 && RATE(srate) != r; srate--) | |
| 290 | ; | |
| 291 | KASSERT(srate >= 0, | |
| 292 | ("fixed rate %d not in rate set", ic->ic_fixed_rate)); | |
| 293 | } | |
| 294 | ath_rate_update(sc, ni, srate); | |
| 295 | #undef RATE | |
| 296 | } | |
| 297 | ||
| 298 | static void | |
| 299 | ath_rate_cb(void *arg, struct ieee80211_node *ni) | |
| 300 | { | |
| 301 | struct ath_softc *sc = arg; | |
| 302 | ||
| 303 | ath_rate_update(sc, ni, 0); | |
| 304 | } | |
| 305 | ||
| 306 | /* | |
| 307 | * Reset the rate control state for each 802.11 state transition. | |
| 308 | */ | |
| 309 | void | |
| 310 | ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state) | |
| 311 | { | |
| 312 | struct onoe_softc *osc = (struct onoe_softc *) sc->sc_rc; | |
| 313 | struct ieee80211com *ic = &sc->sc_ic; | |
| 314 | struct ifnet *ifp = &ic->ic_if; | |
| 315 | struct ieee80211_node *ni; | |
| 316 | ||
| 317 | ASSERT_SERIALIZED(ifp->if_serializer); | |
| 318 | ||
| 319 | if (state == IEEE80211_S_INIT) { | |
| 320 | callout_stop(&osc->timer); | |
| 321 | return; | |
| 322 | } | |
| 323 | if (ic->ic_opmode == IEEE80211_M_STA) { | |
| 324 | /* | |
| 325 | * Reset local xmit state; this is really only | |
| 326 | * meaningful when operating in station mode. | |
| 327 | */ | |
| 328 | ni = ic->ic_bss; | |
| 329 | if (state == IEEE80211_S_RUN) { | |
| 330 | ath_rate_ctl_start(sc, ni); | |
| 331 | } else { | |
| 332 | ath_rate_update(sc, ni, 0); | |
| 333 | } | |
| 334 | } else { | |
| 335 | /* | |
| 336 | * When operating as a station the node table holds | |
| 337 | * the AP's that were discovered during scanning. | |
| 338 | * For any other operating mode we want to reset the | |
| 339 | * tx rate state of each node. | |
| 340 | */ | |
| 341 | ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, sc); | |
| 342 | ath_rate_update(sc, ic->ic_bss, 0); | |
| 343 | } | |
| 344 | if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE && | |
| 345 | state == IEEE80211_S_RUN) { | |
| 346 | int interval; | |
| 347 | /* | |
| 348 | * Start the background rate control thread if we | |
| 349 | * are not configured to use a fixed xmit rate. | |
| 350 | */ | |
| 351 | interval = ath_rateinterval; | |
| 352 | if (ic->ic_opmode == IEEE80211_M_STA) | |
| 353 | interval /= 2; | |
| 354 | callout_reset(&osc->timer, (interval * hz) / 1000, | |
| 355 | ath_ratectl, ifp); | |
| 356 | } | |
| 357 | } | |
| 358 | ||
| 359 | /* | |
| 360 | * Examine and potentially adjust the transmit rate. | |
| 361 | */ | |
| 362 | static void | |
| 363 | ath_rate_ctl(void *arg, struct ieee80211_node *ni) | |
| 364 | { | |
| 365 | struct ath_softc *sc = arg; | |
| 366 | struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni)); | |
| 367 | struct ieee80211_rateset *rs = &ni->ni_rates; | |
| 368 | int dir = 0, nrate, enough; | |
| 369 | ||
| 370 | /* | |
| 371 | * Rate control | |
| 372 | * XXX: very primitive version. | |
| 373 | */ | |
| 374 | enough = (on->on_tx_ok + on->on_tx_err >= 10); | |
| 375 | ||
| 376 | /* no packet reached -> down */ | |
| 377 | if (on->on_tx_err > 0 && on->on_tx_ok == 0) | |
| 378 | dir = -1; | |
| 379 | ||
| 380 | /* all packets needs retry in average -> down */ | |
| 381 | if (enough && on->on_tx_ok < on->on_tx_retr) | |
| 382 | dir = -1; | |
| 383 | ||
| 384 | /* no error and less than rate_raise% of packets need retry -> up */ | |
| 385 | if (enough && on->on_tx_err == 0 && | |
| 386 | on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100) | |
| 387 | dir = 1; | |
| 388 | ||
| 389 | DPRINTF(sc, "%6D: ok %d err %d retr %d upper %d dir %d\n", | |
| 390 | ni->ni_macaddr, ":", | |
| 391 | on->on_tx_ok, on->on_tx_err, on->on_tx_retr, | |
| 392 | on->on_tx_upper, dir); | |
| 393 | ||
| 394 | nrate = ni->ni_txrate; | |
| 395 | switch (dir) { | |
| 396 | case 0: | |
| 397 | if (enough && on->on_tx_upper > 0) | |
| 398 | on->on_tx_upper--; | |
| 399 | break; | |
| 400 | case -1: | |
| 401 | if (nrate > 0) { | |
| 402 | nrate--; | |
| 403 | sc->sc_stats.ast_rate_drop++; | |
| 404 | } | |
| 405 | on->on_tx_upper = 0; | |
| 406 | break; | |
| 407 | case 1: | |
| 408 | /* raise rate if we hit rate_raise_threshold */ | |
| 409 | if (++on->on_tx_upper < ath_rate_raise_threshold) | |
| 410 | break; | |
| 411 | on->on_tx_upper = 0; | |
| 412 | if (nrate + 1 < rs->rs_nrates) { | |
| 413 | nrate++; | |
| 414 | sc->sc_stats.ast_rate_raise++; | |
| 415 | } | |
| 416 | break; | |
| 417 | } | |
| 418 | ||
| 419 | if (nrate != ni->ni_txrate) { | |
| 420 | DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n", | |
| 421 | __func__, | |
| 422 | (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2, | |
| 423 | (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2, | |
| 424 | on->on_tx_ok, on->on_tx_err, on->on_tx_retr); | |
| 425 | ath_rate_update(sc, ni, nrate); | |
| 426 | } else if (enough) { | |
| 427 | on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0; | |
| 428 | } | |
| 429 | } | |
| 430 | ||
| 431 | static void | |
| 432 | ath_ratectl(void *arg) | |
| 433 | { | |
| 434 | struct ifnet *ifp = arg; | |
| 435 | struct ath_softc *sc = ifp->if_softc; | |
| 436 | struct onoe_softc *osc = (struct onoe_softc *) sc->sc_rc; | |
| 437 | struct ieee80211com *ic = &sc->sc_ic; | |
| 438 | int interval; | |
| 439 | ||
| 19996047 | 440 | ifnet_serialize_all(ifp); |
| 193b341d SZ |
441 | |
| 442 | if (ifp->if_flags & IFF_RUNNING) { | |
| 443 | sc->sc_stats.ast_rate_calls++; | |
| 444 | ||
| 445 | if (ic->ic_opmode == IEEE80211_M_STA) | |
| 446 | ath_rate_ctl(sc, ic->ic_bss); /* NB: no reference */ | |
| 447 | else | |
| 448 | ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_ctl, sc); | |
| 449 | } | |
| 450 | interval = ath_rateinterval; | |
| 451 | if (ic->ic_opmode == IEEE80211_M_STA) | |
| 452 | interval /= 2; | |
| 453 | callout_reset(&osc->timer, (interval * hz) / 1000, ath_ratectl, ifp); | |
| 454 | ||
| 19996047 | 455 | ifnet_deserialize_all(ifp); |
| 193b341d SZ |
456 | } |
| 457 | ||
| 458 | static void | |
| 459 | ath_rate_sysctlattach(struct ath_softc *sc) | |
| 460 | { | |
| 461 | struct sysctl_ctx_list *ctx = &sc->sc_sysctl_ctx; | |
| 462 | struct sysctl_oid *tree = sc->sc_sysctl_tree; | |
| 463 | ||
| 464 | SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, | |
| 465 | "rate_interval", CTLFLAG_RW, &ath_rateinterval, 0, | |
| 466 | "rate control: operation interval (ms)"); | |
| 467 | /* XXX bounds check values */ | |
| 468 | SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, | |
| 469 | "rate_raise", CTLFLAG_RW, &ath_rate_raise, 0, | |
| 470 | "rate control: retry threshold to credit rate raise (%%)"); | |
| 471 | SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, | |
| 472 | "rate_raise_threshold", CTLFLAG_RW, &ath_rate_raise_threshold,0, | |
| 473 | "rate control: # good periods before raising rate"); | |
| 474 | } | |
| 475 | ||
| 476 | struct ath_ratectrl * | |
| 477 | ath_rate_attach(struct ath_softc *sc) | |
| 478 | { | |
| 479 | struct onoe_softc *osc; | |
| 480 | ||
| efda3bd0 | 481 | osc = kmalloc(sizeof(struct onoe_softc), M_DEVBUF, M_WAITOK | M_ZERO); |
| 193b341d SZ |
482 | osc->arc.arc_space = sizeof(struct onoe_node); |
| 483 | callout_init(&osc->timer); | |
| 484 | ath_rate_sysctlattach(sc); | |
| 485 | return &osc->arc; | |
| 486 | } | |
| 487 | ||
| 488 | void | |
| 489 | ath_rate_detach(struct ath_ratectrl *arc) | |
| 490 | { | |
| 491 | struct onoe_softc *osc = (struct onoe_softc *) arc; | |
| 492 | ||
| efda3bd0 | 493 | kfree(osc, M_DEVBUF); |
| 193b341d SZ |
494 | } |
| 495 | ||
| 496 | void | |
| 497 | ath_rate_stop(struct ath_ratectrl *arc) | |
| 498 | { | |
| 499 | struct onoe_softc *osc = (struct onoe_softc *) arc; | |
| 500 | ||
| 501 | /* ASSERT_SERIALIZED */ | |
| 502 | callout_stop(&osc->timer); | |
| 503 | } | |
| 504 | ||
| 505 | /* | |
| 506 | * Module glue. | |
| 507 | */ | |
| 508 | static int | |
| 509 | onoe_modevent(module_t mod, int type, void *unused) | |
| 510 | { | |
| 511 | switch (type) { | |
| 512 | case MOD_LOAD: | |
| 513 | if (bootverbose) | |
| e3869ec7 | 514 | kprintf("ath_rate: <Atsushi Onoe's rate control algorithm>\n"); |
| 193b341d SZ |
515 | return 0; |
| 516 | case MOD_UNLOAD: | |
| 517 | return 0; | |
| 518 | } | |
| 519 | return EINVAL; | |
| 520 | } | |
| 521 | ||
| 522 | static moduledata_t onoe_mod = { | |
| 523 | "ath_rate", | |
| 524 | onoe_modevent, | |
| 525 | 0 | |
| 526 | }; | |
| 527 | DECLARE_MODULE(ath_rate, onoe_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); | |
| 528 | MODULE_VERSION(ath_rate, 1); | |
| 529 | MODULE_DEPEND(ath_rate, wlan, 1, 1, 1); |