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. 3568e8e04eSSam Leffler * 36fa20c234SSam Leffler */ 37fa20c234SSam Leffler 38fa20c234SSam Leffler #include <sys/cdefs.h> 39fa20c234SSam Leffler __FBSDID("$FreeBSD$"); 40fa20c234SSam Leffler 41fa20c234SSam Leffler /* 42fa20c234SSam Leffler * John Bicket's SampleRate control algorithm. 43fa20c234SSam Leffler */ 44fa20c234SSam Leffler #include "opt_inet.h" 45b032f27cSSam Leffler #include "opt_wlan.h" 46fa20c234SSam Leffler 47fa20c234SSam Leffler #include <sys/param.h> 48fa20c234SSam Leffler #include <sys/systm.h> 49fa20c234SSam Leffler #include <sys/sysctl.h> 50fa20c234SSam Leffler #include <sys/kernel.h> 51fa20c234SSam Leffler #include <sys/lock.h> 52fa20c234SSam Leffler #include <sys/mutex.h> 53fa20c234SSam Leffler #include <sys/errno.h> 54fa20c234SSam Leffler 55fa20c234SSam Leffler #include <machine/bus.h> 56fa20c234SSam Leffler #include <machine/resource.h> 57fa20c234SSam Leffler #include <sys/bus.h> 58fa20c234SSam Leffler 59fa20c234SSam Leffler #include <sys/socket.h> 60fa20c234SSam Leffler 61fa20c234SSam Leffler #include <net/if.h> 62fa20c234SSam Leffler #include <net/if_media.h> 63fa20c234SSam Leffler #include <net/if_arp.h> 64c1565b61SSam Leffler #include <net/ethernet.h> /* XXX for ether_sprintf */ 65fa20c234SSam Leffler 66fa20c234SSam Leffler #include <net80211/ieee80211_var.h> 67fa20c234SSam Leffler 68fa20c234SSam Leffler #include <net/bpf.h> 69fa20c234SSam Leffler 70fa20c234SSam Leffler #ifdef INET 71fa20c234SSam Leffler #include <netinet/in.h> 72fa20c234SSam Leffler #include <netinet/if_ether.h> 73fa20c234SSam Leffler #endif 74fa20c234SSam Leffler 75fa20c234SSam Leffler #include <dev/ath/if_athvar.h> 76fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h> 7733644623SSam Leffler #include <dev/ath/ath_hal/ah_desc.h> 78fa20c234SSam Leffler 79fa20c234SSam Leffler /* 80fa20c234SSam Leffler * This file is an implementation of the SampleRate algorithm 81fa20c234SSam Leffler * in "Bit-rate Selection in Wireless Networks" 82fa20c234SSam Leffler * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 83fa20c234SSam Leffler * 84fa20c234SSam Leffler * SampleRate chooses the bit-rate it predicts will provide the most 85fa20c234SSam Leffler * throughput based on estimates of the expected per-packet 86fa20c234SSam Leffler * transmission time for each bit-rate. SampleRate periodically sends 87fa20c234SSam Leffler * packets at bit-rates other than the current one to estimate when 88fa20c234SSam Leffler * another bit-rate will provide better performance. SampleRate 89fa20c234SSam Leffler * switches to another bit-rate when its estimated per-packet 90fa20c234SSam Leffler * transmission time becomes smaller than the current bit-rate's. 91fa20c234SSam Leffler * SampleRate reduces the number of bit-rates it must sample by 92fa20c234SSam Leffler * eliminating those that could not perform better than the one 93fa20c234SSam Leffler * currently being used. SampleRate also stops probing at a bit-rate 94fa20c234SSam Leffler * if it experiences several successive losses. 95fa20c234SSam Leffler * 96fa20c234SSam Leffler * The difference between the algorithm in the thesis and the one in this 97fa20c234SSam Leffler * file is that the one in this file uses a ewma instead of a window. 98fa20c234SSam Leffler * 99b91bf513SSam Leffler * Also, this implementation tracks the average transmission time for 100b91bf513SSam Leffler * a few different packet sizes independently for each link. 101fa20c234SSam Leffler */ 102fa20c234SSam Leffler 103b2763056SSam Leffler static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 104fa20c234SSam Leffler 105c1565b61SSam Leffler static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 }; 106c1565b61SSam Leffler 107b91bf513SSam Leffler static __inline int 108b91bf513SSam Leffler size_to_bin(int size) 109fa20c234SSam Leffler { 110c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1 111c1565b61SSam Leffler if (size <= packet_size_bins[0]) 112c1565b61SSam Leffler return 0; 113c1565b61SSam Leffler #endif 114c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2 115c1565b61SSam Leffler if (size <= packet_size_bins[1]) 116c1565b61SSam Leffler return 1; 117c1565b61SSam Leffler #endif 118c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3 119c1565b61SSam Leffler if (size <= packet_size_bins[2]) 120c1565b61SSam Leffler return 2; 121c1565b61SSam Leffler #endif 122c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4 123c1565b61SSam Leffler #error "add support for more packet sizes" 124c1565b61SSam Leffler #endif 125fa20c234SSam Leffler return NUM_PACKET_SIZE_BINS-1; 126fa20c234SSam Leffler } 127fa20c234SSam Leffler 1281bb9a085SSam Leffler static __inline int 129c1565b61SSam Leffler bin_to_size(int index) 130c1565b61SSam Leffler { 131c1565b61SSam Leffler return packet_size_bins[index]; 1321bb9a085SSam Leffler } 1331bb9a085SSam Leffler 134fa20c234SSam Leffler void 135fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 136fa20c234SSam Leffler { 137fa20c234SSam Leffler /* NB: assumed to be zero'd by caller */ 138fa20c234SSam Leffler } 139fa20c234SSam Leffler 140fa20c234SSam Leffler void 141fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 142fa20c234SSam Leffler { 143fa20c234SSam Leffler } 144fa20c234SSam Leffler 145fa20c234SSam Leffler /* 146c1565b61SSam Leffler * Return the rix with the lowest average_tx_time, 147fa20c234SSam Leffler * or -1 if all the average_tx_times are 0. 148fa20c234SSam Leffler */ 149c1565b61SSam Leffler static __inline int 150c1565b61SSam Leffler pick_best_rate(struct sample_node *sn, const HAL_RATE_TABLE *rt, 151c1565b61SSam Leffler int size_bin, int require_acked_before) 152fa20c234SSam Leffler { 153c1565b61SSam Leffler int best_rate_rix, best_rate_tt; 154c1565b61SSam Leffler uint32_t mask; 155c1565b61SSam Leffler int rix, tt; 156b91bf513SSam Leffler 157c1565b61SSam Leffler best_rate_rix = 0; 158c1565b61SSam Leffler best_rate_tt = 0; 159c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 160c1565b61SSam Leffler if ((mask & 1) == 0) /* not a supported rate */ 161c1565b61SSam Leffler continue; 162c1565b61SSam Leffler 163c1565b61SSam Leffler tt = sn->stats[size_bin][rix].average_tx_time; 164c1565b61SSam Leffler if (tt <= 0 || 165c1565b61SSam Leffler (require_acked_before && 166c1565b61SSam Leffler !sn->stats[size_bin][rix].packets_acked)) 167b91bf513SSam Leffler continue; 168b91bf513SSam Leffler 169b91bf513SSam Leffler /* don't use a bit-rate that has been failing */ 170c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > 3) 171b91bf513SSam Leffler continue; 172b91bf513SSam Leffler 173c1565b61SSam Leffler if (best_rate_tt == 0 || tt < best_rate_tt) { 174fa20c234SSam Leffler best_rate_tt = tt; 175c1565b61SSam Leffler best_rate_rix = rix; 176fa20c234SSam Leffler } 177fa20c234SSam Leffler } 178c1565b61SSam Leffler return (best_rate_tt ? best_rate_rix : -1); 179fa20c234SSam Leffler } 180fa20c234SSam Leffler 181fa20c234SSam Leffler /* 182c1565b61SSam Leffler * Pick a good "random" bit-rate to sample other than the current one. 183fa20c234SSam Leffler */ 184b91bf513SSam Leffler static __inline int 185c1565b61SSam Leffler pick_sample_rate(struct sample_softc *ssc , struct sample_node *sn, 186c1565b61SSam Leffler const HAL_RATE_TABLE *rt, int size_bin) 187fa20c234SSam Leffler { 188c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 189c1565b61SSam Leffler int current_rix, rix; 190c1565b61SSam Leffler unsigned current_tt; 191c1565b61SSam Leffler uint32_t mask; 192fa20c234SSam Leffler 193c1565b61SSam Leffler current_rix = sn->current_rix[size_bin]; 194c1565b61SSam Leffler if (current_rix < 0) { 195fa20c234SSam Leffler /* no successes yet, send at the lowest bit-rate */ 196fa20c234SSam Leffler return 0; 197fa20c234SSam Leffler } 198fa20c234SSam Leffler 199c1565b61SSam Leffler current_tt = sn->stats[size_bin][current_rix].average_tx_time; 200fa20c234SSam Leffler 201c1565b61SSam Leffler rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 202c1565b61SSam Leffler mask = sn->ratemask &~ (1<<current_rix);/* don't sample current rate */ 203c1565b61SSam Leffler while (mask != 0) { 204c1565b61SSam Leffler if ((mask & (1<<rix)) == 0) { /* not a supported rate */ 205c1565b61SSam Leffler nextrate: 206c1565b61SSam Leffler if (++rix >= rt->rateCount) 207c1565b61SSam Leffler rix = 0; 208b91bf513SSam Leffler continue; 209c1565b61SSam Leffler } 210b91bf513SSam Leffler 211b91bf513SSam Leffler /* this bit-rate is always worse than the current one */ 212c1565b61SSam Leffler if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 213c1565b61SSam Leffler mask &= ~(1<<rix); 214c1565b61SSam Leffler goto nextrate; 215c1565b61SSam Leffler } 216b91bf513SSam Leffler 217b91bf513SSam Leffler /* rarely sample bit-rates that fail a lot */ 218c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 219c1565b61SSam Leffler ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 220c1565b61SSam Leffler mask &= ~(1<<rix); 221c1565b61SSam Leffler goto nextrate; 222fa20c234SSam Leffler } 223c1565b61SSam Leffler 224c1565b61SSam Leffler /* don't sample more than 2 rates higher for rates > 11M */ 225c1565b61SSam Leffler if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 226c1565b61SSam Leffler mask &= ~(1<<rix); 227c1565b61SSam Leffler goto nextrate; 228c1565b61SSam Leffler } 229c1565b61SSam Leffler 230c1565b61SSam Leffler sn->last_sample_rix[size_bin] = rix; 231c1565b61SSam Leffler return rix; 232c1565b61SSam Leffler } 233c1565b61SSam Leffler return current_rix; 234c1565b61SSam Leffler #undef DOT11RATE 235fa20c234SSam Leffler } 236fa20c234SSam Leffler 237fa20c234SSam Leffler void 238fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 239a4d8dd10SSam Leffler int shortPreamble, size_t frameLen, 240c1565b61SSam Leffler u_int8_t *rix0, int *try0, u_int8_t *txrate) 241fa20c234SSam Leffler { 242c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 243c1565b61SSam Leffler #define RATE(ix) (DOT11RATE(ix) / 2) 244fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 245fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 246b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 247b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 248c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 249c1565b61SSam Leffler const int size_bin = size_to_bin(frameLen); 250c1565b61SSam Leffler int rix, mrr, best_rix, change_rates; 251b2763056SSam Leffler unsigned average_tx_time; 252fa20c234SSam Leffler 253c1565b61SSam Leffler if (sn->static_rix != -1) { 254c1565b61SSam Leffler rix = sn->static_rix; 255c1565b61SSam Leffler *try0 = ATH_TXMAXTRY; 256c1565b61SSam Leffler goto done; 257c1565b61SSam Leffler } 258fa20c234SSam Leffler 259c1565b61SSam Leffler mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); 260c1565b61SSam Leffler 261c1565b61SSam Leffler best_rix = pick_best_rate(sn, rt, size_bin, !mrr); 262c1565b61SSam Leffler if (best_rix >= 0) { 263c1565b61SSam Leffler average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 264fa20c234SSam Leffler } else { 265b2763056SSam Leffler average_tx_time = 0; 266b2763056SSam Leffler } 267fa20c234SSam Leffler /* 268c1565b61SSam Leffler * Limit the time measuring the performance of other tx 269c1565b61SSam Leffler * rates to sample_rate% of the total transmission time. 270fa20c234SSam Leffler */ 271c1565b61SSam Leffler if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 272c1565b61SSam Leffler rix = pick_sample_rate(ssc, sn, rt, size_bin); 273c1565b61SSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 274c1565b61SSam Leffler &an->an_node, "size %u sample rate %d current rate %d", 275c1565b61SSam Leffler bin_to_size(size_bin), RATE(rix), 276c1565b61SSam Leffler RATE(sn->current_rix[size_bin])); 277c1565b61SSam Leffler if (rix != sn->current_rix[size_bin]) { 278c1565b61SSam Leffler sn->current_sample_rix[size_bin] = rix; 279b2763056SSam Leffler } else { 280c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 281b2763056SSam Leffler } 282b2763056SSam Leffler sn->packets_since_sample[size_bin] = 0; 283b2763056SSam Leffler } else { 284b91bf513SSam Leffler change_rates = 0; 285c1565b61SSam Leffler if (!sn->packets_sent[size_bin] || best_rix == -1) { 286b91bf513SSam Leffler /* no packet has been sent successfully yet */ 287c1565b61SSam Leffler for (rix = rt->rateCount-1; rix > 0; rix--) { 288c1565b61SSam Leffler if ((sn->ratemask & (1<<rix)) == 0) 289c1565b61SSam Leffler continue; 290b2763056SSam Leffler /* 291c1565b61SSam Leffler * Pick the highest rate <= 36 Mbps 292b91bf513SSam Leffler * that hasn't failed. 293b2763056SSam Leffler */ 294c1565b61SSam Leffler if (DOT11RATE(rix) <= 72 && 295c1565b61SSam Leffler sn->stats[size_bin][rix].successive_failures == 0) { 296b91bf513SSam Leffler break; 297b91bf513SSam Leffler } 298b91bf513SSam Leffler } 299b91bf513SSam Leffler change_rates = 1; 300c1565b61SSam Leffler best_rix = rix; 301b91bf513SSam Leffler } else if (sn->packets_sent[size_bin] < 20) { 302b91bf513SSam Leffler /* let the bit-rate switch quickly during the first few packets */ 303b91bf513SSam Leffler change_rates = 1; 304c1565b61SSam Leffler } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 305c1565b61SSam Leffler /* min_switch seconds have gone by */ 306b91bf513SSam Leffler change_rates = 1; 307c1565b61SSam Leffler } else if (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time) { 308b91bf513SSam Leffler /* the current bit-rate is twice as slow as the best one */ 309b91bf513SSam Leffler change_rates = 1; 310b91bf513SSam Leffler } 311b91bf513SSam Leffler 312b91bf513SSam Leffler sn->packets_since_sample[size_bin]++; 313b91bf513SSam Leffler 314b91bf513SSam Leffler if (change_rates) { 315c1565b61SSam Leffler if (best_rix != sn->current_rix[size_bin]) { 316b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, 317b032f27cSSam Leffler IEEE80211_MSG_RATECTL, 318b032f27cSSam Leffler &an->an_node, 319b032f27cSSam Leffler "%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d", 320b2763056SSam Leffler __func__, 321c1565b61SSam Leffler bin_to_size(size_bin), 322c1565b61SSam Leffler RATE(sn->current_rix[size_bin]), 323c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 324c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 325c1565b61SSam Leffler RATE(best_rix), 326c1565b61SSam Leffler sn->stats[size_bin][best_rix].average_tx_time, 327c1565b61SSam Leffler sn->stats[size_bin][best_rix].perfect_tx_time, 328b2763056SSam Leffler sn->packets_since_switch[size_bin], 329b2763056SSam Leffler mrr); 330b2763056SSam Leffler } 331b2763056SSam Leffler sn->packets_since_switch[size_bin] = 0; 332c1565b61SSam Leffler sn->current_rix[size_bin] = best_rix; 333b91bf513SSam Leffler sn->ticks_since_switch[size_bin] = ticks; 334b032f27cSSam Leffler /* 335b032f27cSSam Leffler * Set the visible txrate for this node. 336b032f27cSSam Leffler */ 337c1565b61SSam Leffler an->an_node.ni_txrate = DOT11RATE(best_rix); 338b2763056SSam Leffler } 339c1565b61SSam Leffler rix = sn->current_rix[size_bin]; 340b2763056SSam Leffler sn->packets_since_switch[size_bin]++; 341b91bf513SSam Leffler } 342c1565b61SSam Leffler *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 343c1565b61SSam Leffler done: 344c1565b61SSam Leffler KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 345fa20c234SSam Leffler 346c1565b61SSam Leffler *rix0 = rix; 347c1565b61SSam Leffler *txrate = rt->info[rix].rateCode 348c1565b61SSam Leffler | (shortPreamble ? rt->info[rix].shortPreamble : 0); 349fa20c234SSam Leffler sn->packets_sent[size_bin]++; 350c1565b61SSam Leffler #undef DOT11RATE 351c1565b61SSam Leffler #undef RATE 352fa20c234SSam Leffler } 353fa20c234SSam Leffler 354c1565b61SSam Leffler #define A(_r) \ 355c1565b61SSam Leffler (((_r) == 6) ? 0 : (((_r) == 9) ? 1 : (((_r) == 12) ? 2 : \ 356c1565b61SSam Leffler (((_r) == 18) ? 3 : (((_r) == 24) ? 4 : (((_r) == 36) ? 5 : \ 357c1565b61SSam Leffler (((_r) == 48) ? 6 : (((_r) == 54) ? 7 : 0)))))))) 358c1565b61SSam Leffler static const struct txschedule series_11a[] = { 359c1565b61SSam Leffler { 3,A( 6), 3,A( 6), 0,A( 6), 0,A( 6) }, /* 6Mb/s */ 360c1565b61SSam Leffler { 4,A( 9), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 9Mb/s */ 361c1565b61SSam Leffler { 4,A(12), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 12Mb/s */ 362c1565b61SSam Leffler { 4,A(18), 3,A( 12), 4,A( 6), 2,A( 6) }, /* 18Mb/s */ 363c1565b61SSam Leffler { 4,A(24), 3,A( 18), 4,A( 12), 2,A( 6) }, /* 24Mb/s */ 364c1565b61SSam Leffler { 4,A(36), 3,A( 24), 4,A( 18), 2,A( 6) }, /* 36Mb/s */ 365c1565b61SSam Leffler { 4,A(48), 3,A( 36), 4,A( 24), 2,A(12) }, /* 48Mb/s */ 366c1565b61SSam Leffler { 4,A(54), 3,A( 48), 4,A( 36), 2,A(24) } /* 54Mb/s */ 367c1565b61SSam Leffler }; 368c1565b61SSam Leffler #undef A 369c1565b61SSam Leffler 370c1565b61SSam Leffler #define G(_r) \ 371c1565b61SSam Leffler (((_r) == 1) ? 0 : (((_r) == 2) ? 1 : (((_r) == 5.5) ? 2 : \ 372c1565b61SSam Leffler (((_r) == 11) ? 3 : (((_r) == 6) ? 4 : (((_r) == 9) ? 5 : \ 373c1565b61SSam Leffler (((_r) == 12) ? 6 : (((_r) == 18) ? 7 : (((_r) == 24) ? 8 : \ 374c1565b61SSam Leffler (((_r) == 36) ? 9 : (((_r) == 48) ? 10 : (((_r) == 54) ? 11 : 0)))))))))))) 375c1565b61SSam Leffler static const struct txschedule series_11g[] = { 376c1565b61SSam Leffler { 3,G( 1), 3,G( 1), 0,G( 1), 0,G( 1) }, /* 1Mb/s */ 377c1565b61SSam Leffler { 4,G( 2), 3,G( 1), 4,G( 1), 0,G( 1) }, /* 2Mb/s */ 378c1565b61SSam Leffler { 4,G(5.5),3,G( 2), 4,G( 1), 2,G( 1) }, /* 5.5Mb/s */ 379c1565b61SSam Leffler { 4,G(11), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 11Mb/s */ 380c1565b61SSam Leffler { 4,G( 6), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 6Mb/s */ 381c1565b61SSam Leffler { 4,G( 9), 3,G( 6), 4,G(5.5), 2,G( 1) }, /* 9Mb/s */ 382c1565b61SSam Leffler { 4,G(12), 3,G( 11), 4,G(5.5), 2,G( 1) }, /* 12Mb/s */ 383c1565b61SSam Leffler { 4,G(18), 3,G( 12), 4,G( 11), 2,G( 1) }, /* 18Mb/s */ 384c1565b61SSam Leffler { 4,G(24), 3,G( 18), 4,G( 12), 2,G( 1) }, /* 24Mb/s */ 385c1565b61SSam Leffler { 4,G(36), 3,G( 24), 4,G( 18), 2,G( 1) }, /* 36Mb/s */ 386c1565b61SSam Leffler { 4,G(48), 3,G( 36), 4,G( 24), 2,G( 1) }, /* 48Mb/s */ 387c1565b61SSam Leffler { 4,G(54), 3,G( 48), 4,G( 36), 2,G( 1) } /* 54Mb/s */ 388c1565b61SSam Leffler }; 389c1565b61SSam Leffler #undef G 390c1565b61SSam Leffler 391c1565b61SSam Leffler #define H(_r) \ 392c1565b61SSam Leffler (((_r) == 3) ? 0 : (((_r) == 4.5) ? 1 : (((_r) == 6) ? 2 : \ 393c1565b61SSam Leffler (((_r) == 9) ? 3 : (((_r) == 12) ? 4 : (((_r) == 18) ? 5 : \ 394c1565b61SSam Leffler (((_r) == 24) ? 6 : (((_r) == 27) ? 7 : 0)))))))) 395c1565b61SSam Leffler static const struct txschedule series_half[] = { 396c1565b61SSam Leffler { 3,H( 3), 3,H( 3), 0,H( 3), 0,H( 3) }, /* 3Mb/s */ 397c1565b61SSam Leffler { 4,H(4.5),3,H( 3), 4,H( 3), 0,H( 3) }, /* 4.5Mb/s */ 398c1565b61SSam Leffler { 4,H( 6), 3,H( 3), 4,H( 3), 0,H( 3) }, /* 6Mb/s */ 399c1565b61SSam Leffler { 4,H( 9), 3,H( 6), 4,H( 3), 2,H( 3) }, /* 9Mb/s */ 400c1565b61SSam Leffler { 4,H(12), 3,H( 9), 4,H( 6), 2,H( 3) }, /* 12Mb/s */ 401c1565b61SSam Leffler { 4,H(18), 3,H( 12), 4,H( 9), 2,H( 3) }, /* 18Mb/s */ 402c1565b61SSam Leffler { 4,H(24), 3,H( 18), 4,H( 12), 2,H( 6) }, /* 24Mb/s */ 403c1565b61SSam Leffler { 4,H(27), 3,H( 24), 4,H( 18), 2,H(12) } /* 27Mb/s */ 404c1565b61SSam Leffler }; 405c1565b61SSam Leffler #undef H 406c1565b61SSam Leffler 407fe7432d7SSam Leffler #ifdef Q 408fe7432d7SSam Leffler #undef Q /* sun4v bogosity */ 409fe7432d7SSam Leffler #endif 410c1565b61SSam Leffler #define Q(_r) \ 411c1565b61SSam Leffler (((_r) == 1.5) ? 0 : (((_r) ==2.25) ? 1 : (((_r) == 3) ? 2 : \ 412c1565b61SSam Leffler (((_r) == 4.5) ? 3 : (((_r) == 6) ? 4 : (((_r) == 9) ? 5 : \ 413c1565b61SSam Leffler (((_r) == 12) ? 6 : (((_r) == 13.5)? 7 : 0)))))))) 414c1565b61SSam Leffler static const struct txschedule series_quarter[] = { 415c1565b61SSam Leffler { 3,Q( 1.5),3,Q(1.5), 0,Q(1.5), 0,Q(1.5) }, /* 1.5Mb/s */ 416c1565b61SSam Leffler { 4,Q(2.25),3,Q(1.5), 4,Q(1.5), 0,Q(1.5) }, /*2.25Mb/s */ 417c1565b61SSam Leffler { 4,Q( 3),3,Q(1.5), 4,Q(1.5), 0,Q(1.5) }, /* 3Mb/s */ 418c1565b61SSam Leffler { 4,Q( 4.5),3,Q( 3), 4,Q(1.5), 2,Q(1.5) }, /* 4.5Mb/s */ 419c1565b61SSam Leffler { 4,Q( 6),3,Q(4.5), 4,Q( 3), 2,Q(1.5) }, /* 6Mb/s */ 420c1565b61SSam Leffler { 4,Q( 9),3,Q( 6), 4,Q(4.5), 2,Q(1.5) }, /* 9Mb/s */ 421c1565b61SSam Leffler { 4,Q( 12),3,Q( 9), 4,Q( 6), 2,Q( 3) }, /* 12Mb/s */ 422c1565b61SSam Leffler { 4,Q(13.5),3,Q( 12), 4,Q( 9), 2,Q( 6) } /*13.5Mb/s */ 423c1565b61SSam Leffler }; 424c1565b61SSam Leffler #undef Q 425c1565b61SSam Leffler 426fa20c234SSam Leffler void 427fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 428a4d8dd10SSam Leffler struct ath_desc *ds, int shortPreamble, u_int8_t rix) 429fa20c234SSam Leffler { 430fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 431c1565b61SSam Leffler const struct txschedule *sched = &sn->sched[rix]; 432c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 433c1565b61SSam Leffler uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 434fa20c234SSam Leffler 435c1565b61SSam Leffler /* XXX precalculate short preamble tables */ 436c1565b61SSam Leffler rix1 = sched->r1; 437c1565b61SSam Leffler s1code = rt->info[rix1].rateCode 438c1565b61SSam Leffler | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 439c1565b61SSam Leffler rix2 = sched->r2; 440c1565b61SSam Leffler s2code = rt->info[rix2].rateCode 441c1565b61SSam Leffler | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 442c1565b61SSam Leffler rix3 = sched->r3; 443c1565b61SSam Leffler s3code = rt->info[rix3].rateCode 444c1565b61SSam Leffler | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 445c1565b61SSam Leffler ath_hal_setupxtxdesc(sc->sc_ah, ds, 446c1565b61SSam Leffler s1code, sched->t1, /* series 1 */ 447c1565b61SSam Leffler s2code, sched->t2, /* series 2 */ 448c1565b61SSam Leffler s3code, sched->t3); /* series 3 */ 449fa20c234SSam Leffler } 450fa20c234SSam Leffler 451b2763056SSam Leffler static void 452b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an, 453b2763056SSam Leffler int frame_size, 454c1565b61SSam Leffler int rix0, int tries0, 455c1565b61SSam Leffler int rix1, int tries1, 456c1565b61SSam Leffler int rix2, int tries2, 457c1565b61SSam Leffler int rix3, int tries3, 458b2763056SSam Leffler int short_tries, int tries, int status) 459fa20c234SSam Leffler { 460fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 461fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 462c1565b61SSam Leffler const int size_bin = size_to_bin(frame_size); 463c1565b61SSam Leffler const int size = bin_to_size(size_bin); 464c1565b61SSam Leffler int tt, tries_so_far; 465fa20c234SSam Leffler 466c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix0)) 46765f9edeeSSam Leffler return; 468c1565b61SSam Leffler tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, 469b2763056SSam Leffler MIN(tries0, tries) - 1); 470c1565b61SSam Leffler tries_so_far = tries0; 471c1565b61SSam Leffler 472c1565b61SSam Leffler if (tries1 && tries_so_far < tries) { 473c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix1)) 47465f9edeeSSam Leffler return; 475c1565b61SSam Leffler tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries, 476b2763056SSam Leffler MIN(tries1 + tries_so_far, tries) - tries_so_far - 1); 477b2763056SSam Leffler tries_so_far += tries1; 478b2763056SSam Leffler } 479b2763056SSam Leffler 480c1565b61SSam Leffler if (tries2 && tries_so_far < tries) { 481c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix2)) 48265f9edeeSSam Leffler return; 483c1565b61SSam Leffler tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries, 484c1565b61SSam Leffler MIN(tries2 + tries_so_far, tries) - tries_so_far - 1); 485c1565b61SSam Leffler tries_so_far += tries2; 486c1565b61SSam Leffler } 487c1565b61SSam Leffler 488c1565b61SSam Leffler if (tries3 && tries_so_far < tries) { 489c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix3)) 490c1565b61SSam Leffler return; 491c1565b61SSam Leffler tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries, 492b2763056SSam Leffler MIN(tries3 + tries_so_far, tries) - tries_so_far - 1); 493b2763056SSam Leffler } 494c1565b61SSam Leffler 495c1565b61SSam Leffler if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 496fa20c234SSam Leffler /* just average the first few packets */ 497c1565b61SSam Leffler int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 498c1565b61SSam Leffler int packets = sn->stats[size_bin][rix0].total_packets; 499c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+1); 500fa20c234SSam Leffler } else { 501fa20c234SSam Leffler /* use a ewma */ 502c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time = 503c1565b61SSam Leffler ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 504c1565b61SSam Leffler (tt * (100 - ssc->smoothing_rate))) / 100; 505fa20c234SSam Leffler } 506fa20c234SSam Leffler 507c1565b61SSam Leffler if (status != 0) { 508fa20c234SSam Leffler int y; 509c1565b61SSam Leffler sn->stats[size_bin][rix0].successive_failures++; 510b91bf513SSam Leffler for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { 511c1565b61SSam Leffler /* 512c1565b61SSam Leffler * Also say larger packets failed since we 513c1565b61SSam Leffler * assume if a small packet fails at a 514b91bf513SSam Leffler * bit-rate then a larger one will also. 515b91bf513SSam Leffler */ 516c1565b61SSam Leffler sn->stats[y][rix0].successive_failures++; 517c1565b61SSam Leffler sn->stats[y][rix0].last_tx = ticks; 518c1565b61SSam Leffler sn->stats[y][rix0].tries += tries; 519c1565b61SSam Leffler sn->stats[y][rix0].total_packets++; 520fa20c234SSam Leffler } 521fa20c234SSam Leffler } else { 522c1565b61SSam Leffler sn->stats[size_bin][rix0].packets_acked++; 523c1565b61SSam Leffler sn->stats[size_bin][rix0].successive_failures = 0; 524fa20c234SSam Leffler } 525c1565b61SSam Leffler sn->stats[size_bin][rix0].tries += tries; 526c1565b61SSam Leffler sn->stats[size_bin][rix0].last_tx = ticks; 527c1565b61SSam Leffler sn->stats[size_bin][rix0].total_packets++; 528b2763056SSam Leffler 529c1565b61SSam Leffler if (rix0 == sn->current_sample_rix[size_bin]) { 530b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 531b032f27cSSam Leffler &an->an_node, 532b032f27cSSam Leffler "%s: size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)", 533b032f27cSSam Leffler __func__, 53465f9edeeSSam Leffler size, 53565f9edeeSSam Leffler status ? "FAIL" : "OK", 536c1565b61SSam Leffler rix0, short_tries, tries, tt, 537c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time, 538c1565b61SSam Leffler sn->stats[size_bin][rix0].perfect_tx_time); 539b2763056SSam Leffler sn->sample_tt[size_bin] = tt; 540c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 541b2763056SSam Leffler } 542b2763056SSam Leffler } 543b2763056SSam Leffler 544ec9ee5e7SSam Leffler static void 545ec9ee5e7SSam Leffler badrate(struct ifnet *ifp, int series, int hwrate, int tries, int status) 546ec9ee5e7SSam Leffler { 547ec9ee5e7SSam Leffler if_printf(ifp, "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 548ec9ee5e7SSam Leffler series, hwrate, tries, status); 549ec9ee5e7SSam Leffler } 550ec9ee5e7SSam Leffler 551b2763056SSam Leffler void 55243e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 55365f9edeeSSam Leffler const struct ath_buf *bf) 554b2763056SSam Leffler { 555b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 556b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 557b2763056SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 55865f9edeeSSam Leffler const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; 55965f9edeeSSam Leffler const struct ath_desc *ds0 = &bf->bf_desc[0]; 560c1565b61SSam Leffler int final_rix, short_tries, long_tries, frame_size; 56146d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 5621bb9a085SSam Leffler int mrr; 563b2763056SSam Leffler 564f6cbf16aSSam Leffler final_rix = rt->rateCodeToIndex[ts->ts_rate]; 56565f9edeeSSam Leffler short_tries = ts->ts_shortretry; 56665f9edeeSSam Leffler long_tries = ts->ts_longretry + 1; 56743e9cf7cSSam Leffler frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ 56843e9cf7cSSam Leffler if (frame_size == 0) /* NB: should not happen */ 569b2763056SSam Leffler frame_size = 1500; 570b2763056SSam Leffler 571c1565b61SSam Leffler if (sn->ratemask == 0) { 572b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 573b032f27cSSam Leffler &an->an_node, 574b032f27cSSam Leffler "%s: size %d %s rate/try %d/%d no rates yet", 575b032f27cSSam Leffler __func__, 57643e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 57765f9edeeSSam Leffler ts->ts_status ? "FAIL" : "OK", 57843e9cf7cSSam Leffler short_tries, long_tries); 579b2763056SSam Leffler return; 580b2763056SSam Leffler } 58165f9edeeSSam Leffler mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); 582f6cbf16aSSam Leffler if (!mrr || ts->ts_finaltsi == 0) { 583c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, final_rix)) { 584ec9ee5e7SSam Leffler badrate(ifp, 0, ts->ts_rate, long_tries, ts->ts_status); 585ec9ee5e7SSam Leffler return; 586ec9ee5e7SSam Leffler } 58765f9edeeSSam Leffler /* 58865f9edeeSSam Leffler * Only one rate was used; optimize work. 58965f9edeeSSam Leffler */ 590b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 591b032f27cSSam Leffler &an->an_node, "%s: size %d %s rate/try %d/%d/%d", 592b032f27cSSam Leffler __func__, 59343e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 59465f9edeeSSam Leffler ts->ts_status ? "FAIL" : "OK", 595c1565b61SSam Leffler final_rix, short_tries, long_tries); 596b2763056SSam Leffler update_stats(sc, an, frame_size, 597c1565b61SSam Leffler final_rix, long_tries, 598b2763056SSam Leffler 0, 0, 599b2763056SSam Leffler 0, 0, 600b2763056SSam Leffler 0, 0, 60165f9edeeSSam Leffler short_tries, long_tries, ts->ts_status); 602b2763056SSam Leffler } else { 603c1565b61SSam Leffler int hwrate0, rix0, tries0; 604c1565b61SSam Leffler int hwrate1, rix1, tries1; 605c1565b61SSam Leffler int hwrate2, rix2, tries2; 606c1565b61SSam Leffler int hwrate3, rix3, tries3; 60765f9edeeSSam Leffler int finalTSIdx = ts->ts_finaltsi; 608b2763056SSam Leffler 609b2763056SSam Leffler /* 610b2763056SSam Leffler * Process intermediate rates that failed. 611b2763056SSam Leffler */ 612517eabc6SSam Leffler if (sc->sc_ah->ah_magic != 0x20065416) { 613517eabc6SSam Leffler hwrate0 = MS(ds0->ds_ctl3, AR_XmitRate0); 614517eabc6SSam Leffler hwrate1 = MS(ds0->ds_ctl3, AR_XmitRate1); 615517eabc6SSam Leffler hwrate2 = MS(ds0->ds_ctl3, AR_XmitRate2); 616517eabc6SSam Leffler hwrate3 = MS(ds0->ds_ctl3, AR_XmitRate3); 617517eabc6SSam Leffler } else { 618517eabc6SSam Leffler hwrate0 = MS(ds0->ds_ctl3, AR5416_XmitRate0); 619517eabc6SSam Leffler hwrate1 = MS(ds0->ds_ctl3, AR5416_XmitRate1); 620517eabc6SSam Leffler hwrate2 = MS(ds0->ds_ctl3, AR5416_XmitRate2); 621517eabc6SSam Leffler hwrate3 = MS(ds0->ds_ctl3, AR5416_XmitRate3); 622517eabc6SSam Leffler } 623517eabc6SSam Leffler 624c1565b61SSam Leffler rix0 = rt->rateCodeToIndex[hwrate0]; 62565f9edeeSSam Leffler tries0 = MS(ds0->ds_ctl2, AR_XmitDataTries0); 626b2763056SSam Leffler 627c1565b61SSam Leffler rix1 = rt->rateCodeToIndex[hwrate1]; 62865f9edeeSSam Leffler tries1 = MS(ds0->ds_ctl2, AR_XmitDataTries1); 629b2763056SSam Leffler 630c1565b61SSam Leffler rix2 = rt->rateCodeToIndex[hwrate2]; 63165f9edeeSSam Leffler tries2 = MS(ds0->ds_ctl2, AR_XmitDataTries2); 632b2763056SSam Leffler 633c1565b61SSam Leffler rix3 = rt->rateCodeToIndex[hwrate3]; 63465f9edeeSSam Leffler tries3 = MS(ds0->ds_ctl2, AR_XmitDataTries3); 635ec9ee5e7SSam Leffler 636b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 637b032f27cSSam Leffler &an->an_node, 638b032f27cSSam Leffler "%s: size %d finaltsidx %d tries %d %s rate/try [%d/%d %d/%d %d/%d %d/%d]", 639b032f27cSSam Leffler __func__, 640b2763056SSam Leffler bin_to_size(size_to_bin(frame_size)), 641b2763056SSam Leffler finalTSIdx, 642b2763056SSam Leffler long_tries, 64365f9edeeSSam Leffler ts->ts_status ? "FAIL" : "OK", 644c1565b61SSam Leffler rix0, tries0, 645c1565b61SSam Leffler rix1, tries1, 646c1565b61SSam Leffler rix2, tries2, 647c1565b61SSam Leffler rix3, tries3); 648c1565b61SSam Leffler 649c1565b61SSam Leffler if (tries0 && !IS_RATE_DEFINED(sn, rix0)) 650c1565b61SSam Leffler badrate(ifp, 0, hwrate0, tries0, ts->ts_status); 651c1565b61SSam Leffler if (tries1 && !IS_RATE_DEFINED(sn, rix1)) 652c1565b61SSam Leffler badrate(ifp, 1, hwrate1, tries1, ts->ts_status); 653c1565b61SSam Leffler if (tries2 && !IS_RATE_DEFINED(sn, rix2)) 654c1565b61SSam Leffler badrate(ifp, 2, hwrate2, tries2, ts->ts_status); 655c1565b61SSam Leffler if (tries3 && !IS_RATE_DEFINED(sn, rix3)) 656c1565b61SSam Leffler badrate(ifp, 3, hwrate3, tries3, ts->ts_status); 657b2763056SSam Leffler 65865f9edeeSSam Leffler /* 65965f9edeeSSam Leffler * NB: series > 0 are not penalized for failure 66065f9edeeSSam Leffler * based on the try counts under the assumption 66165f9edeeSSam Leffler * that losses are often bursty and since we 66265f9edeeSSam Leffler * sample higher rates 1 try at a time doing so 66365f9edeeSSam Leffler * may unfairly penalize them. 66465f9edeeSSam Leffler */ 665b2763056SSam Leffler if (tries0) { 666b2763056SSam Leffler update_stats(sc, an, frame_size, 667c1565b61SSam Leffler rix0, tries0, 668c1565b61SSam Leffler rix1, tries1, 669c1565b61SSam Leffler rix2, tries2, 670c1565b61SSam Leffler rix3, tries3, 67165f9edeeSSam Leffler short_tries, long_tries, 672b91bf513SSam Leffler long_tries > tries0); 67365f9edeeSSam Leffler long_tries -= tries0; 674b2763056SSam Leffler } 675b2763056SSam Leffler 676b2763056SSam Leffler if (tries1 && finalTSIdx > 0) { 677b2763056SSam Leffler update_stats(sc, an, frame_size, 678c1565b61SSam Leffler rix1, tries1, 679c1565b61SSam Leffler rix2, tries2, 680c1565b61SSam Leffler rix3, tries3, 681b2763056SSam Leffler 0, 0, 68265f9edeeSSam Leffler short_tries, long_tries, 68365f9edeeSSam Leffler ts->ts_status); 68465f9edeeSSam Leffler long_tries -= tries1; 685b2763056SSam Leffler } 686b2763056SSam Leffler 687b2763056SSam Leffler if (tries2 && finalTSIdx > 1) { 688b2763056SSam Leffler update_stats(sc, an, frame_size, 689c1565b61SSam Leffler rix2, tries2, 690c1565b61SSam Leffler rix3, tries3, 691b2763056SSam Leffler 0, 0, 692b2763056SSam Leffler 0, 0, 69365f9edeeSSam Leffler short_tries, long_tries, 69465f9edeeSSam Leffler ts->ts_status); 69565f9edeeSSam Leffler long_tries -= tries2; 696b2763056SSam Leffler } 697b2763056SSam Leffler 698b2763056SSam Leffler if (tries3 && finalTSIdx > 2) { 699b2763056SSam Leffler update_stats(sc, an, frame_size, 700c1565b61SSam Leffler rix3, tries3, 701b2763056SSam Leffler 0, 0, 702b2763056SSam Leffler 0, 0, 703b2763056SSam Leffler 0, 0, 70465f9edeeSSam Leffler short_tries, long_tries, 70565f9edeeSSam Leffler ts->ts_status); 706b2763056SSam Leffler } 707b2763056SSam Leffler } 708fa20c234SSam Leffler } 709fa20c234SSam Leffler 710fa20c234SSam Leffler void 711fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 712fa20c234SSam Leffler { 713fa20c234SSam Leffler if (isnew) 714b2763056SSam Leffler ath_rate_ctl_reset(sc, &an->an_node); 715fa20c234SSam Leffler } 716fa20c234SSam Leffler 717c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 718c1565b61SSam Leffler NULL, /* IEEE80211_MODE_AUTO */ 719c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_11A */ 720c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11B */ 721c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11G */ 722c1565b61SSam Leffler NULL, /* IEEE80211_MODE_FH */ 723c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_TURBO_A */ 724c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_TURBO_G */ 725c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_STURBO_A */ 726c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_11NA */ 727c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11NG */ 728c1565b61SSam Leffler series_half, /* IEEE80211_MODE_HALF */ 729c1565b61SSam Leffler series_quarter, /* IEEE80211_MODE_QUARTER */ 730c1565b61SSam Leffler }; 731c1565b61SSam Leffler 732fa20c234SSam Leffler /* 733fa20c234SSam Leffler * Initialize the tables for a node. 734fa20c234SSam Leffler */ 735fa20c234SSam Leffler static void 736b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 737fa20c234SSam Leffler { 738fa20c234SSam Leffler #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 739c1565b61SSam Leffler #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 740fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 741c62362cbSSam Leffler const struct ieee80211_txparam *tp = ni->ni_txparms; 742fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 743fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 744c1565b61SSam Leffler int x, y, srate, rix; 745fa20c234SSam Leffler 746fa20c234SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 747c1565b61SSam Leffler 748c1565b61SSam Leffler KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 749c1565b61SSam Leffler ("curmode %u", sc->sc_curmode)); 750c1565b61SSam Leffler sn->sched = mrr_schedules[sc->sc_curmode]; 751c1565b61SSam Leffler KASSERT(sn->sched != NULL, 752c1565b61SSam Leffler ("no mrr schedule for mode %u", sc->sc_curmode)); 753c1565b61SSam Leffler 754c1565b61SSam Leffler sn->static_rix = -1; 755b032f27cSSam Leffler if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 756fa20c234SSam Leffler /* 7575f82a460SSam Leffler * A fixed rate is to be used; ucastrate is the IEEE code 7585f82a460SSam Leffler * for this rate (sans basic bit). Check this against the 7595f82a460SSam Leffler * negotiated rate set for the node. Note the fixed rate 7605f82a460SSam Leffler * may not be available for various reasons so we only 7615f82a460SSam Leffler * setup the static rate index if the lookup is successful. 7625f82a460SSam Leffler * XXX handle MCS 763fa20c234SSam Leffler */ 7645f82a460SSam Leffler for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) 7655f82a460SSam Leffler if (RATE(srate) == tp->ucastrate) { 7665f82a460SSam Leffler sn->static_rix = sc->sc_rixmap[tp->ucastrate]; 7675f82a460SSam Leffler break; 7685f82a460SSam Leffler } 7695e86169aSSam Leffler #ifdef IEEE80211_DEBUG 7705e86169aSSam Leffler if (sn->static_rix == -1) { 7715e86169aSSam Leffler IEEE80211_NOTE(ni->ni_vap, 7725e86169aSSam Leffler IEEE80211_MSG_RATECTL, ni, 7735e86169aSSam Leffler "%s: ucastrate %u not found, nrates %u", 7745e86169aSSam Leffler __func__, tp->ucastrate, 7755e86169aSSam Leffler ni->ni_rates.rs_nrates); 7765e86169aSSam Leffler } 7775e86169aSSam Leffler #endif 778fa20c234SSam Leffler } 779b2763056SSam Leffler 780c1565b61SSam Leffler /* 781c1565b61SSam Leffler * Construct a bitmask of usable rates. This has all 782c1565b61SSam Leffler * negotiated rates minus those marked by the hal as 783c1565b61SSam Leffler * to be ignored for doing rate control. 784c1565b61SSam Leffler */ 785c1565b61SSam Leffler sn->ratemask = 0; 786fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 787c1565b61SSam Leffler rix = sc->sc_rixmap[RATE(x)]; 788c1565b61SSam Leffler if (rix == 0xff) 7890ae09ec5SSam Leffler continue; 790c1565b61SSam Leffler /* skip rates marked broken by hal */ 791c1565b61SSam Leffler if (!rt->info[rix].valid) 792c1565b61SSam Leffler continue; 793c1565b61SSam Leffler KASSERT(rix < SAMPLE_MAXRATES, 794c1565b61SSam Leffler ("rate %u has rix %d", RATE(x), rix)); 795c1565b61SSam Leffler sn->ratemask |= 1<<rix; 796b2763056SSam Leffler } 797b032f27cSSam Leffler #ifdef IEEE80211_DEBUG 798b032f27cSSam Leffler if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 799c1565b61SSam Leffler uint32_t mask; 800c1565b61SSam Leffler 801b032f27cSSam Leffler ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 802c1565b61SSam Leffler ni->ni_macaddr, ":", __func__); 803c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 804c1565b61SSam Leffler if ((mask & 1) == 0) 805b032f27cSSam Leffler continue; 806c1565b61SSam Leffler printf(" %d/%d", DOT11RATE(rix) / 2, 807c1565b61SSam Leffler calc_usecs_unicast_packet(sc, 1600, rix, 0,0)); 808b032f27cSSam Leffler } 809b032f27cSSam Leffler printf("\n"); 810b032f27cSSam Leffler } 811b032f27cSSam Leffler #endif 812b2763056SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 813b2763056SSam Leffler int size = bin_to_size(y); 814c1565b61SSam Leffler uint32_t mask; 815c1565b61SSam Leffler 816b2763056SSam Leffler sn->packets_sent[y] = 0; 817c1565b61SSam Leffler sn->current_sample_rix[y] = -1; 818c1565b61SSam Leffler sn->last_sample_rix[y] = 0; 819c1565b61SSam Leffler /* XXX start with first valid rate */ 820c1565b61SSam Leffler sn->current_rix[y] = ffs(sn->ratemask)-1; 821b2763056SSam Leffler 822c1565b61SSam Leffler /* 823c1565b61SSam Leffler * Initialize the statistics buckets; these are 824c1565b61SSam Leffler * indexed by the rate code index. 825c1565b61SSam Leffler */ 826c1565b61SSam Leffler for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 827c1565b61SSam Leffler if ((mask & 1) == 0) /* not a valid rate */ 828c1565b61SSam Leffler continue; 829c1565b61SSam Leffler sn->stats[y][rix].successive_failures = 0; 830c1565b61SSam Leffler sn->stats[y][rix].tries = 0; 831c1565b61SSam Leffler sn->stats[y][rix].total_packets = 0; 832c1565b61SSam Leffler sn->stats[y][rix].packets_acked = 0; 833c1565b61SSam Leffler sn->stats[y][rix].last_tx = 0; 834b2763056SSam Leffler 835c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time = 836c1565b61SSam Leffler calc_usecs_unicast_packet(sc, size, rix, 0, 0); 837c1565b61SSam Leffler sn->stats[y][rix].average_tx_time = 838c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time; 839b2763056SSam Leffler } 840b91bf513SSam Leffler } 841c1565b61SSam Leffler #if 0 842c1565b61SSam Leffler /* XXX 0, num_rates-1 are wrong */ 843b032f27cSSam Leffler IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 844b032f27cSSam Leffler "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 845b91bf513SSam Leffler sn->num_rates, 846c1565b61SSam Leffler DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 847b91bf513SSam Leffler sn->stats[1][0].perfect_tx_time, 848c1565b61SSam Leffler DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 849b91bf513SSam Leffler sn->stats[1][sn->num_rates-1].perfect_tx_time 850b91bf513SSam Leffler ); 851c1565b61SSam Leffler #endif 852b032f27cSSam Leffler /* set the visible bit-rate */ 853c1565b61SSam Leffler if (sn->static_rix != -1) 854c1565b61SSam Leffler ni->ni_txrate = DOT11RATE(sn->static_rix); 855d0d425bfSSam Leffler else 856c1565b61SSam Leffler ni->ni_txrate = RATE(0); 857fa20c234SSam Leffler #undef RATE 858c1565b61SSam Leffler #undef DOT11RATE 859fa20c234SSam Leffler } 860fa20c234SSam Leffler 861f0fd5e07SSam Leffler static void 862c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni) 863c1565b61SSam Leffler { 864c1565b61SSam Leffler struct ath_softc *sc = arg; 865c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 866c1565b61SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 867c1565b61SSam Leffler uint32_t mask; 868c1565b61SSam Leffler int rix, y; 869c1565b61SSam Leffler 870c1565b61SSam Leffler printf("\n[%s] refcnt %d static_rix %d ratemask 0x%x\n", 871c1565b61SSam Leffler ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 872c1565b61SSam Leffler sn->static_rix, sn->ratemask); 873c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 874c1565b61SSam Leffler printf("[%4u] cur rix %d since switch: packets %d ticks %u\n", 875c1565b61SSam Leffler bin_to_size(y), sn->current_rix[y], 876c1565b61SSam Leffler sn->packets_since_switch[y], sn->ticks_since_switch[y]); 877c1565b61SSam Leffler printf("[%4u] last sample %d cur sample %d packets sent %d\n", 878c1565b61SSam Leffler bin_to_size(y), sn->last_sample_rix[y], 879c1565b61SSam Leffler sn->current_sample_rix[y], sn->packets_sent[y]); 880c1565b61SSam Leffler printf("[%4u] packets since sample %d sample tt %u\n", 881c1565b61SSam Leffler bin_to_size(y), sn->packets_since_sample[y], 882c1565b61SSam Leffler sn->sample_tt[y]); 883c1565b61SSam Leffler } 884c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 885c1565b61SSam Leffler if ((mask & 1) == 0) 886c1565b61SSam Leffler continue; 887c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 888c1565b61SSam Leffler if (sn->stats[y][rix].total_packets == 0) 889c1565b61SSam Leffler continue; 890c1565b61SSam Leffler printf("[%2u:%4u] %8d:%-8d (%3d%%) T %8d F %4d avg %5u last %u\n", 891c1565b61SSam Leffler (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL)/2, 892c1565b61SSam Leffler bin_to_size(y), 893c1565b61SSam Leffler sn->stats[y][rix].total_packets, 894c1565b61SSam Leffler sn->stats[y][rix].packets_acked, 895c1565b61SSam Leffler (100*sn->stats[y][rix].packets_acked)/sn->stats[y][rix].total_packets, 896c1565b61SSam Leffler sn->stats[y][rix].tries, 897c1565b61SSam Leffler sn->stats[y][rix].successive_failures, 898c1565b61SSam Leffler sn->stats[y][rix].average_tx_time, 899c1565b61SSam Leffler ticks - sn->stats[y][rix].last_tx); 900c1565b61SSam Leffler } 901c1565b61SSam Leffler } 902c1565b61SSam Leffler } 903c1565b61SSam Leffler 904c1565b61SSam Leffler static int 905c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 906c1565b61SSam Leffler { 907c1565b61SSam Leffler struct ath_softc *sc = arg1; 908c1565b61SSam Leffler struct ifnet *ifp = sc->sc_ifp; 909c1565b61SSam Leffler struct ieee80211com *ic = ifp->if_l2com; 910c1565b61SSam Leffler int error, v; 911c1565b61SSam Leffler 912c1565b61SSam Leffler v = 0; 913c1565b61SSam Leffler error = sysctl_handle_int(oidp, &v, 0, req); 914c1565b61SSam Leffler if (error || !req->newptr) 915c1565b61SSam Leffler return error; 916c1565b61SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 917c1565b61SSam Leffler return 0; 918c1565b61SSam Leffler } 919c1565b61SSam Leffler 920c1565b61SSam Leffler static int 921c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 922c1565b61SSam Leffler { 923c1565b61SSam Leffler struct sample_softc *ssc = arg1; 924c1565b61SSam Leffler int rate, error; 925c1565b61SSam Leffler 926c1565b61SSam Leffler rate = ssc->smoothing_rate; 927c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 928c1565b61SSam Leffler if (error || !req->newptr) 929c1565b61SSam Leffler return error; 930c1565b61SSam Leffler if (!(0 <= rate && rate < 100)) 931c1565b61SSam Leffler return EINVAL; 932c1565b61SSam Leffler ssc->smoothing_rate = rate; 933c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - rate); 934c1565b61SSam Leffler return 0; 935c1565b61SSam Leffler } 936c1565b61SSam Leffler 937c1565b61SSam Leffler static int 938c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 939c1565b61SSam Leffler { 940c1565b61SSam Leffler struct sample_softc *ssc = arg1; 941c1565b61SSam Leffler int rate, error; 942c1565b61SSam Leffler 943c1565b61SSam Leffler rate = ssc->sample_rate; 944c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 945c1565b61SSam Leffler if (error || !req->newptr) 946c1565b61SSam Leffler return error; 947c1565b61SSam Leffler if (!(2 <= rate && rate <= 100)) 948c1565b61SSam Leffler return EINVAL; 949c1565b61SSam Leffler ssc->sample_rate = rate; 950c1565b61SSam Leffler return 0; 951c1565b61SSam Leffler } 952c1565b61SSam Leffler 953c1565b61SSam Leffler static void 954c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 955fa20c234SSam Leffler { 956fa20c234SSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 957fa20c234SSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 958fa20c234SSam Leffler 959c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 960c1565b61SSam Leffler "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 961c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate, "I", 962c1565b61SSam Leffler "sample: smoothing rate for avg tx time (%%)"); 963c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 964c1565b61SSam Leffler "sample_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 965c1565b61SSam Leffler ath_rate_sysctl_sample_rate, "I", 966c1565b61SSam Leffler "sample: percent air time devoted to sampling new rates (%%)"); 967c1565b61SSam Leffler /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 968c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 969c1565b61SSam Leffler "sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 970c1565b61SSam Leffler ath_rate_sysctl_stats, "I", "sample: print statistics"); 971fa20c234SSam Leffler } 972fa20c234SSam Leffler 973fa20c234SSam Leffler struct ath_ratectrl * 974fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc) 975fa20c234SSam Leffler { 976c1565b61SSam Leffler struct sample_softc *ssc; 977fa20c234SSam Leffler 978c1565b61SSam Leffler ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 979c1565b61SSam Leffler if (ssc == NULL) 980fa20c234SSam Leffler return NULL; 981c1565b61SSam Leffler ssc->arc.arc_space = sizeof(struct sample_node); 982c1565b61SSam Leffler ssc->smoothing_rate = 95; /* ewma percentage ([0..99]) */ 983c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 984c1565b61SSam Leffler ssc->sample_rate = 10; /* %time to try diff tx rates */ 985c1565b61SSam Leffler ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 986c1565b61SSam Leffler ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 987c1565b61SSam Leffler ssc->min_switch = hz; /* 1 second */ 988c1565b61SSam Leffler ath_rate_sysctlattach(sc, ssc); 989c1565b61SSam Leffler return &ssc->arc; 990fa20c234SSam Leffler } 991fa20c234SSam Leffler 992fa20c234SSam Leffler void 993fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc) 994fa20c234SSam Leffler { 995c1565b61SSam Leffler struct sample_softc *ssc = (struct sample_softc *) arc; 996fa20c234SSam Leffler 997c1565b61SSam Leffler free(ssc, M_DEVBUF); 998fa20c234SSam Leffler } 999