1143392Ssam/*- 2143392Ssam * Copyright (c) 2005 John Bicket 3143392Ssam * All rights reserved. 4143392Ssam * 5143392Ssam * Redistribution and use in source and binary forms, with or without 6143392Ssam * modification, are permitted provided that the following conditions 7143392Ssam * are met: 8143392Ssam * 1. Redistributions of source code must retain the above copyright 9143392Ssam * notice, this list of conditions and the following disclaimer, 10143392Ssam * without modification. 11143392Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12143392Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13143392Ssam * redistribution must be conditioned upon including a substantially 14143392Ssam * similar Disclaimer requirement for further binary redistribution. 15143392Ssam * 3. Neither the names of the above-listed copyright holders nor the names 16143392Ssam * of any contributors may be used to endorse or promote products derived 17143392Ssam * from this software without specific prior written permission. 18143392Ssam * 19143392Ssam * Alternatively, this software may be distributed under the terms of the 20143392Ssam * GNU General Public License ("GPL") version 2 as published by the Free 21143392Ssam * Software Foundation. 22143392Ssam * 23143392Ssam * NO WARRANTY 24143392Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25143392Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26143392Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27143392Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28143392Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29143392Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30143392Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31143392Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32143392Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33143392Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34143392Ssam * THE POSSIBILITY OF SUCH DAMAGES. 35170530Ssam * 36143392Ssam */ 37143392Ssam 38143392Ssam#include <sys/cdefs.h> 39143392Ssam__FBSDID("$FreeBSD$"); 40143392Ssam 41143392Ssam/* 42143392Ssam * John Bicket's SampleRate control algorithm. 43143392Ssam */ 44237529Sadrian#include "opt_ath.h" 45143392Ssam#include "opt_inet.h" 46178354Ssam#include "opt_wlan.h" 47227340Sadrian#include "opt_ah.h" 48143392Ssam 49143392Ssam#include <sys/param.h> 50143392Ssam#include <sys/systm.h> 51143392Ssam#include <sys/sysctl.h> 52143392Ssam#include <sys/kernel.h> 53143392Ssam#include <sys/lock.h> 54143392Ssam#include <sys/mutex.h> 55143392Ssam#include <sys/errno.h> 56143392Ssam 57143392Ssam#include <machine/bus.h> 58143392Ssam#include <machine/resource.h> 59143392Ssam#include <sys/bus.h> 60143392Ssam 61143392Ssam#include <sys/socket.h> 62143392Ssam 63143392Ssam#include <net/if.h> 64143392Ssam#include <net/if_media.h> 65143392Ssam#include <net/if_arp.h> 66185482Ssam#include <net/ethernet.h> /* XXX for ether_sprintf */ 67143392Ssam 68143392Ssam#include <net80211/ieee80211_var.h> 69143392Ssam 70143392Ssam#include <net/bpf.h> 71143392Ssam 72143392Ssam#ifdef INET 73143392Ssam#include <netinet/in.h> 74143392Ssam#include <netinet/if_ether.h> 75143392Ssam#endif 76143392Ssam 77143392Ssam#include <dev/ath/if_athvar.h> 78143392Ssam#include <dev/ath/ath_rate/sample/sample.h> 79185522Ssam#include <dev/ath/ath_hal/ah_desc.h> 80218013Sadrian#include <dev/ath/ath_rate/sample/tx_schedules.h> 81143392Ssam 82143392Ssam/* 83143392Ssam * This file is an implementation of the SampleRate algorithm 84143392Ssam * in "Bit-rate Selection in Wireless Networks" 85143392Ssam * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 86143392Ssam * 87143392Ssam * SampleRate chooses the bit-rate it predicts will provide the most 88143392Ssam * throughput based on estimates of the expected per-packet 89143392Ssam * transmission time for each bit-rate. SampleRate periodically sends 90143392Ssam * packets at bit-rates other than the current one to estimate when 91143392Ssam * another bit-rate will provide better performance. SampleRate 92143392Ssam * switches to another bit-rate when its estimated per-packet 93143392Ssam * transmission time becomes smaller than the current bit-rate's. 94143392Ssam * SampleRate reduces the number of bit-rates it must sample by 95143392Ssam * eliminating those that could not perform better than the one 96143392Ssam * currently being used. SampleRate also stops probing at a bit-rate 97143392Ssam * if it experiences several successive losses. 98143392Ssam * 99143392Ssam * The difference between the algorithm in the thesis and the one in this 100143392Ssam * file is that the one in this file uses a ewma instead of a window. 101143392Ssam * 102155476Ssam * Also, this implementation tracks the average transmission time for 103155476Ssam * a few different packet sizes independently for each link. 104143392Ssam */ 105143392Ssam 106143853Ssamstatic void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 107143853Ssam 108155476Ssamstatic __inline int 109155476Ssamsize_to_bin(int size) 110143392Ssam{ 111185482Ssam#if NUM_PACKET_SIZE_BINS > 1 112185482Ssam if (size <= packet_size_bins[0]) 113185482Ssam return 0; 114185482Ssam#endif 115185482Ssam#if NUM_PACKET_SIZE_BINS > 2 116185482Ssam if (size <= packet_size_bins[1]) 117185482Ssam return 1; 118185482Ssam#endif 119185482Ssam#if NUM_PACKET_SIZE_BINS > 3 120185482Ssam if (size <= packet_size_bins[2]) 121185482Ssam return 2; 122185482Ssam#endif 123185482Ssam#if NUM_PACKET_SIZE_BINS > 4 124185482Ssam#error "add support for more packet sizes" 125185482Ssam#endif 126143392Ssam return NUM_PACKET_SIZE_BINS-1; 127143392Ssam} 128185482Ssam 129143392Ssamvoid 130143392Ssamath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 131143392Ssam{ 132143392Ssam /* NB: assumed to be zero'd by caller */ 133143392Ssam} 134143392Ssam 135143392Ssamvoid 136143392Ssamath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 137143392Ssam{ 138143392Ssam} 139143392Ssam 140218013Sadrianstatic int 141218013Sadriandot11rate(const HAL_RATE_TABLE *rt, int rix) 142218013Sadrian{ 143227340Sadrian if (rix < 0) 144227340Sadrian return -1; 145218013Sadrian return rt->info[rix].phy == IEEE80211_T_HT ? 146218013Sadrian rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2; 147218013Sadrian} 148218013Sadrian 149219216Sadrianstatic const char * 150219216Sadriandot11rate_label(const HAL_RATE_TABLE *rt, int rix) 151219216Sadrian{ 152227340Sadrian if (rix < 0) 153227340Sadrian return ""; 154219216Sadrian return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; 155219216Sadrian} 156219216Sadrian 157143392Ssam/* 158185482Ssam * Return the rix with the lowest average_tx_time, 159143392Ssam * or -1 if all the average_tx_times are 0. 160143392Ssam */ 161185482Ssamstatic __inline int 162222049Sadrianpick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt, 163185482Ssam int size_bin, int require_acked_before) 164143392Ssam{ 165222049Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 166227364Sadrian int best_rate_rix, best_rate_tt, best_rate_pct; 167239284Sadrian uint64_t mask; 168227364Sadrian int rix, tt, pct; 169185482Ssam 170185482Ssam best_rate_rix = 0; 171185482Ssam best_rate_tt = 0; 172227364Sadrian best_rate_pct = 0; 173185482Ssam for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 174185482Ssam if ((mask & 1) == 0) /* not a supported rate */ 175143853Ssam continue; 176155476Ssam 177222049Sadrian /* Don't pick a non-HT rate for a HT node */ 178222049Sadrian if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 179222049Sadrian (rt->info[rix].phy != IEEE80211_T_HT)) { 180222049Sadrian continue; 181222049Sadrian } 182222049Sadrian 183185482Ssam tt = sn->stats[size_bin][rix].average_tx_time; 184185482Ssam if (tt <= 0 || 185185482Ssam (require_acked_before && 186185482Ssam !sn->stats[size_bin][rix].packets_acked)) 187155476Ssam continue; 188155476Ssam 189227364Sadrian /* Calculate percentage if possible */ 190227364Sadrian if (sn->stats[size_bin][rix].total_packets > 0) { 191227364Sadrian pct = sn->stats[size_bin][rix].ewma_pct; 192227364Sadrian } else { 193227364Sadrian /* XXX for now, assume 95% ok */ 194227364Sadrian pct = 95; 195227364Sadrian } 196227364Sadrian 197155476Ssam /* don't use a bit-rate that has been failing */ 198185482Ssam if (sn->stats[size_bin][rix].successive_failures > 3) 199155476Ssam continue; 200155476Ssam 201227364Sadrian /* 202227364Sadrian * For HT, Don't use a bit rate that is much more 203227364Sadrian * lossy than the best. 204227364Sadrian * 205227364Sadrian * XXX this isn't optimal; it's just designed to 206227364Sadrian * eliminate rates that are going to be obviously 207227364Sadrian * worse. 208227364Sadrian */ 209227364Sadrian if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 210227364Sadrian if (best_rate_pct > (pct + 50)) 211227364Sadrian continue; 212143853Ssam } 213227364Sadrian 214227364Sadrian /* 215227364Sadrian * For non-MCS rates, use the current average txtime for 216227364Sadrian * comparison. 217227364Sadrian */ 218227364Sadrian if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 219227364Sadrian if (best_rate_tt == 0 || tt <= best_rate_tt) { 220227364Sadrian best_rate_tt = tt; 221227364Sadrian best_rate_rix = rix; 222227364Sadrian best_rate_pct = pct; 223227364Sadrian } 224227364Sadrian } 225227364Sadrian 226227364Sadrian /* 227227364Sadrian * Since 2 stream rates have slightly higher TX times, 228227364Sadrian * allow a little bit of leeway. This should later 229227364Sadrian * be abstracted out and properly handled. 230227364Sadrian */ 231227364Sadrian if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 232227364Sadrian if (best_rate_tt == 0 || (tt * 8 <= best_rate_tt * 10)) { 233227364Sadrian best_rate_tt = tt; 234227364Sadrian best_rate_rix = rix; 235227364Sadrian best_rate_pct = pct; 236227364Sadrian } 237227364Sadrian } 238143392Ssam } 239185482Ssam return (best_rate_tt ? best_rate_rix : -1); 240143392Ssam} 241143392Ssam 242143392Ssam/* 243185482Ssam * Pick a good "random" bit-rate to sample other than the current one. 244143392Ssam */ 245155476Ssamstatic __inline int 246222049Sadrianpick_sample_rate(struct sample_softc *ssc , struct ath_node *an, 247185482Ssam const HAL_RATE_TABLE *rt, int size_bin) 248143392Ssam{ 249185482Ssam#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 250218013Sadrian#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 251222049Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 252185482Ssam int current_rix, rix; 253185482Ssam unsigned current_tt; 254239284Sadrian uint64_t mask; 255143392Ssam 256185482Ssam current_rix = sn->current_rix[size_bin]; 257185482Ssam if (current_rix < 0) { 258143392Ssam /* no successes yet, send at the lowest bit-rate */ 259222049Sadrian /* XXX should return MCS0 if HT */ 260143392Ssam return 0; 261143392Ssam } 262155476Ssam 263185482Ssam current_tt = sn->stats[size_bin][current_rix].average_tx_time; 264185482Ssam 265185482Ssam rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 266239284Sadrian mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */ 267185482Ssam while (mask != 0) { 268239284Sadrian if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */ 269185482Ssam nextrate: 270185482Ssam if (++rix >= rt->rateCount) 271185482Ssam rix = 0; 272155476Ssam continue; 273185482Ssam } 274155476Ssam 275242392Sadrian /* 276242392Sadrian * The following code stops trying to sample 277242392Sadrian * non-MCS rates when speaking to an MCS node. 278242392Sadrian * However, at least for CCK rates in 2.4GHz mode, 279242392Sadrian * the non-MCS rates MAY actually provide better 280242392Sadrian * PER at the very far edge of reception. 281242392Sadrian * 282242392Sadrian * However! Until ath_rate_form_aggr() grows 283242392Sadrian * some logic to not form aggregates if the 284242392Sadrian * selected rate is non-MCS, this won't work. 285242392Sadrian * 286242392Sadrian * So don't disable this code until you've taught 287242392Sadrian * ath_rate_form_aggr() to drop out if any of 288242392Sadrian * the selected rates are non-MCS. 289242392Sadrian */ 290242392Sadrian#if 1 291222049Sadrian /* if the node is HT and the rate isn't HT, don't bother sample */ 292222049Sadrian if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 293222049Sadrian (rt->info[rix].phy != IEEE80211_T_HT)) { 294239284Sadrian mask &= ~((uint64_t) 1<<rix); 295222049Sadrian goto nextrate; 296222049Sadrian } 297242392Sadrian#endif 298222049Sadrian 299155476Ssam /* this bit-rate is always worse than the current one */ 300185482Ssam if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 301239284Sadrian mask &= ~((uint64_t) 1<<rix); 302185482Ssam goto nextrate; 303185482Ssam } 304155476Ssam 305155476Ssam /* rarely sample bit-rates that fail a lot */ 306185482Ssam if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 307185482Ssam ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 308239284Sadrian mask &= ~((uint64_t) 1<<rix); 309185482Ssam goto nextrate; 310185482Ssam } 311155476Ssam 312227364Sadrian /* 313240583Sadrian * For HT, only sample a few rates on either side of the 314240583Sadrian * current rix; there's quite likely a lot of them. 315227364Sadrian */ 316227364Sadrian if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 317240583Sadrian if (rix < (current_rix - 3) || 318240583Sadrian rix > (current_rix + 3)) { 319239284Sadrian mask &= ~((uint64_t) 1<<rix); 320227364Sadrian goto nextrate; 321227364Sadrian } 322227364Sadrian } 323227364Sadrian 324222049Sadrian /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */ 325222049Sadrian if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 326222049Sadrian if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 327239284Sadrian mask &= ~((uint64_t) 1<<rix); 328222049Sadrian goto nextrate; 329222049Sadrian } 330185482Ssam } 331143853Ssam 332185482Ssam sn->last_sample_rix[size_bin] = rix; 333185482Ssam return rix; 334143392Ssam } 335185482Ssam return current_rix; 336185482Ssam#undef DOT11RATE 337218013Sadrian#undef MCS 338143392Ssam} 339143392Ssam 340219822Sadrianstatic int 341219822Sadrianath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) 342219822Sadrian{ 343219822Sadrian#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 344219822Sadrian#define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 345219822Sadrian#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 346219822Sadrian const struct ieee80211_txparam *tp = ni->ni_txparms; 347219822Sadrian int srate; 348219822Sadrian 349219822Sadrian /* Check MCS rates */ 350219822Sadrian for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { 351219822Sadrian if (MCS(srate) == tp->ucastrate) 352219822Sadrian return sc->sc_rixmap[tp->ucastrate]; 353219822Sadrian } 354219822Sadrian 355219822Sadrian /* Check legacy rates */ 356219822Sadrian for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { 357219822Sadrian if (RATE(srate) == tp->ucastrate) 358219822Sadrian return sc->sc_rixmap[tp->ucastrate]; 359219822Sadrian } 360219822Sadrian return -1; 361219822Sadrian#undef RATE 362219822Sadrian#undef DOT11RATE 363219822Sadrian#undef MCS 364219822Sadrian} 365219822Sadrian 366219822Sadrianstatic void 367219822Sadrianath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) 368219822Sadrian{ 369219822Sadrian struct ath_node *an = ATH_NODE(ni); 370219822Sadrian const struct ieee80211_txparam *tp = ni->ni_txparms; 371219822Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 372219822Sadrian 373219822Sadrian if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 374219822Sadrian /* 375219822Sadrian * A fixed rate is to be used; ucastrate is the IEEE code 376219822Sadrian * for this rate (sans basic bit). Check this against the 377219822Sadrian * negotiated rate set for the node. Note the fixed rate 378219822Sadrian * may not be available for various reasons so we only 379219822Sadrian * setup the static rate index if the lookup is successful. 380219822Sadrian */ 381219822Sadrian sn->static_rix = ath_rate_get_static_rix(sc, ni); 382219822Sadrian } else { 383219822Sadrian sn->static_rix = -1; 384219822Sadrian } 385219822Sadrian} 386219822Sadrian 387227364Sadrian/* 388227364Sadrian * Pick a non-HT rate to begin using. 389227364Sadrian */ 390227364Sadrianstatic int 391227364Sadrianath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an, 392227364Sadrian int frameLen) 393227364Sadrian{ 394227364Sadrian#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 395227364Sadrian#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 396227364Sadrian#define RATE(ix) (DOT11RATE(ix) / 2) 397227364Sadrian int rix = -1; 398227364Sadrian const HAL_RATE_TABLE *rt = sc->sc_currates; 399227364Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 400227364Sadrian const int size_bin = size_to_bin(frameLen); 401219822Sadrian 402227364Sadrian /* no packet has been sent successfully yet */ 403227364Sadrian for (rix = rt->rateCount-1; rix > 0; rix--) { 404239284Sadrian if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 405227364Sadrian continue; 406219822Sadrian 407227364Sadrian /* Skip HT rates */ 408227364Sadrian if (rt->info[rix].phy == IEEE80211_T_HT) 409227364Sadrian continue; 410227364Sadrian 411227364Sadrian /* 412227364Sadrian * Pick the highest rate <= 36 Mbps 413227364Sadrian * that hasn't failed. 414227364Sadrian */ 415227364Sadrian if (DOT11RATE(rix) <= 72 && 416227364Sadrian sn->stats[size_bin][rix].successive_failures == 0) { 417227364Sadrian break; 418227364Sadrian } 419227364Sadrian } 420227364Sadrian return rix; 421227364Sadrian#undef RATE 422227364Sadrian#undef MCS 423227364Sadrian#undef DOT11RATE 424227364Sadrian} 425227364Sadrian 426227364Sadrian/* 427227364Sadrian * Pick a HT rate to begin using. 428227364Sadrian * 429227364Sadrian * Don't use any non-HT rates; only consider HT rates. 430227364Sadrian */ 431227364Sadrianstatic int 432227364Sadrianath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an, 433227364Sadrian int frameLen) 434227364Sadrian{ 435227364Sadrian#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 436227364Sadrian#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 437227364Sadrian#define RATE(ix) (DOT11RATE(ix) / 2) 438227364Sadrian int rix = -1, ht_rix = -1; 439227364Sadrian const HAL_RATE_TABLE *rt = sc->sc_currates; 440227364Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 441227364Sadrian const int size_bin = size_to_bin(frameLen); 442227364Sadrian 443227364Sadrian /* no packet has been sent successfully yet */ 444227364Sadrian for (rix = rt->rateCount-1; rix > 0; rix--) { 445227364Sadrian /* Skip rates we can't use */ 446239284Sadrian if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 447227364Sadrian continue; 448227364Sadrian 449227364Sadrian /* Keep a copy of the last seen HT rate index */ 450227364Sadrian if (rt->info[rix].phy == IEEE80211_T_HT) 451227364Sadrian ht_rix = rix; 452227364Sadrian 453227364Sadrian /* Skip non-HT rates */ 454227364Sadrian if (rt->info[rix].phy != IEEE80211_T_HT) 455227364Sadrian continue; 456227364Sadrian 457227364Sadrian /* 458227364Sadrian * Pick a medium-speed rate regardless of stream count 459227364Sadrian * which has not seen any failures. Higher rates may fail; 460227364Sadrian * we'll try them later. 461227364Sadrian */ 462227364Sadrian if (((MCS(rix) & 0x7) <= 4) && 463227364Sadrian sn->stats[size_bin][rix].successive_failures == 0) { 464227364Sadrian break; 465227364Sadrian } 466227364Sadrian } 467227364Sadrian 468227364Sadrian /* 469227364Sadrian * If all the MCS rates have successive failures, rix should be 470227364Sadrian * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.) 471227364Sadrian */ 472227364Sadrian return MAX(rix, ht_rix); 473227364Sadrian#undef RATE 474227364Sadrian#undef MCS 475227364Sadrian#undef DOT11RATE 476227364Sadrian} 477227364Sadrian 478227364Sadrian 479143392Ssamvoid 480143392Ssamath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 481144546Ssam int shortPreamble, size_t frameLen, 482185482Ssam u_int8_t *rix0, int *try0, u_int8_t *txrate) 483143392Ssam{ 484185482Ssam#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 485218013Sadrian#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 486185482Ssam#define RATE(ix) (DOT11RATE(ix) / 2) 487143392Ssam struct sample_node *sn = ATH_NODE_SAMPLE(an); 488143392Ssam struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 489178354Ssam struct ifnet *ifp = sc->sc_ifp; 490178354Ssam struct ieee80211com *ic = ifp->if_l2com; 491185482Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 492185482Ssam const int size_bin = size_to_bin(frameLen); 493185482Ssam int rix, mrr, best_rix, change_rates; 494143853Ssam unsigned average_tx_time; 495143392Ssam 496219822Sadrian ath_rate_update_static_rix(sc, &an->an_node); 497219822Sadrian 498232170Sadrian if (sn->currates != sc->sc_currates) { 499232170Sadrian device_printf(sc->sc_dev, "%s: currates != sc_currates!\n", 500232170Sadrian __func__); 501232170Sadrian rix = 0; 502232170Sadrian *try0 = ATH_TXMAXTRY; 503232170Sadrian goto done; 504232170Sadrian } 505232170Sadrian 506185482Ssam if (sn->static_rix != -1) { 507185482Ssam rix = sn->static_rix; 508185482Ssam *try0 = ATH_TXMAXTRY; 509185482Ssam goto done; 510185482Ssam } 511185482Ssam 512238961Sadrian mrr = sc->sc_mrretry; 513238961Sadrian /* XXX check HT protmode too */ 514238962Sadrian if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 515238961Sadrian mrr = 0; 516143853Ssam 517222049Sadrian best_rix = pick_best_rate(an, rt, size_bin, !mrr); 518185482Ssam if (best_rix >= 0) { 519185482Ssam average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 520143853Ssam } else { 521143853Ssam average_tx_time = 0; 522143853Ssam } 523185482Ssam /* 524185482Ssam * Limit the time measuring the performance of other tx 525185482Ssam * rates to sample_rate% of the total transmission time. 526185482Ssam */ 527185482Ssam if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 528222049Sadrian rix = pick_sample_rate(ssc, an, rt, size_bin); 529185482Ssam IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 530227364Sadrian &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s", 531227364Sadrian average_tx_time, 532227364Sadrian sn->sample_tt[size_bin], 533227364Sadrian bin_to_size(size_bin), 534227364Sadrian dot11rate(rt, rix), 535227364Sadrian dot11rate_label(rt, rix), 536227364Sadrian dot11rate(rt, sn->current_rix[size_bin]), 537227364Sadrian dot11rate_label(rt, sn->current_rix[size_bin])); 538185482Ssam if (rix != sn->current_rix[size_bin]) { 539185482Ssam sn->current_sample_rix[size_bin] = rix; 540185482Ssam } else { 541185482Ssam sn->current_sample_rix[size_bin] = -1; 542185482Ssam } 543185482Ssam sn->packets_since_sample[size_bin] = 0; 544143853Ssam } else { 545185482Ssam change_rates = 0; 546185482Ssam if (!sn->packets_sent[size_bin] || best_rix == -1) { 547185482Ssam /* no packet has been sent successfully yet */ 548185482Ssam change_rates = 1; 549227364Sadrian if (an->an_node.ni_flags & IEEE80211_NODE_HT) 550227364Sadrian best_rix = 551227364Sadrian ath_rate_pick_seed_rate_ht(sc, an, frameLen); 552227364Sadrian else 553227364Sadrian best_rix = 554227364Sadrian ath_rate_pick_seed_rate_legacy(sc, an, frameLen); 555185482Ssam } else if (sn->packets_sent[size_bin] < 20) { 556185482Ssam /* let the bit-rate switch quickly during the first few packets */ 557227364Sadrian IEEE80211_NOTE(an->an_node.ni_vap, 558227364Sadrian IEEE80211_MSG_RATECTL, &an->an_node, 559227364Sadrian "%s: switching quickly..", __func__); 560185482Ssam change_rates = 1; 561185482Ssam } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 562185482Ssam /* min_switch seconds have gone by */ 563227364Sadrian IEEE80211_NOTE(an->an_node.ni_vap, 564227364Sadrian IEEE80211_MSG_RATECTL, &an->an_node, 565227364Sadrian "%s: min_switch %d > ticks_since_switch %d..", 566227364Sadrian __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]); 567185482Ssam change_rates = 1; 568227364Sadrian } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) && 569227364Sadrian (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) { 570185482Ssam /* the current bit-rate is twice as slow as the best one */ 571227364Sadrian IEEE80211_NOTE(an->an_node.ni_vap, 572227364Sadrian IEEE80211_MSG_RATECTL, &an->an_node, 573227364Sadrian "%s: 2x att (= %d) < cur_rix att %d", 574227364Sadrian __func__, 575227364Sadrian 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time); 576185482Ssam change_rates = 1; 577227364Sadrian } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) { 578227364Sadrian int cur_rix = sn->current_rix[size_bin]; 579227364Sadrian int cur_att = sn->stats[size_bin][cur_rix].average_tx_time; 580227364Sadrian /* 581227364Sadrian * If the node is HT, upgrade it if the MCS rate is 582227364Sadrian * higher and the average tx time is within 20% of 583227364Sadrian * the current rate. It can fail a little. 584227364Sadrian * 585227364Sadrian * This is likely not optimal! 586227364Sadrian */ 587227364Sadrian#if 0 588227364Sadrian printf("cur rix/att %x/%d, best rix/att %x/%d\n", 589227364Sadrian MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time); 590227364Sadrian#endif 591227364Sadrian if ((MCS(best_rix) > MCS(cur_rix)) && 592227364Sadrian (average_tx_time * 8) <= (cur_att * 10)) { 593227364Sadrian IEEE80211_NOTE(an->an_node.ni_vap, 594227364Sadrian IEEE80211_MSG_RATECTL, &an->an_node, 595227364Sadrian "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d", 596227364Sadrian __func__, 597227364Sadrian MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att); 598227364Sadrian change_rates = 1; 599227364Sadrian } 600185482Ssam } 601155476Ssam 602185482Ssam sn->packets_since_sample[size_bin]++; 603185482Ssam 604185482Ssam if (change_rates) { 605185482Ssam if (best_rix != sn->current_rix[size_bin]) { 606185482Ssam IEEE80211_NOTE(an->an_node.ni_vap, 607185482Ssam IEEE80211_MSG_RATECTL, 608185482Ssam &an->an_node, 609178354Ssam"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d", 610185482Ssam __func__, 611185482Ssam bin_to_size(size_bin), 612185482Ssam RATE(sn->current_rix[size_bin]), 613185482Ssam sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 614185482Ssam sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 615185482Ssam RATE(best_rix), 616185482Ssam sn->stats[size_bin][best_rix].average_tx_time, 617185482Ssam sn->stats[size_bin][best_rix].perfect_tx_time, 618185482Ssam sn->packets_since_switch[size_bin], 619185482Ssam mrr); 620143392Ssam } 621185482Ssam sn->packets_since_switch[size_bin] = 0; 622185482Ssam sn->current_rix[size_bin] = best_rix; 623185482Ssam sn->ticks_since_switch[size_bin] = ticks; 624185482Ssam /* 625185482Ssam * Set the visible txrate for this node. 626185482Ssam */ 627218013Sadrian an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ? MCS(best_rix) : DOT11RATE(best_rix); 628143392Ssam } 629185482Ssam rix = sn->current_rix[size_bin]; 630185482Ssam sn->packets_since_switch[size_bin]++; 631143853Ssam } 632185482Ssam *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 633185482Ssamdone: 634232170Sadrian 635232170Sadrian /* 636232170Sadrian * This bug totally sucks and should be fixed. 637232170Sadrian * 638232170Sadrian * For now though, let's not panic, so we can start to figure 639232170Sadrian * out how to better reproduce it. 640232170Sadrian */ 641232170Sadrian if (rix < 0 || rix >= rt->rateCount) { 642232170Sadrian printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n", 643232170Sadrian __func__, 644232170Sadrian rix, 645232170Sadrian rt->rateCount); 646232170Sadrian rix = 0; /* XXX just default for now */ 647232170Sadrian } 648185482Ssam KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 649143392Ssam 650185482Ssam *rix0 = rix; 651185482Ssam *txrate = rt->info[rix].rateCode 652185482Ssam | (shortPreamble ? rt->info[rix].shortPreamble : 0); 653143392Ssam sn->packets_sent[size_bin]++; 654185482Ssam#undef DOT11RATE 655218013Sadrian#undef MCS 656185482Ssam#undef RATE 657143392Ssam} 658143392Ssam 659218160Sadrian/* 660218160Sadrian * Get the TX rates. Don't fiddle with short preamble flags for them; 661218160Sadrian * the caller can do that. 662218160Sadrian */ 663143392Ssamvoid 664218160Sadrianath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an, 665227364Sadrian uint8_t rix0, struct ath_rc_series *rc) 666218160Sadrian{ 667218160Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 668218160Sadrian const struct txschedule *sched = &sn->sched[rix0]; 669218160Sadrian 670239284Sadrian KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 671239284Sadrian rix0, sched->r0)); 672218160Sadrian 673227364Sadrian rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; 674218160Sadrian 675227364Sadrian rc[0].rix = sched->r0; 676227364Sadrian rc[1].rix = sched->r1; 677227364Sadrian rc[2].rix = sched->r2; 678227364Sadrian rc[3].rix = sched->r3; 679227364Sadrian 680227364Sadrian rc[0].tries = sched->t0; 681227364Sadrian rc[1].tries = sched->t1; 682227364Sadrian rc[2].tries = sched->t2; 683227364Sadrian rc[3].tries = sched->t3; 684218160Sadrian} 685218160Sadrian 686218160Sadrianvoid 687143392Ssamath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 688144546Ssam struct ath_desc *ds, int shortPreamble, u_int8_t rix) 689143392Ssam{ 690143392Ssam struct sample_node *sn = ATH_NODE_SAMPLE(an); 691185482Ssam const struct txschedule *sched = &sn->sched[rix]; 692185482Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 693185482Ssam uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 694143392Ssam 695185482Ssam /* XXX precalculate short preamble tables */ 696185482Ssam rix1 = sched->r1; 697185482Ssam s1code = rt->info[rix1].rateCode 698185482Ssam | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 699185482Ssam rix2 = sched->r2; 700185482Ssam s2code = rt->info[rix2].rateCode 701185482Ssam | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 702185482Ssam rix3 = sched->r3; 703185482Ssam s3code = rt->info[rix3].rateCode 704185482Ssam | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 705185482Ssam ath_hal_setupxtxdesc(sc->sc_ah, ds, 706185482Ssam s1code, sched->t1, /* series 1 */ 707185482Ssam s2code, sched->t2, /* series 2 */ 708185482Ssam s3code, sched->t3); /* series 3 */ 709143392Ssam} 710143392Ssam 711143853Ssamstatic void 712143853Ssamupdate_stats(struct ath_softc *sc, struct ath_node *an, 713143853Ssam int frame_size, 714185482Ssam int rix0, int tries0, 715185482Ssam int rix1, int tries1, 716185482Ssam int rix2, int tries2, 717185482Ssam int rix3, int tries3, 718227364Sadrian int short_tries, int tries, int status, 719227364Sadrian int nframes, int nbad) 720143392Ssam{ 721143392Ssam struct sample_node *sn = ATH_NODE_SAMPLE(an); 722143392Ssam struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 723227371Sadrian#ifdef IEEE80211_DEBUG 724227364Sadrian const HAL_RATE_TABLE *rt = sc->sc_currates; 725227371Sadrian#endif 726185482Ssam const int size_bin = size_to_bin(frame_size); 727185482Ssam const int size = bin_to_size(size_bin); 728185482Ssam int tt, tries_so_far; 729219985Sadrian int is_ht40 = (an->an_node.ni_chw == 40); 730247372Sadrian int pct; 731143392Ssam 732185482Ssam if (!IS_RATE_DEFINED(sn, rix0)) 733165185Ssam return; 734185482Ssam tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, 735218761Sadrian MIN(tries0, tries) - 1, is_ht40); 736185482Ssam tries_so_far = tries0; 737143853Ssam 738185482Ssam if (tries1 && tries_so_far < tries) { 739185482Ssam if (!IS_RATE_DEFINED(sn, rix1)) 740165185Ssam return; 741185482Ssam tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries, 742218761Sadrian MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 743185482Ssam tries_so_far += tries1; 744143392Ssam } 745143853Ssam 746185482Ssam if (tries2 && tries_so_far < tries) { 747185482Ssam if (!IS_RATE_DEFINED(sn, rix2)) 748165185Ssam return; 749185482Ssam tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries, 750218761Sadrian MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 751185482Ssam tries_so_far += tries2; 752143392Ssam } 753143392Ssam 754185482Ssam if (tries3 && tries_so_far < tries) { 755185482Ssam if (!IS_RATE_DEFINED(sn, rix3)) 756165185Ssam return; 757185482Ssam tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries, 758218761Sadrian MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 759143853Ssam } 760185482Ssam 761185482Ssam if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 762143392Ssam /* just average the first few packets */ 763185482Ssam int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 764185482Ssam int packets = sn->stats[size_bin][rix0].total_packets; 765227364Sadrian sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); 766143392Ssam } else { 767143392Ssam /* use a ewma */ 768185482Ssam sn->stats[size_bin][rix0].average_tx_time = 769185482Ssam ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 770185482Ssam (tt * (100 - ssc->smoothing_rate))) / 100; 771143392Ssam } 772143392Ssam 773227364Sadrian /* 774227364Sadrian * XXX Don't mark the higher bit rates as also having failed; as this 775227364Sadrian * unfortunately stops those rates from being tasted when trying to 776227364Sadrian * TX. This happens with 11n aggregation. 777227364Sadrian */ 778227364Sadrian if (nframes == nbad) { 779227364Sadrian#if 0 780143392Ssam int y; 781227364Sadrian#endif 782227364Sadrian sn->stats[size_bin][rix0].successive_failures += nbad; 783227364Sadrian#if 0 784155476Ssam for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { 785185482Ssam /* 786185482Ssam * Also say larger packets failed since we 787185482Ssam * assume if a small packet fails at a 788155476Ssam * bit-rate then a larger one will also. 789155476Ssam */ 790227364Sadrian sn->stats[y][rix0].successive_failures += nbad; 791185482Ssam sn->stats[y][rix0].last_tx = ticks; 792185482Ssam sn->stats[y][rix0].tries += tries; 793227364Sadrian sn->stats[y][rix0].total_packets += nframes; 794143392Ssam } 795227364Sadrian#endif 796143392Ssam } else { 797227364Sadrian sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); 798185482Ssam sn->stats[size_bin][rix0].successive_failures = 0; 799143392Ssam } 800185482Ssam sn->stats[size_bin][rix0].tries += tries; 801185482Ssam sn->stats[size_bin][rix0].last_tx = ticks; 802227364Sadrian sn->stats[size_bin][rix0].total_packets += nframes; 803143853Ssam 804247372Sadrian /* update EWMA for this rix */ 805247372Sadrian 806247372Sadrian /* Calculate percentage based on current rate */ 807247372Sadrian if (nframes == 0) 808247372Sadrian nframes = nbad = 1; 809247372Sadrian pct = ((nframes - nbad) * 1000) / nframes; 810247372Sadrian 811247372Sadrian if (sn->stats[size_bin][rix0].total_packets < 812247372Sadrian ssc->smoothing_minpackets) { 813247372Sadrian /* just average the first few packets */ 814247372Sadrian int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) / 815247372Sadrian (sn->stats[size_bin][rix0].total_packets); 816247372Sadrian sn->stats[size_bin][rix0].ewma_pct = a_pct; 817247372Sadrian } else { 818247372Sadrian /* use a ewma */ 819247372Sadrian sn->stats[size_bin][rix0].ewma_pct = 820247372Sadrian ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) + 821247372Sadrian (pct * (100 - ssc->smoothing_rate))) / 100; 822247372Sadrian } 823247372Sadrian 824247372Sadrian 825185482Ssam if (rix0 == sn->current_sample_rix[size_bin]) { 826178354Ssam IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 827178354Ssam &an->an_node, 828227364Sadrian"%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d", 829178354Ssam __func__, 830165185Ssam size, 831165185Ssam status ? "FAIL" : "OK", 832227364Sadrian dot11rate(rt, rix0), 833227364Sadrian dot11rate_label(rt, rix0), 834227364Sadrian short_tries, tries, tt, 835185482Ssam sn->stats[size_bin][rix0].average_tx_time, 836227364Sadrian sn->stats[size_bin][rix0].perfect_tx_time, 837227364Sadrian nframes, nbad); 838143853Ssam sn->sample_tt[size_bin] = tt; 839185482Ssam sn->current_sample_rix[size_bin] = -1; 840143853Ssam } 841143392Ssam} 842143392Ssam 843184348Ssamstatic void 844184348Ssambadrate(struct ifnet *ifp, int series, int hwrate, int tries, int status) 845184348Ssam{ 846184348Ssam if_printf(ifp, "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 847184348Ssam series, hwrate, tries, status); 848184348Ssam} 849184348Ssam 850143392Ssamvoid 851144348Ssamath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 852227364Sadrian const struct ath_rc_series *rc, const struct ath_tx_status *ts, 853227364Sadrian int frame_size, int nframes, int nbad) 854143392Ssam{ 855178354Ssam struct ifnet *ifp = sc->sc_ifp; 856178354Ssam struct ieee80211com *ic = ifp->if_l2com; 857143392Ssam struct sample_node *sn = ATH_NODE_SAMPLE(an); 858227364Sadrian int final_rix, short_tries, long_tries; 859184368Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 860227364Sadrian int status = ts->ts_status; 861172620Ssam int mrr; 862143392Ssam 863194135Ssam final_rix = rt->rateCodeToIndex[ts->ts_rate]; 864165185Ssam short_tries = ts->ts_shortretry; 865165185Ssam long_tries = ts->ts_longretry + 1; 866227364Sadrian 867247372Sadrian if (nframes == 0) { 868247372Sadrian device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__); 869247372Sadrian return; 870247372Sadrian } 871247372Sadrian 872144348Ssam if (frame_size == 0) /* NB: should not happen */ 873143853Ssam frame_size = 1500; 874143392Ssam 875185482Ssam if (sn->ratemask == 0) { 876178354Ssam IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 877178354Ssam &an->an_node, 878178354Ssam "%s: size %d %s rate/try %d/%d no rates yet", 879178354Ssam __func__, 880165185Ssam bin_to_size(size_to_bin(frame_size)), 881227364Sadrian status ? "FAIL" : "OK", 882165185Ssam short_tries, long_tries); 883143853Ssam return; 884143853Ssam } 885238961Sadrian mrr = sc->sc_mrretry; 886238961Sadrian /* XXX check HT protmode too */ 887238962Sadrian if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 888238961Sadrian mrr = 0; 889238961Sadrian 890194135Ssam if (!mrr || ts->ts_finaltsi == 0) { 891185482Ssam if (!IS_RATE_DEFINED(sn, final_rix)) { 892239284Sadrian device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n", 893239284Sadrian __func__, ts->ts_rate, ts->ts_finaltsi); 894227364Sadrian badrate(ifp, 0, ts->ts_rate, long_tries, status); 895184348Ssam return; 896184348Ssam } 897165185Ssam /* 898165185Ssam * Only one rate was used; optimize work. 899165185Ssam */ 900178354Ssam IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 901239756Sadrian &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]", 902178354Ssam __func__, 903165185Ssam bin_to_size(size_to_bin(frame_size)), 904219822Sadrian frame_size, 905227364Sadrian status ? "FAIL" : "OK", 906227364Sadrian dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), 907227364Sadrian short_tries, long_tries, nframes, nbad); 908165185Ssam update_stats(sc, an, frame_size, 909185482Ssam final_rix, long_tries, 910165185Ssam 0, 0, 911165185Ssam 0, 0, 912165185Ssam 0, 0, 913227364Sadrian short_tries, long_tries, status, 914227364Sadrian nframes, nbad); 915227364Sadrian 916143853Ssam } else { 917165185Ssam int finalTSIdx = ts->ts_finaltsi; 918217628Sadrian int i; 919143392Ssam 920143853Ssam /* 921143853Ssam * Process intermediate rates that failed. 922143853Ssam */ 923218013Sadrian 924178354Ssam IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 925178354Ssam &an->an_node, 926239756Sadrian"%s: size %d (%d bytes) finaltsidx %d short %d long %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]", 927178354Ssam __func__, 928165185Ssam bin_to_size(size_to_bin(frame_size)), 929219822Sadrian frame_size, 930165185Ssam finalTSIdx, 931239756Sadrian short_tries, 932227364Sadrian long_tries, 933227364Sadrian status ? "FAIL" : "OK", 934227364Sadrian dot11rate(rt, rc[0].rix), 935227364Sadrian dot11rate_label(rt, rc[0].rix), rc[0].tries, 936227364Sadrian dot11rate(rt, rc[1].rix), 937227364Sadrian dot11rate_label(rt, rc[1].rix), rc[1].tries, 938227364Sadrian dot11rate(rt, rc[2].rix), 939227364Sadrian dot11rate_label(rt, rc[2].rix), rc[2].tries, 940227364Sadrian dot11rate(rt, rc[3].rix), 941227364Sadrian dot11rate_label(rt, rc[3].rix), rc[3].tries, 942227364Sadrian nframes, nbad); 943143853Ssam 944218013Sadrian for (i = 0; i < 4; i++) { 945227364Sadrian if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) 946227364Sadrian badrate(ifp, 0, rc[i].ratecode, rc[i].tries, 947227364Sadrian status); 948218013Sadrian } 949185482Ssam 950165185Ssam /* 951165185Ssam * NB: series > 0 are not penalized for failure 952165185Ssam * based on the try counts under the assumption 953165185Ssam * that losses are often bursty and since we 954165185Ssam * sample higher rates 1 try at a time doing so 955165185Ssam * may unfairly penalize them. 956165185Ssam */ 957227364Sadrian if (rc[0].tries) { 958227364Sadrian update_stats(sc, an, frame_size, 959227364Sadrian rc[0].rix, rc[0].tries, 960227364Sadrian rc[1].rix, rc[1].tries, 961227364Sadrian rc[2].rix, rc[2].tries, 962227364Sadrian rc[3].rix, rc[3].tries, 963227364Sadrian short_tries, long_tries, 964227364Sadrian long_tries > rc[0].tries, 965227364Sadrian nframes, nbad); 966227364Sadrian long_tries -= rc[0].tries; 967143853Ssam } 968143853Ssam 969227364Sadrian if (rc[1].tries && finalTSIdx > 0) { 970227364Sadrian update_stats(sc, an, frame_size, 971227364Sadrian rc[1].rix, rc[1].tries, 972227364Sadrian rc[2].rix, rc[2].tries, 973227364Sadrian rc[3].rix, rc[3].tries, 974227364Sadrian 0, 0, 975227364Sadrian short_tries, long_tries, 976227364Sadrian status, 977227364Sadrian nframes, nbad); 978227364Sadrian long_tries -= rc[1].tries; 979143853Ssam } 980143853Ssam 981227364Sadrian if (rc[2].tries && finalTSIdx > 1) { 982227364Sadrian update_stats(sc, an, frame_size, 983227364Sadrian rc[2].rix, rc[2].tries, 984227364Sadrian rc[3].rix, rc[3].tries, 985143853Ssam 0, 0, 986143853Ssam 0, 0, 987227364Sadrian short_tries, long_tries, 988227364Sadrian status, 989227364Sadrian nframes, nbad); 990227364Sadrian long_tries -= rc[2].tries; 991143853Ssam } 992143853Ssam 993227364Sadrian if (rc[3].tries && finalTSIdx > 2) { 994227364Sadrian update_stats(sc, an, frame_size, 995227364Sadrian rc[3].rix, rc[3].tries, 996143853Ssam 0, 0, 997143853Ssam 0, 0, 998143853Ssam 0, 0, 999227364Sadrian short_tries, long_tries, 1000227364Sadrian status, 1001227364Sadrian nframes, nbad); 1002143853Ssam } 1003143392Ssam } 1004143853Ssam} 1005143392Ssam 1006143853Ssamvoid 1007143853Ssamath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 1008143853Ssam{ 1009143853Ssam if (isnew) 1010143853Ssam ath_rate_ctl_reset(sc, &an->an_node); 1011143392Ssam} 1012143392Ssam 1013185482Ssamstatic const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 1014185482Ssam NULL, /* IEEE80211_MODE_AUTO */ 1015185482Ssam series_11a, /* IEEE80211_MODE_11A */ 1016185482Ssam series_11g, /* IEEE80211_MODE_11B */ 1017185482Ssam series_11g, /* IEEE80211_MODE_11G */ 1018185482Ssam NULL, /* IEEE80211_MODE_FH */ 1019185482Ssam series_11a, /* IEEE80211_MODE_TURBO_A */ 1020185482Ssam series_11g, /* IEEE80211_MODE_TURBO_G */ 1021185482Ssam series_11a, /* IEEE80211_MODE_STURBO_A */ 1022218013Sadrian series_11na, /* IEEE80211_MODE_11NA */ 1023218013Sadrian series_11ng, /* IEEE80211_MODE_11NG */ 1024185482Ssam series_half, /* IEEE80211_MODE_HALF */ 1025185482Ssam series_quarter, /* IEEE80211_MODE_QUARTER */ 1026185482Ssam}; 1027185482Ssam 1028143392Ssam/* 1029143392Ssam * Initialize the tables for a node. 1030143392Ssam */ 1031143392Ssamstatic void 1032143853Ssamath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 1033143392Ssam{ 1034143392Ssam#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 1035185482Ssam#define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 1036218013Sadrian#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 1037143392Ssam struct ath_node *an = ATH_NODE(ni); 1038143392Ssam struct sample_node *sn = ATH_NODE_SAMPLE(an); 1039143392Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 1040219822Sadrian int x, y, rix; 1041143392Ssam 1042143392Ssam KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 1043185482Ssam 1044185482Ssam KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 1045185482Ssam ("curmode %u", sc->sc_curmode)); 1046239284Sadrian 1047185482Ssam sn->sched = mrr_schedules[sc->sc_curmode]; 1048185482Ssam KASSERT(sn->sched != NULL, 1049185482Ssam ("no mrr schedule for mode %u", sc->sc_curmode)); 1050185482Ssam 1051185482Ssam sn->static_rix = -1; 1052219822Sadrian ath_rate_update_static_rix(sc, ni); 1053218013Sadrian 1054232170Sadrian sn->currates = sc->sc_currates; 1055232170Sadrian 1056185482Ssam /* 1057185482Ssam * Construct a bitmask of usable rates. This has all 1058185482Ssam * negotiated rates minus those marked by the hal as 1059185482Ssam * to be ignored for doing rate control. 1060185482Ssam */ 1061185482Ssam sn->ratemask = 0; 1062218013Sadrian /* MCS rates */ 1063218013Sadrian if (ni->ni_flags & IEEE80211_NODE_HT) { 1064218013Sadrian for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { 1065218013Sadrian rix = sc->sc_rixmap[MCS(x)]; 1066218013Sadrian if (rix == 0xff) 1067218013Sadrian continue; 1068218013Sadrian /* skip rates marked broken by hal */ 1069218013Sadrian if (!rt->info[rix].valid) 1070218013Sadrian continue; 1071218013Sadrian KASSERT(rix < SAMPLE_MAXRATES, 1072218013Sadrian ("mcs %u has rix %d", MCS(x), rix)); 1073239284Sadrian sn->ratemask |= (uint64_t) 1<<rix; 1074218013Sadrian } 1075218013Sadrian } 1076218013Sadrian 1077218013Sadrian /* Legacy rates */ 1078185482Ssam for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 1079185482Ssam rix = sc->sc_rixmap[RATE(x)]; 1080185482Ssam if (rix == 0xff) 1081152447Ssam continue; 1082185482Ssam /* skip rates marked broken by hal */ 1083185482Ssam if (!rt->info[rix].valid) 1084185482Ssam continue; 1085185482Ssam KASSERT(rix < SAMPLE_MAXRATES, 1086185482Ssam ("rate %u has rix %d", RATE(x), rix)); 1087239284Sadrian sn->ratemask |= (uint64_t) 1<<rix; 1088143392Ssam } 1089178354Ssam#ifdef IEEE80211_DEBUG 1090178354Ssam if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 1091239284Sadrian uint64_t mask; 1092185482Ssam 1093178354Ssam ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 1094185482Ssam ni->ni_macaddr, ":", __func__); 1095185482Ssam for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1096185482Ssam if ((mask & 1) == 0) 1097178354Ssam continue; 1098219216Sadrian printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), 1099218761Sadrian calc_usecs_unicast_packet(sc, 1600, rix, 0,0, 1100219985Sadrian (ni->ni_chw == 40))); 1101178354Ssam } 1102178354Ssam printf("\n"); 1103178354Ssam } 1104178354Ssam#endif 1105143853Ssam for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1106143853Ssam int size = bin_to_size(y); 1107239284Sadrian uint64_t mask; 1108185482Ssam 1109143853Ssam sn->packets_sent[y] = 0; 1110185482Ssam sn->current_sample_rix[y] = -1; 1111185482Ssam sn->last_sample_rix[y] = 0; 1112185482Ssam /* XXX start with first valid rate */ 1113185482Ssam sn->current_rix[y] = ffs(sn->ratemask)-1; 1114143853Ssam 1115185482Ssam /* 1116185482Ssam * Initialize the statistics buckets; these are 1117185482Ssam * indexed by the rate code index. 1118185482Ssam */ 1119185482Ssam for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 1120185482Ssam if ((mask & 1) == 0) /* not a valid rate */ 1121185482Ssam continue; 1122185482Ssam sn->stats[y][rix].successive_failures = 0; 1123185482Ssam sn->stats[y][rix].tries = 0; 1124185482Ssam sn->stats[y][rix].total_packets = 0; 1125185482Ssam sn->stats[y][rix].packets_acked = 0; 1126185482Ssam sn->stats[y][rix].last_tx = 0; 1127227364Sadrian sn->stats[y][rix].ewma_pct = 0; 1128143853Ssam 1129185482Ssam sn->stats[y][rix].perfect_tx_time = 1130218761Sadrian calc_usecs_unicast_packet(sc, size, rix, 0, 0, 1131219985Sadrian (ni->ni_chw == 40)); 1132185482Ssam sn->stats[y][rix].average_tx_time = 1133185482Ssam sn->stats[y][rix].perfect_tx_time; 1134143853Ssam } 1135143853Ssam } 1136185482Ssam#if 0 1137185482Ssam /* XXX 0, num_rates-1 are wrong */ 1138178354Ssam IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 1139178354Ssam "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 1140165185Ssam sn->num_rates, 1141185482Ssam DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 1142165185Ssam sn->stats[1][0].perfect_tx_time, 1143185482Ssam DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 1144165185Ssam sn->stats[1][sn->num_rates-1].perfect_tx_time 1145155476Ssam ); 1146185482Ssam#endif 1147178354Ssam /* set the visible bit-rate */ 1148185482Ssam if (sn->static_rix != -1) 1149185482Ssam ni->ni_txrate = DOT11RATE(sn->static_rix); 1150156463Ssam else 1151185482Ssam ni->ni_txrate = RATE(0); 1152143392Ssam#undef RATE 1153185482Ssam#undef DOT11RATE 1154143392Ssam} 1155143392Ssam 1156238633Sadrian/* 1157238633Sadrian * Fetch the statistics for the given node. 1158238633Sadrian * 1159238633Sadrian * The ieee80211 node must be referenced and unlocked, however the ath_node 1160238633Sadrian * must be locked. 1161238633Sadrian * 1162238633Sadrian * The main difference here is that we convert the rate indexes 1163238633Sadrian * to 802.11 rates, or the userland output won't make much sense 1164238633Sadrian * as it has no access to the rix table. 1165238633Sadrian */ 1166238633Sadrianint 1167238633Sadrianath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an, 1168238633Sadrian struct ath_rateioctl *rs) 1169238633Sadrian{ 1170238633Sadrian struct sample_node *sn = ATH_NODE_SAMPLE(an); 1171238633Sadrian const HAL_RATE_TABLE *rt = sc->sc_currates; 1172238633Sadrian struct ath_rateioctl_tlv av; 1173238638Sadrian struct ath_rateioctl_rt *tv; 1174238633Sadrian int y; 1175238638Sadrian int o = 0; 1176238633Sadrian 1177238633Sadrian ATH_NODE_LOCK_ASSERT(an); 1178238633Sadrian 1179238633Sadrian /* 1180238633Sadrian * Ensure there's enough space for the statistics. 1181238633Sadrian */ 1182238633Sadrian if (rs->len < 1183238633Sadrian sizeof(struct ath_rateioctl_tlv) + 1184238638Sadrian sizeof(struct ath_rateioctl_rt) + 1185238638Sadrian sizeof(struct ath_rateioctl_tlv) + 1186238638Sadrian sizeof(struct sample_node)) { 1187238638Sadrian device_printf(sc->sc_dev, "%s: len=%d, too short\n", 1188238638Sadrian __func__, 1189238638Sadrian rs->len); 1190238633Sadrian return (EINVAL); 1191238638Sadrian } 1192238633Sadrian 1193238633Sadrian /* 1194238633Sadrian * Take a temporary copy of the sample node state so we can 1195238633Sadrian * modify it before we copy it. 1196238633Sadrian */ 1197238638Sadrian tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP, 1198238638Sadrian M_NOWAIT | M_ZERO); 1199238638Sadrian if (tv == NULL) { 1200238633Sadrian return (ENOMEM); 1201238638Sadrian } 1202238633Sadrian 1203238638Sadrian /* 1204238638Sadrian * Populate the rate table mapping TLV. 1205238638Sadrian */ 1206238638Sadrian tv->nentries = rt->rateCount; 1207238638Sadrian for (y = 0; y < rt->rateCount; y++) { 1208238638Sadrian tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL; 1209238638Sadrian if (rt->info[y].phy == IEEE80211_T_HT) 1210238638Sadrian tv->ratecode[y] |= IEEE80211_RATE_MCS; 1211238633Sadrian } 1212238633Sadrian 1213238638Sadrian o = 0; 1214238633Sadrian /* 1215238638Sadrian * First TLV - rate code mapping 1216238633Sadrian */ 1217238638Sadrian av.tlv_id = ATH_RATE_TLV_RATETABLE; 1218238638Sadrian av.tlv_len = sizeof(struct ath_rateioctl_rt); 1219238638Sadrian copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1220238638Sadrian o += sizeof(struct ath_rateioctl_tlv); 1221238638Sadrian copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); 1222238638Sadrian o += sizeof(struct ath_rateioctl_rt); 1223238638Sadrian 1224238638Sadrian /* 1225238638Sadrian * Second TLV - sample node statistics 1226238638Sadrian */ 1227238633Sadrian av.tlv_id = ATH_RATE_TLV_SAMPLENODE; 1228238633Sadrian av.tlv_len = sizeof(struct sample_node); 1229238638Sadrian copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1230238638Sadrian o += sizeof(struct ath_rateioctl_tlv); 1231238633Sadrian 1232238633Sadrian /* 1233238633Sadrian * Copy the statistics over to the provided buffer. 1234238633Sadrian */ 1235238638Sadrian copyout(sn, rs->buf + o, sizeof(struct sample_node)); 1236238638Sadrian o += sizeof(struct sample_node); 1237238633Sadrian 1238238638Sadrian free(tv, M_TEMP); 1239238633Sadrian 1240238633Sadrian return (0); 1241238633Sadrian} 1242238633Sadrian 1243144307Ssamstatic void 1244185482Ssamsample_stats(void *arg, struct ieee80211_node *ni) 1245143392Ssam{ 1246185482Ssam struct ath_softc *sc = arg; 1247185482Ssam const HAL_RATE_TABLE *rt = sc->sc_currates; 1248185482Ssam struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 1249239284Sadrian uint64_t mask; 1250185482Ssam int rix, y; 1251185482Ssam 1252239300Skib printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n", 1253185482Ssam ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 1254227364Sadrian dot11rate(rt, sn->static_rix), 1255227364Sadrian dot11rate_label(rt, sn->static_rix), 1256239300Skib (uintmax_t)sn->ratemask); 1257185482Ssam for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1258219216Sadrian printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n", 1259185482Ssam bin_to_size(y), sn->current_rix[y], 1260219216Sadrian dot11rate(rt, sn->current_rix[y]), 1261219216Sadrian dot11rate_label(rt, sn->current_rix[y]), 1262185482Ssam sn->packets_since_switch[y], sn->ticks_since_switch[y]); 1263227364Sadrian printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n", 1264227364Sadrian bin_to_size(y), 1265227364Sadrian dot11rate(rt, sn->last_sample_rix[y]), 1266227364Sadrian dot11rate_label(rt, sn->last_sample_rix[y]), 1267227364Sadrian dot11rate(rt, sn->current_sample_rix[y]), 1268227364Sadrian dot11rate_label(rt, sn->current_sample_rix[y]), 1269227364Sadrian sn->packets_sent[y]); 1270185482Ssam printf("[%4u] packets since sample %d sample tt %u\n", 1271185482Ssam bin_to_size(y), sn->packets_since_sample[y], 1272185482Ssam sn->sample_tt[y]); 1273185482Ssam } 1274185482Ssam for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1275185482Ssam if ((mask & 1) == 0) 1276185482Ssam continue; 1277185482Ssam for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1278185482Ssam if (sn->stats[y][rix].total_packets == 0) 1279185482Ssam continue; 1280227364Sadrian printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n", 1281219216Sadrian dot11rate(rt, rix), dot11rate_label(rt, rix), 1282185482Ssam bin_to_size(y), 1283227340Sadrian (uintmax_t) sn->stats[y][rix].total_packets, 1284227340Sadrian (uintmax_t) sn->stats[y][rix].packets_acked, 1285227340Sadrian (int) ((sn->stats[y][rix].packets_acked * 100ULL) / 1286227340Sadrian sn->stats[y][rix].total_packets), 1287227364Sadrian sn->stats[y][rix].ewma_pct / 10, 1288227364Sadrian sn->stats[y][rix].ewma_pct % 10, 1289227340Sadrian (uintmax_t) sn->stats[y][rix].tries, 1290185482Ssam sn->stats[y][rix].successive_failures, 1291185482Ssam sn->stats[y][rix].average_tx_time, 1292185482Ssam ticks - sn->stats[y][rix].last_tx); 1293185482Ssam } 1294185482Ssam } 1295185482Ssam} 1296185482Ssam 1297185482Ssamstatic int 1298185482Ssamath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 1299185482Ssam{ 1300185482Ssam struct ath_softc *sc = arg1; 1301185482Ssam struct ifnet *ifp = sc->sc_ifp; 1302185482Ssam struct ieee80211com *ic = ifp->if_l2com; 1303185482Ssam int error, v; 1304185482Ssam 1305185482Ssam v = 0; 1306185482Ssam error = sysctl_handle_int(oidp, &v, 0, req); 1307185482Ssam if (error || !req->newptr) 1308185482Ssam return error; 1309185482Ssam ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 1310185482Ssam return 0; 1311185482Ssam} 1312185482Ssam 1313185482Ssamstatic int 1314185482Ssamath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 1315185482Ssam{ 1316185482Ssam struct sample_softc *ssc = arg1; 1317185482Ssam int rate, error; 1318185482Ssam 1319185482Ssam rate = ssc->smoothing_rate; 1320185482Ssam error = sysctl_handle_int(oidp, &rate, 0, req); 1321185482Ssam if (error || !req->newptr) 1322185482Ssam return error; 1323185482Ssam if (!(0 <= rate && rate < 100)) 1324185482Ssam return EINVAL; 1325185482Ssam ssc->smoothing_rate = rate; 1326185482Ssam ssc->smoothing_minpackets = 100 / (100 - rate); 1327185482Ssam return 0; 1328185482Ssam} 1329185482Ssam 1330185482Ssamstatic int 1331185482Ssamath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 1332185482Ssam{ 1333185482Ssam struct sample_softc *ssc = arg1; 1334185482Ssam int rate, error; 1335185482Ssam 1336185482Ssam rate = ssc->sample_rate; 1337185482Ssam error = sysctl_handle_int(oidp, &rate, 0, req); 1338185482Ssam if (error || !req->newptr) 1339185482Ssam return error; 1340185482Ssam if (!(2 <= rate && rate <= 100)) 1341185482Ssam return EINVAL; 1342185482Ssam ssc->sample_rate = rate; 1343185482Ssam return 0; 1344185482Ssam} 1345185482Ssam 1346185482Ssamstatic void 1347185482Ssamath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 1348185482Ssam{ 1349143392Ssam struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 1350143392Ssam struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 1351143392Ssam 1352185482Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1353185482Ssam "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 1354185482Ssam ath_rate_sysctl_smoothing_rate, "I", 1355185482Ssam "sample: smoothing rate for avg tx time (%%)"); 1356185482Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1357185482Ssam "sample_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 1358185482Ssam ath_rate_sysctl_sample_rate, "I", 1359185482Ssam "sample: percent air time devoted to sampling new rates (%%)"); 1360185482Ssam /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 1361185482Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1362185482Ssam "sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1363185482Ssam ath_rate_sysctl_stats, "I", "sample: print statistics"); 1364143392Ssam} 1365143392Ssam 1366143392Ssamstruct ath_ratectrl * 1367143392Ssamath_rate_attach(struct ath_softc *sc) 1368143392Ssam{ 1369185482Ssam struct sample_softc *ssc; 1370143392Ssam 1371185482Ssam ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 1372185482Ssam if (ssc == NULL) 1373143392Ssam return NULL; 1374185482Ssam ssc->arc.arc_space = sizeof(struct sample_node); 1375240583Sadrian ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */ 1376185482Ssam ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 1377185482Ssam ssc->sample_rate = 10; /* %time to try diff tx rates */ 1378185482Ssam ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 1379185482Ssam ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 1380185482Ssam ssc->min_switch = hz; /* 1 second */ 1381185482Ssam ath_rate_sysctlattach(sc, ssc); 1382185482Ssam return &ssc->arc; 1383143392Ssam} 1384143392Ssam 1385143392Ssamvoid 1386143392Ssamath_rate_detach(struct ath_ratectrl *arc) 1387143392Ssam{ 1388185482Ssam struct sample_softc *ssc = (struct sample_softc *) arc; 1389143392Ssam 1390185482Ssam free(ssc, M_DEVBUF); 1391143392Ssam} 1392