1*572ff6f6SMatthew Dillon /*- 2*572ff6f6SMatthew Dillon * Copyright (c) 2005 John Bicket 3*572ff6f6SMatthew Dillon * All rights reserved. 4*572ff6f6SMatthew Dillon * 5*572ff6f6SMatthew Dillon * Redistribution and use in source and binary forms, with or without 6*572ff6f6SMatthew Dillon * modification, are permitted provided that the following conditions 7*572ff6f6SMatthew Dillon * are met: 8*572ff6f6SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 9*572ff6f6SMatthew Dillon * notice, this list of conditions and the following disclaimer, 10*572ff6f6SMatthew Dillon * without modification. 11*572ff6f6SMatthew Dillon * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*572ff6f6SMatthew Dillon * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13*572ff6f6SMatthew Dillon * redistribution must be conditioned upon including a substantially 14*572ff6f6SMatthew Dillon * similar Disclaimer requirement for further binary redistribution. 15*572ff6f6SMatthew Dillon * 3. Neither the names of the above-listed copyright holders nor the names 16*572ff6f6SMatthew Dillon * of any contributors may be used to endorse or promote products derived 17*572ff6f6SMatthew Dillon * from this software without specific prior written permission. 18*572ff6f6SMatthew Dillon * 19*572ff6f6SMatthew Dillon * Alternatively, this software may be distributed under the terms of the 20*572ff6f6SMatthew Dillon * GNU General Public License ("GPL") version 2 as published by the Free 21*572ff6f6SMatthew Dillon * Software Foundation. 22*572ff6f6SMatthew Dillon * 23*572ff6f6SMatthew Dillon * NO WARRANTY 24*572ff6f6SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25*572ff6f6SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26*572ff6f6SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27*572ff6f6SMatthew Dillon * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28*572ff6f6SMatthew Dillon * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29*572ff6f6SMatthew Dillon * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30*572ff6f6SMatthew Dillon * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31*572ff6f6SMatthew Dillon * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32*572ff6f6SMatthew Dillon * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33*572ff6f6SMatthew Dillon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34*572ff6f6SMatthew Dillon * THE POSSIBILITY OF SUCH DAMAGES. 35*572ff6f6SMatthew Dillon * 36*572ff6f6SMatthew Dillon */ 37*572ff6f6SMatthew Dillon 38*572ff6f6SMatthew Dillon #include <sys/cdefs.h> 39*572ff6f6SMatthew Dillon __FBSDID("$FreeBSD$"); 40*572ff6f6SMatthew Dillon 41*572ff6f6SMatthew Dillon /* 42*572ff6f6SMatthew Dillon * John Bicket's SampleRate control algorithm. 43*572ff6f6SMatthew Dillon */ 44*572ff6f6SMatthew Dillon #include "opt_ath.h" 45*572ff6f6SMatthew Dillon #include "opt_inet.h" 46*572ff6f6SMatthew Dillon #include "opt_wlan.h" 47*572ff6f6SMatthew Dillon #include "opt_ah.h" 48*572ff6f6SMatthew Dillon 49*572ff6f6SMatthew Dillon #include <sys/param.h> 50*572ff6f6SMatthew Dillon #include <sys/systm.h> 51*572ff6f6SMatthew Dillon #include <sys/sysctl.h> 52*572ff6f6SMatthew Dillon #include <sys/kernel.h> 53*572ff6f6SMatthew Dillon #include <sys/lock.h> 54*572ff6f6SMatthew Dillon #include <sys/malloc.h> 55*572ff6f6SMatthew Dillon #include <sys/mutex.h> 56*572ff6f6SMatthew Dillon #include <sys/errno.h> 57*572ff6f6SMatthew Dillon 58*572ff6f6SMatthew Dillon #include <machine/bus.h> 59*572ff6f6SMatthew Dillon #include <machine/resource.h> 60*572ff6f6SMatthew Dillon #include <sys/bus.h> 61*572ff6f6SMatthew Dillon 62*572ff6f6SMatthew Dillon #include <sys/socket.h> 63*572ff6f6SMatthew Dillon 64*572ff6f6SMatthew Dillon #include <net/if.h> 65*572ff6f6SMatthew Dillon #include <net/if_var.h> 66*572ff6f6SMatthew Dillon #include <net/if_media.h> 67*572ff6f6SMatthew Dillon #include <net/if_arp.h> 68*572ff6f6SMatthew Dillon #include <net/ethernet.h> /* XXX for ether_sprintf */ 69*572ff6f6SMatthew Dillon 70*572ff6f6SMatthew Dillon #include <net80211/ieee80211_var.h> 71*572ff6f6SMatthew Dillon 72*572ff6f6SMatthew Dillon #include <net/bpf.h> 73*572ff6f6SMatthew Dillon 74*572ff6f6SMatthew Dillon #ifdef INET 75*572ff6f6SMatthew Dillon #include <netinet/in.h> 76*572ff6f6SMatthew Dillon #include <netinet/if_ether.h> 77*572ff6f6SMatthew Dillon #endif 78*572ff6f6SMatthew Dillon 79*572ff6f6SMatthew Dillon #include <dev/ath/if_athvar.h> 80*572ff6f6SMatthew Dillon #include <dev/ath/ath_rate/sample/sample.h> 81*572ff6f6SMatthew Dillon #include <dev/ath/ath_hal/ah_desc.h> 82*572ff6f6SMatthew Dillon #include <dev/ath/ath_rate/sample/tx_schedules.h> 83*572ff6f6SMatthew Dillon 84*572ff6f6SMatthew Dillon /* 85*572ff6f6SMatthew Dillon * This file is an implementation of the SampleRate algorithm 86*572ff6f6SMatthew Dillon * in "Bit-rate Selection in Wireless Networks" 87*572ff6f6SMatthew Dillon * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 88*572ff6f6SMatthew Dillon * 89*572ff6f6SMatthew Dillon * SampleRate chooses the bit-rate it predicts will provide the most 90*572ff6f6SMatthew Dillon * throughput based on estimates of the expected per-packet 91*572ff6f6SMatthew Dillon * transmission time for each bit-rate. SampleRate periodically sends 92*572ff6f6SMatthew Dillon * packets at bit-rates other than the current one to estimate when 93*572ff6f6SMatthew Dillon * another bit-rate will provide better performance. SampleRate 94*572ff6f6SMatthew Dillon * switches to another bit-rate when its estimated per-packet 95*572ff6f6SMatthew Dillon * transmission time becomes smaller than the current bit-rate's. 96*572ff6f6SMatthew Dillon * SampleRate reduces the number of bit-rates it must sample by 97*572ff6f6SMatthew Dillon * eliminating those that could not perform better than the one 98*572ff6f6SMatthew Dillon * currently being used. SampleRate also stops probing at a bit-rate 99*572ff6f6SMatthew Dillon * if it experiences several successive losses. 100*572ff6f6SMatthew Dillon * 101*572ff6f6SMatthew Dillon * The difference between the algorithm in the thesis and the one in this 102*572ff6f6SMatthew Dillon * file is that the one in this file uses a ewma instead of a window. 103*572ff6f6SMatthew Dillon * 104*572ff6f6SMatthew Dillon * Also, this implementation tracks the average transmission time for 105*572ff6f6SMatthew Dillon * a few different packet sizes independently for each link. 106*572ff6f6SMatthew Dillon */ 107*572ff6f6SMatthew Dillon 108*572ff6f6SMatthew Dillon static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 109*572ff6f6SMatthew Dillon 110*572ff6f6SMatthew Dillon static __inline int 111*572ff6f6SMatthew Dillon size_to_bin(int size) 112*572ff6f6SMatthew Dillon { 113*572ff6f6SMatthew Dillon #if NUM_PACKET_SIZE_BINS > 1 114*572ff6f6SMatthew Dillon if (size <= packet_size_bins[0]) 115*572ff6f6SMatthew Dillon return 0; 116*572ff6f6SMatthew Dillon #endif 117*572ff6f6SMatthew Dillon #if NUM_PACKET_SIZE_BINS > 2 118*572ff6f6SMatthew Dillon if (size <= packet_size_bins[1]) 119*572ff6f6SMatthew Dillon return 1; 120*572ff6f6SMatthew Dillon #endif 121*572ff6f6SMatthew Dillon #if NUM_PACKET_SIZE_BINS > 3 122*572ff6f6SMatthew Dillon if (size <= packet_size_bins[2]) 123*572ff6f6SMatthew Dillon return 2; 124*572ff6f6SMatthew Dillon #endif 125*572ff6f6SMatthew Dillon #if NUM_PACKET_SIZE_BINS > 4 126*572ff6f6SMatthew Dillon #error "add support for more packet sizes" 127*572ff6f6SMatthew Dillon #endif 128*572ff6f6SMatthew Dillon return NUM_PACKET_SIZE_BINS-1; 129*572ff6f6SMatthew Dillon } 130*572ff6f6SMatthew Dillon 131*572ff6f6SMatthew Dillon void 132*572ff6f6SMatthew Dillon ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 133*572ff6f6SMatthew Dillon { 134*572ff6f6SMatthew Dillon /* NB: assumed to be zero'd by caller */ 135*572ff6f6SMatthew Dillon } 136*572ff6f6SMatthew Dillon 137*572ff6f6SMatthew Dillon void 138*572ff6f6SMatthew Dillon ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 139*572ff6f6SMatthew Dillon { 140*572ff6f6SMatthew Dillon } 141*572ff6f6SMatthew Dillon 142*572ff6f6SMatthew Dillon static int 143*572ff6f6SMatthew Dillon dot11rate(const HAL_RATE_TABLE *rt, int rix) 144*572ff6f6SMatthew Dillon { 145*572ff6f6SMatthew Dillon if (rix < 0) 146*572ff6f6SMatthew Dillon return -1; 147*572ff6f6SMatthew Dillon return rt->info[rix].phy == IEEE80211_T_HT ? 148*572ff6f6SMatthew Dillon rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2; 149*572ff6f6SMatthew Dillon } 150*572ff6f6SMatthew Dillon 151*572ff6f6SMatthew Dillon static const char * 152*572ff6f6SMatthew Dillon dot11rate_label(const HAL_RATE_TABLE *rt, int rix) 153*572ff6f6SMatthew Dillon { 154*572ff6f6SMatthew Dillon if (rix < 0) 155*572ff6f6SMatthew Dillon return ""; 156*572ff6f6SMatthew Dillon return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; 157*572ff6f6SMatthew Dillon } 158*572ff6f6SMatthew Dillon 159*572ff6f6SMatthew Dillon /* 160*572ff6f6SMatthew Dillon * Return the rix with the lowest average_tx_time, 161*572ff6f6SMatthew Dillon * or -1 if all the average_tx_times are 0. 162*572ff6f6SMatthew Dillon */ 163*572ff6f6SMatthew Dillon static __inline int 164*572ff6f6SMatthew Dillon pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt, 165*572ff6f6SMatthew Dillon int size_bin, int require_acked_before) 166*572ff6f6SMatthew Dillon { 167*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 168*572ff6f6SMatthew Dillon int best_rate_rix, best_rate_tt, best_rate_pct; 169*572ff6f6SMatthew Dillon uint64_t mask; 170*572ff6f6SMatthew Dillon int rix, tt, pct; 171*572ff6f6SMatthew Dillon 172*572ff6f6SMatthew Dillon best_rate_rix = 0; 173*572ff6f6SMatthew Dillon best_rate_tt = 0; 174*572ff6f6SMatthew Dillon best_rate_pct = 0; 175*572ff6f6SMatthew Dillon for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 176*572ff6f6SMatthew Dillon if ((mask & 1) == 0) /* not a supported rate */ 177*572ff6f6SMatthew Dillon continue; 178*572ff6f6SMatthew Dillon 179*572ff6f6SMatthew Dillon /* Don't pick a non-HT rate for a HT node */ 180*572ff6f6SMatthew Dillon if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 181*572ff6f6SMatthew Dillon (rt->info[rix].phy != IEEE80211_T_HT)) { 182*572ff6f6SMatthew Dillon continue; 183*572ff6f6SMatthew Dillon } 184*572ff6f6SMatthew Dillon 185*572ff6f6SMatthew Dillon tt = sn->stats[size_bin][rix].average_tx_time; 186*572ff6f6SMatthew Dillon if (tt <= 0 || 187*572ff6f6SMatthew Dillon (require_acked_before && 188*572ff6f6SMatthew Dillon !sn->stats[size_bin][rix].packets_acked)) 189*572ff6f6SMatthew Dillon continue; 190*572ff6f6SMatthew Dillon 191*572ff6f6SMatthew Dillon /* Calculate percentage if possible */ 192*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix].total_packets > 0) { 193*572ff6f6SMatthew Dillon pct = sn->stats[size_bin][rix].ewma_pct; 194*572ff6f6SMatthew Dillon } else { 195*572ff6f6SMatthew Dillon /* XXX for now, assume 95% ok */ 196*572ff6f6SMatthew Dillon pct = 95; 197*572ff6f6SMatthew Dillon } 198*572ff6f6SMatthew Dillon 199*572ff6f6SMatthew Dillon /* don't use a bit-rate that has been failing */ 200*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix].successive_failures > 3) 201*572ff6f6SMatthew Dillon continue; 202*572ff6f6SMatthew Dillon 203*572ff6f6SMatthew Dillon /* 204*572ff6f6SMatthew Dillon * For HT, Don't use a bit rate that is much more 205*572ff6f6SMatthew Dillon * lossy than the best. 206*572ff6f6SMatthew Dillon * 207*572ff6f6SMatthew Dillon * XXX this isn't optimal; it's just designed to 208*572ff6f6SMatthew Dillon * eliminate rates that are going to be obviously 209*572ff6f6SMatthew Dillon * worse. 210*572ff6f6SMatthew Dillon */ 211*572ff6f6SMatthew Dillon if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 212*572ff6f6SMatthew Dillon if (best_rate_pct > (pct + 50)) 213*572ff6f6SMatthew Dillon continue; 214*572ff6f6SMatthew Dillon } 215*572ff6f6SMatthew Dillon 216*572ff6f6SMatthew Dillon /* 217*572ff6f6SMatthew Dillon * For non-MCS rates, use the current average txtime for 218*572ff6f6SMatthew Dillon * comparison. 219*572ff6f6SMatthew Dillon */ 220*572ff6f6SMatthew Dillon if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 221*572ff6f6SMatthew Dillon if (best_rate_tt == 0 || tt <= best_rate_tt) { 222*572ff6f6SMatthew Dillon best_rate_tt = tt; 223*572ff6f6SMatthew Dillon best_rate_rix = rix; 224*572ff6f6SMatthew Dillon best_rate_pct = pct; 225*572ff6f6SMatthew Dillon } 226*572ff6f6SMatthew Dillon } 227*572ff6f6SMatthew Dillon 228*572ff6f6SMatthew Dillon /* 229*572ff6f6SMatthew Dillon * Since 2 stream rates have slightly higher TX times, 230*572ff6f6SMatthew Dillon * allow a little bit of leeway. This should later 231*572ff6f6SMatthew Dillon * be abstracted out and properly handled. 232*572ff6f6SMatthew Dillon */ 233*572ff6f6SMatthew Dillon if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 234*572ff6f6SMatthew Dillon if (best_rate_tt == 0 || (tt * 8 <= best_rate_tt * 10)) { 235*572ff6f6SMatthew Dillon best_rate_tt = tt; 236*572ff6f6SMatthew Dillon best_rate_rix = rix; 237*572ff6f6SMatthew Dillon best_rate_pct = pct; 238*572ff6f6SMatthew Dillon } 239*572ff6f6SMatthew Dillon } 240*572ff6f6SMatthew Dillon } 241*572ff6f6SMatthew Dillon return (best_rate_tt ? best_rate_rix : -1); 242*572ff6f6SMatthew Dillon } 243*572ff6f6SMatthew Dillon 244*572ff6f6SMatthew Dillon /* 245*572ff6f6SMatthew Dillon * Pick a good "random" bit-rate to sample other than the current one. 246*572ff6f6SMatthew Dillon */ 247*572ff6f6SMatthew Dillon static __inline int 248*572ff6f6SMatthew Dillon pick_sample_rate(struct sample_softc *ssc , struct ath_node *an, 249*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt, int size_bin) 250*572ff6f6SMatthew Dillon { 251*572ff6f6SMatthew Dillon #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 252*572ff6f6SMatthew Dillon #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 253*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 254*572ff6f6SMatthew Dillon int current_rix, rix; 255*572ff6f6SMatthew Dillon unsigned current_tt; 256*572ff6f6SMatthew Dillon uint64_t mask; 257*572ff6f6SMatthew Dillon 258*572ff6f6SMatthew Dillon current_rix = sn->current_rix[size_bin]; 259*572ff6f6SMatthew Dillon if (current_rix < 0) { 260*572ff6f6SMatthew Dillon /* no successes yet, send at the lowest bit-rate */ 261*572ff6f6SMatthew Dillon /* XXX should return MCS0 if HT */ 262*572ff6f6SMatthew Dillon return 0; 263*572ff6f6SMatthew Dillon } 264*572ff6f6SMatthew Dillon 265*572ff6f6SMatthew Dillon current_tt = sn->stats[size_bin][current_rix].average_tx_time; 266*572ff6f6SMatthew Dillon 267*572ff6f6SMatthew Dillon rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 268*572ff6f6SMatthew Dillon mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */ 269*572ff6f6SMatthew Dillon while (mask != 0) { 270*572ff6f6SMatthew Dillon if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */ 271*572ff6f6SMatthew Dillon nextrate: 272*572ff6f6SMatthew Dillon if (++rix >= rt->rateCount) 273*572ff6f6SMatthew Dillon rix = 0; 274*572ff6f6SMatthew Dillon continue; 275*572ff6f6SMatthew Dillon } 276*572ff6f6SMatthew Dillon 277*572ff6f6SMatthew Dillon /* 278*572ff6f6SMatthew Dillon * The following code stops trying to sample 279*572ff6f6SMatthew Dillon * non-MCS rates when speaking to an MCS node. 280*572ff6f6SMatthew Dillon * However, at least for CCK rates in 2.4GHz mode, 281*572ff6f6SMatthew Dillon * the non-MCS rates MAY actually provide better 282*572ff6f6SMatthew Dillon * PER at the very far edge of reception. 283*572ff6f6SMatthew Dillon * 284*572ff6f6SMatthew Dillon * However! Until ath_rate_form_aggr() grows 285*572ff6f6SMatthew Dillon * some logic to not form aggregates if the 286*572ff6f6SMatthew Dillon * selected rate is non-MCS, this won't work. 287*572ff6f6SMatthew Dillon * 288*572ff6f6SMatthew Dillon * So don't disable this code until you've taught 289*572ff6f6SMatthew Dillon * ath_rate_form_aggr() to drop out if any of 290*572ff6f6SMatthew Dillon * the selected rates are non-MCS. 291*572ff6f6SMatthew Dillon */ 292*572ff6f6SMatthew Dillon #if 1 293*572ff6f6SMatthew Dillon /* if the node is HT and the rate isn't HT, don't bother sample */ 294*572ff6f6SMatthew Dillon if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 295*572ff6f6SMatthew Dillon (rt->info[rix].phy != IEEE80211_T_HT)) { 296*572ff6f6SMatthew Dillon mask &= ~((uint64_t) 1<<rix); 297*572ff6f6SMatthew Dillon goto nextrate; 298*572ff6f6SMatthew Dillon } 299*572ff6f6SMatthew Dillon #endif 300*572ff6f6SMatthew Dillon 301*572ff6f6SMatthew Dillon /* this bit-rate is always worse than the current one */ 302*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 303*572ff6f6SMatthew Dillon mask &= ~((uint64_t) 1<<rix); 304*572ff6f6SMatthew Dillon goto nextrate; 305*572ff6f6SMatthew Dillon } 306*572ff6f6SMatthew Dillon 307*572ff6f6SMatthew Dillon /* rarely sample bit-rates that fail a lot */ 308*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 309*572ff6f6SMatthew Dillon ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 310*572ff6f6SMatthew Dillon mask &= ~((uint64_t) 1<<rix); 311*572ff6f6SMatthew Dillon goto nextrate; 312*572ff6f6SMatthew Dillon } 313*572ff6f6SMatthew Dillon 314*572ff6f6SMatthew Dillon /* 315*572ff6f6SMatthew Dillon * For HT, only sample a few rates on either side of the 316*572ff6f6SMatthew Dillon * current rix; there's quite likely a lot of them. 317*572ff6f6SMatthew Dillon */ 318*572ff6f6SMatthew Dillon if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 319*572ff6f6SMatthew Dillon if (rix < (current_rix - 3) || 320*572ff6f6SMatthew Dillon rix > (current_rix + 3)) { 321*572ff6f6SMatthew Dillon mask &= ~((uint64_t) 1<<rix); 322*572ff6f6SMatthew Dillon goto nextrate; 323*572ff6f6SMatthew Dillon } 324*572ff6f6SMatthew Dillon } 325*572ff6f6SMatthew Dillon 326*572ff6f6SMatthew Dillon /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */ 327*572ff6f6SMatthew Dillon if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 328*572ff6f6SMatthew Dillon if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 329*572ff6f6SMatthew Dillon mask &= ~((uint64_t) 1<<rix); 330*572ff6f6SMatthew Dillon goto nextrate; 331*572ff6f6SMatthew Dillon } 332*572ff6f6SMatthew Dillon } 333*572ff6f6SMatthew Dillon 334*572ff6f6SMatthew Dillon sn->last_sample_rix[size_bin] = rix; 335*572ff6f6SMatthew Dillon return rix; 336*572ff6f6SMatthew Dillon } 337*572ff6f6SMatthew Dillon return current_rix; 338*572ff6f6SMatthew Dillon #undef DOT11RATE 339*572ff6f6SMatthew Dillon #undef MCS 340*572ff6f6SMatthew Dillon } 341*572ff6f6SMatthew Dillon 342*572ff6f6SMatthew Dillon static int 343*572ff6f6SMatthew Dillon ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) 344*572ff6f6SMatthew Dillon { 345*572ff6f6SMatthew Dillon #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 346*572ff6f6SMatthew Dillon #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 347*572ff6f6SMatthew Dillon #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 348*572ff6f6SMatthew Dillon const struct ieee80211_txparam *tp = ni->ni_txparms; 349*572ff6f6SMatthew Dillon int srate; 350*572ff6f6SMatthew Dillon 351*572ff6f6SMatthew Dillon /* Check MCS rates */ 352*572ff6f6SMatthew Dillon for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { 353*572ff6f6SMatthew Dillon if (MCS(srate) == tp->ucastrate) 354*572ff6f6SMatthew Dillon return sc->sc_rixmap[tp->ucastrate]; 355*572ff6f6SMatthew Dillon } 356*572ff6f6SMatthew Dillon 357*572ff6f6SMatthew Dillon /* Check legacy rates */ 358*572ff6f6SMatthew Dillon for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { 359*572ff6f6SMatthew Dillon if (RATE(srate) == tp->ucastrate) 360*572ff6f6SMatthew Dillon return sc->sc_rixmap[tp->ucastrate]; 361*572ff6f6SMatthew Dillon } 362*572ff6f6SMatthew Dillon return -1; 363*572ff6f6SMatthew Dillon #undef RATE 364*572ff6f6SMatthew Dillon #undef DOT11RATE 365*572ff6f6SMatthew Dillon #undef MCS 366*572ff6f6SMatthew Dillon } 367*572ff6f6SMatthew Dillon 368*572ff6f6SMatthew Dillon static void 369*572ff6f6SMatthew Dillon ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) 370*572ff6f6SMatthew Dillon { 371*572ff6f6SMatthew Dillon struct ath_node *an = ATH_NODE(ni); 372*572ff6f6SMatthew Dillon const struct ieee80211_txparam *tp = ni->ni_txparms; 373*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 374*572ff6f6SMatthew Dillon 375*572ff6f6SMatthew Dillon if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 376*572ff6f6SMatthew Dillon /* 377*572ff6f6SMatthew Dillon * A fixed rate is to be used; ucastrate is the IEEE code 378*572ff6f6SMatthew Dillon * for this rate (sans basic bit). Check this against the 379*572ff6f6SMatthew Dillon * negotiated rate set for the node. Note the fixed rate 380*572ff6f6SMatthew Dillon * may not be available for various reasons so we only 381*572ff6f6SMatthew Dillon * setup the static rate index if the lookup is successful. 382*572ff6f6SMatthew Dillon */ 383*572ff6f6SMatthew Dillon sn->static_rix = ath_rate_get_static_rix(sc, ni); 384*572ff6f6SMatthew Dillon } else { 385*572ff6f6SMatthew Dillon sn->static_rix = -1; 386*572ff6f6SMatthew Dillon } 387*572ff6f6SMatthew Dillon } 388*572ff6f6SMatthew Dillon 389*572ff6f6SMatthew Dillon /* 390*572ff6f6SMatthew Dillon * Pick a non-HT rate to begin using. 391*572ff6f6SMatthew Dillon */ 392*572ff6f6SMatthew Dillon static int 393*572ff6f6SMatthew Dillon ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an, 394*572ff6f6SMatthew Dillon int frameLen) 395*572ff6f6SMatthew Dillon { 396*572ff6f6SMatthew Dillon #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 397*572ff6f6SMatthew Dillon #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 398*572ff6f6SMatthew Dillon #define RATE(ix) (DOT11RATE(ix) / 2) 399*572ff6f6SMatthew Dillon int rix = -1; 400*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 401*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 402*572ff6f6SMatthew Dillon const int size_bin = size_to_bin(frameLen); 403*572ff6f6SMatthew Dillon 404*572ff6f6SMatthew Dillon /* no packet has been sent successfully yet */ 405*572ff6f6SMatthew Dillon for (rix = rt->rateCount-1; rix > 0; rix--) { 406*572ff6f6SMatthew Dillon if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 407*572ff6f6SMatthew Dillon continue; 408*572ff6f6SMatthew Dillon 409*572ff6f6SMatthew Dillon /* Skip HT rates */ 410*572ff6f6SMatthew Dillon if (rt->info[rix].phy == IEEE80211_T_HT) 411*572ff6f6SMatthew Dillon continue; 412*572ff6f6SMatthew Dillon 413*572ff6f6SMatthew Dillon /* 414*572ff6f6SMatthew Dillon * Pick the highest rate <= 36 Mbps 415*572ff6f6SMatthew Dillon * that hasn't failed. 416*572ff6f6SMatthew Dillon */ 417*572ff6f6SMatthew Dillon if (DOT11RATE(rix) <= 72 && 418*572ff6f6SMatthew Dillon sn->stats[size_bin][rix].successive_failures == 0) { 419*572ff6f6SMatthew Dillon break; 420*572ff6f6SMatthew Dillon } 421*572ff6f6SMatthew Dillon } 422*572ff6f6SMatthew Dillon return rix; 423*572ff6f6SMatthew Dillon #undef RATE 424*572ff6f6SMatthew Dillon #undef MCS 425*572ff6f6SMatthew Dillon #undef DOT11RATE 426*572ff6f6SMatthew Dillon } 427*572ff6f6SMatthew Dillon 428*572ff6f6SMatthew Dillon /* 429*572ff6f6SMatthew Dillon * Pick a HT rate to begin using. 430*572ff6f6SMatthew Dillon * 431*572ff6f6SMatthew Dillon * Don't use any non-HT rates; only consider HT rates. 432*572ff6f6SMatthew Dillon */ 433*572ff6f6SMatthew Dillon static int 434*572ff6f6SMatthew Dillon ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an, 435*572ff6f6SMatthew Dillon int frameLen) 436*572ff6f6SMatthew Dillon { 437*572ff6f6SMatthew Dillon #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 438*572ff6f6SMatthew Dillon #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 439*572ff6f6SMatthew Dillon #define RATE(ix) (DOT11RATE(ix) / 2) 440*572ff6f6SMatthew Dillon int rix = -1, ht_rix = -1; 441*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 442*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 443*572ff6f6SMatthew Dillon const int size_bin = size_to_bin(frameLen); 444*572ff6f6SMatthew Dillon 445*572ff6f6SMatthew Dillon /* no packet has been sent successfully yet */ 446*572ff6f6SMatthew Dillon for (rix = rt->rateCount-1; rix > 0; rix--) { 447*572ff6f6SMatthew Dillon /* Skip rates we can't use */ 448*572ff6f6SMatthew Dillon if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 449*572ff6f6SMatthew Dillon continue; 450*572ff6f6SMatthew Dillon 451*572ff6f6SMatthew Dillon /* Keep a copy of the last seen HT rate index */ 452*572ff6f6SMatthew Dillon if (rt->info[rix].phy == IEEE80211_T_HT) 453*572ff6f6SMatthew Dillon ht_rix = rix; 454*572ff6f6SMatthew Dillon 455*572ff6f6SMatthew Dillon /* Skip non-HT rates */ 456*572ff6f6SMatthew Dillon if (rt->info[rix].phy != IEEE80211_T_HT) 457*572ff6f6SMatthew Dillon continue; 458*572ff6f6SMatthew Dillon 459*572ff6f6SMatthew Dillon /* 460*572ff6f6SMatthew Dillon * Pick a medium-speed rate regardless of stream count 461*572ff6f6SMatthew Dillon * which has not seen any failures. Higher rates may fail; 462*572ff6f6SMatthew Dillon * we'll try them later. 463*572ff6f6SMatthew Dillon */ 464*572ff6f6SMatthew Dillon if (((MCS(rix) & 0x7) <= 4) && 465*572ff6f6SMatthew Dillon sn->stats[size_bin][rix].successive_failures == 0) { 466*572ff6f6SMatthew Dillon break; 467*572ff6f6SMatthew Dillon } 468*572ff6f6SMatthew Dillon } 469*572ff6f6SMatthew Dillon 470*572ff6f6SMatthew Dillon /* 471*572ff6f6SMatthew Dillon * If all the MCS rates have successive failures, rix should be 472*572ff6f6SMatthew Dillon * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.) 473*572ff6f6SMatthew Dillon */ 474*572ff6f6SMatthew Dillon return MAX(rix, ht_rix); 475*572ff6f6SMatthew Dillon #undef RATE 476*572ff6f6SMatthew Dillon #undef MCS 477*572ff6f6SMatthew Dillon #undef DOT11RATE 478*572ff6f6SMatthew Dillon } 479*572ff6f6SMatthew Dillon 480*572ff6f6SMatthew Dillon 481*572ff6f6SMatthew Dillon void 482*572ff6f6SMatthew Dillon ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 483*572ff6f6SMatthew Dillon int shortPreamble, size_t frameLen, 484*572ff6f6SMatthew Dillon u_int8_t *rix0, int *try0, u_int8_t *txrate) 485*572ff6f6SMatthew Dillon { 486*572ff6f6SMatthew Dillon #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 487*572ff6f6SMatthew Dillon #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 488*572ff6f6SMatthew Dillon #define RATE(ix) (DOT11RATE(ix) / 2) 489*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 490*572ff6f6SMatthew Dillon struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 491*572ff6f6SMatthew Dillon struct ifnet *ifp = sc->sc_ifp; 492*572ff6f6SMatthew Dillon struct ieee80211com *ic = ifp->if_l2com; 493*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 494*572ff6f6SMatthew Dillon const int size_bin = size_to_bin(frameLen); 495*572ff6f6SMatthew Dillon int rix, mrr, best_rix, change_rates; 496*572ff6f6SMatthew Dillon unsigned average_tx_time; 497*572ff6f6SMatthew Dillon 498*572ff6f6SMatthew Dillon ath_rate_update_static_rix(sc, &an->an_node); 499*572ff6f6SMatthew Dillon 500*572ff6f6SMatthew Dillon if (sn->currates != sc->sc_currates) { 501*572ff6f6SMatthew Dillon device_printf(sc->sc_dev, "%s: currates != sc_currates!\n", 502*572ff6f6SMatthew Dillon __func__); 503*572ff6f6SMatthew Dillon rix = 0; 504*572ff6f6SMatthew Dillon *try0 = ATH_TXMAXTRY; 505*572ff6f6SMatthew Dillon goto done; 506*572ff6f6SMatthew Dillon } 507*572ff6f6SMatthew Dillon 508*572ff6f6SMatthew Dillon if (sn->static_rix != -1) { 509*572ff6f6SMatthew Dillon rix = sn->static_rix; 510*572ff6f6SMatthew Dillon *try0 = ATH_TXMAXTRY; 511*572ff6f6SMatthew Dillon goto done; 512*572ff6f6SMatthew Dillon } 513*572ff6f6SMatthew Dillon 514*572ff6f6SMatthew Dillon mrr = sc->sc_mrretry; 515*572ff6f6SMatthew Dillon /* XXX check HT protmode too */ 516*572ff6f6SMatthew Dillon if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 517*572ff6f6SMatthew Dillon mrr = 0; 518*572ff6f6SMatthew Dillon 519*572ff6f6SMatthew Dillon best_rix = pick_best_rate(an, rt, size_bin, !mrr); 520*572ff6f6SMatthew Dillon if (best_rix >= 0) { 521*572ff6f6SMatthew Dillon average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 522*572ff6f6SMatthew Dillon } else { 523*572ff6f6SMatthew Dillon average_tx_time = 0; 524*572ff6f6SMatthew Dillon } 525*572ff6f6SMatthew Dillon /* 526*572ff6f6SMatthew Dillon * Limit the time measuring the performance of other tx 527*572ff6f6SMatthew Dillon * rates to sample_rate% of the total transmission time. 528*572ff6f6SMatthew Dillon */ 529*572ff6f6SMatthew Dillon if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 530*572ff6f6SMatthew Dillon rix = pick_sample_rate(ssc, an, rt, size_bin); 531*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 532*572ff6f6SMatthew Dillon &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s", 533*572ff6f6SMatthew Dillon average_tx_time, 534*572ff6f6SMatthew Dillon sn->sample_tt[size_bin], 535*572ff6f6SMatthew Dillon bin_to_size(size_bin), 536*572ff6f6SMatthew Dillon dot11rate(rt, rix), 537*572ff6f6SMatthew Dillon dot11rate_label(rt, rix), 538*572ff6f6SMatthew Dillon dot11rate(rt, sn->current_rix[size_bin]), 539*572ff6f6SMatthew Dillon dot11rate_label(rt, sn->current_rix[size_bin])); 540*572ff6f6SMatthew Dillon if (rix != sn->current_rix[size_bin]) { 541*572ff6f6SMatthew Dillon sn->current_sample_rix[size_bin] = rix; 542*572ff6f6SMatthew Dillon } else { 543*572ff6f6SMatthew Dillon sn->current_sample_rix[size_bin] = -1; 544*572ff6f6SMatthew Dillon } 545*572ff6f6SMatthew Dillon sn->packets_since_sample[size_bin] = 0; 546*572ff6f6SMatthew Dillon } else { 547*572ff6f6SMatthew Dillon change_rates = 0; 548*572ff6f6SMatthew Dillon if (!sn->packets_sent[size_bin] || best_rix == -1) { 549*572ff6f6SMatthew Dillon /* no packet has been sent successfully yet */ 550*572ff6f6SMatthew Dillon change_rates = 1; 551*572ff6f6SMatthew Dillon if (an->an_node.ni_flags & IEEE80211_NODE_HT) 552*572ff6f6SMatthew Dillon best_rix = 553*572ff6f6SMatthew Dillon ath_rate_pick_seed_rate_ht(sc, an, frameLen); 554*572ff6f6SMatthew Dillon else 555*572ff6f6SMatthew Dillon best_rix = 556*572ff6f6SMatthew Dillon ath_rate_pick_seed_rate_legacy(sc, an, frameLen); 557*572ff6f6SMatthew Dillon } else if (sn->packets_sent[size_bin] < 20) { 558*572ff6f6SMatthew Dillon /* let the bit-rate switch quickly during the first few packets */ 559*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, 560*572ff6f6SMatthew Dillon IEEE80211_MSG_RATECTL, &an->an_node, 561*572ff6f6SMatthew Dillon "%s: switching quickly..", __func__); 562*572ff6f6SMatthew Dillon change_rates = 1; 563*572ff6f6SMatthew Dillon } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 564*572ff6f6SMatthew Dillon /* min_switch seconds have gone by */ 565*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, 566*572ff6f6SMatthew Dillon IEEE80211_MSG_RATECTL, &an->an_node, 567*572ff6f6SMatthew Dillon "%s: min_switch %d > ticks_since_switch %d..", 568*572ff6f6SMatthew Dillon __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]); 569*572ff6f6SMatthew Dillon change_rates = 1; 570*572ff6f6SMatthew Dillon } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) && 571*572ff6f6SMatthew Dillon (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) { 572*572ff6f6SMatthew Dillon /* the current bit-rate is twice as slow as the best one */ 573*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, 574*572ff6f6SMatthew Dillon IEEE80211_MSG_RATECTL, &an->an_node, 575*572ff6f6SMatthew Dillon "%s: 2x att (= %d) < cur_rix att %d", 576*572ff6f6SMatthew Dillon __func__, 577*572ff6f6SMatthew Dillon 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time); 578*572ff6f6SMatthew Dillon change_rates = 1; 579*572ff6f6SMatthew Dillon } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) { 580*572ff6f6SMatthew Dillon int cur_rix = sn->current_rix[size_bin]; 581*572ff6f6SMatthew Dillon int cur_att = sn->stats[size_bin][cur_rix].average_tx_time; 582*572ff6f6SMatthew Dillon /* 583*572ff6f6SMatthew Dillon * If the node is HT, upgrade it if the MCS rate is 584*572ff6f6SMatthew Dillon * higher and the average tx time is within 20% of 585*572ff6f6SMatthew Dillon * the current rate. It can fail a little. 586*572ff6f6SMatthew Dillon * 587*572ff6f6SMatthew Dillon * This is likely not optimal! 588*572ff6f6SMatthew Dillon */ 589*572ff6f6SMatthew Dillon #if 0 590*572ff6f6SMatthew Dillon printf("cur rix/att %x/%d, best rix/att %x/%d\n", 591*572ff6f6SMatthew Dillon MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time); 592*572ff6f6SMatthew Dillon #endif 593*572ff6f6SMatthew Dillon if ((MCS(best_rix) > MCS(cur_rix)) && 594*572ff6f6SMatthew Dillon (average_tx_time * 8) <= (cur_att * 10)) { 595*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, 596*572ff6f6SMatthew Dillon IEEE80211_MSG_RATECTL, &an->an_node, 597*572ff6f6SMatthew Dillon "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d", 598*572ff6f6SMatthew Dillon __func__, 599*572ff6f6SMatthew Dillon MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att); 600*572ff6f6SMatthew Dillon change_rates = 1; 601*572ff6f6SMatthew Dillon } 602*572ff6f6SMatthew Dillon } 603*572ff6f6SMatthew Dillon 604*572ff6f6SMatthew Dillon sn->packets_since_sample[size_bin]++; 605*572ff6f6SMatthew Dillon 606*572ff6f6SMatthew Dillon if (change_rates) { 607*572ff6f6SMatthew Dillon if (best_rix != sn->current_rix[size_bin]) { 608*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, 609*572ff6f6SMatthew Dillon IEEE80211_MSG_RATECTL, 610*572ff6f6SMatthew Dillon &an->an_node, 611*572ff6f6SMatthew Dillon "%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d", 612*572ff6f6SMatthew Dillon __func__, 613*572ff6f6SMatthew Dillon bin_to_size(size_bin), 614*572ff6f6SMatthew Dillon RATE(sn->current_rix[size_bin]), 615*572ff6f6SMatthew Dillon sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 616*572ff6f6SMatthew Dillon sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 617*572ff6f6SMatthew Dillon RATE(best_rix), 618*572ff6f6SMatthew Dillon sn->stats[size_bin][best_rix].average_tx_time, 619*572ff6f6SMatthew Dillon sn->stats[size_bin][best_rix].perfect_tx_time, 620*572ff6f6SMatthew Dillon sn->packets_since_switch[size_bin], 621*572ff6f6SMatthew Dillon mrr); 622*572ff6f6SMatthew Dillon } 623*572ff6f6SMatthew Dillon sn->packets_since_switch[size_bin] = 0; 624*572ff6f6SMatthew Dillon sn->current_rix[size_bin] = best_rix; 625*572ff6f6SMatthew Dillon sn->ticks_since_switch[size_bin] = ticks; 626*572ff6f6SMatthew Dillon /* 627*572ff6f6SMatthew Dillon * Set the visible txrate for this node. 628*572ff6f6SMatthew Dillon */ 629*572ff6f6SMatthew Dillon an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ? MCS(best_rix) : DOT11RATE(best_rix); 630*572ff6f6SMatthew Dillon } 631*572ff6f6SMatthew Dillon rix = sn->current_rix[size_bin]; 632*572ff6f6SMatthew Dillon sn->packets_since_switch[size_bin]++; 633*572ff6f6SMatthew Dillon } 634*572ff6f6SMatthew Dillon *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 635*572ff6f6SMatthew Dillon done: 636*572ff6f6SMatthew Dillon 637*572ff6f6SMatthew Dillon /* 638*572ff6f6SMatthew Dillon * This bug totally sucks and should be fixed. 639*572ff6f6SMatthew Dillon * 640*572ff6f6SMatthew Dillon * For now though, let's not panic, so we can start to figure 641*572ff6f6SMatthew Dillon * out how to better reproduce it. 642*572ff6f6SMatthew Dillon */ 643*572ff6f6SMatthew Dillon if (rix < 0 || rix >= rt->rateCount) { 644*572ff6f6SMatthew Dillon printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n", 645*572ff6f6SMatthew Dillon __func__, 646*572ff6f6SMatthew Dillon rix, 647*572ff6f6SMatthew Dillon rt->rateCount); 648*572ff6f6SMatthew Dillon rix = 0; /* XXX just default for now */ 649*572ff6f6SMatthew Dillon } 650*572ff6f6SMatthew Dillon KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 651*572ff6f6SMatthew Dillon 652*572ff6f6SMatthew Dillon *rix0 = rix; 653*572ff6f6SMatthew Dillon *txrate = rt->info[rix].rateCode 654*572ff6f6SMatthew Dillon | (shortPreamble ? rt->info[rix].shortPreamble : 0); 655*572ff6f6SMatthew Dillon sn->packets_sent[size_bin]++; 656*572ff6f6SMatthew Dillon #undef DOT11RATE 657*572ff6f6SMatthew Dillon #undef MCS 658*572ff6f6SMatthew Dillon #undef RATE 659*572ff6f6SMatthew Dillon } 660*572ff6f6SMatthew Dillon 661*572ff6f6SMatthew Dillon /* 662*572ff6f6SMatthew Dillon * Get the TX rates. Don't fiddle with short preamble flags for them; 663*572ff6f6SMatthew Dillon * the caller can do that. 664*572ff6f6SMatthew Dillon */ 665*572ff6f6SMatthew Dillon void 666*572ff6f6SMatthew Dillon ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an, 667*572ff6f6SMatthew Dillon uint8_t rix0, struct ath_rc_series *rc) 668*572ff6f6SMatthew Dillon { 669*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 670*572ff6f6SMatthew Dillon const struct txschedule *sched = &sn->sched[rix0]; 671*572ff6f6SMatthew Dillon 672*572ff6f6SMatthew Dillon KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 673*572ff6f6SMatthew Dillon rix0, sched->r0)); 674*572ff6f6SMatthew Dillon 675*572ff6f6SMatthew Dillon rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; 676*572ff6f6SMatthew Dillon 677*572ff6f6SMatthew Dillon rc[0].rix = sched->r0; 678*572ff6f6SMatthew Dillon rc[1].rix = sched->r1; 679*572ff6f6SMatthew Dillon rc[2].rix = sched->r2; 680*572ff6f6SMatthew Dillon rc[3].rix = sched->r3; 681*572ff6f6SMatthew Dillon 682*572ff6f6SMatthew Dillon rc[0].tries = sched->t0; 683*572ff6f6SMatthew Dillon rc[1].tries = sched->t1; 684*572ff6f6SMatthew Dillon rc[2].tries = sched->t2; 685*572ff6f6SMatthew Dillon rc[3].tries = sched->t3; 686*572ff6f6SMatthew Dillon } 687*572ff6f6SMatthew Dillon 688*572ff6f6SMatthew Dillon void 689*572ff6f6SMatthew Dillon ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 690*572ff6f6SMatthew Dillon struct ath_desc *ds, int shortPreamble, u_int8_t rix) 691*572ff6f6SMatthew Dillon { 692*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 693*572ff6f6SMatthew Dillon const struct txschedule *sched = &sn->sched[rix]; 694*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 695*572ff6f6SMatthew Dillon uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 696*572ff6f6SMatthew Dillon 697*572ff6f6SMatthew Dillon /* XXX precalculate short preamble tables */ 698*572ff6f6SMatthew Dillon rix1 = sched->r1; 699*572ff6f6SMatthew Dillon s1code = rt->info[rix1].rateCode 700*572ff6f6SMatthew Dillon | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 701*572ff6f6SMatthew Dillon rix2 = sched->r2; 702*572ff6f6SMatthew Dillon s2code = rt->info[rix2].rateCode 703*572ff6f6SMatthew Dillon | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 704*572ff6f6SMatthew Dillon rix3 = sched->r3; 705*572ff6f6SMatthew Dillon s3code = rt->info[rix3].rateCode 706*572ff6f6SMatthew Dillon | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 707*572ff6f6SMatthew Dillon ath_hal_setupxtxdesc(sc->sc_ah, ds, 708*572ff6f6SMatthew Dillon s1code, sched->t1, /* series 1 */ 709*572ff6f6SMatthew Dillon s2code, sched->t2, /* series 2 */ 710*572ff6f6SMatthew Dillon s3code, sched->t3); /* series 3 */ 711*572ff6f6SMatthew Dillon } 712*572ff6f6SMatthew Dillon 713*572ff6f6SMatthew Dillon static void 714*572ff6f6SMatthew Dillon update_stats(struct ath_softc *sc, struct ath_node *an, 715*572ff6f6SMatthew Dillon int frame_size, 716*572ff6f6SMatthew Dillon int rix0, int tries0, 717*572ff6f6SMatthew Dillon int rix1, int tries1, 718*572ff6f6SMatthew Dillon int rix2, int tries2, 719*572ff6f6SMatthew Dillon int rix3, int tries3, 720*572ff6f6SMatthew Dillon int short_tries, int tries, int status, 721*572ff6f6SMatthew Dillon int nframes, int nbad) 722*572ff6f6SMatthew Dillon { 723*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 724*572ff6f6SMatthew Dillon struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 725*572ff6f6SMatthew Dillon #ifdef IEEE80211_DEBUG 726*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 727*572ff6f6SMatthew Dillon #endif 728*572ff6f6SMatthew Dillon const int size_bin = size_to_bin(frame_size); 729*572ff6f6SMatthew Dillon const int size = bin_to_size(size_bin); 730*572ff6f6SMatthew Dillon int tt, tries_so_far; 731*572ff6f6SMatthew Dillon int is_ht40 = (an->an_node.ni_chw == 40); 732*572ff6f6SMatthew Dillon int pct; 733*572ff6f6SMatthew Dillon 734*572ff6f6SMatthew Dillon if (!IS_RATE_DEFINED(sn, rix0)) 735*572ff6f6SMatthew Dillon return; 736*572ff6f6SMatthew Dillon tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, 737*572ff6f6SMatthew Dillon MIN(tries0, tries) - 1, is_ht40); 738*572ff6f6SMatthew Dillon tries_so_far = tries0; 739*572ff6f6SMatthew Dillon 740*572ff6f6SMatthew Dillon if (tries1 && tries_so_far < tries) { 741*572ff6f6SMatthew Dillon if (!IS_RATE_DEFINED(sn, rix1)) 742*572ff6f6SMatthew Dillon return; 743*572ff6f6SMatthew Dillon tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries, 744*572ff6f6SMatthew Dillon MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 745*572ff6f6SMatthew Dillon tries_so_far += tries1; 746*572ff6f6SMatthew Dillon } 747*572ff6f6SMatthew Dillon 748*572ff6f6SMatthew Dillon if (tries2 && tries_so_far < tries) { 749*572ff6f6SMatthew Dillon if (!IS_RATE_DEFINED(sn, rix2)) 750*572ff6f6SMatthew Dillon return; 751*572ff6f6SMatthew Dillon tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries, 752*572ff6f6SMatthew Dillon MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 753*572ff6f6SMatthew Dillon tries_so_far += tries2; 754*572ff6f6SMatthew Dillon } 755*572ff6f6SMatthew Dillon 756*572ff6f6SMatthew Dillon if (tries3 && tries_so_far < tries) { 757*572ff6f6SMatthew Dillon if (!IS_RATE_DEFINED(sn, rix3)) 758*572ff6f6SMatthew Dillon return; 759*572ff6f6SMatthew Dillon tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries, 760*572ff6f6SMatthew Dillon MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40); 761*572ff6f6SMatthew Dillon } 762*572ff6f6SMatthew Dillon 763*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 764*572ff6f6SMatthew Dillon /* just average the first few packets */ 765*572ff6f6SMatthew Dillon int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 766*572ff6f6SMatthew Dillon int packets = sn->stats[size_bin][rix0].total_packets; 767*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); 768*572ff6f6SMatthew Dillon } else { 769*572ff6f6SMatthew Dillon /* use a ewma */ 770*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].average_tx_time = 771*572ff6f6SMatthew Dillon ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 772*572ff6f6SMatthew Dillon (tt * (100 - ssc->smoothing_rate))) / 100; 773*572ff6f6SMatthew Dillon } 774*572ff6f6SMatthew Dillon 775*572ff6f6SMatthew Dillon /* 776*572ff6f6SMatthew Dillon * XXX Don't mark the higher bit rates as also having failed; as this 777*572ff6f6SMatthew Dillon * unfortunately stops those rates from being tasted when trying to 778*572ff6f6SMatthew Dillon * TX. This happens with 11n aggregation. 779*572ff6f6SMatthew Dillon */ 780*572ff6f6SMatthew Dillon if (nframes == nbad) { 781*572ff6f6SMatthew Dillon #if 0 782*572ff6f6SMatthew Dillon int y; 783*572ff6f6SMatthew Dillon #endif 784*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].successive_failures += nbad; 785*572ff6f6SMatthew Dillon #if 0 786*572ff6f6SMatthew Dillon for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { 787*572ff6f6SMatthew Dillon /* 788*572ff6f6SMatthew Dillon * Also say larger packets failed since we 789*572ff6f6SMatthew Dillon * assume if a small packet fails at a 790*572ff6f6SMatthew Dillon * bit-rate then a larger one will also. 791*572ff6f6SMatthew Dillon */ 792*572ff6f6SMatthew Dillon sn->stats[y][rix0].successive_failures += nbad; 793*572ff6f6SMatthew Dillon sn->stats[y][rix0].last_tx = ticks; 794*572ff6f6SMatthew Dillon sn->stats[y][rix0].tries += tries; 795*572ff6f6SMatthew Dillon sn->stats[y][rix0].total_packets += nframes; 796*572ff6f6SMatthew Dillon } 797*572ff6f6SMatthew Dillon #endif 798*572ff6f6SMatthew Dillon } else { 799*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); 800*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].successive_failures = 0; 801*572ff6f6SMatthew Dillon } 802*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].tries += tries; 803*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].last_tx = ticks; 804*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].total_packets += nframes; 805*572ff6f6SMatthew Dillon 806*572ff6f6SMatthew Dillon /* update EWMA for this rix */ 807*572ff6f6SMatthew Dillon 808*572ff6f6SMatthew Dillon /* Calculate percentage based on current rate */ 809*572ff6f6SMatthew Dillon if (nframes == 0) 810*572ff6f6SMatthew Dillon nframes = nbad = 1; 811*572ff6f6SMatthew Dillon pct = ((nframes - nbad) * 1000) / nframes; 812*572ff6f6SMatthew Dillon 813*572ff6f6SMatthew Dillon if (sn->stats[size_bin][rix0].total_packets < 814*572ff6f6SMatthew Dillon ssc->smoothing_minpackets) { 815*572ff6f6SMatthew Dillon /* just average the first few packets */ 816*572ff6f6SMatthew Dillon int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) / 817*572ff6f6SMatthew Dillon (sn->stats[size_bin][rix0].total_packets); 818*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].ewma_pct = a_pct; 819*572ff6f6SMatthew Dillon } else { 820*572ff6f6SMatthew Dillon /* use a ewma */ 821*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].ewma_pct = 822*572ff6f6SMatthew Dillon ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) + 823*572ff6f6SMatthew Dillon (pct * (100 - ssc->smoothing_rate))) / 100; 824*572ff6f6SMatthew Dillon } 825*572ff6f6SMatthew Dillon 826*572ff6f6SMatthew Dillon 827*572ff6f6SMatthew Dillon if (rix0 == sn->current_sample_rix[size_bin]) { 828*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 829*572ff6f6SMatthew Dillon &an->an_node, 830*572ff6f6SMatthew Dillon "%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d", 831*572ff6f6SMatthew Dillon __func__, 832*572ff6f6SMatthew Dillon size, 833*572ff6f6SMatthew Dillon status ? "FAIL" : "OK", 834*572ff6f6SMatthew Dillon dot11rate(rt, rix0), 835*572ff6f6SMatthew Dillon dot11rate_label(rt, rix0), 836*572ff6f6SMatthew Dillon short_tries, tries, tt, 837*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].average_tx_time, 838*572ff6f6SMatthew Dillon sn->stats[size_bin][rix0].perfect_tx_time, 839*572ff6f6SMatthew Dillon nframes, nbad); 840*572ff6f6SMatthew Dillon sn->sample_tt[size_bin] = tt; 841*572ff6f6SMatthew Dillon sn->current_sample_rix[size_bin] = -1; 842*572ff6f6SMatthew Dillon } 843*572ff6f6SMatthew Dillon } 844*572ff6f6SMatthew Dillon 845*572ff6f6SMatthew Dillon static void 846*572ff6f6SMatthew Dillon badrate(struct ifnet *ifp, int series, int hwrate, int tries, int status) 847*572ff6f6SMatthew Dillon { 848*572ff6f6SMatthew Dillon if_printf(ifp, "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 849*572ff6f6SMatthew Dillon series, hwrate, tries, status); 850*572ff6f6SMatthew Dillon } 851*572ff6f6SMatthew Dillon 852*572ff6f6SMatthew Dillon void 853*572ff6f6SMatthew Dillon ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 854*572ff6f6SMatthew Dillon const struct ath_rc_series *rc, const struct ath_tx_status *ts, 855*572ff6f6SMatthew Dillon int frame_size, int nframes, int nbad) 856*572ff6f6SMatthew Dillon { 857*572ff6f6SMatthew Dillon struct ifnet *ifp = sc->sc_ifp; 858*572ff6f6SMatthew Dillon struct ieee80211com *ic = ifp->if_l2com; 859*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 860*572ff6f6SMatthew Dillon int final_rix, short_tries, long_tries; 861*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 862*572ff6f6SMatthew Dillon int status = ts->ts_status; 863*572ff6f6SMatthew Dillon int mrr; 864*572ff6f6SMatthew Dillon 865*572ff6f6SMatthew Dillon final_rix = rt->rateCodeToIndex[ts->ts_rate]; 866*572ff6f6SMatthew Dillon short_tries = ts->ts_shortretry; 867*572ff6f6SMatthew Dillon long_tries = ts->ts_longretry + 1; 868*572ff6f6SMatthew Dillon 869*572ff6f6SMatthew Dillon if (nframes == 0) { 870*572ff6f6SMatthew Dillon device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__); 871*572ff6f6SMatthew Dillon return; 872*572ff6f6SMatthew Dillon } 873*572ff6f6SMatthew Dillon 874*572ff6f6SMatthew Dillon if (frame_size == 0) /* NB: should not happen */ 875*572ff6f6SMatthew Dillon frame_size = 1500; 876*572ff6f6SMatthew Dillon 877*572ff6f6SMatthew Dillon if (sn->ratemask == 0) { 878*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 879*572ff6f6SMatthew Dillon &an->an_node, 880*572ff6f6SMatthew Dillon "%s: size %d %s rate/try %d/%d no rates yet", 881*572ff6f6SMatthew Dillon __func__, 882*572ff6f6SMatthew Dillon bin_to_size(size_to_bin(frame_size)), 883*572ff6f6SMatthew Dillon status ? "FAIL" : "OK", 884*572ff6f6SMatthew Dillon short_tries, long_tries); 885*572ff6f6SMatthew Dillon return; 886*572ff6f6SMatthew Dillon } 887*572ff6f6SMatthew Dillon mrr = sc->sc_mrretry; 888*572ff6f6SMatthew Dillon /* XXX check HT protmode too */ 889*572ff6f6SMatthew Dillon if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 890*572ff6f6SMatthew Dillon mrr = 0; 891*572ff6f6SMatthew Dillon 892*572ff6f6SMatthew Dillon if (!mrr || ts->ts_finaltsi == 0) { 893*572ff6f6SMatthew Dillon if (!IS_RATE_DEFINED(sn, final_rix)) { 894*572ff6f6SMatthew Dillon device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n", 895*572ff6f6SMatthew Dillon __func__, ts->ts_rate, ts->ts_finaltsi); 896*572ff6f6SMatthew Dillon badrate(ifp, 0, ts->ts_rate, long_tries, status); 897*572ff6f6SMatthew Dillon return; 898*572ff6f6SMatthew Dillon } 899*572ff6f6SMatthew Dillon /* 900*572ff6f6SMatthew Dillon * Only one rate was used; optimize work. 901*572ff6f6SMatthew Dillon */ 902*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 903*572ff6f6SMatthew Dillon &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]", 904*572ff6f6SMatthew Dillon __func__, 905*572ff6f6SMatthew Dillon bin_to_size(size_to_bin(frame_size)), 906*572ff6f6SMatthew Dillon frame_size, 907*572ff6f6SMatthew Dillon status ? "FAIL" : "OK", 908*572ff6f6SMatthew Dillon dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), 909*572ff6f6SMatthew Dillon short_tries, long_tries, nframes, nbad); 910*572ff6f6SMatthew Dillon update_stats(sc, an, frame_size, 911*572ff6f6SMatthew Dillon final_rix, long_tries, 912*572ff6f6SMatthew Dillon 0, 0, 913*572ff6f6SMatthew Dillon 0, 0, 914*572ff6f6SMatthew Dillon 0, 0, 915*572ff6f6SMatthew Dillon short_tries, long_tries, status, 916*572ff6f6SMatthew Dillon nframes, nbad); 917*572ff6f6SMatthew Dillon 918*572ff6f6SMatthew Dillon } else { 919*572ff6f6SMatthew Dillon int finalTSIdx = ts->ts_finaltsi; 920*572ff6f6SMatthew Dillon int i; 921*572ff6f6SMatthew Dillon 922*572ff6f6SMatthew Dillon /* 923*572ff6f6SMatthew Dillon * Process intermediate rates that failed. 924*572ff6f6SMatthew Dillon */ 925*572ff6f6SMatthew Dillon 926*572ff6f6SMatthew Dillon IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 927*572ff6f6SMatthew Dillon &an->an_node, 928*572ff6f6SMatthew Dillon "%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]", 929*572ff6f6SMatthew Dillon __func__, 930*572ff6f6SMatthew Dillon bin_to_size(size_to_bin(frame_size)), 931*572ff6f6SMatthew Dillon frame_size, 932*572ff6f6SMatthew Dillon finalTSIdx, 933*572ff6f6SMatthew Dillon short_tries, 934*572ff6f6SMatthew Dillon long_tries, 935*572ff6f6SMatthew Dillon status ? "FAIL" : "OK", 936*572ff6f6SMatthew Dillon dot11rate(rt, rc[0].rix), 937*572ff6f6SMatthew Dillon dot11rate_label(rt, rc[0].rix), rc[0].tries, 938*572ff6f6SMatthew Dillon dot11rate(rt, rc[1].rix), 939*572ff6f6SMatthew Dillon dot11rate_label(rt, rc[1].rix), rc[1].tries, 940*572ff6f6SMatthew Dillon dot11rate(rt, rc[2].rix), 941*572ff6f6SMatthew Dillon dot11rate_label(rt, rc[2].rix), rc[2].tries, 942*572ff6f6SMatthew Dillon dot11rate(rt, rc[3].rix), 943*572ff6f6SMatthew Dillon dot11rate_label(rt, rc[3].rix), rc[3].tries, 944*572ff6f6SMatthew Dillon nframes, nbad); 945*572ff6f6SMatthew Dillon 946*572ff6f6SMatthew Dillon for (i = 0; i < 4; i++) { 947*572ff6f6SMatthew Dillon if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) 948*572ff6f6SMatthew Dillon badrate(ifp, 0, rc[i].ratecode, rc[i].tries, 949*572ff6f6SMatthew Dillon status); 950*572ff6f6SMatthew Dillon } 951*572ff6f6SMatthew Dillon 952*572ff6f6SMatthew Dillon /* 953*572ff6f6SMatthew Dillon * NB: series > 0 are not penalized for failure 954*572ff6f6SMatthew Dillon * based on the try counts under the assumption 955*572ff6f6SMatthew Dillon * that losses are often bursty and since we 956*572ff6f6SMatthew Dillon * sample higher rates 1 try at a time doing so 957*572ff6f6SMatthew Dillon * may unfairly penalize them. 958*572ff6f6SMatthew Dillon */ 959*572ff6f6SMatthew Dillon if (rc[0].tries) { 960*572ff6f6SMatthew Dillon update_stats(sc, an, frame_size, 961*572ff6f6SMatthew Dillon rc[0].rix, rc[0].tries, 962*572ff6f6SMatthew Dillon rc[1].rix, rc[1].tries, 963*572ff6f6SMatthew Dillon rc[2].rix, rc[2].tries, 964*572ff6f6SMatthew Dillon rc[3].rix, rc[3].tries, 965*572ff6f6SMatthew Dillon short_tries, long_tries, 966*572ff6f6SMatthew Dillon long_tries > rc[0].tries, 967*572ff6f6SMatthew Dillon nframes, nbad); 968*572ff6f6SMatthew Dillon long_tries -= rc[0].tries; 969*572ff6f6SMatthew Dillon } 970*572ff6f6SMatthew Dillon 971*572ff6f6SMatthew Dillon if (rc[1].tries && finalTSIdx > 0) { 972*572ff6f6SMatthew Dillon update_stats(sc, an, frame_size, 973*572ff6f6SMatthew Dillon rc[1].rix, rc[1].tries, 974*572ff6f6SMatthew Dillon rc[2].rix, rc[2].tries, 975*572ff6f6SMatthew Dillon rc[3].rix, rc[3].tries, 976*572ff6f6SMatthew Dillon 0, 0, 977*572ff6f6SMatthew Dillon short_tries, long_tries, 978*572ff6f6SMatthew Dillon status, 979*572ff6f6SMatthew Dillon nframes, nbad); 980*572ff6f6SMatthew Dillon long_tries -= rc[1].tries; 981*572ff6f6SMatthew Dillon } 982*572ff6f6SMatthew Dillon 983*572ff6f6SMatthew Dillon if (rc[2].tries && finalTSIdx > 1) { 984*572ff6f6SMatthew Dillon update_stats(sc, an, frame_size, 985*572ff6f6SMatthew Dillon rc[2].rix, rc[2].tries, 986*572ff6f6SMatthew Dillon rc[3].rix, rc[3].tries, 987*572ff6f6SMatthew Dillon 0, 0, 988*572ff6f6SMatthew Dillon 0, 0, 989*572ff6f6SMatthew Dillon short_tries, long_tries, 990*572ff6f6SMatthew Dillon status, 991*572ff6f6SMatthew Dillon nframes, nbad); 992*572ff6f6SMatthew Dillon long_tries -= rc[2].tries; 993*572ff6f6SMatthew Dillon } 994*572ff6f6SMatthew Dillon 995*572ff6f6SMatthew Dillon if (rc[3].tries && finalTSIdx > 2) { 996*572ff6f6SMatthew Dillon update_stats(sc, an, frame_size, 997*572ff6f6SMatthew Dillon rc[3].rix, rc[3].tries, 998*572ff6f6SMatthew Dillon 0, 0, 999*572ff6f6SMatthew Dillon 0, 0, 1000*572ff6f6SMatthew Dillon 0, 0, 1001*572ff6f6SMatthew Dillon short_tries, long_tries, 1002*572ff6f6SMatthew Dillon status, 1003*572ff6f6SMatthew Dillon nframes, nbad); 1004*572ff6f6SMatthew Dillon } 1005*572ff6f6SMatthew Dillon } 1006*572ff6f6SMatthew Dillon } 1007*572ff6f6SMatthew Dillon 1008*572ff6f6SMatthew Dillon void 1009*572ff6f6SMatthew Dillon ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 1010*572ff6f6SMatthew Dillon { 1011*572ff6f6SMatthew Dillon if (isnew) 1012*572ff6f6SMatthew Dillon ath_rate_ctl_reset(sc, &an->an_node); 1013*572ff6f6SMatthew Dillon } 1014*572ff6f6SMatthew Dillon 1015*572ff6f6SMatthew Dillon static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 1016*572ff6f6SMatthew Dillon NULL, /* IEEE80211_MODE_AUTO */ 1017*572ff6f6SMatthew Dillon series_11a, /* IEEE80211_MODE_11A */ 1018*572ff6f6SMatthew Dillon series_11g, /* IEEE80211_MODE_11B */ 1019*572ff6f6SMatthew Dillon series_11g, /* IEEE80211_MODE_11G */ 1020*572ff6f6SMatthew Dillon NULL, /* IEEE80211_MODE_FH */ 1021*572ff6f6SMatthew Dillon series_11a, /* IEEE80211_MODE_TURBO_A */ 1022*572ff6f6SMatthew Dillon series_11g, /* IEEE80211_MODE_TURBO_G */ 1023*572ff6f6SMatthew Dillon series_11a, /* IEEE80211_MODE_STURBO_A */ 1024*572ff6f6SMatthew Dillon series_11na, /* IEEE80211_MODE_11NA */ 1025*572ff6f6SMatthew Dillon series_11ng, /* IEEE80211_MODE_11NG */ 1026*572ff6f6SMatthew Dillon series_half, /* IEEE80211_MODE_HALF */ 1027*572ff6f6SMatthew Dillon series_quarter, /* IEEE80211_MODE_QUARTER */ 1028*572ff6f6SMatthew Dillon }; 1029*572ff6f6SMatthew Dillon 1030*572ff6f6SMatthew Dillon /* 1031*572ff6f6SMatthew Dillon * Initialize the tables for a node. 1032*572ff6f6SMatthew Dillon */ 1033*572ff6f6SMatthew Dillon static void 1034*572ff6f6SMatthew Dillon ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 1035*572ff6f6SMatthew Dillon { 1036*572ff6f6SMatthew Dillon #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 1037*572ff6f6SMatthew Dillon #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 1038*572ff6f6SMatthew Dillon #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 1039*572ff6f6SMatthew Dillon struct ath_node *an = ATH_NODE(ni); 1040*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 1041*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 1042*572ff6f6SMatthew Dillon int x, y, rix; 1043*572ff6f6SMatthew Dillon 1044*572ff6f6SMatthew Dillon KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 1045*572ff6f6SMatthew Dillon 1046*572ff6f6SMatthew Dillon KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 1047*572ff6f6SMatthew Dillon ("curmode %u", sc->sc_curmode)); 1048*572ff6f6SMatthew Dillon 1049*572ff6f6SMatthew Dillon sn->sched = mrr_schedules[sc->sc_curmode]; 1050*572ff6f6SMatthew Dillon KASSERT(sn->sched != NULL, 1051*572ff6f6SMatthew Dillon ("no mrr schedule for mode %u", sc->sc_curmode)); 1052*572ff6f6SMatthew Dillon 1053*572ff6f6SMatthew Dillon sn->static_rix = -1; 1054*572ff6f6SMatthew Dillon ath_rate_update_static_rix(sc, ni); 1055*572ff6f6SMatthew Dillon 1056*572ff6f6SMatthew Dillon sn->currates = sc->sc_currates; 1057*572ff6f6SMatthew Dillon 1058*572ff6f6SMatthew Dillon /* 1059*572ff6f6SMatthew Dillon * Construct a bitmask of usable rates. This has all 1060*572ff6f6SMatthew Dillon * negotiated rates minus those marked by the hal as 1061*572ff6f6SMatthew Dillon * to be ignored for doing rate control. 1062*572ff6f6SMatthew Dillon */ 1063*572ff6f6SMatthew Dillon sn->ratemask = 0; 1064*572ff6f6SMatthew Dillon /* MCS rates */ 1065*572ff6f6SMatthew Dillon if (ni->ni_flags & IEEE80211_NODE_HT) { 1066*572ff6f6SMatthew Dillon for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { 1067*572ff6f6SMatthew Dillon rix = sc->sc_rixmap[MCS(x)]; 1068*572ff6f6SMatthew Dillon if (rix == 0xff) 1069*572ff6f6SMatthew Dillon continue; 1070*572ff6f6SMatthew Dillon /* skip rates marked broken by hal */ 1071*572ff6f6SMatthew Dillon if (!rt->info[rix].valid) 1072*572ff6f6SMatthew Dillon continue; 1073*572ff6f6SMatthew Dillon KASSERT(rix < SAMPLE_MAXRATES, 1074*572ff6f6SMatthew Dillon ("mcs %u has rix %d", MCS(x), rix)); 1075*572ff6f6SMatthew Dillon sn->ratemask |= (uint64_t) 1<<rix; 1076*572ff6f6SMatthew Dillon } 1077*572ff6f6SMatthew Dillon } 1078*572ff6f6SMatthew Dillon 1079*572ff6f6SMatthew Dillon /* Legacy rates */ 1080*572ff6f6SMatthew Dillon for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 1081*572ff6f6SMatthew Dillon rix = sc->sc_rixmap[RATE(x)]; 1082*572ff6f6SMatthew Dillon if (rix == 0xff) 1083*572ff6f6SMatthew Dillon continue; 1084*572ff6f6SMatthew Dillon /* skip rates marked broken by hal */ 1085*572ff6f6SMatthew Dillon if (!rt->info[rix].valid) 1086*572ff6f6SMatthew Dillon continue; 1087*572ff6f6SMatthew Dillon KASSERT(rix < SAMPLE_MAXRATES, 1088*572ff6f6SMatthew Dillon ("rate %u has rix %d", RATE(x), rix)); 1089*572ff6f6SMatthew Dillon sn->ratemask |= (uint64_t) 1<<rix; 1090*572ff6f6SMatthew Dillon } 1091*572ff6f6SMatthew Dillon #ifdef IEEE80211_DEBUG 1092*572ff6f6SMatthew Dillon if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 1093*572ff6f6SMatthew Dillon uint64_t mask; 1094*572ff6f6SMatthew Dillon 1095*572ff6f6SMatthew Dillon ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 1096*572ff6f6SMatthew Dillon ni->ni_macaddr, ":", __func__); 1097*572ff6f6SMatthew Dillon for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1098*572ff6f6SMatthew Dillon if ((mask & 1) == 0) 1099*572ff6f6SMatthew Dillon continue; 1100*572ff6f6SMatthew Dillon printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), 1101*572ff6f6SMatthew Dillon calc_usecs_unicast_packet(sc, 1600, rix, 0,0, 1102*572ff6f6SMatthew Dillon (ni->ni_chw == 40))); 1103*572ff6f6SMatthew Dillon } 1104*572ff6f6SMatthew Dillon printf("\n"); 1105*572ff6f6SMatthew Dillon } 1106*572ff6f6SMatthew Dillon #endif 1107*572ff6f6SMatthew Dillon for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1108*572ff6f6SMatthew Dillon int size = bin_to_size(y); 1109*572ff6f6SMatthew Dillon uint64_t mask; 1110*572ff6f6SMatthew Dillon 1111*572ff6f6SMatthew Dillon sn->packets_sent[y] = 0; 1112*572ff6f6SMatthew Dillon sn->current_sample_rix[y] = -1; 1113*572ff6f6SMatthew Dillon sn->last_sample_rix[y] = 0; 1114*572ff6f6SMatthew Dillon /* XXX start with first valid rate */ 1115*572ff6f6SMatthew Dillon sn->current_rix[y] = ffs(sn->ratemask)-1; 1116*572ff6f6SMatthew Dillon 1117*572ff6f6SMatthew Dillon /* 1118*572ff6f6SMatthew Dillon * Initialize the statistics buckets; these are 1119*572ff6f6SMatthew Dillon * indexed by the rate code index. 1120*572ff6f6SMatthew Dillon */ 1121*572ff6f6SMatthew Dillon for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 1122*572ff6f6SMatthew Dillon if ((mask & 1) == 0) /* not a valid rate */ 1123*572ff6f6SMatthew Dillon continue; 1124*572ff6f6SMatthew Dillon sn->stats[y][rix].successive_failures = 0; 1125*572ff6f6SMatthew Dillon sn->stats[y][rix].tries = 0; 1126*572ff6f6SMatthew Dillon sn->stats[y][rix].total_packets = 0; 1127*572ff6f6SMatthew Dillon sn->stats[y][rix].packets_acked = 0; 1128*572ff6f6SMatthew Dillon sn->stats[y][rix].last_tx = 0; 1129*572ff6f6SMatthew Dillon sn->stats[y][rix].ewma_pct = 0; 1130*572ff6f6SMatthew Dillon 1131*572ff6f6SMatthew Dillon sn->stats[y][rix].perfect_tx_time = 1132*572ff6f6SMatthew Dillon calc_usecs_unicast_packet(sc, size, rix, 0, 0, 1133*572ff6f6SMatthew Dillon (ni->ni_chw == 40)); 1134*572ff6f6SMatthew Dillon sn->stats[y][rix].average_tx_time = 1135*572ff6f6SMatthew Dillon sn->stats[y][rix].perfect_tx_time; 1136*572ff6f6SMatthew Dillon } 1137*572ff6f6SMatthew Dillon } 1138*572ff6f6SMatthew Dillon #if 0 1139*572ff6f6SMatthew Dillon /* XXX 0, num_rates-1 are wrong */ 1140*572ff6f6SMatthew Dillon IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 1141*572ff6f6SMatthew Dillon "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 1142*572ff6f6SMatthew Dillon sn->num_rates, 1143*572ff6f6SMatthew Dillon DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 1144*572ff6f6SMatthew Dillon sn->stats[1][0].perfect_tx_time, 1145*572ff6f6SMatthew Dillon DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 1146*572ff6f6SMatthew Dillon sn->stats[1][sn->num_rates-1].perfect_tx_time 1147*572ff6f6SMatthew Dillon ); 1148*572ff6f6SMatthew Dillon #endif 1149*572ff6f6SMatthew Dillon /* set the visible bit-rate */ 1150*572ff6f6SMatthew Dillon if (sn->static_rix != -1) 1151*572ff6f6SMatthew Dillon ni->ni_txrate = DOT11RATE(sn->static_rix); 1152*572ff6f6SMatthew Dillon else 1153*572ff6f6SMatthew Dillon ni->ni_txrate = RATE(0); 1154*572ff6f6SMatthew Dillon #undef RATE 1155*572ff6f6SMatthew Dillon #undef DOT11RATE 1156*572ff6f6SMatthew Dillon } 1157*572ff6f6SMatthew Dillon 1158*572ff6f6SMatthew Dillon /* 1159*572ff6f6SMatthew Dillon * Fetch the statistics for the given node. 1160*572ff6f6SMatthew Dillon * 1161*572ff6f6SMatthew Dillon * The ieee80211 node must be referenced and unlocked, however the ath_node 1162*572ff6f6SMatthew Dillon * must be locked. 1163*572ff6f6SMatthew Dillon * 1164*572ff6f6SMatthew Dillon * The main difference here is that we convert the rate indexes 1165*572ff6f6SMatthew Dillon * to 802.11 rates, or the userland output won't make much sense 1166*572ff6f6SMatthew Dillon * as it has no access to the rix table. 1167*572ff6f6SMatthew Dillon */ 1168*572ff6f6SMatthew Dillon int 1169*572ff6f6SMatthew Dillon ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an, 1170*572ff6f6SMatthew Dillon struct ath_rateioctl *rs) 1171*572ff6f6SMatthew Dillon { 1172*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(an); 1173*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 1174*572ff6f6SMatthew Dillon struct ath_rateioctl_tlv av; 1175*572ff6f6SMatthew Dillon struct ath_rateioctl_rt *tv; 1176*572ff6f6SMatthew Dillon int y; 1177*572ff6f6SMatthew Dillon int o = 0; 1178*572ff6f6SMatthew Dillon 1179*572ff6f6SMatthew Dillon ATH_NODE_LOCK_ASSERT(an); 1180*572ff6f6SMatthew Dillon 1181*572ff6f6SMatthew Dillon /* 1182*572ff6f6SMatthew Dillon * Ensure there's enough space for the statistics. 1183*572ff6f6SMatthew Dillon */ 1184*572ff6f6SMatthew Dillon if (rs->len < 1185*572ff6f6SMatthew Dillon sizeof(struct ath_rateioctl_tlv) + 1186*572ff6f6SMatthew Dillon sizeof(struct ath_rateioctl_rt) + 1187*572ff6f6SMatthew Dillon sizeof(struct ath_rateioctl_tlv) + 1188*572ff6f6SMatthew Dillon sizeof(struct sample_node)) { 1189*572ff6f6SMatthew Dillon device_printf(sc->sc_dev, "%s: len=%d, too short\n", 1190*572ff6f6SMatthew Dillon __func__, 1191*572ff6f6SMatthew Dillon rs->len); 1192*572ff6f6SMatthew Dillon return (EINVAL); 1193*572ff6f6SMatthew Dillon } 1194*572ff6f6SMatthew Dillon 1195*572ff6f6SMatthew Dillon /* 1196*572ff6f6SMatthew Dillon * Take a temporary copy of the sample node state so we can 1197*572ff6f6SMatthew Dillon * modify it before we copy it. 1198*572ff6f6SMatthew Dillon */ 1199*572ff6f6SMatthew Dillon tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP, 1200*572ff6f6SMatthew Dillon M_NOWAIT | M_ZERO); 1201*572ff6f6SMatthew Dillon if (tv == NULL) { 1202*572ff6f6SMatthew Dillon return (ENOMEM); 1203*572ff6f6SMatthew Dillon } 1204*572ff6f6SMatthew Dillon 1205*572ff6f6SMatthew Dillon /* 1206*572ff6f6SMatthew Dillon * Populate the rate table mapping TLV. 1207*572ff6f6SMatthew Dillon */ 1208*572ff6f6SMatthew Dillon tv->nentries = rt->rateCount; 1209*572ff6f6SMatthew Dillon for (y = 0; y < rt->rateCount; y++) { 1210*572ff6f6SMatthew Dillon tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL; 1211*572ff6f6SMatthew Dillon if (rt->info[y].phy == IEEE80211_T_HT) 1212*572ff6f6SMatthew Dillon tv->ratecode[y] |= IEEE80211_RATE_MCS; 1213*572ff6f6SMatthew Dillon } 1214*572ff6f6SMatthew Dillon 1215*572ff6f6SMatthew Dillon o = 0; 1216*572ff6f6SMatthew Dillon /* 1217*572ff6f6SMatthew Dillon * First TLV - rate code mapping 1218*572ff6f6SMatthew Dillon */ 1219*572ff6f6SMatthew Dillon av.tlv_id = ATH_RATE_TLV_RATETABLE; 1220*572ff6f6SMatthew Dillon av.tlv_len = sizeof(struct ath_rateioctl_rt); 1221*572ff6f6SMatthew Dillon copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1222*572ff6f6SMatthew Dillon o += sizeof(struct ath_rateioctl_tlv); 1223*572ff6f6SMatthew Dillon copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); 1224*572ff6f6SMatthew Dillon o += sizeof(struct ath_rateioctl_rt); 1225*572ff6f6SMatthew Dillon 1226*572ff6f6SMatthew Dillon /* 1227*572ff6f6SMatthew Dillon * Second TLV - sample node statistics 1228*572ff6f6SMatthew Dillon */ 1229*572ff6f6SMatthew Dillon av.tlv_id = ATH_RATE_TLV_SAMPLENODE; 1230*572ff6f6SMatthew Dillon av.tlv_len = sizeof(struct sample_node); 1231*572ff6f6SMatthew Dillon copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1232*572ff6f6SMatthew Dillon o += sizeof(struct ath_rateioctl_tlv); 1233*572ff6f6SMatthew Dillon 1234*572ff6f6SMatthew Dillon /* 1235*572ff6f6SMatthew Dillon * Copy the statistics over to the provided buffer. 1236*572ff6f6SMatthew Dillon */ 1237*572ff6f6SMatthew Dillon copyout(sn, rs->buf + o, sizeof(struct sample_node)); 1238*572ff6f6SMatthew Dillon o += sizeof(struct sample_node); 1239*572ff6f6SMatthew Dillon 1240*572ff6f6SMatthew Dillon free(tv, M_TEMP); 1241*572ff6f6SMatthew Dillon 1242*572ff6f6SMatthew Dillon return (0); 1243*572ff6f6SMatthew Dillon } 1244*572ff6f6SMatthew Dillon 1245*572ff6f6SMatthew Dillon static void 1246*572ff6f6SMatthew Dillon sample_stats(void *arg, struct ieee80211_node *ni) 1247*572ff6f6SMatthew Dillon { 1248*572ff6f6SMatthew Dillon struct ath_softc *sc = arg; 1249*572ff6f6SMatthew Dillon const HAL_RATE_TABLE *rt = sc->sc_currates; 1250*572ff6f6SMatthew Dillon struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 1251*572ff6f6SMatthew Dillon uint64_t mask; 1252*572ff6f6SMatthew Dillon int rix, y; 1253*572ff6f6SMatthew Dillon 1254*572ff6f6SMatthew Dillon printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n", 1255*572ff6f6SMatthew Dillon ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 1256*572ff6f6SMatthew Dillon dot11rate(rt, sn->static_rix), 1257*572ff6f6SMatthew Dillon dot11rate_label(rt, sn->static_rix), 1258*572ff6f6SMatthew Dillon (uintmax_t)sn->ratemask); 1259*572ff6f6SMatthew Dillon for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1260*572ff6f6SMatthew Dillon printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n", 1261*572ff6f6SMatthew Dillon bin_to_size(y), sn->current_rix[y], 1262*572ff6f6SMatthew Dillon dot11rate(rt, sn->current_rix[y]), 1263*572ff6f6SMatthew Dillon dot11rate_label(rt, sn->current_rix[y]), 1264*572ff6f6SMatthew Dillon sn->packets_since_switch[y], sn->ticks_since_switch[y]); 1265*572ff6f6SMatthew Dillon printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n", 1266*572ff6f6SMatthew Dillon bin_to_size(y), 1267*572ff6f6SMatthew Dillon dot11rate(rt, sn->last_sample_rix[y]), 1268*572ff6f6SMatthew Dillon dot11rate_label(rt, sn->last_sample_rix[y]), 1269*572ff6f6SMatthew Dillon dot11rate(rt, sn->current_sample_rix[y]), 1270*572ff6f6SMatthew Dillon dot11rate_label(rt, sn->current_sample_rix[y]), 1271*572ff6f6SMatthew Dillon sn->packets_sent[y]); 1272*572ff6f6SMatthew Dillon printf("[%4u] packets since sample %d sample tt %u\n", 1273*572ff6f6SMatthew Dillon bin_to_size(y), sn->packets_since_sample[y], 1274*572ff6f6SMatthew Dillon sn->sample_tt[y]); 1275*572ff6f6SMatthew Dillon } 1276*572ff6f6SMatthew Dillon for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1277*572ff6f6SMatthew Dillon if ((mask & 1) == 0) 1278*572ff6f6SMatthew Dillon continue; 1279*572ff6f6SMatthew Dillon for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1280*572ff6f6SMatthew Dillon if (sn->stats[y][rix].total_packets == 0) 1281*572ff6f6SMatthew Dillon continue; 1282*572ff6f6SMatthew Dillon printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n", 1283*572ff6f6SMatthew Dillon dot11rate(rt, rix), dot11rate_label(rt, rix), 1284*572ff6f6SMatthew Dillon bin_to_size(y), 1285*572ff6f6SMatthew Dillon (uintmax_t) sn->stats[y][rix].total_packets, 1286*572ff6f6SMatthew Dillon (uintmax_t) sn->stats[y][rix].packets_acked, 1287*572ff6f6SMatthew Dillon (int) ((sn->stats[y][rix].packets_acked * 100ULL) / 1288*572ff6f6SMatthew Dillon sn->stats[y][rix].total_packets), 1289*572ff6f6SMatthew Dillon sn->stats[y][rix].ewma_pct / 10, 1290*572ff6f6SMatthew Dillon sn->stats[y][rix].ewma_pct % 10, 1291*572ff6f6SMatthew Dillon (uintmax_t) sn->stats[y][rix].tries, 1292*572ff6f6SMatthew Dillon sn->stats[y][rix].successive_failures, 1293*572ff6f6SMatthew Dillon sn->stats[y][rix].average_tx_time, 1294*572ff6f6SMatthew Dillon ticks - sn->stats[y][rix].last_tx); 1295*572ff6f6SMatthew Dillon } 1296*572ff6f6SMatthew Dillon } 1297*572ff6f6SMatthew Dillon } 1298*572ff6f6SMatthew Dillon 1299*572ff6f6SMatthew Dillon static int 1300*572ff6f6SMatthew Dillon ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 1301*572ff6f6SMatthew Dillon { 1302*572ff6f6SMatthew Dillon struct ath_softc *sc = arg1; 1303*572ff6f6SMatthew Dillon struct ifnet *ifp = sc->sc_ifp; 1304*572ff6f6SMatthew Dillon struct ieee80211com *ic = ifp->if_l2com; 1305*572ff6f6SMatthew Dillon int error, v; 1306*572ff6f6SMatthew Dillon 1307*572ff6f6SMatthew Dillon v = 0; 1308*572ff6f6SMatthew Dillon error = sysctl_handle_int(oidp, &v, 0, req); 1309*572ff6f6SMatthew Dillon if (error || !req->newptr) 1310*572ff6f6SMatthew Dillon return error; 1311*572ff6f6SMatthew Dillon ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 1312*572ff6f6SMatthew Dillon return 0; 1313*572ff6f6SMatthew Dillon } 1314*572ff6f6SMatthew Dillon 1315*572ff6f6SMatthew Dillon static int 1316*572ff6f6SMatthew Dillon ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 1317*572ff6f6SMatthew Dillon { 1318*572ff6f6SMatthew Dillon struct sample_softc *ssc = arg1; 1319*572ff6f6SMatthew Dillon int rate, error; 1320*572ff6f6SMatthew Dillon 1321*572ff6f6SMatthew Dillon rate = ssc->smoothing_rate; 1322*572ff6f6SMatthew Dillon error = sysctl_handle_int(oidp, &rate, 0, req); 1323*572ff6f6SMatthew Dillon if (error || !req->newptr) 1324*572ff6f6SMatthew Dillon return error; 1325*572ff6f6SMatthew Dillon if (!(0 <= rate && rate < 100)) 1326*572ff6f6SMatthew Dillon return EINVAL; 1327*572ff6f6SMatthew Dillon ssc->smoothing_rate = rate; 1328*572ff6f6SMatthew Dillon ssc->smoothing_minpackets = 100 / (100 - rate); 1329*572ff6f6SMatthew Dillon return 0; 1330*572ff6f6SMatthew Dillon } 1331*572ff6f6SMatthew Dillon 1332*572ff6f6SMatthew Dillon static int 1333*572ff6f6SMatthew Dillon ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 1334*572ff6f6SMatthew Dillon { 1335*572ff6f6SMatthew Dillon struct sample_softc *ssc = arg1; 1336*572ff6f6SMatthew Dillon int rate, error; 1337*572ff6f6SMatthew Dillon 1338*572ff6f6SMatthew Dillon rate = ssc->sample_rate; 1339*572ff6f6SMatthew Dillon error = sysctl_handle_int(oidp, &rate, 0, req); 1340*572ff6f6SMatthew Dillon if (error || !req->newptr) 1341*572ff6f6SMatthew Dillon return error; 1342*572ff6f6SMatthew Dillon if (!(2 <= rate && rate <= 100)) 1343*572ff6f6SMatthew Dillon return EINVAL; 1344*572ff6f6SMatthew Dillon ssc->sample_rate = rate; 1345*572ff6f6SMatthew Dillon return 0; 1346*572ff6f6SMatthew Dillon } 1347*572ff6f6SMatthew Dillon 1348*572ff6f6SMatthew Dillon static void 1349*572ff6f6SMatthew Dillon ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 1350*572ff6f6SMatthew Dillon { 1351*572ff6f6SMatthew Dillon struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 1352*572ff6f6SMatthew Dillon struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 1353*572ff6f6SMatthew Dillon 1354*572ff6f6SMatthew Dillon SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1355*572ff6f6SMatthew Dillon "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 1356*572ff6f6SMatthew Dillon ath_rate_sysctl_smoothing_rate, "I", 1357*572ff6f6SMatthew Dillon "sample: smoothing rate for avg tx time (%%)"); 1358*572ff6f6SMatthew Dillon SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1359*572ff6f6SMatthew Dillon "sample_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0, 1360*572ff6f6SMatthew Dillon ath_rate_sysctl_sample_rate, "I", 1361*572ff6f6SMatthew Dillon "sample: percent air time devoted to sampling new rates (%%)"); 1362*572ff6f6SMatthew Dillon /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 1363*572ff6f6SMatthew Dillon SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 1364*572ff6f6SMatthew Dillon "sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1365*572ff6f6SMatthew Dillon ath_rate_sysctl_stats, "I", "sample: print statistics"); 1366*572ff6f6SMatthew Dillon } 1367*572ff6f6SMatthew Dillon 1368*572ff6f6SMatthew Dillon struct ath_ratectrl * 1369*572ff6f6SMatthew Dillon ath_rate_attach(struct ath_softc *sc) 1370*572ff6f6SMatthew Dillon { 1371*572ff6f6SMatthew Dillon struct sample_softc *ssc; 1372*572ff6f6SMatthew Dillon 1373*572ff6f6SMatthew Dillon ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 1374*572ff6f6SMatthew Dillon if (ssc == NULL) 1375*572ff6f6SMatthew Dillon return NULL; 1376*572ff6f6SMatthew Dillon ssc->arc.arc_space = sizeof(struct sample_node); 1377*572ff6f6SMatthew Dillon ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */ 1378*572ff6f6SMatthew Dillon ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 1379*572ff6f6SMatthew Dillon ssc->sample_rate = 10; /* %time to try diff tx rates */ 1380*572ff6f6SMatthew Dillon ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 1381*572ff6f6SMatthew Dillon ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 1382*572ff6f6SMatthew Dillon ssc->min_switch = hz; /* 1 second */ 1383*572ff6f6SMatthew Dillon ath_rate_sysctlattach(sc, ssc); 1384*572ff6f6SMatthew Dillon return &ssc->arc; 1385*572ff6f6SMatthew Dillon } 1386*572ff6f6SMatthew Dillon 1387*572ff6f6SMatthew Dillon void 1388*572ff6f6SMatthew Dillon ath_rate_detach(struct ath_ratectrl *arc) 1389*572ff6f6SMatthew Dillon { 1390*572ff6f6SMatthew Dillon struct sample_softc *ssc = (struct sample_softc *) arc; 1391*572ff6f6SMatthew Dillon 1392*572ff6f6SMatthew Dillon free(ssc, M_DEVBUF); 1393*572ff6f6SMatthew Dillon } 1394