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 __FBSDID("$FreeBSD$"); 42fa20c234SSam Leffler 43fa20c234SSam Leffler /* 44fa20c234SSam Leffler * John Bicket's SampleRate control algorithm. 45fa20c234SSam Leffler */ 46c312fb4aSAdrian Chadd #include "opt_ath.h" 47fa20c234SSam Leffler #include "opt_inet.h" 48b032f27cSSam Leffler #include "opt_wlan.h" 4987acb7d5SAdrian Chadd #include "opt_ah.h" 50fa20c234SSam Leffler 51fa20c234SSam Leffler #include <sys/param.h> 52fa20c234SSam Leffler #include <sys/systm.h> 53fa20c234SSam Leffler #include <sys/sysctl.h> 54fa20c234SSam Leffler #include <sys/kernel.h> 55fa20c234SSam Leffler #include <sys/lock.h> 5676039bc8SGleb Smirnoff #include <sys/malloc.h> 57fa20c234SSam Leffler #include <sys/mutex.h> 58fa20c234SSam Leffler #include <sys/errno.h> 59fa20c234SSam Leffler 60fa20c234SSam Leffler #include <machine/bus.h> 61fa20c234SSam Leffler #include <machine/resource.h> 62fa20c234SSam Leffler #include <sys/bus.h> 63fa20c234SSam Leffler 64fa20c234SSam Leffler #include <sys/socket.h> 65fa20c234SSam Leffler 66fa20c234SSam Leffler #include <net/if.h> 6776039bc8SGleb Smirnoff #include <net/if_var.h> 68fa20c234SSam Leffler #include <net/if_media.h> 69fa20c234SSam Leffler #include <net/if_arp.h> 70c1565b61SSam Leffler #include <net/ethernet.h> /* XXX for ether_sprintf */ 71fa20c234SSam Leffler 72fa20c234SSam Leffler #include <net80211/ieee80211_var.h> 73fa20c234SSam Leffler 74fa20c234SSam Leffler #include <net/bpf.h> 75fa20c234SSam Leffler 76fa20c234SSam Leffler #ifdef INET 77fa20c234SSam Leffler #include <netinet/in.h> 78fa20c234SSam Leffler #include <netinet/if_ether.h> 79fa20c234SSam Leffler #endif 80fa20c234SSam Leffler 81fa20c234SSam Leffler #include <dev/ath/if_athvar.h> 82fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h> 8333644623SSam Leffler #include <dev/ath/ath_hal/ah_desc.h> 84a6a308a4SAdrian Chadd #include <dev/ath/ath_rate/sample/tx_schedules.h> 85fa20c234SSam Leffler 86fa20c234SSam Leffler /* 87fa20c234SSam Leffler * This file is an implementation of the SampleRate algorithm 88fa20c234SSam Leffler * in "Bit-rate Selection in Wireless Networks" 89fa20c234SSam Leffler * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps) 90fa20c234SSam Leffler * 91fa20c234SSam Leffler * SampleRate chooses the bit-rate it predicts will provide the most 92fa20c234SSam Leffler * throughput based on estimates of the expected per-packet 93fa20c234SSam Leffler * transmission time for each bit-rate. SampleRate periodically sends 94fa20c234SSam Leffler * packets at bit-rates other than the current one to estimate when 95fa20c234SSam Leffler * another bit-rate will provide better performance. SampleRate 96fa20c234SSam Leffler * switches to another bit-rate when its estimated per-packet 97fa20c234SSam Leffler * transmission time becomes smaller than the current bit-rate's. 98fa20c234SSam Leffler * SampleRate reduces the number of bit-rates it must sample by 99fa20c234SSam Leffler * eliminating those that could not perform better than the one 100fa20c234SSam Leffler * currently being used. SampleRate also stops probing at a bit-rate 101fa20c234SSam Leffler * if it experiences several successive losses. 102fa20c234SSam Leffler * 103fa20c234SSam Leffler * The difference between the algorithm in the thesis and the one in this 104fa20c234SSam Leffler * file is that the one in this file uses a ewma instead of a window. 105fa20c234SSam Leffler * 106b91bf513SSam Leffler * Also, this implementation tracks the average transmission time for 107b91bf513SSam Leffler * a few different packet sizes independently for each link. 108fa20c234SSam Leffler */ 109fa20c234SSam Leffler 110cce63444SAdrian Chadd /* XXX TODO: move this into ath_hal/net80211 so it can be shared */ 111cce63444SAdrian Chadd 112cce63444SAdrian Chadd #define MCS_HT20 0 113cce63444SAdrian Chadd #define MCS_HT20_SGI 1 114cce63444SAdrian Chadd #define MCS_HT40 2 115cce63444SAdrian Chadd #define MCS_HT40_SGI 3 116cce63444SAdrian Chadd 117cce63444SAdrian Chadd /* 118cce63444SAdrian Chadd * This is currently a copy/paste from the 11n tx code. 119cce63444SAdrian Chadd * 120cce63444SAdrian Chadd * It's used to determine the maximum frame length allowed for the 121cce63444SAdrian Chadd * given rate. For now this ignores SGI/LGI and will assume long-GI. 122cce63444SAdrian Chadd * This only matters for lower rates that can't fill a full 64k A-MPDU. 123cce63444SAdrian Chadd * 124cce63444SAdrian Chadd * (But it's also important because right now rate control doesn't set 125cce63444SAdrian Chadd * flags like SGI/LGI, STBC, LDPC, TX power, etc.) 126cce63444SAdrian Chadd * 127cce63444SAdrian Chadd * When selecting a set of rates the rate control code will iterate 128cce63444SAdrian Chadd * over the HT20/HT40 max frame length and tell the caller the maximum 129cce63444SAdrian Chadd * length (@ LGI.) It will also choose a bucket that's the minimum 130cce63444SAdrian Chadd * of this value and the provided aggregate length. That way the 131cce63444SAdrian Chadd * rate selection will closely match what the eventual formed aggregate 132cce63444SAdrian Chadd * will be rather than "not at all". 133cce63444SAdrian Chadd */ 134cce63444SAdrian Chadd 135cce63444SAdrian Chadd static int ath_rate_sample_max_4ms_framelen[4][32] = { 136cce63444SAdrian Chadd [MCS_HT20] = { 137cce63444SAdrian Chadd 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172, 138cce63444SAdrian Chadd 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280, 139cce63444SAdrian Chadd 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532, 140cce63444SAdrian Chadd 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532, 141cce63444SAdrian Chadd }, 142cce63444SAdrian Chadd [MCS_HT20_SGI] = { 143cce63444SAdrian Chadd 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744, 144cce63444SAdrian Chadd 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532, 145cce63444SAdrian Chadd 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532, 146cce63444SAdrian Chadd 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532, 147cce63444SAdrian Chadd }, 148cce63444SAdrian Chadd [MCS_HT40] = { 149cce63444SAdrian Chadd 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532, 150cce63444SAdrian Chadd 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532, 151cce63444SAdrian Chadd 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532, 152cce63444SAdrian Chadd 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532, 153cce63444SAdrian Chadd }, 154cce63444SAdrian Chadd [MCS_HT40_SGI] = { 155cce63444SAdrian Chadd 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532, 156cce63444SAdrian Chadd 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532, 157cce63444SAdrian Chadd 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532, 158cce63444SAdrian Chadd 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532, 159cce63444SAdrian Chadd } 160cce63444SAdrian Chadd }; 161cce63444SAdrian Chadd 162cce63444SAdrian Chadd /* 163cce63444SAdrian Chadd * Given the (potentially MRR) transmit schedule, calculate the maximum 164cce63444SAdrian Chadd * allowed packet size for forming aggregates based on the lowest 165cce63444SAdrian Chadd * MCS rate in the transmit schedule. 166cce63444SAdrian Chadd * 167cce63444SAdrian Chadd * Returns -1 if it's a legacy rate or no MRR. 168cce63444SAdrian Chadd */ 169cce63444SAdrian Chadd static int 170cce63444SAdrian Chadd ath_rate_sample_find_min_pktlength(struct ath_softc *sc, 171051ea90cSAdrian Chadd struct ath_node *an, uint8_t rix0, int is_aggr) 172cce63444SAdrian Chadd { 173cce63444SAdrian Chadd #define MCS_IDX(ix) (rt->info[ix].dot11Rate) 174cce63444SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 175cce63444SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 176cce63444SAdrian Chadd const struct txschedule *sched = &sn->sched[rix0]; 177cce63444SAdrian Chadd int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE 178cce63444SAdrian Chadd // Note: this may not be true in all cases; need to check? 179cce63444SAdrian Chadd int is_ht40 = (an->an_node.ni_chw == 40); 180cce63444SAdrian Chadd // Note: not great, but good enough.. 181cce63444SAdrian Chadd int idx = is_ht40 ? MCS_HT40 : MCS_HT20; 182cce63444SAdrian Chadd 183cce63444SAdrian Chadd if (rt->info[rix0].phy != IEEE80211_T_HT) { 184cce63444SAdrian Chadd return -1; 185cce63444SAdrian Chadd } 186cce63444SAdrian Chadd 187cce63444SAdrian Chadd if (! sc->sc_mrretry) { 188cce63444SAdrian Chadd return -1; 189cce63444SAdrian Chadd } 190cce63444SAdrian Chadd 191cce63444SAdrian Chadd KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 192cce63444SAdrian Chadd rix0, sched->r0)); 193cce63444SAdrian Chadd 194cce63444SAdrian Chadd /* 195cce63444SAdrian Chadd * Update based on sched->r{0,1,2,3} if sched->t{0,1,2,3} 196cce63444SAdrian Chadd * is not zero. 197cce63444SAdrian Chadd * 198cce63444SAdrian Chadd * Note: assuming all four PHYs are HT! 199051ea90cSAdrian Chadd * 200051ea90cSAdrian Chadd * XXX TODO: right now I hardcode here and in getxtxrates() that 201051ea90cSAdrian Chadd * rates 2 and 3 in the tx schedule are ignored. This is important 202051ea90cSAdrian Chadd * for forming larger aggregates because right now (a) the tx schedule 203051ea90cSAdrian Chadd * per rate is fixed, and (b) reliable packet transmission at those 204051ea90cSAdrian Chadd * higher rates kinda needs a lower MCS rate in there somewhere. 205051ea90cSAdrian Chadd * However, this means we can only form shorter aggregates. 206051ea90cSAdrian Chadd * If we've negotiated aggregation then we can actually just 207051ea90cSAdrian Chadd * rely on software retransmit rather than having things fall 208051ea90cSAdrian Chadd * back to like MCS0/1 in hardware, and rate control will hopefully 209051ea90cSAdrian Chadd * do the right thing. 210051ea90cSAdrian Chadd * 211051ea90cSAdrian Chadd * Once the whole rate schedule is passed into ath_rate_findrate(), 212051ea90cSAdrian Chadd * the ath_rc_series is populated ,the fixed tx schedule stuff 213051ea90cSAdrian Chadd * is removed AND getxtxrates() is removed then we can remove this 214051ea90cSAdrian Chadd * check as it can just NOT populate t2/t3. It also means 215051ea90cSAdrian Chadd * probing can actually use rix0 for probeing and rix1 for the 216051ea90cSAdrian Chadd * current best rate.. 217cce63444SAdrian Chadd */ 218cce63444SAdrian Chadd if (sched->t0 != 0) { 219cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 220cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]); 221cce63444SAdrian Chadd } 222cce63444SAdrian Chadd if (sched->t1 != 0) { 223cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 224cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]); 225cce63444SAdrian Chadd } 226051ea90cSAdrian Chadd if (sched->t2 != 0 && (! is_aggr)) { 227cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 228cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]); 229cce63444SAdrian Chadd } 230051ea90cSAdrian Chadd if (sched->t3 != 0 && (! is_aggr)) { 231cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 232cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]); 233cce63444SAdrian Chadd } 234cce63444SAdrian Chadd 235cce63444SAdrian Chadd return max_pkt_length; 236cce63444SAdrian Chadd #undef MCS 237cce63444SAdrian Chadd } 238cce63444SAdrian Chadd 239b2763056SSam Leffler static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 240fa20c234SSam Leffler 241b91bf513SSam Leffler static __inline int 242b91bf513SSam Leffler size_to_bin(int size) 243fa20c234SSam Leffler { 244c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1 245c1565b61SSam Leffler if (size <= packet_size_bins[0]) 246c1565b61SSam Leffler return 0; 247c1565b61SSam Leffler #endif 248c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2 249c1565b61SSam Leffler if (size <= packet_size_bins[1]) 250c1565b61SSam Leffler return 1; 251c1565b61SSam Leffler #endif 252c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3 253c1565b61SSam Leffler if (size <= packet_size_bins[2]) 254c1565b61SSam Leffler return 2; 255c1565b61SSam Leffler #endif 256c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4 257cce63444SAdrian Chadd if (size <= packet_size_bins[3]) 258cce63444SAdrian Chadd return 3; 259cce63444SAdrian Chadd #endif 260cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 5 261cce63444SAdrian Chadd if (size <= packet_size_bins[4]) 262cce63444SAdrian Chadd return 4; 263cce63444SAdrian Chadd #endif 264cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 6 265cce63444SAdrian Chadd if (size <= packet_size_bins[5]) 266cce63444SAdrian Chadd return 5; 267cce63444SAdrian Chadd #endif 268cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 7 269cce63444SAdrian Chadd if (size <= packet_size_bins[6]) 270cce63444SAdrian Chadd return 6; 271cce63444SAdrian Chadd #endif 272cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 8 273c1565b61SSam Leffler #error "add support for more packet sizes" 274c1565b61SSam Leffler #endif 275fa20c234SSam Leffler return NUM_PACKET_SIZE_BINS-1; 276fa20c234SSam Leffler } 277fa20c234SSam Leffler 278fa20c234SSam Leffler void 279fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 280fa20c234SSam Leffler { 281fa20c234SSam Leffler /* NB: assumed to be zero'd by caller */ 282fa20c234SSam Leffler } 283fa20c234SSam Leffler 284fa20c234SSam Leffler void 285fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 286fa20c234SSam Leffler { 287fa20c234SSam Leffler } 288fa20c234SSam Leffler 289a6a308a4SAdrian Chadd static int 290a6a308a4SAdrian Chadd dot11rate(const HAL_RATE_TABLE *rt, int rix) 291a6a308a4SAdrian Chadd { 29287acb7d5SAdrian Chadd if (rix < 0) 29387acb7d5SAdrian Chadd return -1; 294a6a308a4SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? 295a6a308a4SAdrian Chadd rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2; 296a6a308a4SAdrian Chadd } 297a6a308a4SAdrian Chadd 298ae0944b8SAdrian Chadd static const char * 299ae0944b8SAdrian Chadd dot11rate_label(const HAL_RATE_TABLE *rt, int rix) 300ae0944b8SAdrian Chadd { 30187acb7d5SAdrian Chadd if (rix < 0) 30287acb7d5SAdrian Chadd return ""; 303ae0944b8SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; 304ae0944b8SAdrian Chadd } 305ae0944b8SAdrian Chadd 306fa20c234SSam Leffler /* 307c1565b61SSam Leffler * Return the rix with the lowest average_tx_time, 308fa20c234SSam Leffler * or -1 if all the average_tx_times are 0. 309fa20c234SSam Leffler */ 310c1565b61SSam Leffler static __inline int 31136958948SAdrian Chadd pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt, 312c1565b61SSam Leffler int size_bin, int require_acked_before) 313fa20c234SSam Leffler { 31436958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 315eb6f0de0SAdrian Chadd int best_rate_rix, best_rate_tt, best_rate_pct; 316193bfa21SAdrian Chadd uint64_t mask; 317eb6f0de0SAdrian Chadd int rix, tt, pct; 318b91bf513SSam Leffler 319c1565b61SSam Leffler best_rate_rix = 0; 320c1565b61SSam Leffler best_rate_tt = 0; 321eb6f0de0SAdrian Chadd best_rate_pct = 0; 322c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 323c1565b61SSam Leffler if ((mask & 1) == 0) /* not a supported rate */ 324c1565b61SSam Leffler continue; 325c1565b61SSam Leffler 32636958948SAdrian Chadd /* Don't pick a non-HT rate for a HT node */ 32736958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 32836958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 32936958948SAdrian Chadd continue; 33036958948SAdrian Chadd } 33136958948SAdrian Chadd 332c1565b61SSam Leffler tt = sn->stats[size_bin][rix].average_tx_time; 333c1565b61SSam Leffler if (tt <= 0 || 334c1565b61SSam Leffler (require_acked_before && 335c1565b61SSam Leffler !sn->stats[size_bin][rix].packets_acked)) 336b91bf513SSam Leffler continue; 337b91bf513SSam Leffler 338eb6f0de0SAdrian Chadd /* Calculate percentage if possible */ 339eb6f0de0SAdrian Chadd if (sn->stats[size_bin][rix].total_packets > 0) { 340eb6f0de0SAdrian Chadd pct = sn->stats[size_bin][rix].ewma_pct; 341eb6f0de0SAdrian Chadd } else { 342cce63444SAdrian Chadd pct = -1; /* No percent yet to compare against! */ 343eb6f0de0SAdrian Chadd } 344eb6f0de0SAdrian Chadd 345b91bf513SSam Leffler /* don't use a bit-rate that has been failing */ 346c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > 3) 347b91bf513SSam Leffler continue; 348b91bf513SSam Leffler 349eb6f0de0SAdrian Chadd /* 350cce63444SAdrian Chadd * For HT, Don't use a bit rate that is more 351cce63444SAdrian Chadd * lossy than the best. Give a bit of leeway. 352eb6f0de0SAdrian Chadd * 353cce63444SAdrian Chadd * Don't consider best rates that we haven't seen 354cce63444SAdrian Chadd * packets for yet; let sampling start inflence that. 355eb6f0de0SAdrian Chadd */ 356eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 357cce63444SAdrian Chadd if (pct == -1) 358cce63444SAdrian Chadd continue; 359cce63444SAdrian Chadd #if 0 360cce63444SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 361cce63444SAdrian Chadd IEEE80211_MSG_RATECTL, 362cce63444SAdrian Chadd &an->an_node, 363cce63444SAdrian Chadd "%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) " 364cce63444SAdrian Chadd "to 0x%x pkts/ewma/tt (%ju/%d/%d)", 365cce63444SAdrian Chadd __func__, 366cce63444SAdrian Chadd bin_to_size(size_bin), 367cce63444SAdrian Chadd rt->info[best_rate_rix].dot11Rate, 368cce63444SAdrian Chadd sn->stats[size_bin][best_rate_rix].total_packets, 369cce63444SAdrian Chadd best_rate_pct, 370cce63444SAdrian Chadd best_rate_tt, 371cce63444SAdrian Chadd rt->info[rix].dot11Rate, 372cce63444SAdrian Chadd sn->stats[size_bin][rix].total_packets, 373cce63444SAdrian Chadd pct, 374cce63444SAdrian Chadd tt); 375cce63444SAdrian Chadd #endif 376eb6f0de0SAdrian Chadd if (best_rate_pct > (pct + 50)) 377eb6f0de0SAdrian Chadd continue; 378eb6f0de0SAdrian Chadd } 379eb6f0de0SAdrian Chadd /* 380eb6f0de0SAdrian Chadd * For non-MCS rates, use the current average txtime for 381eb6f0de0SAdrian Chadd * comparison. 382eb6f0de0SAdrian Chadd */ 383eb6f0de0SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 384eb6f0de0SAdrian Chadd if (best_rate_tt == 0 || tt <= best_rate_tt) { 385fa20c234SSam Leffler best_rate_tt = tt; 386c1565b61SSam Leffler best_rate_rix = rix; 387eb6f0de0SAdrian Chadd best_rate_pct = pct; 388eb6f0de0SAdrian Chadd } 389eb6f0de0SAdrian Chadd } 390eb6f0de0SAdrian Chadd 391eb6f0de0SAdrian Chadd /* 392cce63444SAdrian Chadd * Since 2 and 3 stream rates have slightly higher TX times, 393eb6f0de0SAdrian Chadd * allow a little bit of leeway. This should later 394eb6f0de0SAdrian Chadd * be abstracted out and properly handled. 395eb6f0de0SAdrian Chadd */ 396eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 397cce63444SAdrian Chadd if (best_rate_tt == 0 || ((tt * 10) <= (best_rate_tt * 10))) { 398eb6f0de0SAdrian Chadd best_rate_tt = tt; 399eb6f0de0SAdrian Chadd best_rate_rix = rix; 400eb6f0de0SAdrian Chadd best_rate_pct = pct; 401eb6f0de0SAdrian Chadd } 402fa20c234SSam Leffler } 403fa20c234SSam Leffler } 404c1565b61SSam Leffler return (best_rate_tt ? best_rate_rix : -1); 405fa20c234SSam Leffler } 406fa20c234SSam Leffler 407fa20c234SSam Leffler /* 408c1565b61SSam Leffler * Pick a good "random" bit-rate to sample other than the current one. 409fa20c234SSam Leffler */ 410b91bf513SSam Leffler static __inline int 41136958948SAdrian Chadd pick_sample_rate(struct sample_softc *ssc , struct ath_node *an, 412c1565b61SSam Leffler const HAL_RATE_TABLE *rt, int size_bin) 413fa20c234SSam Leffler { 414c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 415a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 41636958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 417c1565b61SSam Leffler int current_rix, rix; 418c1565b61SSam Leffler unsigned current_tt; 419193bfa21SAdrian Chadd uint64_t mask; 420fa20c234SSam Leffler 421c1565b61SSam Leffler current_rix = sn->current_rix[size_bin]; 422c1565b61SSam Leffler if (current_rix < 0) { 423fa20c234SSam Leffler /* no successes yet, send at the lowest bit-rate */ 424cce63444SAdrian Chadd /* XXX TODO should return MCS0 if HT */ 425fa20c234SSam Leffler return 0; 426fa20c234SSam Leffler } 427fa20c234SSam Leffler 428c1565b61SSam Leffler current_tt = sn->stats[size_bin][current_rix].average_tx_time; 429fa20c234SSam Leffler 430c1565b61SSam Leffler rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 431193bfa21SAdrian Chadd mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */ 432c1565b61SSam Leffler while (mask != 0) { 433193bfa21SAdrian Chadd if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */ 434c1565b61SSam Leffler nextrate: 435c1565b61SSam Leffler if (++rix >= rt->rateCount) 436c1565b61SSam Leffler rix = 0; 437b91bf513SSam Leffler continue; 438c1565b61SSam Leffler } 439b91bf513SSam Leffler 440bf57b7b2SAdrian Chadd /* 441bf57b7b2SAdrian Chadd * The following code stops trying to sample 442bf57b7b2SAdrian Chadd * non-MCS rates when speaking to an MCS node. 443bf57b7b2SAdrian Chadd * However, at least for CCK rates in 2.4GHz mode, 444bf57b7b2SAdrian Chadd * the non-MCS rates MAY actually provide better 445bf57b7b2SAdrian Chadd * PER at the very far edge of reception. 446bf57b7b2SAdrian Chadd * 447bf57b7b2SAdrian Chadd * However! Until ath_rate_form_aggr() grows 448bf57b7b2SAdrian Chadd * some logic to not form aggregates if the 449bf57b7b2SAdrian Chadd * selected rate is non-MCS, this won't work. 450bf57b7b2SAdrian Chadd * 451bf57b7b2SAdrian Chadd * So don't disable this code until you've taught 452bf57b7b2SAdrian Chadd * ath_rate_form_aggr() to drop out if any of 453bf57b7b2SAdrian Chadd * the selected rates are non-MCS. 454bf57b7b2SAdrian Chadd */ 455bf57b7b2SAdrian Chadd #if 1 45636958948SAdrian Chadd /* if the node is HT and the rate isn't HT, don't bother sample */ 45736958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 45836958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 459193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 46036958948SAdrian Chadd goto nextrate; 46136958948SAdrian Chadd } 462bf57b7b2SAdrian Chadd #endif 46336958948SAdrian Chadd 464b91bf513SSam Leffler /* this bit-rate is always worse than the current one */ 465c1565b61SSam Leffler if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 466193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 467c1565b61SSam Leffler goto nextrate; 468c1565b61SSam Leffler } 469b91bf513SSam Leffler 470b91bf513SSam Leffler /* rarely sample bit-rates that fail a lot */ 471c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 472c1565b61SSam Leffler ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 473193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 474c1565b61SSam Leffler goto nextrate; 475fa20c234SSam Leffler } 476c1565b61SSam Leffler 477eb6f0de0SAdrian Chadd /* 478e69db8dfSAdrian Chadd * For HT, only sample a few rates on either side of the 479e69db8dfSAdrian Chadd * current rix; there's quite likely a lot of them. 480cce63444SAdrian Chadd * 481cce63444SAdrian Chadd * This is limited to testing rate indexes on either side of 482cce63444SAdrian Chadd * this MCS, but for all spatial streams. 483cce63444SAdrian Chadd * 484cce63444SAdrian Chadd * Otherwise we'll (a) never really sample higher MCS 485cce63444SAdrian Chadd * rates if we're stuck low, and we'll make weird moves 486cce63444SAdrian Chadd * like sample MCS8 if we're using MCS7. 487eb6f0de0SAdrian Chadd */ 488eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 489cce63444SAdrian Chadd uint8_t current_mcs, rix_mcs; 490cce63444SAdrian Chadd 491cce63444SAdrian Chadd current_mcs = MCS(current_rix) & 0x7; 492cce63444SAdrian Chadd rix_mcs = MCS(rix) & 0x7; 493cce63444SAdrian Chadd 494cce63444SAdrian Chadd if (rix_mcs < (current_mcs - 2) || 495cce63444SAdrian Chadd rix_mcs > (current_mcs + 2)) { 496193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 497eb6f0de0SAdrian Chadd goto nextrate; 498eb6f0de0SAdrian Chadd } 499eb6f0de0SAdrian Chadd } 500eb6f0de0SAdrian Chadd 50136958948SAdrian Chadd /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */ 50236958948SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 503c1565b61SSam Leffler if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 504193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 505c1565b61SSam Leffler goto nextrate; 506c1565b61SSam Leffler } 50736958948SAdrian Chadd } 508c1565b61SSam Leffler 509c1565b61SSam Leffler sn->last_sample_rix[size_bin] = rix; 510c1565b61SSam Leffler return rix; 511c1565b61SSam Leffler } 512c1565b61SSam Leffler return current_rix; 513c1565b61SSam Leffler #undef DOT11RATE 514a6a308a4SAdrian Chadd #undef MCS 515fa20c234SSam Leffler } 516fa20c234SSam Leffler 517c4ac32a8SAdrian Chadd static int 518c4ac32a8SAdrian Chadd ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) 519c4ac32a8SAdrian Chadd { 520c4ac32a8SAdrian Chadd #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 521c4ac32a8SAdrian Chadd #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 522c4ac32a8SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 523c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 524c4ac32a8SAdrian Chadd int srate; 525c4ac32a8SAdrian Chadd 526c4ac32a8SAdrian Chadd /* Check MCS rates */ 527c4ac32a8SAdrian Chadd for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { 528c4ac32a8SAdrian Chadd if (MCS(srate) == tp->ucastrate) 529c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 530c4ac32a8SAdrian Chadd } 531c4ac32a8SAdrian Chadd 532c4ac32a8SAdrian Chadd /* Check legacy rates */ 533c4ac32a8SAdrian Chadd for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { 534c4ac32a8SAdrian Chadd if (RATE(srate) == tp->ucastrate) 535c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 536c4ac32a8SAdrian Chadd } 537c4ac32a8SAdrian Chadd return -1; 538c4ac32a8SAdrian Chadd #undef RATE 539c4ac32a8SAdrian Chadd #undef DOT11RATE 540c4ac32a8SAdrian Chadd #undef MCS 541c4ac32a8SAdrian Chadd } 542c4ac32a8SAdrian Chadd 543c4ac32a8SAdrian Chadd static void 544c4ac32a8SAdrian Chadd ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) 545c4ac32a8SAdrian Chadd { 546c4ac32a8SAdrian Chadd struct ath_node *an = ATH_NODE(ni); 547c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 548c4ac32a8SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 549c4ac32a8SAdrian Chadd 550c4ac32a8SAdrian Chadd if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 551c4ac32a8SAdrian Chadd /* 552c4ac32a8SAdrian Chadd * A fixed rate is to be used; ucastrate is the IEEE code 553c4ac32a8SAdrian Chadd * for this rate (sans basic bit). Check this against the 554c4ac32a8SAdrian Chadd * negotiated rate set for the node. Note the fixed rate 555c4ac32a8SAdrian Chadd * may not be available for various reasons so we only 556c4ac32a8SAdrian Chadd * setup the static rate index if the lookup is successful. 557c4ac32a8SAdrian Chadd */ 558c4ac32a8SAdrian Chadd sn->static_rix = ath_rate_get_static_rix(sc, ni); 559c4ac32a8SAdrian Chadd } else { 560c4ac32a8SAdrian Chadd sn->static_rix = -1; 561c4ac32a8SAdrian Chadd } 562c4ac32a8SAdrian Chadd } 563c4ac32a8SAdrian Chadd 564eb6f0de0SAdrian Chadd /* 565eb6f0de0SAdrian Chadd * Pick a non-HT rate to begin using. 566eb6f0de0SAdrian Chadd */ 567eb6f0de0SAdrian Chadd static int 568eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an, 569eb6f0de0SAdrian Chadd int frameLen) 570eb6f0de0SAdrian Chadd { 571eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 572eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 573eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 574eb6f0de0SAdrian Chadd int rix = -1; 575eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 576eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 577eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 578eb6f0de0SAdrian Chadd 579eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 580eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 581193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 582eb6f0de0SAdrian Chadd continue; 583eb6f0de0SAdrian Chadd 584eb6f0de0SAdrian Chadd /* Skip HT rates */ 585eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 586eb6f0de0SAdrian Chadd continue; 587eb6f0de0SAdrian Chadd 588eb6f0de0SAdrian Chadd /* 589eb6f0de0SAdrian Chadd * Pick the highest rate <= 36 Mbps 590eb6f0de0SAdrian Chadd * that hasn't failed. 591eb6f0de0SAdrian Chadd */ 592eb6f0de0SAdrian Chadd if (DOT11RATE(rix) <= 72 && 593eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 594eb6f0de0SAdrian Chadd break; 595eb6f0de0SAdrian Chadd } 596eb6f0de0SAdrian Chadd } 597eb6f0de0SAdrian Chadd return rix; 598eb6f0de0SAdrian Chadd #undef RATE 599eb6f0de0SAdrian Chadd #undef MCS 600eb6f0de0SAdrian Chadd #undef DOT11RATE 601eb6f0de0SAdrian Chadd } 602eb6f0de0SAdrian Chadd 603eb6f0de0SAdrian Chadd /* 604eb6f0de0SAdrian Chadd * Pick a HT rate to begin using. 605eb6f0de0SAdrian Chadd * 606eb6f0de0SAdrian Chadd * Don't use any non-HT rates; only consider HT rates. 607eb6f0de0SAdrian Chadd */ 608eb6f0de0SAdrian Chadd static int 609eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an, 610eb6f0de0SAdrian Chadd int frameLen) 611eb6f0de0SAdrian Chadd { 612eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 613eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 614eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 615eb6f0de0SAdrian Chadd int rix = -1, ht_rix = -1; 616eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 617eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 618eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 619eb6f0de0SAdrian Chadd 620eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 621eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 622eb6f0de0SAdrian Chadd /* Skip rates we can't use */ 623193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 624eb6f0de0SAdrian Chadd continue; 625eb6f0de0SAdrian Chadd 626eb6f0de0SAdrian Chadd /* Keep a copy of the last seen HT rate index */ 627eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 628eb6f0de0SAdrian Chadd ht_rix = rix; 629eb6f0de0SAdrian Chadd 630eb6f0de0SAdrian Chadd /* Skip non-HT rates */ 631eb6f0de0SAdrian Chadd if (rt->info[rix].phy != IEEE80211_T_HT) 632eb6f0de0SAdrian Chadd continue; 633eb6f0de0SAdrian Chadd 634eb6f0de0SAdrian Chadd /* 635cce63444SAdrian Chadd * Pick a medium-speed rate at 1 spatial stream 636cce63444SAdrian Chadd * which has not seen any failures. 637cce63444SAdrian Chadd * Higher rates may fail; we'll try them later. 638eb6f0de0SAdrian Chadd */ 639cce63444SAdrian Chadd if (((MCS(rix)& 0x7f) <= 4) && 640eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 641eb6f0de0SAdrian Chadd break; 642eb6f0de0SAdrian Chadd } 643eb6f0de0SAdrian Chadd } 644eb6f0de0SAdrian Chadd 645eb6f0de0SAdrian Chadd /* 646eb6f0de0SAdrian Chadd * If all the MCS rates have successive failures, rix should be 647eb6f0de0SAdrian Chadd * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.) 648eb6f0de0SAdrian Chadd */ 649eb6f0de0SAdrian Chadd return MAX(rix, ht_rix); 650eb6f0de0SAdrian Chadd #undef RATE 651eb6f0de0SAdrian Chadd #undef MCS 652eb6f0de0SAdrian Chadd #undef DOT11RATE 653eb6f0de0SAdrian Chadd } 654c4ac32a8SAdrian Chadd 655c4ac32a8SAdrian Chadd 656fa20c234SSam Leffler void 657fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 65884f950a5SAdrian Chadd int shortPreamble, size_t frameLen, int tid, 659cce63444SAdrian Chadd int is_aggr, u_int8_t *rix0, int *try0, 660cce63444SAdrian Chadd u_int8_t *txrate, int *maxdur, int *maxpktlen) 661fa20c234SSam Leffler { 662c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 663a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 664c1565b61SSam Leffler #define RATE(ix) (DOT11RATE(ix) / 2) 665fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 666fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 6677a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 668c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 669cce63444SAdrian Chadd int size_bin = size_to_bin(frameLen); 670c1565b61SSam Leffler int rix, mrr, best_rix, change_rates; 671b2763056SSam Leffler unsigned average_tx_time; 672cce63444SAdrian Chadd int max_pkt_len; 673fa20c234SSam Leffler 674c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, &an->an_node); 675c4ac32a8SAdrian Chadd 67684f950a5SAdrian Chadd /* For now don't take TID, is_aggr into account */ 67784f950a5SAdrian Chadd /* Also for now don't calculate a max duration; that'll come later */ 67884f950a5SAdrian Chadd *maxdur = -1; 67984f950a5SAdrian Chadd 680cce63444SAdrian Chadd /* 681cce63444SAdrian Chadd * For now just set it to the frame length; we'll optimise it later. 682cce63444SAdrian Chadd */ 683cce63444SAdrian Chadd *maxpktlen = frameLen; 684cce63444SAdrian Chadd 685cc86f1eaSAdrian Chadd if (sn->currates != sc->sc_currates) { 686cc86f1eaSAdrian Chadd device_printf(sc->sc_dev, "%s: currates != sc_currates!\n", 687cc86f1eaSAdrian Chadd __func__); 688cc86f1eaSAdrian Chadd rix = 0; 689cc86f1eaSAdrian Chadd *try0 = ATH_TXMAXTRY; 690cc86f1eaSAdrian Chadd goto done; 691cc86f1eaSAdrian Chadd } 692cc86f1eaSAdrian Chadd 693c1565b61SSam Leffler if (sn->static_rix != -1) { 694c1565b61SSam Leffler rix = sn->static_rix; 695c1565b61SSam Leffler *try0 = ATH_TXMAXTRY; 696c1565b61SSam Leffler goto done; 697c1565b61SSam Leffler } 698fa20c234SSam Leffler 699af017101SAdrian Chadd mrr = sc->sc_mrretry; 700af017101SAdrian Chadd /* XXX check HT protmode too */ 701cce63444SAdrian Chadd /* XXX turn into a cap; 11n MACs support MRR+RTSCTS */ 7029f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 703af017101SAdrian Chadd mrr = 0; 704c1565b61SSam Leffler 70536958948SAdrian Chadd best_rix = pick_best_rate(an, rt, size_bin, !mrr); 706cce63444SAdrian Chadd 707cce63444SAdrian Chadd /* 708cce63444SAdrian Chadd * At this point we've chosen the best rix, so now we 709cce63444SAdrian Chadd * need to potentially update our maximum packet length 710cce63444SAdrian Chadd * and size_bin if we're doing 11n rates. 711cce63444SAdrian Chadd */ 712051ea90cSAdrian Chadd max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix, 713051ea90cSAdrian Chadd is_aggr); 714cce63444SAdrian Chadd if (max_pkt_len > 0) { 715cce63444SAdrian Chadd #if 0 716cce63444SAdrian Chadd device_printf(sc->sc_dev, 717cce63444SAdrian Chadd "Limiting maxpktlen from %d to %d bytes\n", 718cce63444SAdrian Chadd (int) frameLen, max_pkt_len); 719cce63444SAdrian Chadd #endif 720cce63444SAdrian Chadd *maxpktlen = frameLen = MIN(frameLen, max_pkt_len); 721cce63444SAdrian Chadd size_bin = size_to_bin(frameLen); 722cce63444SAdrian Chadd } 723cce63444SAdrian Chadd 724c1565b61SSam Leffler if (best_rix >= 0) { 725c1565b61SSam Leffler average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 726fa20c234SSam Leffler } else { 727b2763056SSam Leffler average_tx_time = 0; 728b2763056SSam Leffler } 729cce63444SAdrian Chadd 730fa20c234SSam Leffler /* 731c1565b61SSam Leffler * Limit the time measuring the performance of other tx 732c1565b61SSam Leffler * rates to sample_rate% of the total transmission time. 733fa20c234SSam Leffler */ 7345add7017SAdrian Chadd if (sn->sample_tt[size_bin] < 7355add7017SAdrian Chadd average_tx_time * 7365add7017SAdrian Chadd (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 73736958948SAdrian Chadd rix = pick_sample_rate(ssc, an, rt, size_bin); 738c1565b61SSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 7395add7017SAdrian Chadd &an->an_node, "att %d sample_tt %d size %u " 7405add7017SAdrian Chadd "sample rate %d %s current rate %d %s", 741eb6f0de0SAdrian Chadd average_tx_time, 742eb6f0de0SAdrian Chadd sn->sample_tt[size_bin], 743eb6f0de0SAdrian Chadd bin_to_size(size_bin), 744eb6f0de0SAdrian Chadd dot11rate(rt, rix), 745eb6f0de0SAdrian Chadd dot11rate_label(rt, rix), 746eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 747eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin])); 748c1565b61SSam Leffler if (rix != sn->current_rix[size_bin]) { 749c1565b61SSam Leffler sn->current_sample_rix[size_bin] = rix; 750b2763056SSam Leffler } else { 751c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 752b2763056SSam Leffler } 753b2763056SSam Leffler sn->packets_since_sample[size_bin] = 0; 754b2763056SSam Leffler } else { 755b91bf513SSam Leffler change_rates = 0; 756c1565b61SSam Leffler if (!sn->packets_sent[size_bin] || best_rix == -1) { 757b91bf513SSam Leffler /* no packet has been sent successfully yet */ 758b91bf513SSam Leffler change_rates = 1; 759eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) 760eb6f0de0SAdrian Chadd best_rix = 761eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(sc, an, frameLen); 762eb6f0de0SAdrian Chadd else 763eb6f0de0SAdrian Chadd best_rix = 764eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(sc, an, frameLen); 765b91bf513SSam Leffler } else if (sn->packets_sent[size_bin] < 20) { 766b91bf513SSam Leffler /* let the bit-rate switch quickly during the first few packets */ 767eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 768eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 769eb6f0de0SAdrian Chadd "%s: switching quickly..", __func__); 770b91bf513SSam Leffler change_rates = 1; 771c1565b61SSam Leffler } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 772c1565b61SSam Leffler /* min_switch seconds have gone by */ 773eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 774eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 775eb6f0de0SAdrian Chadd "%s: min_switch %d > ticks_since_switch %d..", 776eb6f0de0SAdrian Chadd __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]); 777b91bf513SSam Leffler change_rates = 1; 778eb6f0de0SAdrian Chadd } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) && 779eb6f0de0SAdrian Chadd (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) { 780b91bf513SSam Leffler /* the current bit-rate is twice as slow as the best one */ 781eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 782eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 783eb6f0de0SAdrian Chadd "%s: 2x att (= %d) < cur_rix att %d", 784eb6f0de0SAdrian Chadd __func__, 785eb6f0de0SAdrian Chadd 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time); 786b91bf513SSam Leffler change_rates = 1; 787eb6f0de0SAdrian Chadd } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) { 788eb6f0de0SAdrian Chadd int cur_rix = sn->current_rix[size_bin]; 789eb6f0de0SAdrian Chadd int cur_att = sn->stats[size_bin][cur_rix].average_tx_time; 790eb6f0de0SAdrian Chadd /* 791051ea90cSAdrian Chadd * If the node is HT, it if the rate isn't the 792051ea90cSAdrian Chadd * same and the average tx time is within 10% 793051ea90cSAdrian Chadd * of the current rate. It can fail a little. 794eb6f0de0SAdrian Chadd * 795eb6f0de0SAdrian Chadd * This is likely not optimal! 796eb6f0de0SAdrian Chadd */ 797eb6f0de0SAdrian Chadd #if 0 798eb6f0de0SAdrian Chadd printf("cur rix/att %x/%d, best rix/att %x/%d\n", 799eb6f0de0SAdrian Chadd MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time); 800eb6f0de0SAdrian Chadd #endif 8015add7017SAdrian Chadd if ((best_rix != cur_rix) && 8025add7017SAdrian Chadd (average_tx_time * 9) <= (cur_att * 10)) { 803eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 804eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 805cce63444SAdrian Chadd "%s: HT: size %d best_rix 0x%x > " 806cce63444SAdrian Chadd " cur_rix 0x%x, average_tx_time %d," 807cce63444SAdrian Chadd " cur_att %d", 808cce63444SAdrian Chadd __func__, bin_to_size(size_bin), 809cce63444SAdrian Chadd MCS(best_rix), MCS(cur_rix), 810cce63444SAdrian Chadd average_tx_time, cur_att); 811eb6f0de0SAdrian Chadd change_rates = 1; 812eb6f0de0SAdrian Chadd } 813b91bf513SSam Leffler } 814b91bf513SSam Leffler 815b91bf513SSam Leffler sn->packets_since_sample[size_bin]++; 816b91bf513SSam Leffler 817b91bf513SSam Leffler if (change_rates) { 818c1565b61SSam Leffler if (best_rix != sn->current_rix[size_bin]) { 819b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, 820b032f27cSSam Leffler IEEE80211_MSG_RATECTL, 821b032f27cSSam Leffler &an->an_node, 822cce63444SAdrian Chadd "%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d", 823b2763056SSam Leffler __func__, 824c1565b61SSam Leffler bin_to_size(size_bin), 825cce63444SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 826cce63444SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin]), 827c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 828c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 829cce63444SAdrian Chadd sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct, 830cce63444SAdrian Chadd dot11rate(rt, best_rix), 831cce63444SAdrian Chadd dot11rate_label(rt, best_rix), 832c1565b61SSam Leffler sn->stats[size_bin][best_rix].average_tx_time, 833c1565b61SSam Leffler sn->stats[size_bin][best_rix].perfect_tx_time, 834cce63444SAdrian Chadd sn->stats[size_bin][best_rix].ewma_pct, 835b2763056SSam Leffler sn->packets_since_switch[size_bin], 836b2763056SSam Leffler mrr); 837b2763056SSam Leffler } 838b2763056SSam Leffler sn->packets_since_switch[size_bin] = 0; 839c1565b61SSam Leffler sn->current_rix[size_bin] = best_rix; 840b91bf513SSam Leffler sn->ticks_since_switch[size_bin] = ticks; 841b032f27cSSam Leffler /* 842b032f27cSSam Leffler * Set the visible txrate for this node. 843b032f27cSSam Leffler */ 8445add7017SAdrian Chadd an->an_node.ni_txrate = 8455add7017SAdrian Chadd (rt->info[best_rix].phy == IEEE80211_T_HT) ? 8465add7017SAdrian Chadd MCS(best_rix) : DOT11RATE(best_rix); 847b2763056SSam Leffler } 848c1565b61SSam Leffler rix = sn->current_rix[size_bin]; 849b2763056SSam Leffler sn->packets_since_switch[size_bin]++; 850b91bf513SSam Leffler } 851c1565b61SSam Leffler *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 852c1565b61SSam Leffler done: 853cc86f1eaSAdrian Chadd 854cc86f1eaSAdrian Chadd /* 855cc86f1eaSAdrian Chadd * This bug totally sucks and should be fixed. 856cc86f1eaSAdrian Chadd * 857cc86f1eaSAdrian Chadd * For now though, let's not panic, so we can start to figure 858cc86f1eaSAdrian Chadd * out how to better reproduce it. 859cc86f1eaSAdrian Chadd */ 860cc86f1eaSAdrian Chadd if (rix < 0 || rix >= rt->rateCount) { 861cc86f1eaSAdrian Chadd printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n", 862cc86f1eaSAdrian Chadd __func__, 863cc86f1eaSAdrian Chadd rix, 864cc86f1eaSAdrian Chadd rt->rateCount); 865cc86f1eaSAdrian Chadd rix = 0; /* XXX just default for now */ 866cc86f1eaSAdrian Chadd } 867c1565b61SSam Leffler KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 868fa20c234SSam Leffler 869c1565b61SSam Leffler *rix0 = rix; 870c1565b61SSam Leffler *txrate = rt->info[rix].rateCode 871c1565b61SSam Leffler | (shortPreamble ? rt->info[rix].shortPreamble : 0); 872fa20c234SSam Leffler sn->packets_sent[size_bin]++; 873cce63444SAdrian Chadd 874c1565b61SSam Leffler #undef DOT11RATE 875a6a308a4SAdrian Chadd #undef MCS 876c1565b61SSam Leffler #undef RATE 877fa20c234SSam Leffler } 878fa20c234SSam Leffler 879710c3778SAdrian Chadd /* 880710c3778SAdrian Chadd * Get the TX rates. Don't fiddle with short preamble flags for them; 881710c3778SAdrian Chadd * the caller can do that. 882710c3778SAdrian Chadd */ 883710c3778SAdrian Chadd void 884710c3778SAdrian Chadd ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an, 885051ea90cSAdrian Chadd uint8_t rix0, int is_aggr, struct ath_rc_series *rc) 886710c3778SAdrian Chadd { 887710c3778SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 888710c3778SAdrian Chadd const struct txschedule *sched = &sn->sched[rix0]; 889710c3778SAdrian Chadd 890193bfa21SAdrian Chadd KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 891193bfa21SAdrian Chadd rix0, sched->r0)); 892710c3778SAdrian Chadd 893eb6f0de0SAdrian Chadd rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; 894710c3778SAdrian Chadd 895eb6f0de0SAdrian Chadd rc[0].rix = sched->r0; 896eb6f0de0SAdrian Chadd rc[1].rix = sched->r1; 897eb6f0de0SAdrian Chadd rc[2].rix = sched->r2; 898eb6f0de0SAdrian Chadd rc[3].rix = sched->r3; 899eb6f0de0SAdrian Chadd 900eb6f0de0SAdrian Chadd rc[0].tries = sched->t0; 901eb6f0de0SAdrian Chadd rc[1].tries = sched->t1; 902051ea90cSAdrian Chadd 903051ea90cSAdrian Chadd if (is_aggr) { 904051ea90cSAdrian Chadd rc[2].tries = rc[3].tries = 0; 905051ea90cSAdrian Chadd } else { 906eb6f0de0SAdrian Chadd rc[2].tries = sched->t2; 907eb6f0de0SAdrian Chadd rc[3].tries = sched->t3; 908710c3778SAdrian Chadd } 909051ea90cSAdrian Chadd } 910710c3778SAdrian Chadd 911fa20c234SSam Leffler void 912fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 913a4d8dd10SSam Leffler struct ath_desc *ds, int shortPreamble, u_int8_t rix) 914fa20c234SSam Leffler { 915fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 916c1565b61SSam Leffler const struct txschedule *sched = &sn->sched[rix]; 917c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 918c1565b61SSam Leffler uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 919fa20c234SSam Leffler 920c1565b61SSam Leffler /* XXX precalculate short preamble tables */ 921c1565b61SSam Leffler rix1 = sched->r1; 922c1565b61SSam Leffler s1code = rt->info[rix1].rateCode 923c1565b61SSam Leffler | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 924c1565b61SSam Leffler rix2 = sched->r2; 925c1565b61SSam Leffler s2code = rt->info[rix2].rateCode 926c1565b61SSam Leffler | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 927c1565b61SSam Leffler rix3 = sched->r3; 928c1565b61SSam Leffler s3code = rt->info[rix3].rateCode 929c1565b61SSam Leffler | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 930c1565b61SSam Leffler ath_hal_setupxtxdesc(sc->sc_ah, ds, 931c1565b61SSam Leffler s1code, sched->t1, /* series 1 */ 932c1565b61SSam Leffler s2code, sched->t2, /* series 2 */ 933c1565b61SSam Leffler s3code, sched->t3); /* series 3 */ 934fa20c234SSam Leffler } 935fa20c234SSam Leffler 936*cf431555SAdrian Chadd /* 937*cf431555SAdrian Chadd * Update the current statistics. 938*cf431555SAdrian Chadd * 939*cf431555SAdrian Chadd * Note that status is for the FINAL transmit status, not this 940*cf431555SAdrian Chadd * particular attempt. So, check if tries > tries0 and if so 941*cf431555SAdrian Chadd * assume this status failed. 942*cf431555SAdrian Chadd * 943*cf431555SAdrian Chadd * This is important because some failures are due to both 944*cf431555SAdrian Chadd * short AND long retries; if the final issue was a short 945*cf431555SAdrian Chadd * retry failure then we still want to account for the 946*cf431555SAdrian Chadd * bad long retry attempts. 947*cf431555SAdrian Chadd */ 948b2763056SSam Leffler static void 949b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an, 950b2763056SSam Leffler int frame_size, 951c1565b61SSam Leffler int rix0, int tries0, 952eb6f0de0SAdrian Chadd int short_tries, int tries, int status, 953eb6f0de0SAdrian Chadd int nframes, int nbad) 954fa20c234SSam Leffler { 955fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 956fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 957ec3dec2fSAdrian Chadd #ifdef IEEE80211_DEBUG 958eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 959ec3dec2fSAdrian Chadd #endif 960c1565b61SSam Leffler const int size_bin = size_to_bin(frame_size); 961c1565b61SSam Leffler const int size = bin_to_size(size_bin); 962*cf431555SAdrian Chadd int tt; 963532f2442SAdrian Chadd int is_ht40 = (an->an_node.ni_chw == 40); 964ee563d63SAdrian Chadd int pct; 965fa20c234SSam Leffler 966c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix0)) 96765f9edeeSSam Leffler return; 968cce63444SAdrian Chadd 969cce63444SAdrian Chadd /* 970*cf431555SAdrian Chadd * Treat long retries as us exceeding retries, even 971*cf431555SAdrian Chadd * if the eventual attempt at some other MRR schedule 972*cf431555SAdrian Chadd * succeeded. 973*cf431555SAdrian Chadd */ 974*cf431555SAdrian Chadd if (tries > tries0) { 975*cf431555SAdrian Chadd status = HAL_TXERR_XRETRY; 976*cf431555SAdrian Chadd } 977*cf431555SAdrian Chadd 978*cf431555SAdrian Chadd /* 979cce63444SAdrian Chadd * If status is FAIL then we treat all frames as bad. 980cce63444SAdrian Chadd * This better accurately tracks EWMA and average TX time 981cce63444SAdrian Chadd * because even if the eventual transmission succeeded, 982cce63444SAdrian Chadd * transmission at this rate did not. 983cce63444SAdrian Chadd */ 984cce63444SAdrian Chadd if (status != 0) 985cce63444SAdrian Chadd nbad = nframes; 986cce63444SAdrian Chadd 987051ea90cSAdrian Chadd /* 988051ea90cSAdrian Chadd * Ignore short tries count as contributing to failure. 989051ea90cSAdrian Chadd * Right now there's no way to know if it's part of any 990051ea90cSAdrian Chadd * given rate attempt, and outside of the RTS/CTS management 991051ea90cSAdrian Chadd * rate, it doesn't /really/ help. 992051ea90cSAdrian Chadd */ 993051ea90cSAdrian Chadd tt = calc_usecs_unicast_packet(sc, size, rix0, 994051ea90cSAdrian Chadd 0 /* short_tries */, MIN(tries0, tries) - 1, is_ht40); 995c1565b61SSam Leffler 996c1565b61SSam Leffler if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 997fa20c234SSam Leffler /* just average the first few packets */ 998c1565b61SSam Leffler int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 999c1565b61SSam Leffler int packets = sn->stats[size_bin][rix0].total_packets; 1000eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); 1001fa20c234SSam Leffler } else { 1002fa20c234SSam Leffler /* use a ewma */ 1003c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time = 1004c1565b61SSam Leffler ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 1005c1565b61SSam Leffler (tt * (100 - ssc->smoothing_rate))) / 100; 1006fa20c234SSam Leffler } 1007fa20c234SSam Leffler 1008eb6f0de0SAdrian Chadd if (nframes == nbad) { 1009eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].successive_failures += nbad; 1010fa20c234SSam Leffler } else { 1011eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); 1012c1565b61SSam Leffler sn->stats[size_bin][rix0].successive_failures = 0; 1013fa20c234SSam Leffler } 1014c1565b61SSam Leffler sn->stats[size_bin][rix0].tries += tries; 1015c1565b61SSam Leffler sn->stats[size_bin][rix0].last_tx = ticks; 1016eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].total_packets += nframes; 1017b2763056SSam Leffler 1018ee563d63SAdrian Chadd /* update EWMA for this rix */ 1019ee563d63SAdrian Chadd 1020ee563d63SAdrian Chadd /* Calculate percentage based on current rate */ 1021ee563d63SAdrian Chadd if (nframes == 0) 1022ee563d63SAdrian Chadd nframes = nbad = 1; 1023ee563d63SAdrian Chadd pct = ((nframes - nbad) * 1000) / nframes; 1024ee563d63SAdrian Chadd 1025ee563d63SAdrian Chadd if (sn->stats[size_bin][rix0].total_packets < 1026ee563d63SAdrian Chadd ssc->smoothing_minpackets) { 1027ee563d63SAdrian Chadd /* just average the first few packets */ 1028ee563d63SAdrian Chadd int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) / 1029ee563d63SAdrian Chadd (sn->stats[size_bin][rix0].total_packets); 1030ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = a_pct; 1031ee563d63SAdrian Chadd } else { 1032ee563d63SAdrian Chadd /* use a ewma */ 1033ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = 1034ee563d63SAdrian Chadd ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) + 1035ee563d63SAdrian Chadd (pct * (100 - ssc->smoothing_rate))) / 100; 1036ee563d63SAdrian Chadd } 1037ee563d63SAdrian Chadd 1038cce63444SAdrian Chadd /* 1039cce63444SAdrian Chadd * Only update the sample time for the initial sample rix. 1040cce63444SAdrian Chadd * We've updated the statistics on each of the other retries 1041cce63444SAdrian Chadd * fine, but we should only update the sample_tt with what 1042cce63444SAdrian Chadd * was actually sampled. 1043cce63444SAdrian Chadd * 1044cce63444SAdrian Chadd * However, to aide in debugging, log all the failures for 1045cce63444SAdrian Chadd * each of the buckets 1046cce63444SAdrian Chadd */ 1047b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1048b032f27cSSam Leffler &an->an_node, 1049cce63444SAdrian Chadd "%s: size %d %s %s rate %d %s tries (%d/%d) tt %d " 1050cce63444SAdrian Chadd "avg_tt (%d/%d) nfrm %d nbad %d", 1051b032f27cSSam Leffler __func__, 105265f9edeeSSam Leffler size, 105365f9edeeSSam Leffler status ? "FAIL" : "OK", 1054cce63444SAdrian Chadd rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr", 1055eb6f0de0SAdrian Chadd dot11rate(rt, rix0), 1056eb6f0de0SAdrian Chadd dot11rate_label(rt, rix0), 1057eb6f0de0SAdrian Chadd short_tries, tries, tt, 1058c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time, 1059eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].perfect_tx_time, 1060eb6f0de0SAdrian Chadd nframes, nbad); 1061cce63444SAdrian Chadd 1062cce63444SAdrian Chadd if (rix0 == sn->current_sample_rix[size_bin]) { 1063b2763056SSam Leffler sn->sample_tt[size_bin] = tt; 1064c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 1065b2763056SSam Leffler } 1066b2763056SSam Leffler } 1067b2763056SSam Leffler 1068ec9ee5e7SSam Leffler static void 106976e6fd5dSGleb Smirnoff badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status) 1070ec9ee5e7SSam Leffler { 107176e6fd5dSGleb Smirnoff 107276e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 107376e6fd5dSGleb Smirnoff "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 1074ec9ee5e7SSam Leffler series, hwrate, tries, status); 1075ec9ee5e7SSam Leffler } 1076ec9ee5e7SSam Leffler 1077b2763056SSam Leffler void 107843e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 1079eb6f0de0SAdrian Chadd const struct ath_rc_series *rc, const struct ath_tx_status *ts, 1080cce63444SAdrian Chadd int frame_size, int rc_framesize, int nframes, int nbad) 1081b2763056SSam Leffler { 10827a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1083b2763056SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1084eb6f0de0SAdrian Chadd int final_rix, short_tries, long_tries; 108546d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1086eb6f0de0SAdrian Chadd int status = ts->ts_status; 10871bb9a085SSam Leffler int mrr; 1088b2763056SSam Leffler 1089f6cbf16aSSam Leffler final_rix = rt->rateCodeToIndex[ts->ts_rate]; 109065f9edeeSSam Leffler short_tries = ts->ts_shortretry; 109165f9edeeSSam Leffler long_tries = ts->ts_longretry + 1; 1092eb6f0de0SAdrian Chadd 1093ee563d63SAdrian Chadd if (nframes == 0) { 1094ee563d63SAdrian Chadd device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__); 1095ee563d63SAdrian Chadd return; 1096ee563d63SAdrian Chadd } 1097ee563d63SAdrian Chadd 109843e9cf7cSSam Leffler if (frame_size == 0) /* NB: should not happen */ 1099b2763056SSam Leffler frame_size = 1500; 1100cce63444SAdrian Chadd if (rc_framesize == 0) /* NB: should not happen */ 1101cce63444SAdrian Chadd rc_framesize = 1500; 1102cce63444SAdrian Chadd 1103cce63444SAdrian Chadd /* 1104cce63444SAdrian Chadd * There are still some places where what rate control set as 1105cce63444SAdrian Chadd * a limit but the hardware decided, for some reason, to transmit 1106cce63444SAdrian Chadd * at a smaller size that fell into a different bucket. 1107cce63444SAdrian Chadd * 1108cce63444SAdrian Chadd * The eternal question here is - which size_bin should it go in? 1109cce63444SAdrian Chadd * The one that was requested, or the one that was transmitted? 1110cce63444SAdrian Chadd * 1111cce63444SAdrian Chadd * Here's the problem - if we use the one that was transmitted, 1112cce63444SAdrian Chadd * we may continue to hit corner cases where we make a rate 1113cce63444SAdrian Chadd * selection using a higher bin but only update the smaller bin; 1114cce63444SAdrian Chadd * thus never really "adapting". 1115cce63444SAdrian Chadd * 1116cce63444SAdrian Chadd * If however we update the larger bin, we're not accurately 1117cce63444SAdrian Chadd * representing the channel state at that frame/aggregate size. 1118cce63444SAdrian Chadd * However if we keep hitting the larger request but completing 1119cce63444SAdrian Chadd * a smaller size, we at least updates based on what the 1120cce63444SAdrian Chadd * request was /for/. 1121cce63444SAdrian Chadd * 1122cce63444SAdrian Chadd * I'm going to err on the side of caution and choose the 1123cce63444SAdrian Chadd * latter. 1124cce63444SAdrian Chadd */ 1125cce63444SAdrian Chadd if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) { 1126cce63444SAdrian Chadd #if 0 1127cce63444SAdrian Chadd device_printf(sc->sc_dev, 1128cce63444SAdrian Chadd "%s: completed but frame size buckets mismatch " 1129cce63444SAdrian Chadd "(completed %d tx'ed %d)\n", 1130cce63444SAdrian Chadd __func__, frame_size, rc_framesize); 1131cce63444SAdrian Chadd #endif 1132cce63444SAdrian Chadd frame_size = rc_framesize; 1133cce63444SAdrian Chadd } 1134b2763056SSam Leffler 1135c1565b61SSam Leffler if (sn->ratemask == 0) { 1136b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1137b032f27cSSam Leffler &an->an_node, 1138b032f27cSSam Leffler "%s: size %d %s rate/try %d/%d no rates yet", 1139b032f27cSSam Leffler __func__, 114043e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1141eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 114243e9cf7cSSam Leffler short_tries, long_tries); 1143b2763056SSam Leffler return; 1144b2763056SSam Leffler } 1145af017101SAdrian Chadd mrr = sc->sc_mrretry; 1146af017101SAdrian Chadd /* XXX check HT protmode too */ 11479f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 1148af017101SAdrian Chadd mrr = 0; 1149af017101SAdrian Chadd 1150f6cbf16aSSam Leffler if (!mrr || ts->ts_finaltsi == 0) { 1151c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, final_rix)) { 115276e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 115376e6fd5dSGleb Smirnoff "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", 115406c746edSAdrian Chadd __func__, ts->ts_rate, ts->ts_finaltsi, final_rix); 115576e6fd5dSGleb Smirnoff badrate(sc, 0, ts->ts_rate, long_tries, status); 1156ec9ee5e7SSam Leffler return; 1157ec9ee5e7SSam Leffler } 115865f9edeeSSam Leffler /* 115965f9edeeSSam Leffler * Only one rate was used; optimize work. 116065f9edeeSSam Leffler */ 1161b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1162f6fd8c7aSAdrian Chadd &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]", 1163b032f27cSSam Leffler __func__, 116443e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1165c4ac32a8SAdrian Chadd frame_size, 1166eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1167eb6f0de0SAdrian Chadd dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), 1168eb6f0de0SAdrian Chadd short_tries, long_tries, nframes, nbad); 1169b2763056SSam Leffler update_stats(sc, an, frame_size, 1170c1565b61SSam Leffler final_rix, long_tries, 1171eb6f0de0SAdrian Chadd short_tries, long_tries, status, 1172eb6f0de0SAdrian Chadd nframes, nbad); 1173eb6f0de0SAdrian Chadd 1174b2763056SSam Leffler } else { 117565f9edeeSSam Leffler int finalTSIdx = ts->ts_finaltsi; 1176bd97c52aSAdrian Chadd int i; 1177b2763056SSam Leffler 1178b2763056SSam Leffler /* 1179b2763056SSam Leffler * Process intermediate rates that failed. 1180b2763056SSam Leffler */ 1181ec9ee5e7SSam Leffler 1182b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1183b032f27cSSam Leffler &an->an_node, 1184f6fd8c7aSAdrian 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]", 1185b032f27cSSam Leffler __func__, 1186b2763056SSam Leffler bin_to_size(size_to_bin(frame_size)), 1187c4ac32a8SAdrian Chadd frame_size, 1188b2763056SSam Leffler finalTSIdx, 1189f6fd8c7aSAdrian Chadd short_tries, 1190b2763056SSam Leffler long_tries, 1191eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1192eb6f0de0SAdrian Chadd dot11rate(rt, rc[0].rix), 1193eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[0].rix), rc[0].tries, 1194eb6f0de0SAdrian Chadd dot11rate(rt, rc[1].rix), 1195eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[1].rix), rc[1].tries, 1196eb6f0de0SAdrian Chadd dot11rate(rt, rc[2].rix), 1197eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[2].rix), rc[2].tries, 1198eb6f0de0SAdrian Chadd dot11rate(rt, rc[3].rix), 1199eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[3].rix), rc[3].tries, 1200eb6f0de0SAdrian Chadd nframes, nbad); 1201c1565b61SSam Leffler 1202a6a308a4SAdrian Chadd for (i = 0; i < 4; i++) { 1203eb6f0de0SAdrian Chadd if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) 120476e6fd5dSGleb Smirnoff badrate(sc, 0, rc[i].ratecode, rc[i].tries, 1205eb6f0de0SAdrian Chadd status); 1206a6a308a4SAdrian Chadd } 1207b2763056SSam Leffler 120865f9edeeSSam Leffler /* 1209cce63444SAdrian Chadd * This used to not penalise other tries because loss 1210cce63444SAdrian Chadd * can be bursty, but it's then not accurately keeping 1211cce63444SAdrian Chadd * the avg TX time and EWMA updated. 121265f9edeeSSam Leffler */ 1213eb6f0de0SAdrian Chadd if (rc[0].tries) { 1214b2763056SSam Leffler update_stats(sc, an, frame_size, 1215eb6f0de0SAdrian Chadd rc[0].rix, rc[0].tries, 121665f9edeeSSam Leffler short_tries, long_tries, 1217*cf431555SAdrian Chadd status, 1218eb6f0de0SAdrian Chadd nframes, nbad); 1219eb6f0de0SAdrian Chadd long_tries -= rc[0].tries; 1220b2763056SSam Leffler } 1221b2763056SSam Leffler 1222eb6f0de0SAdrian Chadd if (rc[1].tries && finalTSIdx > 0) { 1223b2763056SSam Leffler update_stats(sc, an, frame_size, 1224eb6f0de0SAdrian Chadd rc[1].rix, rc[1].tries, 122565f9edeeSSam Leffler short_tries, long_tries, 1226*cf431555SAdrian Chadd status, 1227eb6f0de0SAdrian Chadd nframes, nbad); 1228eb6f0de0SAdrian Chadd long_tries -= rc[1].tries; 1229b2763056SSam Leffler } 1230b2763056SSam Leffler 1231eb6f0de0SAdrian Chadd if (rc[2].tries && finalTSIdx > 1) { 1232b2763056SSam Leffler update_stats(sc, an, frame_size, 1233eb6f0de0SAdrian Chadd rc[2].rix, rc[2].tries, 123465f9edeeSSam Leffler short_tries, long_tries, 1235*cf431555SAdrian Chadd status, 1236eb6f0de0SAdrian Chadd nframes, nbad); 1237eb6f0de0SAdrian Chadd long_tries -= rc[2].tries; 1238b2763056SSam Leffler } 1239b2763056SSam Leffler 1240eb6f0de0SAdrian Chadd if (rc[3].tries && finalTSIdx > 2) { 1241b2763056SSam Leffler update_stats(sc, an, frame_size, 1242eb6f0de0SAdrian Chadd rc[3].rix, rc[3].tries, 124365f9edeeSSam Leffler short_tries, long_tries, 1244*cf431555SAdrian Chadd status, 1245eb6f0de0SAdrian Chadd nframes, nbad); 124638fda926SAdrian Chadd } 1247b2763056SSam Leffler } 1248fa20c234SSam Leffler } 1249fa20c234SSam Leffler 1250fa20c234SSam Leffler void 1251fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 1252fa20c234SSam Leffler { 1253fa20c234SSam Leffler if (isnew) 1254b2763056SSam Leffler ath_rate_ctl_reset(sc, &an->an_node); 1255fa20c234SSam Leffler } 1256fa20c234SSam Leffler 12577d450faaSAdrian Chadd void 12587d450faaSAdrian Chadd ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi) 12597d450faaSAdrian Chadd { 12607d450faaSAdrian Chadd } 12617d450faaSAdrian Chadd 12627d450faaSAdrian Chadd 1263c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 1264c1565b61SSam Leffler NULL, /* IEEE80211_MODE_AUTO */ 1265c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_11A */ 1266c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11B */ 1267c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11G */ 1268c1565b61SSam Leffler NULL, /* IEEE80211_MODE_FH */ 1269c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_TURBO_A */ 1270c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_TURBO_G */ 1271c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_STURBO_A */ 1272a6a308a4SAdrian Chadd series_11na, /* IEEE80211_MODE_11NA */ 1273a6a308a4SAdrian Chadd series_11ng, /* IEEE80211_MODE_11NG */ 1274c1565b61SSam Leffler series_half, /* IEEE80211_MODE_HALF */ 1275c1565b61SSam Leffler series_quarter, /* IEEE80211_MODE_QUARTER */ 1276c1565b61SSam Leffler }; 1277c1565b61SSam Leffler 1278fa20c234SSam Leffler /* 1279fa20c234SSam Leffler * Initialize the tables for a node. 1280fa20c234SSam Leffler */ 1281fa20c234SSam Leffler static void 1282b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 1283fa20c234SSam Leffler { 1284fa20c234SSam Leffler #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 1285c1565b61SSam Leffler #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 1286a6a308a4SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 1287fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 1288fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1289fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1290c4ac32a8SAdrian Chadd int x, y, rix; 1291fa20c234SSam Leffler 1292fa20c234SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 1293c1565b61SSam Leffler 1294c1565b61SSam Leffler KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 1295c1565b61SSam Leffler ("curmode %u", sc->sc_curmode)); 1296193bfa21SAdrian Chadd 1297c1565b61SSam Leffler sn->sched = mrr_schedules[sc->sc_curmode]; 1298c1565b61SSam Leffler KASSERT(sn->sched != NULL, 1299c1565b61SSam Leffler ("no mrr schedule for mode %u", sc->sc_curmode)); 1300c1565b61SSam Leffler 1301c1565b61SSam Leffler sn->static_rix = -1; 1302c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, ni); 1303b2763056SSam Leffler 1304cc86f1eaSAdrian Chadd sn->currates = sc->sc_currates; 1305cc86f1eaSAdrian Chadd 1306c1565b61SSam Leffler /* 1307c1565b61SSam Leffler * Construct a bitmask of usable rates. This has all 1308c1565b61SSam Leffler * negotiated rates minus those marked by the hal as 1309c1565b61SSam Leffler * to be ignored for doing rate control. 1310c1565b61SSam Leffler */ 1311c1565b61SSam Leffler sn->ratemask = 0; 1312a6a308a4SAdrian Chadd /* MCS rates */ 1313a6a308a4SAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_HT) { 1314a6a308a4SAdrian Chadd for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { 1315a6a308a4SAdrian Chadd rix = sc->sc_rixmap[MCS(x)]; 1316a6a308a4SAdrian Chadd if (rix == 0xff) 1317a6a308a4SAdrian Chadd continue; 1318a6a308a4SAdrian Chadd /* skip rates marked broken by hal */ 1319a6a308a4SAdrian Chadd if (!rt->info[rix].valid) 1320a6a308a4SAdrian Chadd continue; 1321a6a308a4SAdrian Chadd KASSERT(rix < SAMPLE_MAXRATES, 1322a6a308a4SAdrian Chadd ("mcs %u has rix %d", MCS(x), rix)); 1323193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1324a6a308a4SAdrian Chadd } 1325a6a308a4SAdrian Chadd } 1326a6a308a4SAdrian Chadd 1327a6a308a4SAdrian Chadd /* Legacy rates */ 1328fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 1329c1565b61SSam Leffler rix = sc->sc_rixmap[RATE(x)]; 1330c1565b61SSam Leffler if (rix == 0xff) 13310ae09ec5SSam Leffler continue; 1332c1565b61SSam Leffler /* skip rates marked broken by hal */ 1333c1565b61SSam Leffler if (!rt->info[rix].valid) 1334c1565b61SSam Leffler continue; 1335c1565b61SSam Leffler KASSERT(rix < SAMPLE_MAXRATES, 1336c1565b61SSam Leffler ("rate %u has rix %d", RATE(x), rix)); 1337193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1338b2763056SSam Leffler } 1339b032f27cSSam Leffler #ifdef IEEE80211_DEBUG 1340b032f27cSSam Leffler if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 1341193bfa21SAdrian Chadd uint64_t mask; 1342c1565b61SSam Leffler 1343b032f27cSSam Leffler ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 1344c1565b61SSam Leffler ni->ni_macaddr, ":", __func__); 1345c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1346c1565b61SSam Leffler if ((mask & 1) == 0) 1347b032f27cSSam Leffler continue; 1348ae0944b8SAdrian Chadd printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), 1349e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, 1600, rix, 0,0, 1350532f2442SAdrian Chadd (ni->ni_chw == 40))); 1351b032f27cSSam Leffler } 1352b032f27cSSam Leffler printf("\n"); 1353b032f27cSSam Leffler } 1354b032f27cSSam Leffler #endif 1355b2763056SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1356b2763056SSam Leffler int size = bin_to_size(y); 1357193bfa21SAdrian Chadd uint64_t mask; 1358c1565b61SSam Leffler 1359b2763056SSam Leffler sn->packets_sent[y] = 0; 1360c1565b61SSam Leffler sn->current_sample_rix[y] = -1; 1361c1565b61SSam Leffler sn->last_sample_rix[y] = 0; 1362c1565b61SSam Leffler /* XXX start with first valid rate */ 1363c1565b61SSam Leffler sn->current_rix[y] = ffs(sn->ratemask)-1; 1364b2763056SSam Leffler 1365c1565b61SSam Leffler /* 1366c1565b61SSam Leffler * Initialize the statistics buckets; these are 1367c1565b61SSam Leffler * indexed by the rate code index. 1368c1565b61SSam Leffler */ 1369c1565b61SSam Leffler for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 1370c1565b61SSam Leffler if ((mask & 1) == 0) /* not a valid rate */ 1371c1565b61SSam Leffler continue; 1372c1565b61SSam Leffler sn->stats[y][rix].successive_failures = 0; 1373c1565b61SSam Leffler sn->stats[y][rix].tries = 0; 1374c1565b61SSam Leffler sn->stats[y][rix].total_packets = 0; 1375c1565b61SSam Leffler sn->stats[y][rix].packets_acked = 0; 1376c1565b61SSam Leffler sn->stats[y][rix].last_tx = 0; 1377eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct = 0; 1378b2763056SSam Leffler 1379c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time = 1380e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, size, rix, 0, 0, 1381532f2442SAdrian Chadd (ni->ni_chw == 40)); 1382c1565b61SSam Leffler sn->stats[y][rix].average_tx_time = 1383c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time; 1384b2763056SSam Leffler } 1385b91bf513SSam Leffler } 1386c1565b61SSam Leffler #if 0 1387c1565b61SSam Leffler /* XXX 0, num_rates-1 are wrong */ 1388b032f27cSSam Leffler IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 1389b032f27cSSam Leffler "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 1390b91bf513SSam Leffler sn->num_rates, 1391c1565b61SSam Leffler DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 1392b91bf513SSam Leffler sn->stats[1][0].perfect_tx_time, 1393c1565b61SSam Leffler DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 1394b91bf513SSam Leffler sn->stats[1][sn->num_rates-1].perfect_tx_time 1395b91bf513SSam Leffler ); 1396c1565b61SSam Leffler #endif 1397b032f27cSSam Leffler /* set the visible bit-rate */ 1398c1565b61SSam Leffler if (sn->static_rix != -1) 1399c1565b61SSam Leffler ni->ni_txrate = DOT11RATE(sn->static_rix); 1400d0d425bfSSam Leffler else 1401c1565b61SSam Leffler ni->ni_txrate = RATE(0); 1402fa20c234SSam Leffler #undef RATE 1403c1565b61SSam Leffler #undef DOT11RATE 1404fa20c234SSam Leffler } 1405fa20c234SSam Leffler 14062d20d655SAdrian Chadd /* 14072d20d655SAdrian Chadd * Fetch the statistics for the given node. 14082d20d655SAdrian Chadd * 14092d20d655SAdrian Chadd * The ieee80211 node must be referenced and unlocked, however the ath_node 14102d20d655SAdrian Chadd * must be locked. 14112d20d655SAdrian Chadd * 14122d20d655SAdrian Chadd * The main difference here is that we convert the rate indexes 14132d20d655SAdrian Chadd * to 802.11 rates, or the userland output won't make much sense 14142d20d655SAdrian Chadd * as it has no access to the rix table. 14152d20d655SAdrian Chadd */ 14162d20d655SAdrian Chadd int 14172d20d655SAdrian Chadd ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an, 14182d20d655SAdrian Chadd struct ath_rateioctl *rs) 14192d20d655SAdrian Chadd { 14202d20d655SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 14212d20d655SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 14222d20d655SAdrian Chadd struct ath_rateioctl_tlv av; 1423be4f96a6SAdrian Chadd struct ath_rateioctl_rt *tv; 14242d20d655SAdrian Chadd int y; 1425be4f96a6SAdrian Chadd int o = 0; 14262d20d655SAdrian Chadd 14272d20d655SAdrian Chadd ATH_NODE_LOCK_ASSERT(an); 14282d20d655SAdrian Chadd 14292d20d655SAdrian Chadd /* 14302d20d655SAdrian Chadd * Ensure there's enough space for the statistics. 14312d20d655SAdrian Chadd */ 14322d20d655SAdrian Chadd if (rs->len < 14332d20d655SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1434be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_rt) + 1435be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1436be4f96a6SAdrian Chadd sizeof(struct sample_node)) { 1437be4f96a6SAdrian Chadd device_printf(sc->sc_dev, "%s: len=%d, too short\n", 1438be4f96a6SAdrian Chadd __func__, 1439be4f96a6SAdrian Chadd rs->len); 14402d20d655SAdrian Chadd return (EINVAL); 1441be4f96a6SAdrian Chadd } 14422d20d655SAdrian Chadd 14432d20d655SAdrian Chadd /* 14442d20d655SAdrian Chadd * Take a temporary copy of the sample node state so we can 14452d20d655SAdrian Chadd * modify it before we copy it. 14462d20d655SAdrian Chadd */ 1447be4f96a6SAdrian Chadd tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP, 1448be4f96a6SAdrian Chadd M_NOWAIT | M_ZERO); 1449be4f96a6SAdrian Chadd if (tv == NULL) { 14502d20d655SAdrian Chadd return (ENOMEM); 14512d20d655SAdrian Chadd } 14522d20d655SAdrian Chadd 14532d20d655SAdrian Chadd /* 1454be4f96a6SAdrian Chadd * Populate the rate table mapping TLV. 1455be4f96a6SAdrian Chadd */ 1456be4f96a6SAdrian Chadd tv->nentries = rt->rateCount; 1457be4f96a6SAdrian Chadd for (y = 0; y < rt->rateCount; y++) { 1458be4f96a6SAdrian Chadd tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL; 1459be4f96a6SAdrian Chadd if (rt->info[y].phy == IEEE80211_T_HT) 1460be4f96a6SAdrian Chadd tv->ratecode[y] |= IEEE80211_RATE_MCS; 1461be4f96a6SAdrian Chadd } 1462be4f96a6SAdrian Chadd 1463be4f96a6SAdrian Chadd o = 0; 1464be4f96a6SAdrian Chadd /* 1465be4f96a6SAdrian Chadd * First TLV - rate code mapping 1466be4f96a6SAdrian Chadd */ 1467be4f96a6SAdrian Chadd av.tlv_id = ATH_RATE_TLV_RATETABLE; 1468be4f96a6SAdrian Chadd av.tlv_len = sizeof(struct ath_rateioctl_rt); 1469be4f96a6SAdrian Chadd copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1470be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 1471be4f96a6SAdrian Chadd copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); 1472be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_rt); 1473be4f96a6SAdrian Chadd 1474be4f96a6SAdrian Chadd /* 1475be4f96a6SAdrian Chadd * Second TLV - sample node statistics 14762d20d655SAdrian Chadd */ 14772d20d655SAdrian Chadd av.tlv_id = ATH_RATE_TLV_SAMPLENODE; 14782d20d655SAdrian Chadd av.tlv_len = sizeof(struct sample_node); 1479be4f96a6SAdrian Chadd copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1480be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 14812d20d655SAdrian Chadd 14822d20d655SAdrian Chadd /* 14832d20d655SAdrian Chadd * Copy the statistics over to the provided buffer. 14842d20d655SAdrian Chadd */ 1485be4f96a6SAdrian Chadd copyout(sn, rs->buf + o, sizeof(struct sample_node)); 1486be4f96a6SAdrian Chadd o += sizeof(struct sample_node); 14872d20d655SAdrian Chadd 1488be4f96a6SAdrian Chadd free(tv, M_TEMP); 14892d20d655SAdrian Chadd 14902d20d655SAdrian Chadd return (0); 14912d20d655SAdrian Chadd } 14922d20d655SAdrian Chadd 1493f0fd5e07SSam Leffler static void 1494c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni) 1495c1565b61SSam Leffler { 1496c1565b61SSam Leffler struct ath_softc *sc = arg; 1497c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1498c1565b61SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 1499193bfa21SAdrian Chadd uint64_t mask; 1500c1565b61SSam Leffler int rix, y; 1501c1565b61SSam Leffler 1502a055e7ceSKonstantin Belousov printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n", 1503c1565b61SSam Leffler ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 1504eb6f0de0SAdrian Chadd dot11rate(rt, sn->static_rix), 1505eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->static_rix), 1506a055e7ceSKonstantin Belousov (uintmax_t)sn->ratemask); 1507c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1508ae0944b8SAdrian Chadd printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n", 1509c1565b61SSam Leffler bin_to_size(y), sn->current_rix[y], 1510ae0944b8SAdrian Chadd dot11rate(rt, sn->current_rix[y]), 1511ae0944b8SAdrian Chadd dot11rate_label(rt, sn->current_rix[y]), 1512c1565b61SSam Leffler sn->packets_since_switch[y], sn->ticks_since_switch[y]); 1513eb6f0de0SAdrian Chadd printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n", 1514eb6f0de0SAdrian Chadd bin_to_size(y), 1515eb6f0de0SAdrian Chadd dot11rate(rt, sn->last_sample_rix[y]), 1516eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->last_sample_rix[y]), 1517eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_sample_rix[y]), 1518eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_sample_rix[y]), 1519eb6f0de0SAdrian Chadd sn->packets_sent[y]); 1520c1565b61SSam Leffler printf("[%4u] packets since sample %d sample tt %u\n", 1521c1565b61SSam Leffler bin_to_size(y), sn->packets_since_sample[y], 1522c1565b61SSam Leffler sn->sample_tt[y]); 1523c1565b61SSam Leffler } 1524c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1525c1565b61SSam Leffler if ((mask & 1) == 0) 1526c1565b61SSam Leffler continue; 1527c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1528c1565b61SSam Leffler if (sn->stats[y][rix].total_packets == 0) 1529c1565b61SSam Leffler continue; 1530eb6f0de0SAdrian Chadd printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n", 1531ae0944b8SAdrian Chadd dot11rate(rt, rix), dot11rate_label(rt, rix), 1532c1565b61SSam Leffler bin_to_size(y), 153387acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].total_packets, 153487acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].packets_acked, 153587acb7d5SAdrian Chadd (int) ((sn->stats[y][rix].packets_acked * 100ULL) / 153687acb7d5SAdrian Chadd sn->stats[y][rix].total_packets), 1537eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct / 10, 1538eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct % 10, 153987acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].tries, 1540c1565b61SSam Leffler sn->stats[y][rix].successive_failures, 1541c1565b61SSam Leffler sn->stats[y][rix].average_tx_time, 1542c1565b61SSam Leffler ticks - sn->stats[y][rix].last_tx); 1543c1565b61SSam Leffler } 1544c1565b61SSam Leffler } 1545c1565b61SSam Leffler } 1546c1565b61SSam Leffler 1547c1565b61SSam Leffler static int 1548c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 1549c1565b61SSam Leffler { 1550c1565b61SSam Leffler struct ath_softc *sc = arg1; 15517a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1552c1565b61SSam Leffler int error, v; 1553c1565b61SSam Leffler 1554c1565b61SSam Leffler v = 0; 1555c1565b61SSam Leffler error = sysctl_handle_int(oidp, &v, 0, req); 1556c1565b61SSam Leffler if (error || !req->newptr) 1557c1565b61SSam Leffler return error; 1558c1565b61SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 1559c1565b61SSam Leffler return 0; 1560c1565b61SSam Leffler } 1561c1565b61SSam Leffler 1562c1565b61SSam Leffler static int 1563c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 1564c1565b61SSam Leffler { 1565c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1566c1565b61SSam Leffler int rate, error; 1567c1565b61SSam Leffler 1568c1565b61SSam Leffler rate = ssc->smoothing_rate; 1569c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1570c1565b61SSam Leffler if (error || !req->newptr) 1571c1565b61SSam Leffler return error; 1572c1565b61SSam Leffler if (!(0 <= rate && rate < 100)) 1573c1565b61SSam Leffler return EINVAL; 1574c1565b61SSam Leffler ssc->smoothing_rate = rate; 1575c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - rate); 1576c1565b61SSam Leffler return 0; 1577c1565b61SSam Leffler } 1578c1565b61SSam Leffler 1579c1565b61SSam Leffler static int 1580c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 1581c1565b61SSam Leffler { 1582c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1583c1565b61SSam Leffler int rate, error; 1584c1565b61SSam Leffler 1585c1565b61SSam Leffler rate = ssc->sample_rate; 1586c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1587c1565b61SSam Leffler if (error || !req->newptr) 1588c1565b61SSam Leffler return error; 1589c1565b61SSam Leffler if (!(2 <= rate && rate <= 100)) 1590c1565b61SSam Leffler return EINVAL; 1591c1565b61SSam Leffler ssc->sample_rate = rate; 1592c1565b61SSam Leffler return 0; 1593c1565b61SSam Leffler } 1594c1565b61SSam Leffler 1595c1565b61SSam Leffler static void 1596c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 1597fa20c234SSam Leffler { 1598fa20c234SSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 1599fa20c234SSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 1600fa20c234SSam Leffler 1601c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 160208f5e6bbSPawel Biernacki "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 160308f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_smoothing_rate, "I", 1604c1565b61SSam Leffler "sample: smoothing rate for avg tx time (%%)"); 1605c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 160608f5e6bbSPawel Biernacki "sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 160708f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_sample_rate, "I", 1608c1565b61SSam Leffler "sample: percent air time devoted to sampling new rates (%%)"); 1609c1565b61SSam Leffler /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 1610c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 161108f5e6bbSPawel Biernacki "sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 161208f5e6bbSPawel Biernacki sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics"); 1613fa20c234SSam Leffler } 1614fa20c234SSam Leffler 1615fa20c234SSam Leffler struct ath_ratectrl * 1616fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc) 1617fa20c234SSam Leffler { 1618c1565b61SSam Leffler struct sample_softc *ssc; 1619fa20c234SSam Leffler 1620c1565b61SSam Leffler ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 1621c1565b61SSam Leffler if (ssc == NULL) 1622fa20c234SSam Leffler return NULL; 1623c1565b61SSam Leffler ssc->arc.arc_space = sizeof(struct sample_node); 1624e69db8dfSAdrian Chadd ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */ 1625c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 1626c1565b61SSam Leffler ssc->sample_rate = 10; /* %time to try diff tx rates */ 1627c1565b61SSam Leffler ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 1628c1565b61SSam Leffler ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 1629c1565b61SSam Leffler ssc->min_switch = hz; /* 1 second */ 1630c1565b61SSam Leffler ath_rate_sysctlattach(sc, ssc); 1631c1565b61SSam Leffler return &ssc->arc; 1632fa20c234SSam Leffler } 1633fa20c234SSam Leffler 1634fa20c234SSam Leffler void 1635fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc) 1636fa20c234SSam Leffler { 1637c1565b61SSam Leffler struct sample_softc *ssc = (struct sample_softc *) arc; 1638fa20c234SSam Leffler 1639c1565b61SSam Leffler free(ssc, M_DEVBUF); 1640fa20c234SSam Leffler } 1641