1fa20c234SSam Leffler /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3718cf2ccSPedro F. Giffuni * 4fa20c234SSam Leffler * Copyright (c) 2005 John Bicket 5fa20c234SSam Leffler * All rights reserved. 6fa20c234SSam Leffler * 7fa20c234SSam Leffler * Redistribution and use in source and binary forms, with or without 8fa20c234SSam Leffler * modification, are permitted provided that the following conditions 9fa20c234SSam Leffler * are met: 10fa20c234SSam Leffler * 1. Redistributions of source code must retain the above copyright 11fa20c234SSam Leffler * notice, this list of conditions and the following disclaimer, 12fa20c234SSam Leffler * without modification. 13fa20c234SSam Leffler * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14fa20c234SSam Leffler * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15fa20c234SSam Leffler * redistribution must be conditioned upon including a substantially 16fa20c234SSam Leffler * similar Disclaimer requirement for further binary redistribution. 17fa20c234SSam Leffler * 3. Neither the names of the above-listed copyright holders nor the names 18fa20c234SSam Leffler * of any contributors may be used to endorse or promote products derived 19fa20c234SSam Leffler * from this software without specific prior written permission. 20fa20c234SSam Leffler * 21fa20c234SSam Leffler * Alternatively, this software may be distributed under the terms of the 22fa20c234SSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 23fa20c234SSam Leffler * Software Foundation. 24fa20c234SSam Leffler * 25fa20c234SSam Leffler * NO WARRANTY 26fa20c234SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27fa20c234SSam Leffler * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28fa20c234SSam Leffler * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 29fa20c234SSam Leffler * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 30fa20c234SSam Leffler * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 31fa20c234SSam Leffler * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32fa20c234SSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33fa20c234SSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 34fa20c234SSam Leffler * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35fa20c234SSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 36fa20c234SSam Leffler * THE POSSIBILITY OF SUCH DAMAGES. 3768e8e04eSSam Leffler * 38fa20c234SSam Leffler */ 39fa20c234SSam Leffler 40fa20c234SSam Leffler #include <sys/cdefs.h> 41fa20c234SSam Leffler /* 42fa20c234SSam Leffler * John Bicket's SampleRate control algorithm. 43fa20c234SSam Leffler */ 44c312fb4aSAdrian Chadd #include "opt_ath.h" 45fa20c234SSam Leffler #include "opt_inet.h" 46b032f27cSSam Leffler #include "opt_wlan.h" 4787acb7d5SAdrian Chadd #include "opt_ah.h" 48fa20c234SSam Leffler 49fa20c234SSam Leffler #include <sys/param.h> 50fa20c234SSam Leffler #include <sys/systm.h> 51fa20c234SSam Leffler #include <sys/sysctl.h> 52fa20c234SSam Leffler #include <sys/kernel.h> 53fa20c234SSam Leffler #include <sys/lock.h> 5476039bc8SGleb Smirnoff #include <sys/malloc.h> 55fa20c234SSam Leffler #include <sys/mutex.h> 56fa20c234SSam Leffler #include <sys/errno.h> 57fa20c234SSam Leffler 58fa20c234SSam Leffler #include <machine/bus.h> 59fa20c234SSam Leffler #include <machine/resource.h> 60fa20c234SSam Leffler #include <sys/bus.h> 61fa20c234SSam Leffler 62fa20c234SSam Leffler #include <sys/socket.h> 63fa20c234SSam Leffler 64fa20c234SSam Leffler #include <net/if.h> 6576039bc8SGleb Smirnoff #include <net/if_var.h> 66fa20c234SSam Leffler #include <net/if_media.h> 67fa20c234SSam Leffler #include <net/if_arp.h> 68c1565b61SSam Leffler #include <net/ethernet.h> /* XXX for ether_sprintf */ 69fa20c234SSam Leffler 70fa20c234SSam Leffler #include <net80211/ieee80211_var.h> 71fa20c234SSam Leffler 72fa20c234SSam Leffler #include <net/bpf.h> 73fa20c234SSam Leffler 74fa20c234SSam Leffler #ifdef INET 75fa20c234SSam Leffler #include <netinet/in.h> 76fa20c234SSam Leffler #include <netinet/if_ether.h> 77fa20c234SSam Leffler #endif 78fa20c234SSam Leffler 79fa20c234SSam Leffler #include <dev/ath/if_athvar.h> 80fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h> 8133644623SSam Leffler #include <dev/ath/ath_hal/ah_desc.h> 82a6a308a4SAdrian Chadd #include <dev/ath/ath_rate/sample/tx_schedules.h> 83fa20c234SSam Leffler 84fa20c234SSam Leffler /* 85fa20c234SSam Leffler * This file is an implementation of the SampleRate algorithm 86fa20c234SSam Leffler * in "Bit-rate Selection in Wireless Networks" 87fa20c234SSam Leffler * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 88fa20c234SSam Leffler * 89fa20c234SSam Leffler * SampleRate chooses the bit-rate it predicts will provide the most 90fa20c234SSam Leffler * throughput based on estimates of the expected per-packet 91fa20c234SSam Leffler * transmission time for each bit-rate. SampleRate periodically sends 92fa20c234SSam Leffler * packets at bit-rates other than the current one to estimate when 93fa20c234SSam Leffler * another bit-rate will provide better performance. SampleRate 94fa20c234SSam Leffler * switches to another bit-rate when its estimated per-packet 95fa20c234SSam Leffler * transmission time becomes smaller than the current bit-rate's. 96fa20c234SSam Leffler * SampleRate reduces the number of bit-rates it must sample by 97fa20c234SSam Leffler * eliminating those that could not perform better than the one 98fa20c234SSam Leffler * currently being used. SampleRate also stops probing at a bit-rate 99fa20c234SSam Leffler * if it experiences several successive losses. 100fa20c234SSam Leffler * 101fa20c234SSam Leffler * The difference between the algorithm in the thesis and the one in this 102fa20c234SSam Leffler * file is that the one in this file uses a ewma instead of a window. 103fa20c234SSam Leffler * 104b91bf513SSam Leffler * Also, this implementation tracks the average transmission time for 105b91bf513SSam Leffler * a few different packet sizes independently for each link. 106fa20c234SSam Leffler */ 107fa20c234SSam Leffler 108cce63444SAdrian Chadd /* XXX TODO: move this into ath_hal/net80211 so it can be shared */ 109cce63444SAdrian Chadd 110cce63444SAdrian Chadd #define MCS_HT20 0 111cce63444SAdrian Chadd #define MCS_HT20_SGI 1 112cce63444SAdrian Chadd #define MCS_HT40 2 113cce63444SAdrian Chadd #define MCS_HT40_SGI 3 114cce63444SAdrian Chadd 115cce63444SAdrian Chadd /* 116cce63444SAdrian Chadd * This is currently a copy/paste from the 11n tx code. 117cce63444SAdrian Chadd * 118cce63444SAdrian Chadd * It's used to determine the maximum frame length allowed for the 119cce63444SAdrian Chadd * given rate. For now this ignores SGI/LGI and will assume long-GI. 120cce63444SAdrian Chadd * This only matters for lower rates that can't fill a full 64k A-MPDU. 121cce63444SAdrian Chadd * 122cce63444SAdrian Chadd * (But it's also important because right now rate control doesn't set 123cce63444SAdrian Chadd * flags like SGI/LGI, STBC, LDPC, TX power, etc.) 124cce63444SAdrian Chadd * 125cce63444SAdrian Chadd * When selecting a set of rates the rate control code will iterate 126cce63444SAdrian Chadd * over the HT20/HT40 max frame length and tell the caller the maximum 127cce63444SAdrian Chadd * length (@ LGI.) It will also choose a bucket that's the minimum 128cce63444SAdrian Chadd * of this value and the provided aggregate length. That way the 129cce63444SAdrian Chadd * rate selection will closely match what the eventual formed aggregate 130cce63444SAdrian Chadd * will be rather than "not at all". 131cce63444SAdrian Chadd */ 132cce63444SAdrian Chadd 133cce63444SAdrian Chadd static int ath_rate_sample_max_4ms_framelen[4][32] = { 134cce63444SAdrian Chadd [MCS_HT20] = { 135cce63444SAdrian Chadd 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172, 136cce63444SAdrian Chadd 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280, 137cce63444SAdrian Chadd 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532, 138cce63444SAdrian Chadd 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532, 139cce63444SAdrian Chadd }, 140cce63444SAdrian Chadd [MCS_HT20_SGI] = { 141cce63444SAdrian Chadd 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744, 142cce63444SAdrian Chadd 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532, 143cce63444SAdrian Chadd 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532, 144cce63444SAdrian Chadd 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532, 145cce63444SAdrian Chadd }, 146cce63444SAdrian Chadd [MCS_HT40] = { 147cce63444SAdrian Chadd 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532, 148cce63444SAdrian Chadd 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532, 149cce63444SAdrian Chadd 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532, 150cce63444SAdrian Chadd 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532, 151cce63444SAdrian Chadd }, 152cce63444SAdrian Chadd [MCS_HT40_SGI] = { 153cce63444SAdrian Chadd 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532, 154cce63444SAdrian Chadd 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532, 155cce63444SAdrian Chadd 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532, 156cce63444SAdrian Chadd 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532, 157cce63444SAdrian Chadd } 158cce63444SAdrian Chadd }; 159cce63444SAdrian Chadd 160cce63444SAdrian Chadd /* 161cce63444SAdrian Chadd * Given the (potentially MRR) transmit schedule, calculate the maximum 162cce63444SAdrian Chadd * allowed packet size for forming aggregates based on the lowest 163cce63444SAdrian Chadd * MCS rate in the transmit schedule. 164cce63444SAdrian Chadd * 165cce63444SAdrian Chadd * Returns -1 if it's a legacy rate or no MRR. 1668af14459SAdrian Chadd * 1678af14459SAdrian Chadd * XXX TODO: this needs to be limited by the RTS/CTS AR5416 8KB bug limit! 1688af14459SAdrian Chadd * (by checking rts/cts flags and applying sc_rts_aggr_limit) 1698af14459SAdrian Chadd * 1708af14459SAdrian Chadd * XXX TODO: apply per-node max-ampdu size and driver ampdu size limits too. 171cce63444SAdrian Chadd */ 172cce63444SAdrian Chadd static int 173cce63444SAdrian Chadd ath_rate_sample_find_min_pktlength(struct ath_softc *sc, 174051ea90cSAdrian Chadd struct ath_node *an, uint8_t rix0, int is_aggr) 175cce63444SAdrian Chadd { 176cce63444SAdrian Chadd #define MCS_IDX(ix) (rt->info[ix].dot11Rate) 177cce63444SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 178cce63444SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 179cce63444SAdrian Chadd const struct txschedule *sched = &sn->sched[rix0]; 180cce63444SAdrian Chadd int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE 181cce63444SAdrian Chadd // Note: this may not be true in all cases; need to check? 182ca389486SBjoern A. Zeeb int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40); 183cce63444SAdrian Chadd // Note: not great, but good enough.. 184cce63444SAdrian Chadd int idx = is_ht40 ? MCS_HT40 : MCS_HT20; 185cce63444SAdrian Chadd 186cce63444SAdrian Chadd if (rt->info[rix0].phy != IEEE80211_T_HT) { 187cce63444SAdrian Chadd return -1; 188cce63444SAdrian Chadd } 189cce63444SAdrian Chadd 190cce63444SAdrian Chadd if (! sc->sc_mrretry) { 191cce63444SAdrian Chadd return -1; 192cce63444SAdrian Chadd } 193cce63444SAdrian Chadd 194cce63444SAdrian Chadd KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 195cce63444SAdrian Chadd rix0, sched->r0)); 196cce63444SAdrian Chadd 197cce63444SAdrian Chadd /* 198cce63444SAdrian Chadd * Update based on sched->r{0,1,2,3} if sched->t{0,1,2,3} 199cce63444SAdrian Chadd * is not zero. 200cce63444SAdrian Chadd * 201cce63444SAdrian Chadd * Note: assuming all four PHYs are HT! 202051ea90cSAdrian Chadd * 203051ea90cSAdrian Chadd * XXX TODO: right now I hardcode here and in getxtxrates() that 204051ea90cSAdrian Chadd * rates 2 and 3 in the tx schedule are ignored. This is important 205051ea90cSAdrian Chadd * for forming larger aggregates because right now (a) the tx schedule 206051ea90cSAdrian Chadd * per rate is fixed, and (b) reliable packet transmission at those 207051ea90cSAdrian Chadd * higher rates kinda needs a lower MCS rate in there somewhere. 208051ea90cSAdrian Chadd * However, this means we can only form shorter aggregates. 209051ea90cSAdrian Chadd * If we've negotiated aggregation then we can actually just 210051ea90cSAdrian Chadd * rely on software retransmit rather than having things fall 211051ea90cSAdrian Chadd * back to like MCS0/1 in hardware, and rate control will hopefully 212051ea90cSAdrian Chadd * do the right thing. 213051ea90cSAdrian Chadd * 214051ea90cSAdrian Chadd * Once the whole rate schedule is passed into ath_rate_findrate(), 215051ea90cSAdrian Chadd * the ath_rc_series is populated ,the fixed tx schedule stuff 216051ea90cSAdrian Chadd * is removed AND getxtxrates() is removed then we can remove this 217051ea90cSAdrian Chadd * check as it can just NOT populate t2/t3. It also means 218051ea90cSAdrian Chadd * probing can actually use rix0 for probeing and rix1 for the 219051ea90cSAdrian Chadd * current best rate.. 220cce63444SAdrian Chadd */ 221cce63444SAdrian Chadd if (sched->t0 != 0) { 222cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 223cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]); 224cce63444SAdrian Chadd } 225cce63444SAdrian Chadd if (sched->t1 != 0) { 226cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 227cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]); 228cce63444SAdrian Chadd } 229051ea90cSAdrian Chadd if (sched->t2 != 0 && (! is_aggr)) { 230cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 231cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]); 232cce63444SAdrian Chadd } 233051ea90cSAdrian Chadd if (sched->t3 != 0 && (! is_aggr)) { 234cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 235cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]); 236cce63444SAdrian Chadd } 237cce63444SAdrian Chadd 238cce63444SAdrian Chadd return max_pkt_length; 239cce63444SAdrian Chadd #undef MCS 240cce63444SAdrian Chadd } 241cce63444SAdrian Chadd 242b2763056SSam Leffler static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 243fa20c234SSam Leffler 244b91bf513SSam Leffler static __inline int 245b91bf513SSam Leffler size_to_bin(int size) 246fa20c234SSam Leffler { 247c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1 248c1565b61SSam Leffler if (size <= packet_size_bins[0]) 249c1565b61SSam Leffler return 0; 250c1565b61SSam Leffler #endif 251c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2 252c1565b61SSam Leffler if (size <= packet_size_bins[1]) 253c1565b61SSam Leffler return 1; 254c1565b61SSam Leffler #endif 255c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3 256c1565b61SSam Leffler if (size <= packet_size_bins[2]) 257c1565b61SSam Leffler return 2; 258c1565b61SSam Leffler #endif 259c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4 260cce63444SAdrian Chadd if (size <= packet_size_bins[3]) 261cce63444SAdrian Chadd return 3; 262cce63444SAdrian Chadd #endif 263cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 5 264cce63444SAdrian Chadd if (size <= packet_size_bins[4]) 265cce63444SAdrian Chadd return 4; 266cce63444SAdrian Chadd #endif 267cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 6 268cce63444SAdrian Chadd if (size <= packet_size_bins[5]) 269cce63444SAdrian Chadd return 5; 270cce63444SAdrian Chadd #endif 271cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 7 272cce63444SAdrian Chadd if (size <= packet_size_bins[6]) 273cce63444SAdrian Chadd return 6; 274cce63444SAdrian Chadd #endif 275cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 8 276c1565b61SSam Leffler #error "add support for more packet sizes" 277c1565b61SSam Leffler #endif 278fa20c234SSam Leffler return NUM_PACKET_SIZE_BINS-1; 279fa20c234SSam Leffler } 280fa20c234SSam Leffler 281fa20c234SSam Leffler void 282fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 283fa20c234SSam Leffler { 284fa20c234SSam Leffler /* NB: assumed to be zero'd by caller */ 285fa20c234SSam Leffler } 286fa20c234SSam Leffler 287fa20c234SSam Leffler void 288fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 289fa20c234SSam Leffler { 290fa20c234SSam Leffler } 291fa20c234SSam Leffler 292a6a308a4SAdrian Chadd static int 293a6a308a4SAdrian Chadd dot11rate(const HAL_RATE_TABLE *rt, int rix) 294a6a308a4SAdrian Chadd { 29587acb7d5SAdrian Chadd if (rix < 0) 29687acb7d5SAdrian Chadd return -1; 297a6a308a4SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? 298a6a308a4SAdrian Chadd rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2; 299a6a308a4SAdrian Chadd } 300a6a308a4SAdrian Chadd 301ae0944b8SAdrian Chadd static const char * 302ae0944b8SAdrian Chadd dot11rate_label(const HAL_RATE_TABLE *rt, int rix) 303ae0944b8SAdrian Chadd { 30487acb7d5SAdrian Chadd if (rix < 0) 30587acb7d5SAdrian Chadd return ""; 306ae0944b8SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; 307ae0944b8SAdrian Chadd } 308ae0944b8SAdrian Chadd 309fa20c234SSam Leffler /* 310c1565b61SSam Leffler * Return the rix with the lowest average_tx_time, 311fa20c234SSam Leffler * or -1 if all the average_tx_times are 0. 312fa20c234SSam Leffler */ 313c1565b61SSam Leffler static __inline int 31436958948SAdrian Chadd pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt, 315c1565b61SSam Leffler int size_bin, int require_acked_before) 316fa20c234SSam Leffler { 31736958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 318eb6f0de0SAdrian Chadd int best_rate_rix, best_rate_tt, best_rate_pct; 319193bfa21SAdrian Chadd uint64_t mask; 320eb6f0de0SAdrian Chadd int rix, tt, pct; 321b91bf513SSam Leffler 322c1565b61SSam Leffler best_rate_rix = 0; 323c1565b61SSam Leffler best_rate_tt = 0; 324eb6f0de0SAdrian Chadd best_rate_pct = 0; 325c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 326c1565b61SSam Leffler if ((mask & 1) == 0) /* not a supported rate */ 327c1565b61SSam Leffler continue; 328c1565b61SSam Leffler 32936958948SAdrian Chadd /* Don't pick a non-HT rate for a HT node */ 33036958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 33136958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 33236958948SAdrian Chadd continue; 33336958948SAdrian Chadd } 33436958948SAdrian Chadd 335c1565b61SSam Leffler tt = sn->stats[size_bin][rix].average_tx_time; 336c1565b61SSam Leffler if (tt <= 0 || 337c1565b61SSam Leffler (require_acked_before && 338c1565b61SSam Leffler !sn->stats[size_bin][rix].packets_acked)) 339b91bf513SSam Leffler continue; 340b91bf513SSam Leffler 341eb6f0de0SAdrian Chadd /* Calculate percentage if possible */ 342eb6f0de0SAdrian Chadd if (sn->stats[size_bin][rix].total_packets > 0) { 343eb6f0de0SAdrian Chadd pct = sn->stats[size_bin][rix].ewma_pct; 344eb6f0de0SAdrian Chadd } else { 345cce63444SAdrian Chadd pct = -1; /* No percent yet to compare against! */ 346eb6f0de0SAdrian Chadd } 347eb6f0de0SAdrian Chadd 348b91bf513SSam Leffler /* don't use a bit-rate that has been failing */ 349c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > 3) 350b91bf513SSam Leffler continue; 351b91bf513SSam Leffler 352eb6f0de0SAdrian Chadd /* 353cce63444SAdrian Chadd * For HT, Don't use a bit rate that is more 354cce63444SAdrian Chadd * lossy than the best. Give a bit of leeway. 355eb6f0de0SAdrian Chadd * 356cce63444SAdrian Chadd * Don't consider best rates that we haven't seen 357cce63444SAdrian Chadd * packets for yet; let sampling start inflence that. 358eb6f0de0SAdrian Chadd */ 359eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 360cce63444SAdrian Chadd if (pct == -1) 361cce63444SAdrian Chadd continue; 362cce63444SAdrian Chadd #if 0 363cce63444SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 364cce63444SAdrian Chadd IEEE80211_MSG_RATECTL, 365cce63444SAdrian Chadd &an->an_node, 366cce63444SAdrian Chadd "%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) " 367cce63444SAdrian Chadd "to 0x%x pkts/ewma/tt (%ju/%d/%d)", 368cce63444SAdrian Chadd __func__, 369cce63444SAdrian Chadd bin_to_size(size_bin), 370cce63444SAdrian Chadd rt->info[best_rate_rix].dot11Rate, 371cce63444SAdrian Chadd sn->stats[size_bin][best_rate_rix].total_packets, 372cce63444SAdrian Chadd best_rate_pct, 373cce63444SAdrian Chadd best_rate_tt, 374cce63444SAdrian Chadd rt->info[rix].dot11Rate, 375cce63444SAdrian Chadd sn->stats[size_bin][rix].total_packets, 376cce63444SAdrian Chadd pct, 377cce63444SAdrian Chadd tt); 378cce63444SAdrian Chadd #endif 379eb6f0de0SAdrian Chadd if (best_rate_pct > (pct + 50)) 380eb6f0de0SAdrian Chadd continue; 381eb6f0de0SAdrian Chadd } 382eb6f0de0SAdrian Chadd /* 383eb6f0de0SAdrian Chadd * For non-MCS rates, use the current average txtime for 384eb6f0de0SAdrian Chadd * comparison. 385eb6f0de0SAdrian Chadd */ 386eb6f0de0SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 387eb6f0de0SAdrian Chadd if (best_rate_tt == 0 || tt <= best_rate_tt) { 388fa20c234SSam Leffler best_rate_tt = tt; 389c1565b61SSam Leffler best_rate_rix = rix; 390eb6f0de0SAdrian Chadd best_rate_pct = pct; 391eb6f0de0SAdrian Chadd } 392eb6f0de0SAdrian Chadd } 393eb6f0de0SAdrian Chadd 394eb6f0de0SAdrian Chadd /* 395cce63444SAdrian Chadd * Since 2 and 3 stream rates have slightly higher TX times, 396eb6f0de0SAdrian Chadd * allow a little bit of leeway. This should later 397eb6f0de0SAdrian Chadd * be abstracted out and properly handled. 398eb6f0de0SAdrian Chadd */ 399eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 40025af78d0SAdrian Chadd if (best_rate_tt == 0 || 40125af78d0SAdrian Chadd ((tt * 9) <= (best_rate_tt * 10))) { 402eb6f0de0SAdrian Chadd best_rate_tt = tt; 403eb6f0de0SAdrian Chadd best_rate_rix = rix; 404eb6f0de0SAdrian Chadd best_rate_pct = pct; 405eb6f0de0SAdrian Chadd } 406fa20c234SSam Leffler } 407fa20c234SSam Leffler } 408c1565b61SSam Leffler return (best_rate_tt ? best_rate_rix : -1); 409fa20c234SSam Leffler } 410fa20c234SSam Leffler 411fa20c234SSam Leffler /* 412c1565b61SSam Leffler * Pick a good "random" bit-rate to sample other than the current one. 413fa20c234SSam Leffler */ 414b91bf513SSam Leffler static __inline int 41536958948SAdrian Chadd pick_sample_rate(struct sample_softc *ssc , struct ath_node *an, 416c1565b61SSam Leffler const HAL_RATE_TABLE *rt, int size_bin) 417fa20c234SSam Leffler { 418c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 419a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 42036958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 421c1565b61SSam Leffler int current_rix, rix; 422c1565b61SSam Leffler unsigned current_tt; 423193bfa21SAdrian Chadd uint64_t mask; 424fa20c234SSam Leffler 425c1565b61SSam Leffler current_rix = sn->current_rix[size_bin]; 426c1565b61SSam Leffler if (current_rix < 0) { 427fa20c234SSam Leffler /* no successes yet, send at the lowest bit-rate */ 428cce63444SAdrian Chadd /* XXX TODO should return MCS0 if HT */ 429fa20c234SSam Leffler return 0; 430fa20c234SSam Leffler } 431fa20c234SSam Leffler 432c1565b61SSam Leffler current_tt = sn->stats[size_bin][current_rix].average_tx_time; 433fa20c234SSam Leffler 434c1565b61SSam Leffler rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 435193bfa21SAdrian Chadd mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */ 436c1565b61SSam Leffler while (mask != 0) { 437193bfa21SAdrian Chadd if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */ 438c1565b61SSam Leffler nextrate: 439c1565b61SSam Leffler if (++rix >= rt->rateCount) 440c1565b61SSam Leffler rix = 0; 441b91bf513SSam Leffler continue; 442c1565b61SSam Leffler } 443b91bf513SSam Leffler 444bf57b7b2SAdrian Chadd /* 445bf57b7b2SAdrian Chadd * The following code stops trying to sample 446bf57b7b2SAdrian Chadd * non-MCS rates when speaking to an MCS node. 447bf57b7b2SAdrian Chadd * However, at least for CCK rates in 2.4GHz mode, 448bf57b7b2SAdrian Chadd * the non-MCS rates MAY actually provide better 449bf57b7b2SAdrian Chadd * PER at the very far edge of reception. 450bf57b7b2SAdrian Chadd * 451bf57b7b2SAdrian Chadd * However! Until ath_rate_form_aggr() grows 452bf57b7b2SAdrian Chadd * some logic to not form aggregates if the 453bf57b7b2SAdrian Chadd * selected rate is non-MCS, this won't work. 454bf57b7b2SAdrian Chadd * 455bf57b7b2SAdrian Chadd * So don't disable this code until you've taught 456bf57b7b2SAdrian Chadd * ath_rate_form_aggr() to drop out if any of 457bf57b7b2SAdrian Chadd * the selected rates are non-MCS. 458bf57b7b2SAdrian Chadd */ 459bf57b7b2SAdrian Chadd #if 1 46036958948SAdrian Chadd /* if the node is HT and the rate isn't HT, don't bother sample */ 46136958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 46236958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 463193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 46436958948SAdrian Chadd goto nextrate; 46536958948SAdrian Chadd } 466bf57b7b2SAdrian Chadd #endif 46736958948SAdrian Chadd 468b91bf513SSam Leffler /* this bit-rate is always worse than the current one */ 469c1565b61SSam Leffler if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 470193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 471c1565b61SSam Leffler goto nextrate; 472c1565b61SSam Leffler } 473b91bf513SSam Leffler 474b91bf513SSam Leffler /* rarely sample bit-rates that fail a lot */ 475c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 476c1565b61SSam Leffler ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 477193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 478c1565b61SSam Leffler goto nextrate; 479fa20c234SSam Leffler } 480c1565b61SSam Leffler 481eb6f0de0SAdrian Chadd /* 482e69db8dfSAdrian Chadd * For HT, only sample a few rates on either side of the 483e69db8dfSAdrian Chadd * current rix; there's quite likely a lot of them. 484cce63444SAdrian Chadd * 485cce63444SAdrian Chadd * This is limited to testing rate indexes on either side of 486cce63444SAdrian Chadd * this MCS, but for all spatial streams. 487cce63444SAdrian Chadd * 488cce63444SAdrian Chadd * Otherwise we'll (a) never really sample higher MCS 489cce63444SAdrian Chadd * rates if we're stuck low, and we'll make weird moves 490cce63444SAdrian Chadd * like sample MCS8 if we're using MCS7. 491eb6f0de0SAdrian Chadd */ 492eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 493cce63444SAdrian Chadd uint8_t current_mcs, rix_mcs; 494cce63444SAdrian Chadd 495cce63444SAdrian Chadd current_mcs = MCS(current_rix) & 0x7; 496cce63444SAdrian Chadd rix_mcs = MCS(rix) & 0x7; 497cce63444SAdrian Chadd 498cce63444SAdrian Chadd if (rix_mcs < (current_mcs - 2) || 499cce63444SAdrian Chadd rix_mcs > (current_mcs + 2)) { 500193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 501eb6f0de0SAdrian Chadd goto nextrate; 502eb6f0de0SAdrian Chadd } 503eb6f0de0SAdrian Chadd } 504eb6f0de0SAdrian Chadd 50536958948SAdrian Chadd /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */ 50636958948SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 507c1565b61SSam Leffler if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 508193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 509c1565b61SSam Leffler goto nextrate; 510c1565b61SSam Leffler } 51136958948SAdrian Chadd } 512c1565b61SSam Leffler 513c1565b61SSam Leffler sn->last_sample_rix[size_bin] = rix; 514c1565b61SSam Leffler return rix; 515c1565b61SSam Leffler } 516c1565b61SSam Leffler return current_rix; 517c1565b61SSam Leffler #undef DOT11RATE 518a6a308a4SAdrian Chadd #undef MCS 519fa20c234SSam Leffler } 520fa20c234SSam Leffler 521c4ac32a8SAdrian Chadd static int 522c4ac32a8SAdrian Chadd ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) 523c4ac32a8SAdrian Chadd { 524c4ac32a8SAdrian Chadd #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 525c4ac32a8SAdrian Chadd #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 526c4ac32a8SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 527c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 528c4ac32a8SAdrian Chadd int srate; 529c4ac32a8SAdrian Chadd 530c4ac32a8SAdrian Chadd /* Check MCS rates */ 531c4ac32a8SAdrian Chadd for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { 532c4ac32a8SAdrian Chadd if (MCS(srate) == tp->ucastrate) 533c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 534c4ac32a8SAdrian Chadd } 535c4ac32a8SAdrian Chadd 536c4ac32a8SAdrian Chadd /* Check legacy rates */ 537c4ac32a8SAdrian Chadd for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { 538c4ac32a8SAdrian Chadd if (RATE(srate) == tp->ucastrate) 539c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 540c4ac32a8SAdrian Chadd } 541c4ac32a8SAdrian Chadd return -1; 542c4ac32a8SAdrian Chadd #undef RATE 543c4ac32a8SAdrian Chadd #undef DOT11RATE 544c4ac32a8SAdrian Chadd #undef MCS 545c4ac32a8SAdrian Chadd } 546c4ac32a8SAdrian Chadd 547c4ac32a8SAdrian Chadd static void 548c4ac32a8SAdrian Chadd ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) 549c4ac32a8SAdrian Chadd { 550c4ac32a8SAdrian Chadd struct ath_node *an = ATH_NODE(ni); 551c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 552c4ac32a8SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 553c4ac32a8SAdrian Chadd 554c4ac32a8SAdrian Chadd if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 555c4ac32a8SAdrian Chadd /* 556c4ac32a8SAdrian Chadd * A fixed rate is to be used; ucastrate is the IEEE code 557c4ac32a8SAdrian Chadd * for this rate (sans basic bit). Check this against the 558c4ac32a8SAdrian Chadd * negotiated rate set for the node. Note the fixed rate 559c4ac32a8SAdrian Chadd * may not be available for various reasons so we only 560c4ac32a8SAdrian Chadd * setup the static rate index if the lookup is successful. 561c4ac32a8SAdrian Chadd */ 562c4ac32a8SAdrian Chadd sn->static_rix = ath_rate_get_static_rix(sc, ni); 563c4ac32a8SAdrian Chadd } else { 564c4ac32a8SAdrian Chadd sn->static_rix = -1; 565c4ac32a8SAdrian Chadd } 566c4ac32a8SAdrian Chadd } 567c4ac32a8SAdrian Chadd 568eb6f0de0SAdrian Chadd /* 569eb6f0de0SAdrian Chadd * Pick a non-HT rate to begin using. 570eb6f0de0SAdrian Chadd */ 571eb6f0de0SAdrian Chadd static int 572eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an, 573eb6f0de0SAdrian Chadd int frameLen) 574eb6f0de0SAdrian Chadd { 575eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 576eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 577eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 578eb6f0de0SAdrian Chadd int rix = -1; 579eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 580eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 581eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 582eb6f0de0SAdrian Chadd 583eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 584eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 585193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 586eb6f0de0SAdrian Chadd continue; 587eb6f0de0SAdrian Chadd 588eb6f0de0SAdrian Chadd /* Skip HT rates */ 589eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 590eb6f0de0SAdrian Chadd continue; 591eb6f0de0SAdrian Chadd 592eb6f0de0SAdrian Chadd /* 593eb6f0de0SAdrian Chadd * Pick the highest rate <= 36 Mbps 594eb6f0de0SAdrian Chadd * that hasn't failed. 595eb6f0de0SAdrian Chadd */ 596eb6f0de0SAdrian Chadd if (DOT11RATE(rix) <= 72 && 597eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 598eb6f0de0SAdrian Chadd break; 599eb6f0de0SAdrian Chadd } 600eb6f0de0SAdrian Chadd } 601eb6f0de0SAdrian Chadd return rix; 602eb6f0de0SAdrian Chadd #undef RATE 603eb6f0de0SAdrian Chadd #undef MCS 604eb6f0de0SAdrian Chadd #undef DOT11RATE 605eb6f0de0SAdrian Chadd } 606eb6f0de0SAdrian Chadd 607eb6f0de0SAdrian Chadd /* 608eb6f0de0SAdrian Chadd * Pick a HT rate to begin using. 609eb6f0de0SAdrian Chadd * 610eb6f0de0SAdrian Chadd * Don't use any non-HT rates; only consider HT rates. 611eb6f0de0SAdrian Chadd */ 612eb6f0de0SAdrian Chadd static int 613eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an, 614eb6f0de0SAdrian Chadd int frameLen) 615eb6f0de0SAdrian Chadd { 616eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 617eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 618eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 619eb6f0de0SAdrian Chadd int rix = -1, ht_rix = -1; 620eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 621eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 622eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 623eb6f0de0SAdrian Chadd 624eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 625eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 626eb6f0de0SAdrian Chadd /* Skip rates we can't use */ 627193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 628eb6f0de0SAdrian Chadd continue; 629eb6f0de0SAdrian Chadd 630eb6f0de0SAdrian Chadd /* Keep a copy of the last seen HT rate index */ 631eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 632eb6f0de0SAdrian Chadd ht_rix = rix; 633eb6f0de0SAdrian Chadd 634eb6f0de0SAdrian Chadd /* Skip non-HT rates */ 635eb6f0de0SAdrian Chadd if (rt->info[rix].phy != IEEE80211_T_HT) 636eb6f0de0SAdrian Chadd continue; 637eb6f0de0SAdrian Chadd 638eb6f0de0SAdrian Chadd /* 639cce63444SAdrian Chadd * Pick a medium-speed rate at 1 spatial stream 640cce63444SAdrian Chadd * which has not seen any failures. 641cce63444SAdrian Chadd * Higher rates may fail; we'll try them later. 642eb6f0de0SAdrian Chadd */ 643cce63444SAdrian Chadd if (((MCS(rix)& 0x7f) <= 4) && 644eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 645eb6f0de0SAdrian Chadd break; 646eb6f0de0SAdrian Chadd } 647eb6f0de0SAdrian Chadd } 648eb6f0de0SAdrian Chadd 649eb6f0de0SAdrian Chadd /* 650eb6f0de0SAdrian Chadd * If all the MCS rates have successive failures, rix should be 651eb6f0de0SAdrian Chadd * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.) 652eb6f0de0SAdrian Chadd */ 653eb6f0de0SAdrian Chadd return MAX(rix, ht_rix); 654eb6f0de0SAdrian Chadd #undef RATE 655eb6f0de0SAdrian Chadd #undef MCS 656eb6f0de0SAdrian Chadd #undef DOT11RATE 657eb6f0de0SAdrian Chadd } 658c4ac32a8SAdrian Chadd 659fa20c234SSam Leffler void 660fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 66184f950a5SAdrian Chadd int shortPreamble, size_t frameLen, int tid, 662cce63444SAdrian Chadd int is_aggr, u_int8_t *rix0, int *try0, 663cce63444SAdrian Chadd u_int8_t *txrate, int *maxdur, int *maxpktlen) 664fa20c234SSam Leffler { 665c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 666a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 667c1565b61SSam Leffler #define RATE(ix) (DOT11RATE(ix) / 2) 668fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 669fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 6707a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 671c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 672cce63444SAdrian Chadd int size_bin = size_to_bin(frameLen); 673c1565b61SSam Leffler int rix, mrr, best_rix, change_rates; 674b2763056SSam Leffler unsigned average_tx_time; 675cce63444SAdrian Chadd int max_pkt_len; 676fa20c234SSam Leffler 677c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, &an->an_node); 678c4ac32a8SAdrian Chadd 67984f950a5SAdrian Chadd /* For now don't take TID, is_aggr into account */ 68084f950a5SAdrian Chadd /* Also for now don't calculate a max duration; that'll come later */ 68184f950a5SAdrian Chadd *maxdur = -1; 68284f950a5SAdrian Chadd 683cce63444SAdrian Chadd /* 684cce63444SAdrian Chadd * For now just set it to the frame length; we'll optimise it later. 685cce63444SAdrian Chadd */ 686cce63444SAdrian Chadd *maxpktlen = frameLen; 687cce63444SAdrian Chadd 688cc86f1eaSAdrian Chadd if (sn->currates != sc->sc_currates) { 689cc86f1eaSAdrian Chadd device_printf(sc->sc_dev, "%s: currates != sc_currates!\n", 690cc86f1eaSAdrian Chadd __func__); 691cc86f1eaSAdrian Chadd rix = 0; 692cc86f1eaSAdrian Chadd *try0 = ATH_TXMAXTRY; 693cc86f1eaSAdrian Chadd goto done; 694cc86f1eaSAdrian Chadd } 695cc86f1eaSAdrian Chadd 696c1565b61SSam Leffler if (sn->static_rix != -1) { 697c1565b61SSam Leffler rix = sn->static_rix; 698c1565b61SSam Leffler *try0 = ATH_TXMAXTRY; 6998af14459SAdrian Chadd 7008af14459SAdrian Chadd /* 7018af14459SAdrian Chadd * Ensure we limit max packet length here too! 7028af14459SAdrian Chadd */ 7038af14459SAdrian Chadd max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, 7048af14459SAdrian Chadd sn->static_rix, 7058af14459SAdrian Chadd is_aggr); 7068af14459SAdrian Chadd if (max_pkt_len > 0) { 7078af14459SAdrian Chadd *maxpktlen = frameLen = MIN(frameLen, max_pkt_len); 7088af14459SAdrian Chadd size_bin = size_to_bin(frameLen); 7098af14459SAdrian Chadd } 710c1565b61SSam Leffler goto done; 711c1565b61SSam Leffler } 712fa20c234SSam Leffler 713af017101SAdrian Chadd mrr = sc->sc_mrretry; 714af017101SAdrian Chadd /* XXX check HT protmode too */ 715cce63444SAdrian Chadd /* XXX turn into a cap; 11n MACs support MRR+RTSCTS */ 7169f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 717af017101SAdrian Chadd mrr = 0; 718c1565b61SSam Leffler 71936958948SAdrian Chadd best_rix = pick_best_rate(an, rt, size_bin, !mrr); 720cce63444SAdrian Chadd 721cce63444SAdrian Chadd /* 722cce63444SAdrian Chadd * At this point we've chosen the best rix, so now we 723cce63444SAdrian Chadd * need to potentially update our maximum packet length 724cce63444SAdrian Chadd * and size_bin if we're doing 11n rates. 725cce63444SAdrian Chadd */ 726051ea90cSAdrian Chadd max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix, 727051ea90cSAdrian Chadd is_aggr); 728cce63444SAdrian Chadd if (max_pkt_len > 0) { 729cce63444SAdrian Chadd #if 0 730cce63444SAdrian Chadd device_printf(sc->sc_dev, 731cce63444SAdrian Chadd "Limiting maxpktlen from %d to %d bytes\n", 732cce63444SAdrian Chadd (int) frameLen, max_pkt_len); 733cce63444SAdrian Chadd #endif 734cce63444SAdrian Chadd *maxpktlen = frameLen = MIN(frameLen, max_pkt_len); 735cce63444SAdrian Chadd size_bin = size_to_bin(frameLen); 736cce63444SAdrian Chadd } 737cce63444SAdrian Chadd 738c1565b61SSam Leffler if (best_rix >= 0) { 739c1565b61SSam Leffler average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 740fa20c234SSam Leffler } else { 741b2763056SSam Leffler average_tx_time = 0; 742b2763056SSam Leffler } 743cce63444SAdrian Chadd 744fa20c234SSam Leffler /* 745c1565b61SSam Leffler * Limit the time measuring the performance of other tx 746c1565b61SSam Leffler * rates to sample_rate% of the total transmission time. 747fa20c234SSam Leffler */ 7485add7017SAdrian Chadd if (sn->sample_tt[size_bin] < 7495add7017SAdrian Chadd average_tx_time * 7505add7017SAdrian Chadd (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 75136958948SAdrian Chadd rix = pick_sample_rate(ssc, an, rt, size_bin); 752c1565b61SSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 7535add7017SAdrian Chadd &an->an_node, "att %d sample_tt %d size %u " 7545add7017SAdrian Chadd "sample rate %d %s current rate %d %s", 755eb6f0de0SAdrian Chadd average_tx_time, 756eb6f0de0SAdrian Chadd sn->sample_tt[size_bin], 757eb6f0de0SAdrian Chadd bin_to_size(size_bin), 758eb6f0de0SAdrian Chadd dot11rate(rt, rix), 759eb6f0de0SAdrian Chadd dot11rate_label(rt, rix), 760eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 761eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin])); 762c1565b61SSam Leffler if (rix != sn->current_rix[size_bin]) { 763c1565b61SSam Leffler sn->current_sample_rix[size_bin] = rix; 764b2763056SSam Leffler } else { 765c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 766b2763056SSam Leffler } 767b2763056SSam Leffler sn->packets_since_sample[size_bin] = 0; 768b2763056SSam Leffler } else { 769b91bf513SSam Leffler change_rates = 0; 770c1565b61SSam Leffler if (!sn->packets_sent[size_bin] || best_rix == -1) { 771b91bf513SSam Leffler /* no packet has been sent successfully yet */ 772b91bf513SSam Leffler change_rates = 1; 773eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) 774eb6f0de0SAdrian Chadd best_rix = 775eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(sc, an, frameLen); 776eb6f0de0SAdrian Chadd else 777eb6f0de0SAdrian Chadd best_rix = 778eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(sc, an, frameLen); 779b91bf513SSam Leffler } else if (sn->packets_sent[size_bin] < 20) { 780b91bf513SSam Leffler /* let the bit-rate switch quickly during the first few packets */ 781eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 782eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 783eb6f0de0SAdrian Chadd "%s: switching quickly..", __func__); 784b91bf513SSam Leffler change_rates = 1; 785c1565b61SSam Leffler } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 786c1565b61SSam Leffler /* min_switch seconds have gone by */ 787eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 788eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 789eb6f0de0SAdrian Chadd "%s: min_switch %d > ticks_since_switch %d..", 790eb6f0de0SAdrian Chadd __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]); 791b91bf513SSam Leffler change_rates = 1; 792eb6f0de0SAdrian Chadd } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) && 793eb6f0de0SAdrian Chadd (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) { 794b91bf513SSam Leffler /* the current bit-rate is twice as slow as the best one */ 795eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 796eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 797eb6f0de0SAdrian Chadd "%s: 2x att (= %d) < cur_rix att %d", 798eb6f0de0SAdrian Chadd __func__, 799eb6f0de0SAdrian Chadd 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time); 800b91bf513SSam Leffler change_rates = 1; 801eb6f0de0SAdrian Chadd } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) { 802eb6f0de0SAdrian Chadd int cur_rix = sn->current_rix[size_bin]; 803eb6f0de0SAdrian Chadd int cur_att = sn->stats[size_bin][cur_rix].average_tx_time; 804eb6f0de0SAdrian Chadd /* 805051ea90cSAdrian Chadd * If the node is HT, it if the rate isn't the 806051ea90cSAdrian Chadd * same and the average tx time is within 10% 807051ea90cSAdrian Chadd * of the current rate. It can fail a little. 808eb6f0de0SAdrian Chadd * 809eb6f0de0SAdrian Chadd * This is likely not optimal! 810eb6f0de0SAdrian Chadd */ 811eb6f0de0SAdrian Chadd #if 0 812eb6f0de0SAdrian Chadd printf("cur rix/att %x/%d, best rix/att %x/%d\n", 813eb6f0de0SAdrian Chadd MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time); 814eb6f0de0SAdrian Chadd #endif 8155add7017SAdrian Chadd if ((best_rix != cur_rix) && 8165add7017SAdrian Chadd (average_tx_time * 9) <= (cur_att * 10)) { 817eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 818eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 819cce63444SAdrian Chadd "%s: HT: size %d best_rix 0x%x > " 820cce63444SAdrian Chadd " cur_rix 0x%x, average_tx_time %d," 821cce63444SAdrian Chadd " cur_att %d", 822cce63444SAdrian Chadd __func__, bin_to_size(size_bin), 823cce63444SAdrian Chadd MCS(best_rix), MCS(cur_rix), 824cce63444SAdrian Chadd average_tx_time, cur_att); 825eb6f0de0SAdrian Chadd change_rates = 1; 826eb6f0de0SAdrian Chadd } 827b91bf513SSam Leffler } 828b91bf513SSam Leffler 829b91bf513SSam Leffler sn->packets_since_sample[size_bin]++; 830b91bf513SSam Leffler 831b91bf513SSam Leffler if (change_rates) { 832c1565b61SSam Leffler if (best_rix != sn->current_rix[size_bin]) { 833b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, 834b032f27cSSam Leffler IEEE80211_MSG_RATECTL, 835b032f27cSSam Leffler &an->an_node, 836cce63444SAdrian Chadd "%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d", 837b2763056SSam Leffler __func__, 838c1565b61SSam Leffler bin_to_size(size_bin), 839cce63444SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 840cce63444SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin]), 841c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 842c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 843cce63444SAdrian Chadd sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct, 844cce63444SAdrian Chadd dot11rate(rt, best_rix), 845cce63444SAdrian Chadd dot11rate_label(rt, best_rix), 846c1565b61SSam Leffler sn->stats[size_bin][best_rix].average_tx_time, 847c1565b61SSam Leffler sn->stats[size_bin][best_rix].perfect_tx_time, 848cce63444SAdrian Chadd sn->stats[size_bin][best_rix].ewma_pct, 849b2763056SSam Leffler sn->packets_since_switch[size_bin], 850b2763056SSam Leffler mrr); 851b2763056SSam Leffler } 852b2763056SSam Leffler sn->packets_since_switch[size_bin] = 0; 853c1565b61SSam Leffler sn->current_rix[size_bin] = best_rix; 854b91bf513SSam Leffler sn->ticks_since_switch[size_bin] = ticks; 855b032f27cSSam Leffler /* 856b032f27cSSam Leffler * Set the visible txrate for this node. 857b032f27cSSam Leffler */ 858*70674500SAdrian Chadd if (rt->info[best_rix].phy == IEEE80211_T_HT) 859*70674500SAdrian Chadd ieee80211_node_set_txrate_ht_mcsrate( 860*70674500SAdrian Chadd &an->an_node, MCS(best_rix)); 861*70674500SAdrian Chadd else 862*70674500SAdrian Chadd ieee80211_node_set_txrate_dot11rate( 863*70674500SAdrian Chadd &an->an_node, 864*70674500SAdrian Chadd DOT11RATE(best_rix)); 865b2763056SSam Leffler } 866c1565b61SSam Leffler rix = sn->current_rix[size_bin]; 867b2763056SSam Leffler sn->packets_since_switch[size_bin]++; 868b91bf513SSam Leffler } 869c1565b61SSam Leffler *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 870c1565b61SSam Leffler done: 871cc86f1eaSAdrian Chadd 872cc86f1eaSAdrian Chadd /* 873cc86f1eaSAdrian Chadd * This bug totally sucks and should be fixed. 874cc86f1eaSAdrian Chadd * 875cc86f1eaSAdrian Chadd * For now though, let's not panic, so we can start to figure 876cc86f1eaSAdrian Chadd * out how to better reproduce it. 877cc86f1eaSAdrian Chadd */ 878cc86f1eaSAdrian Chadd if (rix < 0 || rix >= rt->rateCount) { 879cc86f1eaSAdrian Chadd printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n", 880cc86f1eaSAdrian Chadd __func__, 881cc86f1eaSAdrian Chadd rix, 882cc86f1eaSAdrian Chadd rt->rateCount); 883cc86f1eaSAdrian Chadd rix = 0; /* XXX just default for now */ 884cc86f1eaSAdrian Chadd } 885c1565b61SSam Leffler KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 886fa20c234SSam Leffler 887c1565b61SSam Leffler *rix0 = rix; 888c1565b61SSam Leffler *txrate = rt->info[rix].rateCode 889c1565b61SSam Leffler | (shortPreamble ? rt->info[rix].shortPreamble : 0); 890fa20c234SSam Leffler sn->packets_sent[size_bin]++; 891cce63444SAdrian Chadd 892c1565b61SSam Leffler #undef DOT11RATE 893a6a308a4SAdrian Chadd #undef MCS 894c1565b61SSam Leffler #undef RATE 895fa20c234SSam Leffler } 896fa20c234SSam Leffler 897710c3778SAdrian Chadd /* 898710c3778SAdrian Chadd * Get the TX rates. Don't fiddle with short preamble flags for them; 899710c3778SAdrian Chadd * the caller can do that. 900710c3778SAdrian Chadd */ 901710c3778SAdrian Chadd void 902710c3778SAdrian Chadd ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an, 903051ea90cSAdrian Chadd uint8_t rix0, int is_aggr, struct ath_rc_series *rc) 904710c3778SAdrian Chadd { 905710c3778SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 906710c3778SAdrian Chadd const struct txschedule *sched = &sn->sched[rix0]; 907710c3778SAdrian Chadd 908193bfa21SAdrian Chadd KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 909193bfa21SAdrian Chadd rix0, sched->r0)); 910710c3778SAdrian Chadd 911eb6f0de0SAdrian Chadd rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; 912710c3778SAdrian Chadd 913eb6f0de0SAdrian Chadd rc[0].rix = sched->r0; 914eb6f0de0SAdrian Chadd rc[1].rix = sched->r1; 915eb6f0de0SAdrian Chadd rc[2].rix = sched->r2; 916eb6f0de0SAdrian Chadd rc[3].rix = sched->r3; 917eb6f0de0SAdrian Chadd 918eb6f0de0SAdrian Chadd rc[0].tries = sched->t0; 919eb6f0de0SAdrian Chadd rc[1].tries = sched->t1; 920051ea90cSAdrian Chadd 921051ea90cSAdrian Chadd if (is_aggr) { 922051ea90cSAdrian Chadd rc[2].tries = rc[3].tries = 0; 923051ea90cSAdrian Chadd } else { 924eb6f0de0SAdrian Chadd rc[2].tries = sched->t2; 925eb6f0de0SAdrian Chadd rc[3].tries = sched->t3; 926710c3778SAdrian Chadd } 927051ea90cSAdrian Chadd } 928710c3778SAdrian Chadd 929fa20c234SSam Leffler void 930fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 931a4d8dd10SSam Leffler struct ath_desc *ds, int shortPreamble, u_int8_t rix) 932fa20c234SSam Leffler { 933fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 934c1565b61SSam Leffler const struct txschedule *sched = &sn->sched[rix]; 935c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 936c1565b61SSam Leffler uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 937fa20c234SSam Leffler 938c1565b61SSam Leffler /* XXX precalculate short preamble tables */ 939c1565b61SSam Leffler rix1 = sched->r1; 940c1565b61SSam Leffler s1code = rt->info[rix1].rateCode 941c1565b61SSam Leffler | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 942c1565b61SSam Leffler rix2 = sched->r2; 943c1565b61SSam Leffler s2code = rt->info[rix2].rateCode 944c1565b61SSam Leffler | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 945c1565b61SSam Leffler rix3 = sched->r3; 946c1565b61SSam Leffler s3code = rt->info[rix3].rateCode 947c1565b61SSam Leffler | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 948c1565b61SSam Leffler ath_hal_setupxtxdesc(sc->sc_ah, ds, 949c1565b61SSam Leffler s1code, sched->t1, /* series 1 */ 950c1565b61SSam Leffler s2code, sched->t2, /* series 2 */ 951c1565b61SSam Leffler s3code, sched->t3); /* series 3 */ 952fa20c234SSam Leffler } 953fa20c234SSam Leffler 954cf431555SAdrian Chadd /* 955cf431555SAdrian Chadd * Update the current statistics. 956cf431555SAdrian Chadd * 957cf431555SAdrian Chadd * Note that status is for the FINAL transmit status, not this 958cf431555SAdrian Chadd * particular attempt. So, check if tries > tries0 and if so 959cf431555SAdrian Chadd * assume this status failed. 960cf431555SAdrian Chadd * 961cf431555SAdrian Chadd * This is important because some failures are due to both 962cf431555SAdrian Chadd * short AND long retries; if the final issue was a short 963cf431555SAdrian Chadd * retry failure then we still want to account for the 964cf431555SAdrian Chadd * bad long retry attempts. 965cf431555SAdrian Chadd */ 966b2763056SSam Leffler static void 967b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an, 968b2763056SSam Leffler int frame_size, 969c1565b61SSam Leffler int rix0, int tries0, 970eb6f0de0SAdrian Chadd int short_tries, int tries, int status, 971eb6f0de0SAdrian Chadd int nframes, int nbad) 972fa20c234SSam Leffler { 973fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 974fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 975ec3dec2fSAdrian Chadd #ifdef IEEE80211_DEBUG 976eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 977ec3dec2fSAdrian Chadd #endif 978c1565b61SSam Leffler const int size_bin = size_to_bin(frame_size); 979c1565b61SSam Leffler const int size = bin_to_size(size_bin); 980cf431555SAdrian Chadd int tt; 981ca389486SBjoern A. Zeeb int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40); 982ee563d63SAdrian Chadd int pct; 983fa20c234SSam Leffler 984c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix0)) 98565f9edeeSSam Leffler return; 986cce63444SAdrian Chadd 987cce63444SAdrian Chadd /* 988cf431555SAdrian Chadd * Treat long retries as us exceeding retries, even 989cf431555SAdrian Chadd * if the eventual attempt at some other MRR schedule 990cf431555SAdrian Chadd * succeeded. 991cf431555SAdrian Chadd */ 992cf431555SAdrian Chadd if (tries > tries0) { 993cf431555SAdrian Chadd status = HAL_TXERR_XRETRY; 994cf431555SAdrian Chadd } 995cf431555SAdrian Chadd 996cf431555SAdrian Chadd /* 997cce63444SAdrian Chadd * If status is FAIL then we treat all frames as bad. 998cce63444SAdrian Chadd * This better accurately tracks EWMA and average TX time 999cce63444SAdrian Chadd * because even if the eventual transmission succeeded, 1000cce63444SAdrian Chadd * transmission at this rate did not. 1001cce63444SAdrian Chadd */ 1002cce63444SAdrian Chadd if (status != 0) 1003cce63444SAdrian Chadd nbad = nframes; 1004cce63444SAdrian Chadd 1005051ea90cSAdrian Chadd /* 1006051ea90cSAdrian Chadd * Ignore short tries count as contributing to failure. 1007051ea90cSAdrian Chadd * Right now there's no way to know if it's part of any 1008051ea90cSAdrian Chadd * given rate attempt, and outside of the RTS/CTS management 1009051ea90cSAdrian Chadd * rate, it doesn't /really/ help. 1010051ea90cSAdrian Chadd */ 1011051ea90cSAdrian Chadd tt = calc_usecs_unicast_packet(sc, size, rix0, 1012051ea90cSAdrian Chadd 0 /* short_tries */, MIN(tries0, tries) - 1, is_ht40); 1013c1565b61SSam Leffler 1014c1565b61SSam Leffler if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 1015fa20c234SSam Leffler /* just average the first few packets */ 1016c1565b61SSam Leffler int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 1017c1565b61SSam Leffler int packets = sn->stats[size_bin][rix0].total_packets; 1018eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); 1019fa20c234SSam Leffler } else { 1020fa20c234SSam Leffler /* use a ewma */ 1021c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time = 1022c1565b61SSam Leffler ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 1023c1565b61SSam Leffler (tt * (100 - ssc->smoothing_rate))) / 100; 1024fa20c234SSam Leffler } 1025fa20c234SSam Leffler 1026eb6f0de0SAdrian Chadd if (nframes == nbad) { 1027eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].successive_failures += nbad; 1028fa20c234SSam Leffler } else { 1029eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); 1030c1565b61SSam Leffler sn->stats[size_bin][rix0].successive_failures = 0; 1031fa20c234SSam Leffler } 1032c1565b61SSam Leffler sn->stats[size_bin][rix0].tries += tries; 1033c1565b61SSam Leffler sn->stats[size_bin][rix0].last_tx = ticks; 1034eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].total_packets += nframes; 1035b2763056SSam Leffler 1036ee563d63SAdrian Chadd /* update EWMA for this rix */ 1037ee563d63SAdrian Chadd 1038ee563d63SAdrian Chadd /* Calculate percentage based on current rate */ 1039ee563d63SAdrian Chadd if (nframes == 0) 1040ee563d63SAdrian Chadd nframes = nbad = 1; 1041ee563d63SAdrian Chadd pct = ((nframes - nbad) * 1000) / nframes; 1042ee563d63SAdrian Chadd 1043ee563d63SAdrian Chadd if (sn->stats[size_bin][rix0].total_packets < 1044ee563d63SAdrian Chadd ssc->smoothing_minpackets) { 1045ee563d63SAdrian Chadd /* just average the first few packets */ 1046ee563d63SAdrian Chadd int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) / 1047ee563d63SAdrian Chadd (sn->stats[size_bin][rix0].total_packets); 1048ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = a_pct; 1049ee563d63SAdrian Chadd } else { 1050ee563d63SAdrian Chadd /* use a ewma */ 1051ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = 1052ee563d63SAdrian Chadd ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) + 1053ee563d63SAdrian Chadd (pct * (100 - ssc->smoothing_rate))) / 100; 1054ee563d63SAdrian Chadd } 1055ee563d63SAdrian Chadd 1056cce63444SAdrian Chadd /* 1057cce63444SAdrian Chadd * Only update the sample time for the initial sample rix. 1058cce63444SAdrian Chadd * We've updated the statistics on each of the other retries 1059cce63444SAdrian Chadd * fine, but we should only update the sample_tt with what 1060cce63444SAdrian Chadd * was actually sampled. 1061cce63444SAdrian Chadd * 1062cce63444SAdrian Chadd * However, to aide in debugging, log all the failures for 1063cce63444SAdrian Chadd * each of the buckets 1064cce63444SAdrian Chadd */ 1065b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1066b032f27cSSam Leffler &an->an_node, 1067cce63444SAdrian Chadd "%s: size %d %s %s rate %d %s tries (%d/%d) tt %d " 1068cce63444SAdrian Chadd "avg_tt (%d/%d) nfrm %d nbad %d", 1069b032f27cSSam Leffler __func__, 107065f9edeeSSam Leffler size, 107165f9edeeSSam Leffler status ? "FAIL" : "OK", 1072cce63444SAdrian Chadd rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr", 1073eb6f0de0SAdrian Chadd dot11rate(rt, rix0), 1074eb6f0de0SAdrian Chadd dot11rate_label(rt, rix0), 1075eb6f0de0SAdrian Chadd short_tries, tries, tt, 1076c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time, 1077eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].perfect_tx_time, 1078eb6f0de0SAdrian Chadd nframes, nbad); 1079cce63444SAdrian Chadd 1080cce63444SAdrian Chadd if (rix0 == sn->current_sample_rix[size_bin]) { 1081b2763056SSam Leffler sn->sample_tt[size_bin] = tt; 1082c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 1083b2763056SSam Leffler } 1084b2763056SSam Leffler } 1085b2763056SSam Leffler 1086ec9ee5e7SSam Leffler static void 108776e6fd5dSGleb Smirnoff badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status) 1088ec9ee5e7SSam Leffler { 108976e6fd5dSGleb Smirnoff 109076e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 109176e6fd5dSGleb Smirnoff "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 1092ec9ee5e7SSam Leffler series, hwrate, tries, status); 1093ec9ee5e7SSam Leffler } 1094ec9ee5e7SSam Leffler 1095b2763056SSam Leffler void 109643e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 1097eb6f0de0SAdrian Chadd const struct ath_rc_series *rc, const struct ath_tx_status *ts, 1098cce63444SAdrian Chadd int frame_size, int rc_framesize, int nframes, int nbad) 1099b2763056SSam Leffler { 11007a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1101b2763056SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1102eb6f0de0SAdrian Chadd int final_rix, short_tries, long_tries; 110346d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1104eb6f0de0SAdrian Chadd int status = ts->ts_status; 11051bb9a085SSam Leffler int mrr; 1106b2763056SSam Leffler 1107f6cbf16aSSam Leffler final_rix = rt->rateCodeToIndex[ts->ts_rate]; 110865f9edeeSSam Leffler short_tries = ts->ts_shortretry; 110965f9edeeSSam Leffler long_tries = ts->ts_longretry + 1; 1110eb6f0de0SAdrian Chadd 1111ee563d63SAdrian Chadd if (nframes == 0) { 1112ee563d63SAdrian Chadd device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__); 1113ee563d63SAdrian Chadd return; 1114ee563d63SAdrian Chadd } 1115ee563d63SAdrian Chadd 111643e9cf7cSSam Leffler if (frame_size == 0) /* NB: should not happen */ 1117b2763056SSam Leffler frame_size = 1500; 1118cce63444SAdrian Chadd if (rc_framesize == 0) /* NB: should not happen */ 1119cce63444SAdrian Chadd rc_framesize = 1500; 1120cce63444SAdrian Chadd 1121cce63444SAdrian Chadd /* 1122cce63444SAdrian Chadd * There are still some places where what rate control set as 1123cce63444SAdrian Chadd * a limit but the hardware decided, for some reason, to transmit 1124cce63444SAdrian Chadd * at a smaller size that fell into a different bucket. 1125cce63444SAdrian Chadd * 1126cce63444SAdrian Chadd * The eternal question here is - which size_bin should it go in? 1127cce63444SAdrian Chadd * The one that was requested, or the one that was transmitted? 1128cce63444SAdrian Chadd * 1129cce63444SAdrian Chadd * Here's the problem - if we use the one that was transmitted, 1130cce63444SAdrian Chadd * we may continue to hit corner cases where we make a rate 1131cce63444SAdrian Chadd * selection using a higher bin but only update the smaller bin; 1132cce63444SAdrian Chadd * thus never really "adapting". 1133cce63444SAdrian Chadd * 1134cce63444SAdrian Chadd * If however we update the larger bin, we're not accurately 1135cce63444SAdrian Chadd * representing the channel state at that frame/aggregate size. 1136cce63444SAdrian Chadd * However if we keep hitting the larger request but completing 1137cce63444SAdrian Chadd * a smaller size, we at least updates based on what the 1138cce63444SAdrian Chadd * request was /for/. 1139cce63444SAdrian Chadd * 1140cce63444SAdrian Chadd * I'm going to err on the side of caution and choose the 1141cce63444SAdrian Chadd * latter. 1142cce63444SAdrian Chadd */ 1143cce63444SAdrian Chadd if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) { 1144cce63444SAdrian Chadd #if 0 1145cce63444SAdrian Chadd device_printf(sc->sc_dev, 1146cce63444SAdrian Chadd "%s: completed but frame size buckets mismatch " 1147cce63444SAdrian Chadd "(completed %d tx'ed %d)\n", 1148cce63444SAdrian Chadd __func__, frame_size, rc_framesize); 1149cce63444SAdrian Chadd #endif 1150cce63444SAdrian Chadd frame_size = rc_framesize; 1151cce63444SAdrian Chadd } 1152b2763056SSam Leffler 1153c1565b61SSam Leffler if (sn->ratemask == 0) { 1154b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1155b032f27cSSam Leffler &an->an_node, 1156b032f27cSSam Leffler "%s: size %d %s rate/try %d/%d no rates yet", 1157b032f27cSSam Leffler __func__, 115843e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1159eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 116043e9cf7cSSam Leffler short_tries, long_tries); 1161b2763056SSam Leffler return; 1162b2763056SSam Leffler } 1163af017101SAdrian Chadd mrr = sc->sc_mrretry; 1164af017101SAdrian Chadd /* XXX check HT protmode too */ 11659f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 1166af017101SAdrian Chadd mrr = 0; 1167af017101SAdrian Chadd 1168f6cbf16aSSam Leffler if (!mrr || ts->ts_finaltsi == 0) { 1169c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, final_rix)) { 117076e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 117176e6fd5dSGleb Smirnoff "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", 117206c746edSAdrian Chadd __func__, ts->ts_rate, ts->ts_finaltsi, final_rix); 117376e6fd5dSGleb Smirnoff badrate(sc, 0, ts->ts_rate, long_tries, status); 1174ec9ee5e7SSam Leffler return; 1175ec9ee5e7SSam Leffler } 117665f9edeeSSam Leffler /* 117765f9edeeSSam Leffler * Only one rate was used; optimize work. 117865f9edeeSSam Leffler */ 1179b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1180f6fd8c7aSAdrian Chadd &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]", 1181b032f27cSSam Leffler __func__, 118243e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1183c4ac32a8SAdrian Chadd frame_size, 1184eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1185eb6f0de0SAdrian Chadd dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), 1186eb6f0de0SAdrian Chadd short_tries, long_tries, nframes, nbad); 1187b2763056SSam Leffler update_stats(sc, an, frame_size, 1188c1565b61SSam Leffler final_rix, long_tries, 1189eb6f0de0SAdrian Chadd short_tries, long_tries, status, 1190eb6f0de0SAdrian Chadd nframes, nbad); 1191eb6f0de0SAdrian Chadd 1192b2763056SSam Leffler } else { 119365f9edeeSSam Leffler int finalTSIdx = ts->ts_finaltsi; 1194bd97c52aSAdrian Chadd int i; 1195b2763056SSam Leffler 1196b2763056SSam Leffler /* 1197b2763056SSam Leffler * Process intermediate rates that failed. 1198b2763056SSam Leffler */ 1199ec9ee5e7SSam Leffler 1200b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1201b032f27cSSam Leffler &an->an_node, 1202f6fd8c7aSAdrian Chadd "%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]", 1203b032f27cSSam Leffler __func__, 1204b2763056SSam Leffler bin_to_size(size_to_bin(frame_size)), 1205c4ac32a8SAdrian Chadd frame_size, 1206b2763056SSam Leffler finalTSIdx, 1207f6fd8c7aSAdrian Chadd short_tries, 1208b2763056SSam Leffler long_tries, 1209eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1210eb6f0de0SAdrian Chadd dot11rate(rt, rc[0].rix), 1211eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[0].rix), rc[0].tries, 1212eb6f0de0SAdrian Chadd dot11rate(rt, rc[1].rix), 1213eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[1].rix), rc[1].tries, 1214eb6f0de0SAdrian Chadd dot11rate(rt, rc[2].rix), 1215eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[2].rix), rc[2].tries, 1216eb6f0de0SAdrian Chadd dot11rate(rt, rc[3].rix), 1217eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[3].rix), rc[3].tries, 1218eb6f0de0SAdrian Chadd nframes, nbad); 1219c1565b61SSam Leffler 1220a6a308a4SAdrian Chadd for (i = 0; i < 4; i++) { 1221eb6f0de0SAdrian Chadd if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) 122276e6fd5dSGleb Smirnoff badrate(sc, 0, rc[i].ratecode, rc[i].tries, 1223eb6f0de0SAdrian Chadd status); 1224a6a308a4SAdrian Chadd } 1225b2763056SSam Leffler 122665f9edeeSSam Leffler /* 1227cce63444SAdrian Chadd * This used to not penalise other tries because loss 1228cce63444SAdrian Chadd * can be bursty, but it's then not accurately keeping 1229cce63444SAdrian Chadd * the avg TX time and EWMA updated. 123065f9edeeSSam Leffler */ 1231eb6f0de0SAdrian Chadd if (rc[0].tries) { 1232b2763056SSam Leffler update_stats(sc, an, frame_size, 1233eb6f0de0SAdrian Chadd rc[0].rix, rc[0].tries, 123465f9edeeSSam Leffler short_tries, long_tries, 1235cf431555SAdrian Chadd status, 1236eb6f0de0SAdrian Chadd nframes, nbad); 1237eb6f0de0SAdrian Chadd long_tries -= rc[0].tries; 1238b2763056SSam Leffler } 1239b2763056SSam Leffler 1240eb6f0de0SAdrian Chadd if (rc[1].tries && finalTSIdx > 0) { 1241b2763056SSam Leffler update_stats(sc, an, frame_size, 1242eb6f0de0SAdrian Chadd rc[1].rix, rc[1].tries, 124365f9edeeSSam Leffler short_tries, long_tries, 1244cf431555SAdrian Chadd status, 1245eb6f0de0SAdrian Chadd nframes, nbad); 1246eb6f0de0SAdrian Chadd long_tries -= rc[1].tries; 1247b2763056SSam Leffler } 1248b2763056SSam Leffler 1249eb6f0de0SAdrian Chadd if (rc[2].tries && finalTSIdx > 1) { 1250b2763056SSam Leffler update_stats(sc, an, frame_size, 1251eb6f0de0SAdrian Chadd rc[2].rix, rc[2].tries, 125265f9edeeSSam Leffler short_tries, long_tries, 1253cf431555SAdrian Chadd status, 1254eb6f0de0SAdrian Chadd nframes, nbad); 1255eb6f0de0SAdrian Chadd long_tries -= rc[2].tries; 1256b2763056SSam Leffler } 1257b2763056SSam Leffler 1258eb6f0de0SAdrian Chadd if (rc[3].tries && finalTSIdx > 2) { 1259b2763056SSam Leffler update_stats(sc, an, frame_size, 1260eb6f0de0SAdrian Chadd rc[3].rix, rc[3].tries, 126165f9edeeSSam Leffler short_tries, long_tries, 1262cf431555SAdrian Chadd status, 1263eb6f0de0SAdrian Chadd nframes, nbad); 126438fda926SAdrian Chadd } 1265b2763056SSam Leffler } 1266fa20c234SSam Leffler } 1267fa20c234SSam Leffler 1268fa20c234SSam Leffler void 1269fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 1270fa20c234SSam Leffler { 1271fa20c234SSam Leffler if (isnew) 1272b2763056SSam Leffler ath_rate_ctl_reset(sc, &an->an_node); 1273fa20c234SSam Leffler } 1274fa20c234SSam Leffler 12757d450faaSAdrian Chadd void 12767d450faaSAdrian Chadd ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi) 12777d450faaSAdrian Chadd { 12787d450faaSAdrian Chadd } 12797d450faaSAdrian Chadd 1280c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 1281c1565b61SSam Leffler NULL, /* IEEE80211_MODE_AUTO */ 1282c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_11A */ 1283c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11B */ 1284c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11G */ 1285c1565b61SSam Leffler NULL, /* IEEE80211_MODE_FH */ 1286c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_TURBO_A */ 1287c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_TURBO_G */ 1288c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_STURBO_A */ 1289a6a308a4SAdrian Chadd series_11na, /* IEEE80211_MODE_11NA */ 1290a6a308a4SAdrian Chadd series_11ng, /* IEEE80211_MODE_11NG */ 1291c1565b61SSam Leffler series_half, /* IEEE80211_MODE_HALF */ 1292c1565b61SSam Leffler series_quarter, /* IEEE80211_MODE_QUARTER */ 1293c1565b61SSam Leffler }; 1294c1565b61SSam Leffler 1295fa20c234SSam Leffler /* 1296fa20c234SSam Leffler * Initialize the tables for a node. 1297fa20c234SSam Leffler */ 1298fa20c234SSam Leffler static void 1299b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 1300fa20c234SSam Leffler { 1301fa20c234SSam Leffler #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 1302c1565b61SSam Leffler #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 1303a6a308a4SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 1304fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 1305fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1306fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1307c4ac32a8SAdrian Chadd int x, y, rix; 1308fa20c234SSam Leffler 1309fa20c234SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 1310c1565b61SSam Leffler 1311c1565b61SSam Leffler KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 1312c1565b61SSam Leffler ("curmode %u", sc->sc_curmode)); 1313193bfa21SAdrian Chadd 1314c1565b61SSam Leffler sn->sched = mrr_schedules[sc->sc_curmode]; 1315c1565b61SSam Leffler KASSERT(sn->sched != NULL, 1316c1565b61SSam Leffler ("no mrr schedule for mode %u", sc->sc_curmode)); 1317c1565b61SSam Leffler 1318c1565b61SSam Leffler sn->static_rix = -1; 1319c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, ni); 1320b2763056SSam Leffler 1321cc86f1eaSAdrian Chadd sn->currates = sc->sc_currates; 1322cc86f1eaSAdrian Chadd 1323c1565b61SSam Leffler /* 1324c1565b61SSam Leffler * Construct a bitmask of usable rates. This has all 1325c1565b61SSam Leffler * negotiated rates minus those marked by the hal as 1326c1565b61SSam Leffler * to be ignored for doing rate control. 1327c1565b61SSam Leffler */ 1328c1565b61SSam Leffler sn->ratemask = 0; 1329a6a308a4SAdrian Chadd /* MCS rates */ 1330a6a308a4SAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_HT) { 1331a6a308a4SAdrian Chadd for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { 1332a6a308a4SAdrian Chadd rix = sc->sc_rixmap[MCS(x)]; 1333a6a308a4SAdrian Chadd if (rix == 0xff) 1334a6a308a4SAdrian Chadd continue; 1335a6a308a4SAdrian Chadd /* skip rates marked broken by hal */ 1336a6a308a4SAdrian Chadd if (!rt->info[rix].valid) 1337a6a308a4SAdrian Chadd continue; 1338a6a308a4SAdrian Chadd KASSERT(rix < SAMPLE_MAXRATES, 1339a6a308a4SAdrian Chadd ("mcs %u has rix %d", MCS(x), rix)); 1340193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1341a6a308a4SAdrian Chadd } 1342a6a308a4SAdrian Chadd } 1343a6a308a4SAdrian Chadd 1344a6a308a4SAdrian Chadd /* Legacy rates */ 1345fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 1346c1565b61SSam Leffler rix = sc->sc_rixmap[RATE(x)]; 1347c1565b61SSam Leffler if (rix == 0xff) 13480ae09ec5SSam Leffler continue; 1349c1565b61SSam Leffler /* skip rates marked broken by hal */ 1350c1565b61SSam Leffler if (!rt->info[rix].valid) 1351c1565b61SSam Leffler continue; 1352c1565b61SSam Leffler KASSERT(rix < SAMPLE_MAXRATES, 1353c1565b61SSam Leffler ("rate %u has rix %d", RATE(x), rix)); 1354193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1355b2763056SSam Leffler } 1356b032f27cSSam Leffler #ifdef IEEE80211_DEBUG 1357b032f27cSSam Leffler if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 1358193bfa21SAdrian Chadd uint64_t mask; 1359c1565b61SSam Leffler 1360b032f27cSSam Leffler ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 1361c1565b61SSam Leffler ni->ni_macaddr, ":", __func__); 1362c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1363c1565b61SSam Leffler if ((mask & 1) == 0) 1364b032f27cSSam Leffler continue; 1365ae0944b8SAdrian Chadd printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), 1366e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, 1600, rix, 0,0, 1367ca389486SBjoern A. Zeeb (ni->ni_chw == IEEE80211_STA_RX_BW_40))); 1368b032f27cSSam Leffler } 1369b032f27cSSam Leffler printf("\n"); 1370b032f27cSSam Leffler } 1371b032f27cSSam Leffler #endif 1372b2763056SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1373b2763056SSam Leffler int size = bin_to_size(y); 1374193bfa21SAdrian Chadd uint64_t mask; 1375c1565b61SSam Leffler 1376b2763056SSam Leffler sn->packets_sent[y] = 0; 1377c1565b61SSam Leffler sn->current_sample_rix[y] = -1; 1378c1565b61SSam Leffler sn->last_sample_rix[y] = 0; 1379c1565b61SSam Leffler /* XXX start with first valid rate */ 1380c1565b61SSam Leffler sn->current_rix[y] = ffs(sn->ratemask)-1; 1381b2763056SSam Leffler 1382c1565b61SSam Leffler /* 1383c1565b61SSam Leffler * Initialize the statistics buckets; these are 1384c1565b61SSam Leffler * indexed by the rate code index. 1385c1565b61SSam Leffler */ 1386c1565b61SSam Leffler for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 1387c1565b61SSam Leffler if ((mask & 1) == 0) /* not a valid rate */ 1388c1565b61SSam Leffler continue; 1389c1565b61SSam Leffler sn->stats[y][rix].successive_failures = 0; 1390c1565b61SSam Leffler sn->stats[y][rix].tries = 0; 1391c1565b61SSam Leffler sn->stats[y][rix].total_packets = 0; 1392c1565b61SSam Leffler sn->stats[y][rix].packets_acked = 0; 1393c1565b61SSam Leffler sn->stats[y][rix].last_tx = 0; 1394eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct = 0; 1395b2763056SSam Leffler 1396c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time = 1397e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, size, rix, 0, 0, 1398ca389486SBjoern A. Zeeb (ni->ni_chw == IEEE80211_STA_RX_BW_40)); 1399c1565b61SSam Leffler sn->stats[y][rix].average_tx_time = 1400c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time; 1401b2763056SSam Leffler } 1402b91bf513SSam Leffler } 1403c1565b61SSam Leffler #if 0 1404c1565b61SSam Leffler /* XXX 0, num_rates-1 are wrong */ 1405b032f27cSSam Leffler IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 1406b032f27cSSam Leffler "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 1407b91bf513SSam Leffler sn->num_rates, 1408c1565b61SSam Leffler DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 1409b91bf513SSam Leffler sn->stats[1][0].perfect_tx_time, 1410c1565b61SSam Leffler DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 1411b91bf513SSam Leffler sn->stats[1][sn->num_rates-1].perfect_tx_time 1412b91bf513SSam Leffler ); 1413c1565b61SSam Leffler #endif 1414b032f27cSSam Leffler /* set the visible bit-rate */ 1415c1565b61SSam Leffler if (sn->static_rix != -1) 1416*70674500SAdrian Chadd ieee80211_node_set_txrate_dot11rate(ni, 1417*70674500SAdrian Chadd DOT11RATE(sn->static_rix)); 1418d0d425bfSSam Leffler else 1419*70674500SAdrian Chadd ieee80211_node_set_txrate_dot11rate(ni, RATE(0)); 1420fa20c234SSam Leffler #undef RATE 1421c1565b61SSam Leffler #undef DOT11RATE 1422fa20c234SSam Leffler } 1423fa20c234SSam Leffler 14242d20d655SAdrian Chadd /* 14252d20d655SAdrian Chadd * Fetch the statistics for the given node. 14262d20d655SAdrian Chadd * 14272d20d655SAdrian Chadd * The ieee80211 node must be referenced and unlocked, however the ath_node 14282d20d655SAdrian Chadd * must be locked. 14292d20d655SAdrian Chadd * 14302d20d655SAdrian Chadd * The main difference here is that we convert the rate indexes 14312d20d655SAdrian Chadd * to 802.11 rates, or the userland output won't make much sense 14322d20d655SAdrian Chadd * as it has no access to the rix table. 14332d20d655SAdrian Chadd */ 14342d20d655SAdrian Chadd int 14352d20d655SAdrian Chadd ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an, 14362d20d655SAdrian Chadd struct ath_rateioctl *rs) 14372d20d655SAdrian Chadd { 14382d20d655SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 14392d20d655SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 14402d20d655SAdrian Chadd struct ath_rateioctl_tlv av; 1441be4f96a6SAdrian Chadd struct ath_rateioctl_rt *tv; 144271188059SMark Johnston int error, y; 1443be4f96a6SAdrian Chadd int o = 0; 14442d20d655SAdrian Chadd 14452d20d655SAdrian Chadd ATH_NODE_LOCK_ASSERT(an); 14462d20d655SAdrian Chadd 144771188059SMark Johnston error = 0; 144871188059SMark Johnston 14492d20d655SAdrian Chadd /* 14502d20d655SAdrian Chadd * Ensure there's enough space for the statistics. 14512d20d655SAdrian Chadd */ 14522d20d655SAdrian Chadd if (rs->len < 14532d20d655SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1454be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_rt) + 1455be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1456be4f96a6SAdrian Chadd sizeof(struct sample_node)) { 1457be4f96a6SAdrian Chadd device_printf(sc->sc_dev, "%s: len=%d, too short\n", 1458be4f96a6SAdrian Chadd __func__, 1459be4f96a6SAdrian Chadd rs->len); 14602d20d655SAdrian Chadd return (EINVAL); 1461be4f96a6SAdrian Chadd } 14622d20d655SAdrian Chadd 14632d20d655SAdrian Chadd /* 14642d20d655SAdrian Chadd * Take a temporary copy of the sample node state so we can 14652d20d655SAdrian Chadd * modify it before we copy it. 14662d20d655SAdrian Chadd */ 1467be4f96a6SAdrian Chadd tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP, 1468be4f96a6SAdrian Chadd M_NOWAIT | M_ZERO); 1469be4f96a6SAdrian Chadd if (tv == NULL) { 14702d20d655SAdrian Chadd return (ENOMEM); 14712d20d655SAdrian Chadd } 14722d20d655SAdrian Chadd 14732d20d655SAdrian Chadd /* 1474be4f96a6SAdrian Chadd * Populate the rate table mapping TLV. 1475be4f96a6SAdrian Chadd */ 1476be4f96a6SAdrian Chadd tv->nentries = rt->rateCount; 1477be4f96a6SAdrian Chadd for (y = 0; y < rt->rateCount; y++) { 1478be4f96a6SAdrian Chadd tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL; 1479be4f96a6SAdrian Chadd if (rt->info[y].phy == IEEE80211_T_HT) 1480be4f96a6SAdrian Chadd tv->ratecode[y] |= IEEE80211_RATE_MCS; 1481be4f96a6SAdrian Chadd } 1482be4f96a6SAdrian Chadd 1483be4f96a6SAdrian Chadd o = 0; 1484be4f96a6SAdrian Chadd /* 1485be4f96a6SAdrian Chadd * First TLV - rate code mapping 1486be4f96a6SAdrian Chadd */ 1487be4f96a6SAdrian Chadd av.tlv_id = ATH_RATE_TLV_RATETABLE; 1488be4f96a6SAdrian Chadd av.tlv_len = sizeof(struct ath_rateioctl_rt); 148971188059SMark Johnston error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 149071188059SMark Johnston if (error != 0) 149171188059SMark Johnston goto out; 1492be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 149371188059SMark Johnston error = copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); 149471188059SMark Johnston if (error != 0) 149571188059SMark Johnston goto out; 1496be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_rt); 1497be4f96a6SAdrian Chadd 1498be4f96a6SAdrian Chadd /* 1499be4f96a6SAdrian Chadd * Second TLV - sample node statistics 15002d20d655SAdrian Chadd */ 15012d20d655SAdrian Chadd av.tlv_id = ATH_RATE_TLV_SAMPLENODE; 15022d20d655SAdrian Chadd av.tlv_len = sizeof(struct sample_node); 150371188059SMark Johnston error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 150471188059SMark Johnston if (error != 0) 150571188059SMark Johnston goto out; 1506be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 15072d20d655SAdrian Chadd 15082d20d655SAdrian Chadd /* 15092d20d655SAdrian Chadd * Copy the statistics over to the provided buffer. 15102d20d655SAdrian Chadd */ 151171188059SMark Johnston error = copyout(sn, rs->buf + o, sizeof(struct sample_node)); 151271188059SMark Johnston if (error != 0) 151371188059SMark Johnston goto out; 1514be4f96a6SAdrian Chadd o += sizeof(struct sample_node); 15152d20d655SAdrian Chadd 151671188059SMark Johnston out: 1517be4f96a6SAdrian Chadd free(tv, M_TEMP); 151871188059SMark Johnston return (error); 15192d20d655SAdrian Chadd } 15202d20d655SAdrian Chadd 1521f0fd5e07SSam Leffler static void 1522c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni) 1523c1565b61SSam Leffler { 1524c1565b61SSam Leffler struct ath_softc *sc = arg; 1525c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1526c1565b61SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 1527193bfa21SAdrian Chadd uint64_t mask; 1528c1565b61SSam Leffler int rix, y; 1529c1565b61SSam Leffler 1530a055e7ceSKonstantin Belousov printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n", 1531c1565b61SSam Leffler ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 1532eb6f0de0SAdrian Chadd dot11rate(rt, sn->static_rix), 1533eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->static_rix), 1534a055e7ceSKonstantin Belousov (uintmax_t)sn->ratemask); 1535c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1536ae0944b8SAdrian Chadd printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n", 1537c1565b61SSam Leffler bin_to_size(y), sn->current_rix[y], 1538ae0944b8SAdrian Chadd dot11rate(rt, sn->current_rix[y]), 1539ae0944b8SAdrian Chadd dot11rate_label(rt, sn->current_rix[y]), 1540c1565b61SSam Leffler sn->packets_since_switch[y], sn->ticks_since_switch[y]); 1541eb6f0de0SAdrian Chadd printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n", 1542eb6f0de0SAdrian Chadd bin_to_size(y), 1543eb6f0de0SAdrian Chadd dot11rate(rt, sn->last_sample_rix[y]), 1544eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->last_sample_rix[y]), 1545eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_sample_rix[y]), 1546eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_sample_rix[y]), 1547eb6f0de0SAdrian Chadd sn->packets_sent[y]); 1548c1565b61SSam Leffler printf("[%4u] packets since sample %d sample tt %u\n", 1549c1565b61SSam Leffler bin_to_size(y), sn->packets_since_sample[y], 1550c1565b61SSam Leffler sn->sample_tt[y]); 1551c1565b61SSam Leffler } 1552c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1553c1565b61SSam Leffler if ((mask & 1) == 0) 1554c1565b61SSam Leffler continue; 1555c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1556c1565b61SSam Leffler if (sn->stats[y][rix].total_packets == 0) 1557c1565b61SSam Leffler continue; 1558eb6f0de0SAdrian Chadd printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n", 1559ae0944b8SAdrian Chadd dot11rate(rt, rix), dot11rate_label(rt, rix), 1560c1565b61SSam Leffler bin_to_size(y), 156187acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].total_packets, 156287acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].packets_acked, 156387acb7d5SAdrian Chadd (int) ((sn->stats[y][rix].packets_acked * 100ULL) / 156487acb7d5SAdrian Chadd sn->stats[y][rix].total_packets), 1565eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct / 10, 1566eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct % 10, 156787acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].tries, 1568c1565b61SSam Leffler sn->stats[y][rix].successive_failures, 1569c1565b61SSam Leffler sn->stats[y][rix].average_tx_time, 1570c1565b61SSam Leffler ticks - sn->stats[y][rix].last_tx); 1571c1565b61SSam Leffler } 1572c1565b61SSam Leffler } 1573c1565b61SSam Leffler } 1574c1565b61SSam Leffler 1575c1565b61SSam Leffler static int 1576c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 1577c1565b61SSam Leffler { 1578c1565b61SSam Leffler struct ath_softc *sc = arg1; 15797a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1580c1565b61SSam Leffler int error, v; 1581c1565b61SSam Leffler 1582c1565b61SSam Leffler v = 0; 1583c1565b61SSam Leffler error = sysctl_handle_int(oidp, &v, 0, req); 1584c1565b61SSam Leffler if (error || !req->newptr) 1585c1565b61SSam Leffler return error; 1586c1565b61SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 1587c1565b61SSam Leffler return 0; 1588c1565b61SSam Leffler } 1589c1565b61SSam Leffler 1590c1565b61SSam Leffler static int 1591c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 1592c1565b61SSam Leffler { 1593c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1594c1565b61SSam Leffler int rate, error; 1595c1565b61SSam Leffler 1596c1565b61SSam Leffler rate = ssc->smoothing_rate; 1597c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1598c1565b61SSam Leffler if (error || !req->newptr) 1599c1565b61SSam Leffler return error; 1600c1565b61SSam Leffler if (!(0 <= rate && rate < 100)) 1601c1565b61SSam Leffler return EINVAL; 1602c1565b61SSam Leffler ssc->smoothing_rate = rate; 1603c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - rate); 1604c1565b61SSam Leffler return 0; 1605c1565b61SSam Leffler } 1606c1565b61SSam Leffler 1607c1565b61SSam Leffler static int 1608c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 1609c1565b61SSam Leffler { 1610c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1611c1565b61SSam Leffler int rate, error; 1612c1565b61SSam Leffler 1613c1565b61SSam Leffler rate = ssc->sample_rate; 1614c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1615c1565b61SSam Leffler if (error || !req->newptr) 1616c1565b61SSam Leffler return error; 1617c1565b61SSam Leffler if (!(2 <= rate && rate <= 100)) 1618c1565b61SSam Leffler return EINVAL; 1619c1565b61SSam Leffler ssc->sample_rate = rate; 1620c1565b61SSam Leffler return 0; 1621c1565b61SSam Leffler } 1622c1565b61SSam Leffler 1623c1565b61SSam Leffler static void 1624c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 1625fa20c234SSam Leffler { 1626fa20c234SSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 1627fa20c234SSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 1628fa20c234SSam Leffler 1629c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 163008f5e6bbSPawel Biernacki "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 163108f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_smoothing_rate, "I", 1632c1565b61SSam Leffler "sample: smoothing rate for avg tx time (%%)"); 1633c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 163408f5e6bbSPawel Biernacki "sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 163508f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_sample_rate, "I", 1636c1565b61SSam Leffler "sample: percent air time devoted to sampling new rates (%%)"); 1637c1565b61SSam Leffler /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 1638c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 163908f5e6bbSPawel Biernacki "sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 164008f5e6bbSPawel Biernacki sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics"); 1641fa20c234SSam Leffler } 1642fa20c234SSam Leffler 1643fa20c234SSam Leffler struct ath_ratectrl * 1644fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc) 1645fa20c234SSam Leffler { 1646c1565b61SSam Leffler struct sample_softc *ssc; 1647fa20c234SSam Leffler 1648c1565b61SSam Leffler ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 1649c1565b61SSam Leffler if (ssc == NULL) 1650fa20c234SSam Leffler return NULL; 1651c1565b61SSam Leffler ssc->arc.arc_space = sizeof(struct sample_node); 1652e69db8dfSAdrian Chadd ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */ 1653c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 1654c1565b61SSam Leffler ssc->sample_rate = 10; /* %time to try diff tx rates */ 1655c1565b61SSam Leffler ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 1656c1565b61SSam Leffler ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 1657c1565b61SSam Leffler ssc->min_switch = hz; /* 1 second */ 1658c1565b61SSam Leffler ath_rate_sysctlattach(sc, ssc); 1659c1565b61SSam Leffler return &ssc->arc; 1660fa20c234SSam Leffler } 1661fa20c234SSam Leffler 1662fa20c234SSam Leffler void 1663fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc) 1664fa20c234SSam Leffler { 1665c1565b61SSam Leffler struct sample_softc *ssc = (struct sample_softc *) arc; 1666fa20c234SSam Leffler 1667c1565b61SSam Leffler free(ssc, M_DEVBUF); 1668fa20c234SSam Leffler } 1669