1fa20c234SSam Leffler /*- 2fa20c234SSam Leffler * Copyright (c) 2005 John Bicket 3fa20c234SSam Leffler * All rights reserved. 4fa20c234SSam Leffler * 5fa20c234SSam Leffler * Redistribution and use in source and binary forms, with or without 6fa20c234SSam Leffler * modification, are permitted provided that the following conditions 7fa20c234SSam Leffler * are met: 8fa20c234SSam Leffler * 1. Redistributions of source code must retain the above copyright 9fa20c234SSam Leffler * notice, this list of conditions and the following disclaimer, 10fa20c234SSam Leffler * without modification. 11fa20c234SSam Leffler * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12fa20c234SSam Leffler * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13fa20c234SSam Leffler * redistribution must be conditioned upon including a substantially 14fa20c234SSam Leffler * similar Disclaimer requirement for further binary redistribution. 15fa20c234SSam Leffler * 3. Neither the names of the above-listed copyright holders nor the names 16fa20c234SSam Leffler * of any contributors may be used to endorse or promote products derived 17fa20c234SSam Leffler * from this software without specific prior written permission. 18fa20c234SSam Leffler * 19fa20c234SSam Leffler * Alternatively, this software may be distributed under the terms of the 20fa20c234SSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 21fa20c234SSam Leffler * Software Foundation. 22fa20c234SSam Leffler * 23fa20c234SSam Leffler * NO WARRANTY 24fa20c234SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25fa20c234SSam Leffler * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26fa20c234SSam Leffler * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27fa20c234SSam Leffler * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28fa20c234SSam Leffler * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29fa20c234SSam Leffler * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30fa20c234SSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31fa20c234SSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32fa20c234SSam Leffler * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33fa20c234SSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34fa20c234SSam Leffler * THE POSSIBILITY OF SUCH DAMAGES. 35fa20c234SSam Leffler */ 36fa20c234SSam Leffler 37fa20c234SSam Leffler #include <sys/cdefs.h> 38fa20c234SSam Leffler __FBSDID("$FreeBSD$"); 39fa20c234SSam Leffler 40fa20c234SSam Leffler /* 41fa20c234SSam Leffler * John Bicket's SampleRate control algorithm. 42fa20c234SSam Leffler */ 43fa20c234SSam Leffler #include "opt_inet.h" 44fa20c234SSam Leffler 45fa20c234SSam Leffler #include <sys/param.h> 46fa20c234SSam Leffler #include <sys/systm.h> 47fa20c234SSam Leffler #include <sys/sysctl.h> 48fa20c234SSam Leffler #include <sys/module.h> 49fa20c234SSam Leffler #include <sys/kernel.h> 50fa20c234SSam Leffler #include <sys/lock.h> 51fa20c234SSam Leffler #include <sys/mutex.h> 52fa20c234SSam Leffler #include <sys/errno.h> 53fa20c234SSam Leffler 54fa20c234SSam Leffler #include <machine/bus.h> 55fa20c234SSam Leffler #include <machine/resource.h> 56fa20c234SSam Leffler #include <sys/bus.h> 57fa20c234SSam Leffler 58fa20c234SSam Leffler #include <sys/socket.h> 59fa20c234SSam Leffler 60fa20c234SSam Leffler #include <net/if.h> 61fa20c234SSam Leffler #include <net/if_media.h> 62fa20c234SSam Leffler #include <net/if_arp.h> 63fa20c234SSam Leffler #include <net/ethernet.h> /* XXX for ether_sprintf */ 64fa20c234SSam Leffler 65fa20c234SSam Leffler #include <net80211/ieee80211_var.h> 66fa20c234SSam Leffler 67fa20c234SSam Leffler #include <net/bpf.h> 68fa20c234SSam Leffler 69fa20c234SSam Leffler #ifdef INET 70fa20c234SSam Leffler #include <netinet/in.h> 71fa20c234SSam Leffler #include <netinet/if_ether.h> 72fa20c234SSam Leffler #endif 73fa20c234SSam Leffler 74fa20c234SSam Leffler #include <dev/ath/if_athvar.h> 75fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h> 76fa20c234SSam Leffler #include <contrib/dev/ath/ah_desc.h> 77fa20c234SSam Leffler 78fa20c234SSam Leffler #define SAMPLE_DEBUG 79fa20c234SSam Leffler #ifdef SAMPLE_DEBUG 80fa20c234SSam Leffler enum { 81fa20c234SSam Leffler ATH_DEBUG_RATE = 0x00000010, /* rate control */ 82fa20c234SSam Leffler }; 83fa20c234SSam Leffler #define DPRINTF(sc, _fmt, ...) do { \ 84fa20c234SSam Leffler if (sc->sc_debug & ATH_DEBUG_RATE) \ 85fa20c234SSam Leffler printf(_fmt, __VA_ARGS__); \ 86fa20c234SSam Leffler } while (0) 87fa20c234SSam Leffler #else 88fa20c234SSam Leffler #define DPRINTF(sc, _fmt, ...) 89fa20c234SSam Leffler #endif 90fa20c234SSam Leffler 91fa20c234SSam Leffler /* 92fa20c234SSam Leffler * This file is an implementation of the SampleRate algorithm 93fa20c234SSam Leffler * in "Bit-rate Selection in Wireless Networks" 94fa20c234SSam Leffler * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 95fa20c234SSam Leffler * 96fa20c234SSam Leffler * SampleRate chooses the bit-rate it predicts will provide the most 97fa20c234SSam Leffler * throughput based on estimates of the expected per-packet 98fa20c234SSam Leffler * transmission time for each bit-rate. SampleRate periodically sends 99fa20c234SSam Leffler * packets at bit-rates other than the current one to estimate when 100fa20c234SSam Leffler * another bit-rate will provide better performance. SampleRate 101fa20c234SSam Leffler * switches to another bit-rate when its estimated per-packet 102fa20c234SSam Leffler * transmission time becomes smaller than the current bit-rate's. 103fa20c234SSam Leffler * SampleRate reduces the number of bit-rates it must sample by 104fa20c234SSam Leffler * eliminating those that could not perform better than the one 105fa20c234SSam Leffler * currently being used. SampleRate also stops probing at a bit-rate 106fa20c234SSam Leffler * if it experiences several successive losses. 107fa20c234SSam Leffler * 108fa20c234SSam Leffler * The difference between the algorithm in the thesis and the one in this 109fa20c234SSam Leffler * file is that the one in this file uses a ewma instead of a window. 110fa20c234SSam Leffler * 111fa20c234SSam Leffler */ 112fa20c234SSam Leffler 113fa20c234SSam Leffler static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *); 114fa20c234SSam Leffler 115fa20c234SSam Leffler static __inline int size_to_bin(int size) 116fa20c234SSam Leffler { 117fa20c234SSam Leffler int x = 0; 118fa20c234SSam Leffler for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) { 119fa20c234SSam Leffler if (size < packet_size_bins[x]) { 120fa20c234SSam Leffler return x; 121fa20c234SSam Leffler } 122fa20c234SSam Leffler } 123fa20c234SSam Leffler return NUM_PACKET_SIZE_BINS-1; 124fa20c234SSam Leffler } 125fa20c234SSam Leffler static __inline int bin_to_size(int index) { 126fa20c234SSam Leffler return packet_size_bins[index]; 127fa20c234SSam Leffler } 128fa20c234SSam Leffler 129fa20c234SSam Leffler /* 130fa20c234SSam Leffler * Setup rate codes for management/control frames. We force 131fa20c234SSam Leffler * all such frames to the lowest rate. 132fa20c234SSam Leffler */ 133fa20c234SSam Leffler static void 134fa20c234SSam Leffler ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an) 135fa20c234SSam Leffler { 136fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 137fa20c234SSam Leffler 138fa20c234SSam Leffler /* setup rates for management frames */ 139fa20c234SSam Leffler /* XXX management/control frames always go at lowest speed */ 140fa20c234SSam Leffler an->an_tx_mgtrate = rt->info[0].rateCode; 141fa20c234SSam Leffler an->an_tx_mgtratesp = an->an_tx_mgtrate 142fa20c234SSam Leffler | rt->info[0].shortPreamble; 143fa20c234SSam Leffler } 144fa20c234SSam Leffler 145fa20c234SSam Leffler void 146fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 147fa20c234SSam Leffler { 148fa20c234SSam Leffler DPRINTF(sc, "%s:\n", __func__); 149fa20c234SSam Leffler /* NB: assumed to be zero'd by caller */ 150fa20c234SSam Leffler ath_rate_setmgtrates(sc, an); 151fa20c234SSam Leffler } 152fa20c234SSam Leffler 153fa20c234SSam Leffler void 154fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 155fa20c234SSam Leffler { 156fa20c234SSam Leffler DPRINTF(sc, "%s:\n", __func__); 157fa20c234SSam Leffler } 158fa20c234SSam Leffler 159fa20c234SSam Leffler 160fa20c234SSam Leffler /* 161fa20c234SSam Leffler * returns the ndx with the lowest average_tx_time, 162fa20c234SSam Leffler * or -1 if all the average_tx_times are 0. 163fa20c234SSam Leffler */ 164fa20c234SSam Leffler static __inline int best_rate_ndx(struct sample_node *sn, int size_bin) 165fa20c234SSam Leffler { 166fa20c234SSam Leffler int x = 0; 167fa20c234SSam Leffler int best_rate_ndx = 0; 168fa20c234SSam Leffler int best_rate_tt = 0; 169fa20c234SSam Leffler for (x = 0; x < sn->num_rates; x++) { 170fa20c234SSam Leffler int tt = sn->stats[size_bin][x].average_tx_time; 171fa20c234SSam Leffler if (tt > 0) { 172fa20c234SSam Leffler if (!best_rate_tt || best_rate_tt > tt) { 173fa20c234SSam Leffler best_rate_tt = tt; 174fa20c234SSam Leffler best_rate_ndx = x; 175fa20c234SSam Leffler } 176fa20c234SSam Leffler } 177fa20c234SSam Leffler } 178fa20c234SSam Leffler return (best_rate_tt) ? best_rate_ndx : -1; 179fa20c234SSam Leffler } 180fa20c234SSam Leffler 181fa20c234SSam Leffler /* 182fa20c234SSam Leffler * pick a ndx s.t. the perfect_tx_time 183fa20c234SSam Leffler * is less than the best bit-rate's average_tx_time 184fa20c234SSam Leffler * and the ndx has not had four successive failures. 185fa20c234SSam Leffler */ 186fa20c234SSam Leffler static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin) 187fa20c234SSam Leffler { 188fa20c234SSam Leffler int x = 0; 189fa20c234SSam Leffler int best_ndx = best_rate_ndx(sn, size_bin); 190fa20c234SSam Leffler int best_tt = 0; 191fa20c234SSam Leffler int num_eligible = 0; 192fa20c234SSam Leffler 193fa20c234SSam Leffler if (best_ndx < 0) { 194fa20c234SSam Leffler /* no successes yet, send at the lowest bit-rate */ 195fa20c234SSam Leffler return 0; 196fa20c234SSam Leffler } 197fa20c234SSam Leffler 198fa20c234SSam Leffler best_tt = sn->stats[size_bin][best_ndx].average_tx_time; 199fa20c234SSam Leffler sn->sample_num[size_bin]++; 200fa20c234SSam Leffler 201fa20c234SSam Leffler /* 202fa20c234SSam Leffler * first, find the number of bit-rates we could potentially 203fa20c234SSam Leffler * sample. we assume this list doesn't change a lot, so 204fa20c234SSam Leffler * we will just cycle through them. 205fa20c234SSam Leffler */ 206fa20c234SSam Leffler for (x = 0; x < sn->num_rates; x++) { 207fa20c234SSam Leffler if (x != best_ndx && 208fa20c234SSam Leffler sn->stats[size_bin][x].perfect_tx_time < best_tt && 209fa20c234SSam Leffler sn->stats[size_bin][x].successive_failures < 4) { 210fa20c234SSam Leffler num_eligible++; 211fa20c234SSam Leffler } 212fa20c234SSam Leffler } 213fa20c234SSam Leffler 214fa20c234SSam Leffler if (num_eligible > 0) { 215fa20c234SSam Leffler int pick = sn->sample_num[size_bin] % num_eligible; 216fa20c234SSam Leffler for (x = 0; x < sn->num_rates; x++) { 217fa20c234SSam Leffler if (x != best_ndx && 218fa20c234SSam Leffler sn->stats[size_bin][x].perfect_tx_time < best_tt && 219fa20c234SSam Leffler sn->stats[size_bin][x].successive_failures < 4) { 220fa20c234SSam Leffler if (pick == 0) { 221fa20c234SSam Leffler return x; 222fa20c234SSam Leffler } 223fa20c234SSam Leffler pick--; 224fa20c234SSam Leffler } 225fa20c234SSam Leffler } 226fa20c234SSam Leffler } 227fa20c234SSam Leffler return best_ndx; 228fa20c234SSam Leffler } 229fa20c234SSam Leffler 230fa20c234SSam Leffler void 231fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 232fa20c234SSam Leffler HAL_BOOL shortPreamble, size_t frameLen, 233fa20c234SSam Leffler u_int8_t *rix, int *try0, u_int8_t *txrate) 234fa20c234SSam Leffler { 235fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 236fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 237fa20c234SSam Leffler int x; 238fa20c234SSam Leffler int ndx = 0; 239fa20c234SSam Leffler int size_bin = size_to_bin(frameLen); 240fa20c234SSam Leffler int best_ndx = best_rate_ndx(sn, size_bin); 241fa20c234SSam Leffler 242fa20c234SSam Leffler if (sn->static_rate_ndx != -1) { 243fa20c234SSam Leffler *try0 = 4; 244fa20c234SSam Leffler *rix = sn->rates[sn->static_rate_ndx].rix; 245fa20c234SSam Leffler *txrate = sn->rates[sn->static_rate_ndx].rateCode; 246fa20c234SSam Leffler return; 247fa20c234SSam Leffler } 248fa20c234SSam Leffler 249fa20c234SSam Leffler *try0 = 2; 250fa20c234SSam Leffler 251fa20c234SSam Leffler best_ndx = best_rate_ndx(sn, size_bin); 252fa20c234SSam Leffler if (!sn->packets_sent[size_bin] || 253fa20c234SSam Leffler sn->packets_sent[size_bin] % ssc->ath_sample_rate > 0) { 254fa20c234SSam Leffler /* 255fa20c234SSam Leffler * for most packets, send the packet at the bit-rate with 256fa20c234SSam Leffler * the lowest estimated transmission time. 257fa20c234SSam Leffler */ 258fa20c234SSam Leffler if (best_ndx != -1) { 259fa20c234SSam Leffler ndx = best_ndx; 260fa20c234SSam Leffler } else { 261fa20c234SSam Leffler /* 262fa20c234SSam Leffler * no packet has succeeded, try the highest bitrate 263fa20c234SSam Leffler * that hasn't failed. 264fa20c234SSam Leffler */ 265fa20c234SSam Leffler for (ndx = sn->num_rates-1; ndx >= 0; ndx--) { 266fa20c234SSam Leffler if (sn->stats[size_bin][ndx].successive_failures == 0) { 267fa20c234SSam Leffler break; 268fa20c234SSam Leffler } 269fa20c234SSam Leffler } 270fa20c234SSam Leffler } 271fa20c234SSam Leffler if (size_bin == 0) { 272fa20c234SSam Leffler /* update the visible txrate for this node */ 273fa20c234SSam Leffler an->an_node.ni_txrate = ndx; 274fa20c234SSam Leffler } 275fa20c234SSam Leffler } else { 276fa20c234SSam Leffler /* 277fa20c234SSam Leffler * before we pick a bit-rate to "sample", clear any 278fa20c234SSam Leffler * stale stuff out. 279fa20c234SSam Leffler */ 280fa20c234SSam Leffler for (x = 0; x < sn->num_rates; x++) { 281fa20c234SSam Leffler if (ticks - sn->stats[size_bin][x].last_tx > ((hz * 10000)/1000)) { 282fa20c234SSam Leffler sn->stats[size_bin][x].average_tx_time = sn->stats[size_bin][x].perfect_tx_time; 283fa20c234SSam Leffler sn->stats[size_bin][x].successive_failures = 0; 284fa20c234SSam Leffler sn->stats[size_bin][x].tries = 0; 285fa20c234SSam Leffler sn->stats[size_bin][x].total_packets = 0; 286fa20c234SSam Leffler sn->stats[size_bin][x].packets_acked = 0; 287fa20c234SSam Leffler } 288fa20c234SSam Leffler } 289fa20c234SSam Leffler 290fa20c234SSam Leffler /* send the packet at a different bit-rate */ 291fa20c234SSam Leffler ndx = pick_sample_ndx(sn, size_bin); 292fa20c234SSam Leffler } 293fa20c234SSam Leffler 294fa20c234SSam Leffler 295fa20c234SSam Leffler *rix = sn->rates[ndx].rix; 296fa20c234SSam Leffler if (shortPreamble) { 297fa20c234SSam Leffler *txrate = sn->rates[ndx].shortPreambleRateCode; 298fa20c234SSam Leffler } else { 299fa20c234SSam Leffler 300fa20c234SSam Leffler *txrate = sn->rates[ndx].rateCode; 301fa20c234SSam Leffler } 302fa20c234SSam Leffler 303fa20c234SSam Leffler sn->packets_sent[size_bin]++; 304fa20c234SSam Leffler } 305fa20c234SSam Leffler 306fa20c234SSam Leffler void 307fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 308fa20c234SSam Leffler struct ath_desc *ds, HAL_BOOL shortPreamble, u_int8_t rix) 309fa20c234SSam Leffler { 310fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 311fa20c234SSam Leffler int rateCode = -1; 312fa20c234SSam Leffler int frame_size; 313fa20c234SSam Leffler int size_bin; 314fa20c234SSam Leffler int best_ndx; 315fa20c234SSam Leffler 316fa20c234SSam Leffler frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ 317fa20c234SSam Leffler if (frame_size == 0) 318fa20c234SSam Leffler frame_size = 1500; 319fa20c234SSam Leffler size_bin = size_to_bin(frame_size); 320fa20c234SSam Leffler best_ndx = best_rate_ndx(sn, size_bin); 321fa20c234SSam Leffler 322fa20c234SSam Leffler if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) { 323fa20c234SSam Leffler /* 324fa20c234SSam Leffler * no packet has succeeded, so also try twice at the lowest bitate. 325fa20c234SSam Leffler */ 326fa20c234SSam Leffler if (shortPreamble) { 327fa20c234SSam Leffler rateCode = sn->rates[0].shortPreambleRateCode; 328fa20c234SSam Leffler } else { 329fa20c234SSam Leffler rateCode = sn->rates[0].rateCode; 330fa20c234SSam Leffler } 331fa20c234SSam Leffler } else if (sn->rates[best_ndx].rix != rix) { 332fa20c234SSam Leffler /* 333fa20c234SSam Leffler * we're trying a different bit-rate, and it could be lossy, 334fa20c234SSam Leffler * so if it fails try at the best bit-rate. 335fa20c234SSam Leffler */ 336fa20c234SSam Leffler if (shortPreamble) { 337fa20c234SSam Leffler rateCode = sn->rates[MAX(0,best_ndx-1)].shortPreambleRateCode; 338fa20c234SSam Leffler } else { 339fa20c234SSam Leffler rateCode = sn->rates[MAX(0,best_ndx-1)].rateCode; 340fa20c234SSam Leffler } 341fa20c234SSam Leffler } 342fa20c234SSam Leffler if (rateCode != -1) { 343fa20c234SSam Leffler ath_hal_setupxtxdesc(sc->sc_ah, ds 344fa20c234SSam Leffler , rateCode, 1 /* series 1 */ 345fa20c234SSam Leffler , rateCode, 1 /* series 2 */ 346fa20c234SSam Leffler , rateCode, 1 /* series 3 */ 347fa20c234SSam Leffler ); 348fa20c234SSam Leffler } 349fa20c234SSam Leffler 350fa20c234SSam Leffler } 351fa20c234SSam Leffler 352fa20c234SSam Leffler void 353fa20c234SSam Leffler ath_rate_tx_complete(struct ath_softc *sc, 354fa20c234SSam Leffler struct ath_node *an, const struct ath_desc *ds) 355fa20c234SSam Leffler { 356fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 357fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 358fa20c234SSam Leffler int rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate; 359fa20c234SSam Leffler int retries = ds->ds_txstat.ts_longretry; 360fa20c234SSam Leffler int initial_rate_failed = ((ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE) 361fa20c234SSam Leffler || ds->ds_txstat.ts_status != 0 || 362fa20c234SSam Leffler retries > 3); 363fa20c234SSam Leffler int tt = 0; 364fa20c234SSam Leffler int rix = -1; 365fa20c234SSam Leffler int x = 0; 366fa20c234SSam Leffler int frame_size; /* low-order 12 bits of ds_ctl0 */ 367fa20c234SSam Leffler int size_bin; 368fa20c234SSam Leffler int size; 369fa20c234SSam Leffler 370fa20c234SSam Leffler if (!sn->num_rates) { 371fa20c234SSam Leffler DPRINTF(sc, "%s: no rates yet\n", __func__); 372fa20c234SSam Leffler return; 373fa20c234SSam Leffler } 374fa20c234SSam Leffler for (x = 0; x < sn->num_rates; x++) { 375fa20c234SSam Leffler if (sn->rates[x].rate == rate) { 376fa20c234SSam Leffler rix = x; 377fa20c234SSam Leffler break; 378fa20c234SSam Leffler } 379fa20c234SSam Leffler } 380fa20c234SSam Leffler 381fa20c234SSam Leffler if (rix < 0 || rix > sn->num_rates) { 382fa20c234SSam Leffler /* maybe a management packet */ 383fa20c234SSam Leffler return; 384fa20c234SSam Leffler } 385fa20c234SSam Leffler 386fa20c234SSam Leffler frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ 387fa20c234SSam Leffler if (frame_size == 0) 388fa20c234SSam Leffler frame_size = 1500; 389fa20c234SSam Leffler size_bin = size_to_bin(frame_size); 390fa20c234SSam Leffler size = bin_to_size(size_bin); 391fa20c234SSam Leffler tt = calc_usecs_unicast_packet(sc, size, sn->rates[rix].rix, 392fa20c234SSam Leffler retries); 393fa20c234SSam Leffler 394fa20c234SSam Leffler DPRINTF(sc, "%s: rate %d rix %d frame_size %d (%d) retries %d status %d tt %d avg_tt %d perfect_tt %d ts-rate %d\n", 395fa20c234SSam Leffler __func__, rate, rix, frame_size, size, retries, initial_rate_failed, tt, 396fa20c234SSam Leffler sn->stats[size_bin][rix].average_tx_time, 397fa20c234SSam Leffler sn->stats[size_bin][rix].perfect_tx_time, 398fa20c234SSam Leffler ds->ds_txstat.ts_rate); 399fa20c234SSam Leffler 400fa20c234SSam Leffler if (sn->stats[size_bin][rix].total_packets < 7) { 401fa20c234SSam Leffler /* just average the first few packets */ 402fa20c234SSam Leffler int avg_tx = sn->stats[size_bin][rix].average_tx_time; 403fa20c234SSam Leffler int packets = sn->stats[size_bin][rix].total_packets; 404fa20c234SSam Leffler sn->stats[size_bin][rix].average_tx_time = (tt+(avg_tx*packets))/(packets+1); 405fa20c234SSam Leffler } else { 406fa20c234SSam Leffler /* use a ewma */ 407fa20c234SSam Leffler sn->stats[size_bin][rix].average_tx_time = 408fa20c234SSam Leffler ((sn->stats[size_bin][rix].average_tx_time * ssc->ath_smoothing_rate) + 409fa20c234SSam Leffler (tt * (100 - ssc->ath_smoothing_rate))) / 100; 410fa20c234SSam Leffler } 411fa20c234SSam Leffler 412fa20c234SSam Leffler if (initial_rate_failed) { 413fa20c234SSam Leffler /* 414fa20c234SSam Leffler * this packet failed - count this as a failure 415fa20c234SSam Leffler * for larger packets also, since we assume 416fa20c234SSam Leffler * if a small packet fails at a lower bit-rate 417fa20c234SSam Leffler * then a larger one will also. 418fa20c234SSam Leffler */ 419fa20c234SSam Leffler int y; 420fa20c234SSam Leffler for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) { 421fa20c234SSam Leffler sn->stats[y][rix].successive_failures++; 422fa20c234SSam Leffler sn->stats[y][rix].last_tx = ticks; 423fa20c234SSam Leffler } 424fa20c234SSam Leffler } else { 425fa20c234SSam Leffler sn->stats[size_bin][rix].packets_acked++; 426fa20c234SSam Leffler sn->stats[size_bin][rix].successive_failures = 0; 427fa20c234SSam Leffler } 428fa20c234SSam Leffler sn->stats[size_bin][rix].tries += (1+retries); 429fa20c234SSam Leffler sn->stats[size_bin][rix].last_tx = ticks; 430fa20c234SSam Leffler sn->stats[size_bin][rix].total_packets++; 431fa20c234SSam Leffler } 432fa20c234SSam Leffler 433fa20c234SSam Leffler void 434fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 435fa20c234SSam Leffler { 436fa20c234SSam Leffler DPRINTF(sc, "%s:\n", __func__); 437fa20c234SSam Leffler if (isnew) 438fa20c234SSam Leffler ath_rate_ctl_start(sc, &an->an_node); 439fa20c234SSam Leffler } 440fa20c234SSam Leffler 441fa20c234SSam Leffler static void 442fa20c234SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 443fa20c234SSam Leffler { 444fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 445fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 446fa20c234SSam Leffler int x = 0; 447fa20c234SSam Leffler int y = 0; 448fa20c234SSam Leffler 449fa20c234SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 450fa20c234SSam Leffler int size = bin_to_size(y); 451fa20c234SSam Leffler sn->packets_sent[y] = 0; 452fa20c234SSam Leffler sn->sample_num[y] = 0; 453fa20c234SSam Leffler 454fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 455fa20c234SSam Leffler sn->stats[y][x].successive_failures = 0; 456fa20c234SSam Leffler sn->stats[y][x].tries = 0; 457fa20c234SSam Leffler sn->stats[y][x].total_packets = 0; 458fa20c234SSam Leffler sn->stats[y][x].packets_acked = 0; 459fa20c234SSam Leffler sn->stats[y][x].last_tx = 0; 460fa20c234SSam Leffler sn->stats[y][x].perfect_tx_time = calc_usecs_unicast_packet(sc, size, 461fa20c234SSam Leffler sn->rates[x].rix, 462fa20c234SSam Leffler 0); 463fa20c234SSam Leffler sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time; 464fa20c234SSam Leffler 465fa20c234SSam Leffler 466fa20c234SSam Leffler DPRINTF(sc, "%s: %d rate %d rix %d rateCode %d perfect_tx_time %d \n", __func__, 467fa20c234SSam Leffler x, sn->rates[x].rate, 468fa20c234SSam Leffler sn->rates[x].rix, sn->rates[x].rateCode, 469fa20c234SSam Leffler sn->stats[0][x].perfect_tx_time); 470fa20c234SSam Leffler } 471fa20c234SSam Leffler 472fa20c234SSam Leffler } 473fa20c234SSam Leffler 474fa20c234SSam Leffler /* set the visible bit-rate to the lowest one available */ 475fa20c234SSam Leffler ni->ni_txrate = 0; 476fa20c234SSam Leffler 477fa20c234SSam Leffler } 478fa20c234SSam Leffler 479fa20c234SSam Leffler /* 480fa20c234SSam Leffler * Initialize the tables for a node. 481fa20c234SSam Leffler */ 482fa20c234SSam Leffler static void 483fa20c234SSam Leffler ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) 484fa20c234SSam Leffler { 485fa20c234SSam Leffler #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 486fa20c234SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 487fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 488fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 489fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 490fa20c234SSam Leffler 491fa20c234SSam Leffler int x; 492fa20c234SSam Leffler int srate; 493fa20c234SSam Leffler 494fa20c234SSam Leffler DPRINTF(sc, "%s:\n", __func__); 495fa20c234SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 496fa20c234SSam Leffler KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); 497fa20c234SSam Leffler sn->static_rate_ndx = -1; 498fa20c234SSam Leffler if (ic->ic_fixed_rate != -1) { 499fa20c234SSam Leffler /* 500fa20c234SSam Leffler * A fixed rate is to be used; ic_fixed_rate is an 501fa20c234SSam Leffler * index into the supported rate set. Convert this 502fa20c234SSam Leffler * to the index into the negotiated rate set for 503fa20c234SSam Leffler * the node. We know the rate is there because the 504fa20c234SSam Leffler * rate set is checked when the station associates. 505fa20c234SSam Leffler */ 506fa20c234SSam Leffler const struct ieee80211_rateset *rs = 507fa20c234SSam Leffler &ic->ic_sup_rates[ic->ic_curmode]; 508fa20c234SSam Leffler int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; 509fa20c234SSam Leffler /* NB: the rate set is assumed sorted */ 510fa20c234SSam Leffler srate = ni->ni_rates.rs_nrates - 1; 511fa20c234SSam Leffler for (; srate >= 0 && RATE(srate) != r; srate--) 512fa20c234SSam Leffler ; 513fa20c234SSam Leffler KASSERT(srate >= 0, 514fa20c234SSam Leffler ("fixed rate %d not in rate set", ic->ic_fixed_rate)); 515fa20c234SSam Leffler sn->static_rate_ndx = srate; 516fa20c234SSam Leffler 517fa20c234SSam Leffler } 518fa20c234SSam Leffler sn->num_rates = ni->ni_rates.rs_nrates; 519fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 520fa20c234SSam Leffler sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL; 521fa20c234SSam Leffler sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate]; 522fa20c234SSam Leffler sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode; 523fa20c234SSam Leffler sn->rates[x].shortPreambleRateCode = 524fa20c234SSam Leffler rt->info[sn->rates[x].rix].rateCode | 525fa20c234SSam Leffler rt->info[sn->rates[x].rix].shortPreamble; 526fa20c234SSam Leffler } 527fa20c234SSam Leffler ath_rate_ctl_reset(sc, ni); 528fa20c234SSam Leffler 529fa20c234SSam Leffler #undef RATE 530fa20c234SSam Leffler } 531fa20c234SSam Leffler 532fa20c234SSam Leffler /* 533fa20c234SSam Leffler * Reset the rate control state for each 802.11 state transition. 534fa20c234SSam Leffler */ 535fa20c234SSam Leffler void 536fa20c234SSam Leffler ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state) 537fa20c234SSam Leffler { 538fa20c234SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 539fa20c234SSam Leffler 540fa20c234SSam Leffler if (state == IEEE80211_S_RUN) 541fa20c234SSam Leffler ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1); 542fa20c234SSam Leffler } 543fa20c234SSam Leffler 544fa20c234SSam Leffler static void 545fa20c234SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc) 546fa20c234SSam Leffler { 547fa20c234SSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 548fa20c234SSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 549fa20c234SSam Leffler 550fa20c234SSam Leffler /* XXX bounds check [0..100] */ 551fa20c234SSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 552fa20c234SSam Leffler "smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0, 553fa20c234SSam Leffler "rate control: retry threshold to credit rate raise (%%)"); 554fa20c234SSam Leffler /* XXX bounds check [2..100] */ 555fa20c234SSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 556fa20c234SSam Leffler "sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0, 557fa20c234SSam Leffler "rate control: # good periods before raising rate"); 558fa20c234SSam Leffler } 559fa20c234SSam Leffler 560fa20c234SSam Leffler struct ath_ratectrl * 561fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc) 562fa20c234SSam Leffler { 563fa20c234SSam Leffler struct sample_softc *osc; 564fa20c234SSam Leffler 565fa20c234SSam Leffler DPRINTF(sc, "%s:\n", __func__); 566fa20c234SSam Leffler osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 567fa20c234SSam Leffler if (osc == NULL) 568fa20c234SSam Leffler return NULL; 569fa20c234SSam Leffler osc->arc.arc_space = sizeof(struct sample_node); 570fa20c234SSam Leffler osc->ath_smoothing_rate = 95; /* ewma percentage (out of 100) */ 571fa20c234SSam Leffler osc->ath_sample_rate = 10; /* send a different bit-rate 1/X packets */ 572fa20c234SSam Leffler ath_rate_sysctlattach(sc, osc); 573fa20c234SSam Leffler return &osc->arc; 574fa20c234SSam Leffler } 575fa20c234SSam Leffler 576fa20c234SSam Leffler void 577fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc) 578fa20c234SSam Leffler { 579fa20c234SSam Leffler struct sample_softc *osc = (struct sample_softc *) arc; 580fa20c234SSam Leffler 581fa20c234SSam Leffler free(osc, M_DEVBUF); 582fa20c234SSam Leffler } 583fa20c234SSam Leffler 584fa20c234SSam Leffler /* 585fa20c234SSam Leffler * Module glue. 586fa20c234SSam Leffler */ 587fa20c234SSam Leffler static int 588fa20c234SSam Leffler sample_modevent(module_t mod, int type, void *unused) 589fa20c234SSam Leffler { 590fa20c234SSam Leffler switch (type) { 591fa20c234SSam Leffler case MOD_LOAD: 592fa20c234SSam Leffler if (bootverbose) 593fa20c234SSam Leffler printf("ath_rate: <SampleRate bit-rate selection algorithm>\n"); 594fa20c234SSam Leffler return 0; 595fa20c234SSam Leffler case MOD_UNLOAD: 596fa20c234SSam Leffler return 0; 597fa20c234SSam Leffler } 598fa20c234SSam Leffler return EINVAL; 599fa20c234SSam Leffler } 600fa20c234SSam Leffler 601fa20c234SSam Leffler static moduledata_t sample_mod = { 602fa20c234SSam Leffler "ath_rate", 603fa20c234SSam Leffler sample_modevent, 604fa20c234SSam Leffler 0 605fa20c234SSam Leffler }; 606fa20c234SSam Leffler DECLARE_MODULE(ath_rate, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 607fa20c234SSam Leffler MODULE_VERSION(ath_rate, 1); 608fa20c234SSam Leffler MODULE_DEPEND(ath_rate, wlan, 1, 1, 1); 609