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, 171cce63444SAdrian Chadd struct ath_node *an, uint8_t rix0) 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! 199cce63444SAdrian Chadd */ 200cce63444SAdrian Chadd if (sched->t0 != 0) { 201cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 202cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]); 203cce63444SAdrian Chadd } 204cce63444SAdrian Chadd if (sched->t1 != 0) { 205cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 206cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]); 207cce63444SAdrian Chadd } 208cce63444SAdrian Chadd if (sched->t2 != 0) { 209cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 210cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]); 211cce63444SAdrian Chadd } 212cce63444SAdrian Chadd if (sched->t3 != 0) { 213cce63444SAdrian Chadd max_pkt_length = MIN(max_pkt_length, 214cce63444SAdrian Chadd ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]); 215cce63444SAdrian Chadd } 216cce63444SAdrian Chadd 217cce63444SAdrian Chadd return max_pkt_length; 218cce63444SAdrian Chadd #undef MCS 219cce63444SAdrian Chadd } 220cce63444SAdrian Chadd 221b2763056SSam Leffler static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); 222fa20c234SSam Leffler 223b91bf513SSam Leffler static __inline int 224b91bf513SSam Leffler size_to_bin(int size) 225fa20c234SSam Leffler { 226c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1 227c1565b61SSam Leffler if (size <= packet_size_bins[0]) 228c1565b61SSam Leffler return 0; 229c1565b61SSam Leffler #endif 230c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2 231c1565b61SSam Leffler if (size <= packet_size_bins[1]) 232c1565b61SSam Leffler return 1; 233c1565b61SSam Leffler #endif 234c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3 235c1565b61SSam Leffler if (size <= packet_size_bins[2]) 236c1565b61SSam Leffler return 2; 237c1565b61SSam Leffler #endif 238c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4 239cce63444SAdrian Chadd if (size <= packet_size_bins[3]) 240cce63444SAdrian Chadd return 3; 241cce63444SAdrian Chadd #endif 242cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 5 243cce63444SAdrian Chadd if (size <= packet_size_bins[4]) 244cce63444SAdrian Chadd return 4; 245cce63444SAdrian Chadd #endif 246cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 6 247cce63444SAdrian Chadd if (size <= packet_size_bins[5]) 248cce63444SAdrian Chadd return 5; 249cce63444SAdrian Chadd #endif 250cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 7 251cce63444SAdrian Chadd if (size <= packet_size_bins[6]) 252cce63444SAdrian Chadd return 6; 253cce63444SAdrian Chadd #endif 254cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 8 255c1565b61SSam Leffler #error "add support for more packet sizes" 256c1565b61SSam Leffler #endif 257fa20c234SSam Leffler return NUM_PACKET_SIZE_BINS-1; 258fa20c234SSam Leffler } 259fa20c234SSam Leffler 260fa20c234SSam Leffler void 261fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) 262fa20c234SSam Leffler { 263fa20c234SSam Leffler /* NB: assumed to be zero'd by caller */ 264fa20c234SSam Leffler } 265fa20c234SSam Leffler 266fa20c234SSam Leffler void 267fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an) 268fa20c234SSam Leffler { 269fa20c234SSam Leffler } 270fa20c234SSam Leffler 271a6a308a4SAdrian Chadd static int 272a6a308a4SAdrian Chadd dot11rate(const HAL_RATE_TABLE *rt, int rix) 273a6a308a4SAdrian Chadd { 27487acb7d5SAdrian Chadd if (rix < 0) 27587acb7d5SAdrian Chadd return -1; 276a6a308a4SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? 277a6a308a4SAdrian Chadd rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2; 278a6a308a4SAdrian Chadd } 279a6a308a4SAdrian Chadd 280ae0944b8SAdrian Chadd static const char * 281ae0944b8SAdrian Chadd dot11rate_label(const HAL_RATE_TABLE *rt, int rix) 282ae0944b8SAdrian Chadd { 28387acb7d5SAdrian Chadd if (rix < 0) 28487acb7d5SAdrian Chadd return ""; 285ae0944b8SAdrian Chadd return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; 286ae0944b8SAdrian Chadd } 287ae0944b8SAdrian Chadd 288fa20c234SSam Leffler /* 289c1565b61SSam Leffler * Return the rix with the lowest average_tx_time, 290fa20c234SSam Leffler * or -1 if all the average_tx_times are 0. 291fa20c234SSam Leffler */ 292c1565b61SSam Leffler static __inline int 29336958948SAdrian Chadd pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt, 294c1565b61SSam Leffler int size_bin, int require_acked_before) 295fa20c234SSam Leffler { 29636958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 297eb6f0de0SAdrian Chadd int best_rate_rix, best_rate_tt, best_rate_pct; 298193bfa21SAdrian Chadd uint64_t mask; 299eb6f0de0SAdrian Chadd int rix, tt, pct; 300b91bf513SSam Leffler 301c1565b61SSam Leffler best_rate_rix = 0; 302c1565b61SSam Leffler best_rate_tt = 0; 303eb6f0de0SAdrian Chadd best_rate_pct = 0; 304c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 305c1565b61SSam Leffler if ((mask & 1) == 0) /* not a supported rate */ 306c1565b61SSam Leffler continue; 307c1565b61SSam Leffler 30836958948SAdrian Chadd /* Don't pick a non-HT rate for a HT node */ 30936958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 31036958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 31136958948SAdrian Chadd continue; 31236958948SAdrian Chadd } 31336958948SAdrian Chadd 314c1565b61SSam Leffler tt = sn->stats[size_bin][rix].average_tx_time; 315c1565b61SSam Leffler if (tt <= 0 || 316c1565b61SSam Leffler (require_acked_before && 317c1565b61SSam Leffler !sn->stats[size_bin][rix].packets_acked)) 318b91bf513SSam Leffler continue; 319b91bf513SSam Leffler 320eb6f0de0SAdrian Chadd /* Calculate percentage if possible */ 321eb6f0de0SAdrian Chadd if (sn->stats[size_bin][rix].total_packets > 0) { 322eb6f0de0SAdrian Chadd pct = sn->stats[size_bin][rix].ewma_pct; 323eb6f0de0SAdrian Chadd } else { 324cce63444SAdrian Chadd pct = -1; /* No percent yet to compare against! */ 325eb6f0de0SAdrian Chadd } 326eb6f0de0SAdrian Chadd 327b91bf513SSam Leffler /* don't use a bit-rate that has been failing */ 328c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > 3) 329b91bf513SSam Leffler continue; 330b91bf513SSam Leffler 331eb6f0de0SAdrian Chadd /* 332cce63444SAdrian Chadd * For HT, Don't use a bit rate that is more 333cce63444SAdrian Chadd * lossy than the best. Give a bit of leeway. 334eb6f0de0SAdrian Chadd * 335cce63444SAdrian Chadd * Don't consider best rates that we haven't seen 336cce63444SAdrian Chadd * packets for yet; let sampling start inflence that. 337eb6f0de0SAdrian Chadd */ 338eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 339cce63444SAdrian Chadd if (pct == -1) 340cce63444SAdrian Chadd continue; 341cce63444SAdrian Chadd #if 0 342cce63444SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 343cce63444SAdrian Chadd IEEE80211_MSG_RATECTL, 344cce63444SAdrian Chadd &an->an_node, 345cce63444SAdrian Chadd "%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) " 346cce63444SAdrian Chadd "to 0x%x pkts/ewma/tt (%ju/%d/%d)", 347cce63444SAdrian Chadd __func__, 348cce63444SAdrian Chadd bin_to_size(size_bin), 349cce63444SAdrian Chadd rt->info[best_rate_rix].dot11Rate, 350cce63444SAdrian Chadd sn->stats[size_bin][best_rate_rix].total_packets, 351cce63444SAdrian Chadd best_rate_pct, 352cce63444SAdrian Chadd best_rate_tt, 353cce63444SAdrian Chadd rt->info[rix].dot11Rate, 354cce63444SAdrian Chadd sn->stats[size_bin][rix].total_packets, 355cce63444SAdrian Chadd pct, 356cce63444SAdrian Chadd tt); 357cce63444SAdrian Chadd #endif 358eb6f0de0SAdrian Chadd if (best_rate_pct > (pct + 50)) 359eb6f0de0SAdrian Chadd continue; 360eb6f0de0SAdrian Chadd } 361eb6f0de0SAdrian Chadd /* 362eb6f0de0SAdrian Chadd * For non-MCS rates, use the current average txtime for 363eb6f0de0SAdrian Chadd * comparison. 364eb6f0de0SAdrian Chadd */ 365eb6f0de0SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 366eb6f0de0SAdrian Chadd if (best_rate_tt == 0 || tt <= best_rate_tt) { 367fa20c234SSam Leffler best_rate_tt = tt; 368c1565b61SSam Leffler best_rate_rix = rix; 369eb6f0de0SAdrian Chadd best_rate_pct = pct; 370eb6f0de0SAdrian Chadd } 371eb6f0de0SAdrian Chadd } 372eb6f0de0SAdrian Chadd 373eb6f0de0SAdrian Chadd /* 374cce63444SAdrian Chadd * Since 2 and 3 stream rates have slightly higher TX times, 375eb6f0de0SAdrian Chadd * allow a little bit of leeway. This should later 376eb6f0de0SAdrian Chadd * be abstracted out and properly handled. 377eb6f0de0SAdrian Chadd */ 378eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 379cce63444SAdrian Chadd if (best_rate_tt == 0 || ((tt * 10) <= (best_rate_tt * 10))) { 380eb6f0de0SAdrian Chadd best_rate_tt = tt; 381eb6f0de0SAdrian Chadd best_rate_rix = rix; 382eb6f0de0SAdrian Chadd best_rate_pct = pct; 383eb6f0de0SAdrian Chadd } 384fa20c234SSam Leffler } 385fa20c234SSam Leffler } 386c1565b61SSam Leffler return (best_rate_tt ? best_rate_rix : -1); 387fa20c234SSam Leffler } 388fa20c234SSam Leffler 389fa20c234SSam Leffler /* 390c1565b61SSam Leffler * Pick a good "random" bit-rate to sample other than the current one. 391fa20c234SSam Leffler */ 392b91bf513SSam Leffler static __inline int 39336958948SAdrian Chadd pick_sample_rate(struct sample_softc *ssc , struct ath_node *an, 394c1565b61SSam Leffler const HAL_RATE_TABLE *rt, int size_bin) 395fa20c234SSam Leffler { 396c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 397a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 39836958948SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 399c1565b61SSam Leffler int current_rix, rix; 400c1565b61SSam Leffler unsigned current_tt; 401193bfa21SAdrian Chadd uint64_t mask; 402fa20c234SSam Leffler 403c1565b61SSam Leffler current_rix = sn->current_rix[size_bin]; 404c1565b61SSam Leffler if (current_rix < 0) { 405fa20c234SSam Leffler /* no successes yet, send at the lowest bit-rate */ 406cce63444SAdrian Chadd /* XXX TODO should return MCS0 if HT */ 407fa20c234SSam Leffler return 0; 408fa20c234SSam Leffler } 409fa20c234SSam Leffler 410c1565b61SSam Leffler current_tt = sn->stats[size_bin][current_rix].average_tx_time; 411fa20c234SSam Leffler 412c1565b61SSam Leffler rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */ 413193bfa21SAdrian Chadd mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */ 414c1565b61SSam Leffler while (mask != 0) { 415193bfa21SAdrian Chadd if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */ 416c1565b61SSam Leffler nextrate: 417c1565b61SSam Leffler if (++rix >= rt->rateCount) 418c1565b61SSam Leffler rix = 0; 419b91bf513SSam Leffler continue; 420c1565b61SSam Leffler } 421b91bf513SSam Leffler 422bf57b7b2SAdrian Chadd /* 423bf57b7b2SAdrian Chadd * The following code stops trying to sample 424bf57b7b2SAdrian Chadd * non-MCS rates when speaking to an MCS node. 425bf57b7b2SAdrian Chadd * However, at least for CCK rates in 2.4GHz mode, 426bf57b7b2SAdrian Chadd * the non-MCS rates MAY actually provide better 427bf57b7b2SAdrian Chadd * PER at the very far edge of reception. 428bf57b7b2SAdrian Chadd * 429bf57b7b2SAdrian Chadd * However! Until ath_rate_form_aggr() grows 430bf57b7b2SAdrian Chadd * some logic to not form aggregates if the 431bf57b7b2SAdrian Chadd * selected rate is non-MCS, this won't work. 432bf57b7b2SAdrian Chadd * 433bf57b7b2SAdrian Chadd * So don't disable this code until you've taught 434bf57b7b2SAdrian Chadd * ath_rate_form_aggr() to drop out if any of 435bf57b7b2SAdrian Chadd * the selected rates are non-MCS. 436bf57b7b2SAdrian Chadd */ 437bf57b7b2SAdrian Chadd #if 1 43836958948SAdrian Chadd /* if the node is HT and the rate isn't HT, don't bother sample */ 43936958948SAdrian Chadd if ((an->an_node.ni_flags & IEEE80211_NODE_HT) && 44036958948SAdrian Chadd (rt->info[rix].phy != IEEE80211_T_HT)) { 441193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 44236958948SAdrian Chadd goto nextrate; 44336958948SAdrian Chadd } 444bf57b7b2SAdrian Chadd #endif 44536958948SAdrian Chadd 446b91bf513SSam Leffler /* this bit-rate is always worse than the current one */ 447c1565b61SSam Leffler if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) { 448193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 449c1565b61SSam Leffler goto nextrate; 450c1565b61SSam Leffler } 451b91bf513SSam Leffler 452b91bf513SSam Leffler /* rarely sample bit-rates that fail a lot */ 453c1565b61SSam Leffler if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures && 454c1565b61SSam Leffler ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) { 455193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 456c1565b61SSam Leffler goto nextrate; 457fa20c234SSam Leffler } 458c1565b61SSam Leffler 459eb6f0de0SAdrian Chadd /* 460e69db8dfSAdrian Chadd * For HT, only sample a few rates on either side of the 461e69db8dfSAdrian Chadd * current rix; there's quite likely a lot of them. 462cce63444SAdrian Chadd * 463cce63444SAdrian Chadd * This is limited to testing rate indexes on either side of 464cce63444SAdrian Chadd * this MCS, but for all spatial streams. 465cce63444SAdrian Chadd * 466cce63444SAdrian Chadd * Otherwise we'll (a) never really sample higher MCS 467cce63444SAdrian Chadd * rates if we're stuck low, and we'll make weird moves 468cce63444SAdrian Chadd * like sample MCS8 if we're using MCS7. 469eb6f0de0SAdrian Chadd */ 470eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) { 471cce63444SAdrian Chadd uint8_t current_mcs, rix_mcs; 472cce63444SAdrian Chadd 473cce63444SAdrian Chadd current_mcs = MCS(current_rix) & 0x7; 474cce63444SAdrian Chadd rix_mcs = MCS(rix) & 0x7; 475cce63444SAdrian Chadd 476cce63444SAdrian Chadd if (rix_mcs < (current_mcs - 2) || 477cce63444SAdrian Chadd rix_mcs > (current_mcs + 2)) { 478193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 479eb6f0de0SAdrian Chadd goto nextrate; 480eb6f0de0SAdrian Chadd } 481eb6f0de0SAdrian Chadd } 482eb6f0de0SAdrian Chadd 48336958948SAdrian Chadd /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */ 48436958948SAdrian Chadd if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) { 485c1565b61SSam Leffler if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) { 486193bfa21SAdrian Chadd mask &= ~((uint64_t) 1<<rix); 487c1565b61SSam Leffler goto nextrate; 488c1565b61SSam Leffler } 48936958948SAdrian Chadd } 490c1565b61SSam Leffler 491c1565b61SSam Leffler sn->last_sample_rix[size_bin] = rix; 492c1565b61SSam Leffler return rix; 493c1565b61SSam Leffler } 494c1565b61SSam Leffler return current_rix; 495c1565b61SSam Leffler #undef DOT11RATE 496a6a308a4SAdrian Chadd #undef MCS 497fa20c234SSam Leffler } 498fa20c234SSam Leffler 499c4ac32a8SAdrian Chadd static int 500c4ac32a8SAdrian Chadd ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) 501c4ac32a8SAdrian Chadd { 502c4ac32a8SAdrian Chadd #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 503c4ac32a8SAdrian Chadd #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 504c4ac32a8SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 505c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 506c4ac32a8SAdrian Chadd int srate; 507c4ac32a8SAdrian Chadd 508c4ac32a8SAdrian Chadd /* Check MCS rates */ 509c4ac32a8SAdrian Chadd for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { 510c4ac32a8SAdrian Chadd if (MCS(srate) == tp->ucastrate) 511c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 512c4ac32a8SAdrian Chadd } 513c4ac32a8SAdrian Chadd 514c4ac32a8SAdrian Chadd /* Check legacy rates */ 515c4ac32a8SAdrian Chadd for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { 516c4ac32a8SAdrian Chadd if (RATE(srate) == tp->ucastrate) 517c4ac32a8SAdrian Chadd return sc->sc_rixmap[tp->ucastrate]; 518c4ac32a8SAdrian Chadd } 519c4ac32a8SAdrian Chadd return -1; 520c4ac32a8SAdrian Chadd #undef RATE 521c4ac32a8SAdrian Chadd #undef DOT11RATE 522c4ac32a8SAdrian Chadd #undef MCS 523c4ac32a8SAdrian Chadd } 524c4ac32a8SAdrian Chadd 525c4ac32a8SAdrian Chadd static void 526c4ac32a8SAdrian Chadd ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) 527c4ac32a8SAdrian Chadd { 528c4ac32a8SAdrian Chadd struct ath_node *an = ATH_NODE(ni); 529c4ac32a8SAdrian Chadd const struct ieee80211_txparam *tp = ni->ni_txparms; 530c4ac32a8SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 531c4ac32a8SAdrian Chadd 532c4ac32a8SAdrian Chadd if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 533c4ac32a8SAdrian Chadd /* 534c4ac32a8SAdrian Chadd * A fixed rate is to be used; ucastrate is the IEEE code 535c4ac32a8SAdrian Chadd * for this rate (sans basic bit). Check this against the 536c4ac32a8SAdrian Chadd * negotiated rate set for the node. Note the fixed rate 537c4ac32a8SAdrian Chadd * may not be available for various reasons so we only 538c4ac32a8SAdrian Chadd * setup the static rate index if the lookup is successful. 539c4ac32a8SAdrian Chadd */ 540c4ac32a8SAdrian Chadd sn->static_rix = ath_rate_get_static_rix(sc, ni); 541c4ac32a8SAdrian Chadd } else { 542c4ac32a8SAdrian Chadd sn->static_rix = -1; 543c4ac32a8SAdrian Chadd } 544c4ac32a8SAdrian Chadd } 545c4ac32a8SAdrian Chadd 546eb6f0de0SAdrian Chadd /* 547eb6f0de0SAdrian Chadd * Pick a non-HT rate to begin using. 548eb6f0de0SAdrian Chadd */ 549eb6f0de0SAdrian Chadd static int 550eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an, 551eb6f0de0SAdrian Chadd int frameLen) 552eb6f0de0SAdrian Chadd { 553eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 554eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 555eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 556eb6f0de0SAdrian Chadd int rix = -1; 557eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 558eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 559eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 560eb6f0de0SAdrian Chadd 561eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 562eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 563193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 564eb6f0de0SAdrian Chadd continue; 565eb6f0de0SAdrian Chadd 566eb6f0de0SAdrian Chadd /* Skip HT rates */ 567eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 568eb6f0de0SAdrian Chadd continue; 569eb6f0de0SAdrian Chadd 570eb6f0de0SAdrian Chadd /* 571eb6f0de0SAdrian Chadd * Pick the highest rate <= 36 Mbps 572eb6f0de0SAdrian Chadd * that hasn't failed. 573eb6f0de0SAdrian Chadd */ 574eb6f0de0SAdrian Chadd if (DOT11RATE(rix) <= 72 && 575eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 576eb6f0de0SAdrian Chadd break; 577eb6f0de0SAdrian Chadd } 578eb6f0de0SAdrian Chadd } 579eb6f0de0SAdrian Chadd return rix; 580eb6f0de0SAdrian Chadd #undef RATE 581eb6f0de0SAdrian Chadd #undef MCS 582eb6f0de0SAdrian Chadd #undef DOT11RATE 583eb6f0de0SAdrian Chadd } 584eb6f0de0SAdrian Chadd 585eb6f0de0SAdrian Chadd /* 586eb6f0de0SAdrian Chadd * Pick a HT rate to begin using. 587eb6f0de0SAdrian Chadd * 588eb6f0de0SAdrian Chadd * Don't use any non-HT rates; only consider HT rates. 589eb6f0de0SAdrian Chadd */ 590eb6f0de0SAdrian Chadd static int 591eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an, 592eb6f0de0SAdrian Chadd int frameLen) 593eb6f0de0SAdrian Chadd { 594eb6f0de0SAdrian Chadd #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 595eb6f0de0SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 596eb6f0de0SAdrian Chadd #define RATE(ix) (DOT11RATE(ix) / 2) 597eb6f0de0SAdrian Chadd int rix = -1, ht_rix = -1; 598eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 599eb6f0de0SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 600eb6f0de0SAdrian Chadd const int size_bin = size_to_bin(frameLen); 601eb6f0de0SAdrian Chadd 602eb6f0de0SAdrian Chadd /* no packet has been sent successfully yet */ 603eb6f0de0SAdrian Chadd for (rix = rt->rateCount-1; rix > 0; rix--) { 604eb6f0de0SAdrian Chadd /* Skip rates we can't use */ 605193bfa21SAdrian Chadd if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0) 606eb6f0de0SAdrian Chadd continue; 607eb6f0de0SAdrian Chadd 608eb6f0de0SAdrian Chadd /* Keep a copy of the last seen HT rate index */ 609eb6f0de0SAdrian Chadd if (rt->info[rix].phy == IEEE80211_T_HT) 610eb6f0de0SAdrian Chadd ht_rix = rix; 611eb6f0de0SAdrian Chadd 612eb6f0de0SAdrian Chadd /* Skip non-HT rates */ 613eb6f0de0SAdrian Chadd if (rt->info[rix].phy != IEEE80211_T_HT) 614eb6f0de0SAdrian Chadd continue; 615eb6f0de0SAdrian Chadd 616eb6f0de0SAdrian Chadd /* 617cce63444SAdrian Chadd * Pick a medium-speed rate at 1 spatial stream 618cce63444SAdrian Chadd * which has not seen any failures. 619cce63444SAdrian Chadd * Higher rates may fail; we'll try them later. 620eb6f0de0SAdrian Chadd */ 621cce63444SAdrian Chadd if (((MCS(rix)& 0x7f) <= 4) && 622eb6f0de0SAdrian Chadd sn->stats[size_bin][rix].successive_failures == 0) { 623eb6f0de0SAdrian Chadd break; 624eb6f0de0SAdrian Chadd } 625eb6f0de0SAdrian Chadd } 626eb6f0de0SAdrian Chadd 627eb6f0de0SAdrian Chadd /* 628eb6f0de0SAdrian Chadd * If all the MCS rates have successive failures, rix should be 629eb6f0de0SAdrian Chadd * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.) 630eb6f0de0SAdrian Chadd */ 631eb6f0de0SAdrian Chadd return MAX(rix, ht_rix); 632eb6f0de0SAdrian Chadd #undef RATE 633eb6f0de0SAdrian Chadd #undef MCS 634eb6f0de0SAdrian Chadd #undef DOT11RATE 635eb6f0de0SAdrian Chadd } 636c4ac32a8SAdrian Chadd 637c4ac32a8SAdrian Chadd 638fa20c234SSam Leffler void 639fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, 64084f950a5SAdrian Chadd int shortPreamble, size_t frameLen, int tid, 641cce63444SAdrian Chadd int is_aggr, u_int8_t *rix0, int *try0, 642cce63444SAdrian Chadd u_int8_t *txrate, int *maxdur, int *maxpktlen) 643fa20c234SSam Leffler { 644c1565b61SSam Leffler #define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL) 645a6a308a4SAdrian Chadd #define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS) 646c1565b61SSam Leffler #define RATE(ix) (DOT11RATE(ix) / 2) 647fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 648fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 6497a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 650c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 651cce63444SAdrian Chadd int size_bin = size_to_bin(frameLen); 652c1565b61SSam Leffler int rix, mrr, best_rix, change_rates; 653b2763056SSam Leffler unsigned average_tx_time; 654cce63444SAdrian Chadd int max_pkt_len; 655fa20c234SSam Leffler 656c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, &an->an_node); 657c4ac32a8SAdrian Chadd 65884f950a5SAdrian Chadd /* For now don't take TID, is_aggr into account */ 65984f950a5SAdrian Chadd /* Also for now don't calculate a max duration; that'll come later */ 66084f950a5SAdrian Chadd *maxdur = -1; 66184f950a5SAdrian Chadd 662cce63444SAdrian Chadd /* 663cce63444SAdrian Chadd * For now just set it to the frame length; we'll optimise it later. 664cce63444SAdrian Chadd */ 665cce63444SAdrian Chadd *maxpktlen = frameLen; 666cce63444SAdrian Chadd 667cc86f1eaSAdrian Chadd if (sn->currates != sc->sc_currates) { 668cc86f1eaSAdrian Chadd device_printf(sc->sc_dev, "%s: currates != sc_currates!\n", 669cc86f1eaSAdrian Chadd __func__); 670cc86f1eaSAdrian Chadd rix = 0; 671cc86f1eaSAdrian Chadd *try0 = ATH_TXMAXTRY; 672cc86f1eaSAdrian Chadd goto done; 673cc86f1eaSAdrian Chadd } 674cc86f1eaSAdrian Chadd 675c1565b61SSam Leffler if (sn->static_rix != -1) { 676c1565b61SSam Leffler rix = sn->static_rix; 677c1565b61SSam Leffler *try0 = ATH_TXMAXTRY; 678c1565b61SSam Leffler goto done; 679c1565b61SSam Leffler } 680fa20c234SSam Leffler 681af017101SAdrian Chadd mrr = sc->sc_mrretry; 682af017101SAdrian Chadd /* XXX check HT protmode too */ 683cce63444SAdrian Chadd /* XXX turn into a cap; 11n MACs support MRR+RTSCTS */ 6849f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 685af017101SAdrian Chadd mrr = 0; 686c1565b61SSam Leffler 68736958948SAdrian Chadd best_rix = pick_best_rate(an, rt, size_bin, !mrr); 688cce63444SAdrian Chadd 689cce63444SAdrian Chadd /* 690cce63444SAdrian Chadd * At this point we've chosen the best rix, so now we 691cce63444SAdrian Chadd * need to potentially update our maximum packet length 692cce63444SAdrian Chadd * and size_bin if we're doing 11n rates. 693cce63444SAdrian Chadd */ 694cce63444SAdrian Chadd max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix); 695cce63444SAdrian Chadd if (max_pkt_len > 0) { 696cce63444SAdrian Chadd #if 0 697cce63444SAdrian Chadd device_printf(sc->sc_dev, 698cce63444SAdrian Chadd "Limiting maxpktlen from %d to %d bytes\n", 699cce63444SAdrian Chadd (int) frameLen, max_pkt_len); 700cce63444SAdrian Chadd #endif 701cce63444SAdrian Chadd *maxpktlen = frameLen = MIN(frameLen, max_pkt_len); 702cce63444SAdrian Chadd size_bin = size_to_bin(frameLen); 703cce63444SAdrian Chadd } 704cce63444SAdrian Chadd 705c1565b61SSam Leffler if (best_rix >= 0) { 706c1565b61SSam Leffler average_tx_time = sn->stats[size_bin][best_rix].average_tx_time; 707fa20c234SSam Leffler } else { 708b2763056SSam Leffler average_tx_time = 0; 709b2763056SSam Leffler } 710cce63444SAdrian Chadd 711fa20c234SSam Leffler /* 712c1565b61SSam Leffler * Limit the time measuring the performance of other tx 713c1565b61SSam Leffler * rates to sample_rate% of the total transmission time. 714fa20c234SSam Leffler */ 715*5add7017SAdrian Chadd if (sn->sample_tt[size_bin] < 716*5add7017SAdrian Chadd average_tx_time * 717*5add7017SAdrian Chadd (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) { 71836958948SAdrian Chadd rix = pick_sample_rate(ssc, an, rt, size_bin); 719c1565b61SSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 720*5add7017SAdrian Chadd &an->an_node, "att %d sample_tt %d size %u " 721*5add7017SAdrian Chadd "sample rate %d %s current rate %d %s", 722eb6f0de0SAdrian Chadd average_tx_time, 723eb6f0de0SAdrian Chadd sn->sample_tt[size_bin], 724eb6f0de0SAdrian Chadd bin_to_size(size_bin), 725eb6f0de0SAdrian Chadd dot11rate(rt, rix), 726eb6f0de0SAdrian Chadd dot11rate_label(rt, rix), 727eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 728eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin])); 729c1565b61SSam Leffler if (rix != sn->current_rix[size_bin]) { 730c1565b61SSam Leffler sn->current_sample_rix[size_bin] = rix; 731b2763056SSam Leffler } else { 732c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 733b2763056SSam Leffler } 734b2763056SSam Leffler sn->packets_since_sample[size_bin] = 0; 735b2763056SSam Leffler } else { 736b91bf513SSam Leffler change_rates = 0; 737c1565b61SSam Leffler if (!sn->packets_sent[size_bin] || best_rix == -1) { 738b91bf513SSam Leffler /* no packet has been sent successfully yet */ 739b91bf513SSam Leffler change_rates = 1; 740eb6f0de0SAdrian Chadd if (an->an_node.ni_flags & IEEE80211_NODE_HT) 741eb6f0de0SAdrian Chadd best_rix = 742eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(sc, an, frameLen); 743eb6f0de0SAdrian Chadd else 744eb6f0de0SAdrian Chadd best_rix = 745eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(sc, an, frameLen); 746b91bf513SSam Leffler } else if (sn->packets_sent[size_bin] < 20) { 747b91bf513SSam Leffler /* let the bit-rate switch quickly during the first few packets */ 748eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 749eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 750eb6f0de0SAdrian Chadd "%s: switching quickly..", __func__); 751b91bf513SSam Leffler change_rates = 1; 752c1565b61SSam Leffler } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) { 753c1565b61SSam Leffler /* min_switch seconds have gone by */ 754eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 755eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 756eb6f0de0SAdrian Chadd "%s: min_switch %d > ticks_since_switch %d..", 757eb6f0de0SAdrian Chadd __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]); 758b91bf513SSam Leffler change_rates = 1; 759eb6f0de0SAdrian Chadd } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) && 760eb6f0de0SAdrian Chadd (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) { 761b91bf513SSam Leffler /* the current bit-rate is twice as slow as the best one */ 762eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 763eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 764eb6f0de0SAdrian Chadd "%s: 2x att (= %d) < cur_rix att %d", 765eb6f0de0SAdrian Chadd __func__, 766eb6f0de0SAdrian Chadd 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time); 767b91bf513SSam Leffler change_rates = 1; 768eb6f0de0SAdrian Chadd } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) { 769eb6f0de0SAdrian Chadd int cur_rix = sn->current_rix[size_bin]; 770eb6f0de0SAdrian Chadd int cur_att = sn->stats[size_bin][cur_rix].average_tx_time; 771eb6f0de0SAdrian Chadd /* 772cce63444SAdrian Chadd * If the node is HT, upgrade it if the MCS rate without 773cce63444SAdrian Chadd * the stream is higher and the average tx time is 774cce63444SAdrian Chadd * within 10% of the current rate. It can fail a little. 775eb6f0de0SAdrian Chadd * 776eb6f0de0SAdrian Chadd * This is likely not optimal! 777eb6f0de0SAdrian Chadd */ 778eb6f0de0SAdrian Chadd #if 0 779eb6f0de0SAdrian Chadd printf("cur rix/att %x/%d, best rix/att %x/%d\n", 780eb6f0de0SAdrian Chadd MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time); 781eb6f0de0SAdrian Chadd #endif 782*5add7017SAdrian Chadd if ((best_rix != cur_rix) && 783*5add7017SAdrian Chadd ((MCS(best_rix) & 0x7) >= (MCS(cur_rix) & 0x7)) && 784*5add7017SAdrian Chadd (average_tx_time * 9) <= (cur_att * 10)) { 785eb6f0de0SAdrian Chadd IEEE80211_NOTE(an->an_node.ni_vap, 786eb6f0de0SAdrian Chadd IEEE80211_MSG_RATECTL, &an->an_node, 787cce63444SAdrian Chadd "%s: HT: size %d best_rix 0x%x > " 788cce63444SAdrian Chadd " cur_rix 0x%x, average_tx_time %d," 789cce63444SAdrian Chadd " cur_att %d", 790cce63444SAdrian Chadd __func__, bin_to_size(size_bin), 791cce63444SAdrian Chadd MCS(best_rix), MCS(cur_rix), 792cce63444SAdrian Chadd average_tx_time, cur_att); 793eb6f0de0SAdrian Chadd change_rates = 1; 794eb6f0de0SAdrian Chadd } 795b91bf513SSam Leffler } 796b91bf513SSam Leffler 797b91bf513SSam Leffler sn->packets_since_sample[size_bin]++; 798b91bf513SSam Leffler 799b91bf513SSam Leffler if (change_rates) { 800c1565b61SSam Leffler if (best_rix != sn->current_rix[size_bin]) { 801b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, 802b032f27cSSam Leffler IEEE80211_MSG_RATECTL, 803b032f27cSSam Leffler &an->an_node, 804cce63444SAdrian Chadd "%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d", 805b2763056SSam Leffler __func__, 806c1565b61SSam Leffler bin_to_size(size_bin), 807cce63444SAdrian Chadd dot11rate(rt, sn->current_rix[size_bin]), 808cce63444SAdrian Chadd dot11rate_label(rt, sn->current_rix[size_bin]), 809c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time, 810c1565b61SSam Leffler sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time, 811cce63444SAdrian Chadd sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct, 812cce63444SAdrian Chadd dot11rate(rt, best_rix), 813cce63444SAdrian Chadd dot11rate_label(rt, best_rix), 814c1565b61SSam Leffler sn->stats[size_bin][best_rix].average_tx_time, 815c1565b61SSam Leffler sn->stats[size_bin][best_rix].perfect_tx_time, 816cce63444SAdrian Chadd sn->stats[size_bin][best_rix].ewma_pct, 817b2763056SSam Leffler sn->packets_since_switch[size_bin], 818b2763056SSam Leffler mrr); 819b2763056SSam Leffler } 820b2763056SSam Leffler sn->packets_since_switch[size_bin] = 0; 821c1565b61SSam Leffler sn->current_rix[size_bin] = best_rix; 822b91bf513SSam Leffler sn->ticks_since_switch[size_bin] = ticks; 823b032f27cSSam Leffler /* 824b032f27cSSam Leffler * Set the visible txrate for this node. 825b032f27cSSam Leffler */ 826*5add7017SAdrian Chadd an->an_node.ni_txrate = 827*5add7017SAdrian Chadd (rt->info[best_rix].phy == IEEE80211_T_HT) ? 828*5add7017SAdrian Chadd MCS(best_rix) : DOT11RATE(best_rix); 829b2763056SSam Leffler } 830c1565b61SSam Leffler rix = sn->current_rix[size_bin]; 831b2763056SSam Leffler sn->packets_since_switch[size_bin]++; 832b91bf513SSam Leffler } 833c1565b61SSam Leffler *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY; 834c1565b61SSam Leffler done: 835cc86f1eaSAdrian Chadd 836cc86f1eaSAdrian Chadd /* 837cc86f1eaSAdrian Chadd * This bug totally sucks and should be fixed. 838cc86f1eaSAdrian Chadd * 839cc86f1eaSAdrian Chadd * For now though, let's not panic, so we can start to figure 840cc86f1eaSAdrian Chadd * out how to better reproduce it. 841cc86f1eaSAdrian Chadd */ 842cc86f1eaSAdrian Chadd if (rix < 0 || rix >= rt->rateCount) { 843cc86f1eaSAdrian Chadd printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n", 844cc86f1eaSAdrian Chadd __func__, 845cc86f1eaSAdrian Chadd rix, 846cc86f1eaSAdrian Chadd rt->rateCount); 847cc86f1eaSAdrian Chadd rix = 0; /* XXX just default for now */ 848cc86f1eaSAdrian Chadd } 849c1565b61SSam Leffler KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix)); 850fa20c234SSam Leffler 851c1565b61SSam Leffler *rix0 = rix; 852c1565b61SSam Leffler *txrate = rt->info[rix].rateCode 853c1565b61SSam Leffler | (shortPreamble ? rt->info[rix].shortPreamble : 0); 854fa20c234SSam Leffler sn->packets_sent[size_bin]++; 855cce63444SAdrian Chadd 856c1565b61SSam Leffler #undef DOT11RATE 857a6a308a4SAdrian Chadd #undef MCS 858c1565b61SSam Leffler #undef RATE 859fa20c234SSam Leffler } 860fa20c234SSam Leffler 861710c3778SAdrian Chadd /* 862710c3778SAdrian Chadd * Get the TX rates. Don't fiddle with short preamble flags for them; 863710c3778SAdrian Chadd * the caller can do that. 864710c3778SAdrian Chadd */ 865710c3778SAdrian Chadd void 866710c3778SAdrian Chadd ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an, 867eb6f0de0SAdrian Chadd uint8_t rix0, struct ath_rc_series *rc) 868710c3778SAdrian Chadd { 869710c3778SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 870710c3778SAdrian Chadd const struct txschedule *sched = &sn->sched[rix0]; 871710c3778SAdrian Chadd 872193bfa21SAdrian Chadd KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", 873193bfa21SAdrian Chadd rix0, sched->r0)); 874710c3778SAdrian Chadd 875eb6f0de0SAdrian Chadd rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; 876710c3778SAdrian Chadd 877eb6f0de0SAdrian Chadd rc[0].rix = sched->r0; 878eb6f0de0SAdrian Chadd rc[1].rix = sched->r1; 879eb6f0de0SAdrian Chadd rc[2].rix = sched->r2; 880eb6f0de0SAdrian Chadd rc[3].rix = sched->r3; 881eb6f0de0SAdrian Chadd 882eb6f0de0SAdrian Chadd rc[0].tries = sched->t0; 883eb6f0de0SAdrian Chadd rc[1].tries = sched->t1; 884eb6f0de0SAdrian Chadd rc[2].tries = sched->t2; 885eb6f0de0SAdrian Chadd rc[3].tries = sched->t3; 886710c3778SAdrian Chadd } 887710c3778SAdrian Chadd 888fa20c234SSam Leffler void 889fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, 890a4d8dd10SSam Leffler struct ath_desc *ds, int shortPreamble, u_int8_t rix) 891fa20c234SSam Leffler { 892fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 893c1565b61SSam Leffler const struct txschedule *sched = &sn->sched[rix]; 894c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 895c1565b61SSam Leffler uint8_t rix1, s1code, rix2, s2code, rix3, s3code; 896fa20c234SSam Leffler 897c1565b61SSam Leffler /* XXX precalculate short preamble tables */ 898c1565b61SSam Leffler rix1 = sched->r1; 899c1565b61SSam Leffler s1code = rt->info[rix1].rateCode 900c1565b61SSam Leffler | (shortPreamble ? rt->info[rix1].shortPreamble : 0); 901c1565b61SSam Leffler rix2 = sched->r2; 902c1565b61SSam Leffler s2code = rt->info[rix2].rateCode 903c1565b61SSam Leffler | (shortPreamble ? rt->info[rix2].shortPreamble : 0); 904c1565b61SSam Leffler rix3 = sched->r3; 905c1565b61SSam Leffler s3code = rt->info[rix3].rateCode 906c1565b61SSam Leffler | (shortPreamble ? rt->info[rix3].shortPreamble : 0); 907c1565b61SSam Leffler ath_hal_setupxtxdesc(sc->sc_ah, ds, 908c1565b61SSam Leffler s1code, sched->t1, /* series 1 */ 909c1565b61SSam Leffler s2code, sched->t2, /* series 2 */ 910c1565b61SSam Leffler s3code, sched->t3); /* series 3 */ 911fa20c234SSam Leffler } 912fa20c234SSam Leffler 913b2763056SSam Leffler static void 914b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an, 915b2763056SSam Leffler int frame_size, 916c1565b61SSam Leffler int rix0, int tries0, 917eb6f0de0SAdrian Chadd int short_tries, int tries, int status, 918eb6f0de0SAdrian Chadd int nframes, int nbad) 919fa20c234SSam Leffler { 920fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 921fa20c234SSam Leffler struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); 922ec3dec2fSAdrian Chadd #ifdef IEEE80211_DEBUG 923eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 924ec3dec2fSAdrian Chadd #endif 925c1565b61SSam Leffler const int size_bin = size_to_bin(frame_size); 926c1565b61SSam Leffler const int size = bin_to_size(size_bin); 927c1565b61SSam Leffler int tt, tries_so_far; 928532f2442SAdrian Chadd int is_ht40 = (an->an_node.ni_chw == 40); 929ee563d63SAdrian Chadd int pct; 930fa20c234SSam Leffler 931c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, rix0)) 93265f9edeeSSam Leffler return; 933cce63444SAdrian Chadd 934cce63444SAdrian Chadd /* 935cce63444SAdrian Chadd * If status is FAIL then we treat all frames as bad. 936cce63444SAdrian Chadd * This better accurately tracks EWMA and average TX time 937cce63444SAdrian Chadd * because even if the eventual transmission succeeded, 938cce63444SAdrian Chadd * transmission at this rate did not. 939cce63444SAdrian Chadd */ 940cce63444SAdrian Chadd if (status != 0) 941cce63444SAdrian Chadd nbad = nframes; 942cce63444SAdrian Chadd 943c1565b61SSam Leffler tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, 944e09c8c4cSAdrian Chadd MIN(tries0, tries) - 1, is_ht40); 945c1565b61SSam Leffler tries_so_far = tries0; 946c1565b61SSam Leffler 947c1565b61SSam Leffler if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { 948fa20c234SSam Leffler /* just average the first few packets */ 949c1565b61SSam Leffler int avg_tx = sn->stats[size_bin][rix0].average_tx_time; 950c1565b61SSam Leffler int packets = sn->stats[size_bin][rix0].total_packets; 951eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); 952fa20c234SSam Leffler } else { 953fa20c234SSam Leffler /* use a ewma */ 954c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time = 955c1565b61SSam Leffler ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 956c1565b61SSam Leffler (tt * (100 - ssc->smoothing_rate))) / 100; 957fa20c234SSam Leffler } 958fa20c234SSam Leffler 959eb6f0de0SAdrian Chadd if (nframes == nbad) { 960eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].successive_failures += nbad; 961fa20c234SSam Leffler } else { 962eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); 963c1565b61SSam Leffler sn->stats[size_bin][rix0].successive_failures = 0; 964fa20c234SSam Leffler } 965c1565b61SSam Leffler sn->stats[size_bin][rix0].tries += tries; 966c1565b61SSam Leffler sn->stats[size_bin][rix0].last_tx = ticks; 967eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].total_packets += nframes; 968b2763056SSam Leffler 969ee563d63SAdrian Chadd /* update EWMA for this rix */ 970ee563d63SAdrian Chadd 971ee563d63SAdrian Chadd /* Calculate percentage based on current rate */ 972ee563d63SAdrian Chadd if (nframes == 0) 973ee563d63SAdrian Chadd nframes = nbad = 1; 974ee563d63SAdrian Chadd pct = ((nframes - nbad) * 1000) / nframes; 975ee563d63SAdrian Chadd 976ee563d63SAdrian Chadd if (sn->stats[size_bin][rix0].total_packets < 977ee563d63SAdrian Chadd ssc->smoothing_minpackets) { 978ee563d63SAdrian Chadd /* just average the first few packets */ 979ee563d63SAdrian Chadd int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) / 980ee563d63SAdrian Chadd (sn->stats[size_bin][rix0].total_packets); 981ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = a_pct; 982ee563d63SAdrian Chadd } else { 983ee563d63SAdrian Chadd /* use a ewma */ 984ee563d63SAdrian Chadd sn->stats[size_bin][rix0].ewma_pct = 985ee563d63SAdrian Chadd ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) + 986ee563d63SAdrian Chadd (pct * (100 - ssc->smoothing_rate))) / 100; 987ee563d63SAdrian Chadd } 988ee563d63SAdrian Chadd 989cce63444SAdrian Chadd /* 990cce63444SAdrian Chadd * Only update the sample time for the initial sample rix. 991cce63444SAdrian Chadd * We've updated the statistics on each of the other retries 992cce63444SAdrian Chadd * fine, but we should only update the sample_tt with what 993cce63444SAdrian Chadd * was actually sampled. 994cce63444SAdrian Chadd * 995cce63444SAdrian Chadd * However, to aide in debugging, log all the failures for 996cce63444SAdrian Chadd * each of the buckets 997cce63444SAdrian Chadd */ 998b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 999b032f27cSSam Leffler &an->an_node, 1000cce63444SAdrian Chadd "%s: size %d %s %s rate %d %s tries (%d/%d) tt %d " 1001cce63444SAdrian Chadd "avg_tt (%d/%d) nfrm %d nbad %d", 1002b032f27cSSam Leffler __func__, 100365f9edeeSSam Leffler size, 100465f9edeeSSam Leffler status ? "FAIL" : "OK", 1005cce63444SAdrian Chadd rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr", 1006eb6f0de0SAdrian Chadd dot11rate(rt, rix0), 1007eb6f0de0SAdrian Chadd dot11rate_label(rt, rix0), 1008eb6f0de0SAdrian Chadd short_tries, tries, tt, 1009c1565b61SSam Leffler sn->stats[size_bin][rix0].average_tx_time, 1010eb6f0de0SAdrian Chadd sn->stats[size_bin][rix0].perfect_tx_time, 1011eb6f0de0SAdrian Chadd nframes, nbad); 1012cce63444SAdrian Chadd 1013cce63444SAdrian Chadd if (rix0 == sn->current_sample_rix[size_bin]) { 1014b2763056SSam Leffler sn->sample_tt[size_bin] = tt; 1015c1565b61SSam Leffler sn->current_sample_rix[size_bin] = -1; 1016b2763056SSam Leffler } 1017b2763056SSam Leffler } 1018b2763056SSam Leffler 1019ec9ee5e7SSam Leffler static void 102076e6fd5dSGleb Smirnoff badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status) 1021ec9ee5e7SSam Leffler { 102276e6fd5dSGleb Smirnoff 102376e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 102476e6fd5dSGleb Smirnoff "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", 1025ec9ee5e7SSam Leffler series, hwrate, tries, status); 1026ec9ee5e7SSam Leffler } 1027ec9ee5e7SSam Leffler 1028b2763056SSam Leffler void 102943e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, 1030eb6f0de0SAdrian Chadd const struct ath_rc_series *rc, const struct ath_tx_status *ts, 1031cce63444SAdrian Chadd int frame_size, int rc_framesize, int nframes, int nbad) 1032b2763056SSam Leffler { 10337a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1034b2763056SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1035eb6f0de0SAdrian Chadd int final_rix, short_tries, long_tries; 103646d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1037eb6f0de0SAdrian Chadd int status = ts->ts_status; 10381bb9a085SSam Leffler int mrr; 1039b2763056SSam Leffler 1040f6cbf16aSSam Leffler final_rix = rt->rateCodeToIndex[ts->ts_rate]; 104165f9edeeSSam Leffler short_tries = ts->ts_shortretry; 104265f9edeeSSam Leffler long_tries = ts->ts_longretry + 1; 1043eb6f0de0SAdrian Chadd 1044ee563d63SAdrian Chadd if (nframes == 0) { 1045ee563d63SAdrian Chadd device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__); 1046ee563d63SAdrian Chadd return; 1047ee563d63SAdrian Chadd } 1048ee563d63SAdrian Chadd 104943e9cf7cSSam Leffler if (frame_size == 0) /* NB: should not happen */ 1050b2763056SSam Leffler frame_size = 1500; 1051cce63444SAdrian Chadd if (rc_framesize == 0) /* NB: should not happen */ 1052cce63444SAdrian Chadd rc_framesize = 1500; 1053cce63444SAdrian Chadd 1054cce63444SAdrian Chadd /* 1055cce63444SAdrian Chadd * There are still some places where what rate control set as 1056cce63444SAdrian Chadd * a limit but the hardware decided, for some reason, to transmit 1057cce63444SAdrian Chadd * at a smaller size that fell into a different bucket. 1058cce63444SAdrian Chadd * 1059cce63444SAdrian Chadd * The eternal question here is - which size_bin should it go in? 1060cce63444SAdrian Chadd * The one that was requested, or the one that was transmitted? 1061cce63444SAdrian Chadd * 1062cce63444SAdrian Chadd * Here's the problem - if we use the one that was transmitted, 1063cce63444SAdrian Chadd * we may continue to hit corner cases where we make a rate 1064cce63444SAdrian Chadd * selection using a higher bin but only update the smaller bin; 1065cce63444SAdrian Chadd * thus never really "adapting". 1066cce63444SAdrian Chadd * 1067cce63444SAdrian Chadd * If however we update the larger bin, we're not accurately 1068cce63444SAdrian Chadd * representing the channel state at that frame/aggregate size. 1069cce63444SAdrian Chadd * However if we keep hitting the larger request but completing 1070cce63444SAdrian Chadd * a smaller size, we at least updates based on what the 1071cce63444SAdrian Chadd * request was /for/. 1072cce63444SAdrian Chadd * 1073cce63444SAdrian Chadd * I'm going to err on the side of caution and choose the 1074cce63444SAdrian Chadd * latter. 1075cce63444SAdrian Chadd */ 1076cce63444SAdrian Chadd if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) { 1077cce63444SAdrian Chadd #if 0 1078cce63444SAdrian Chadd device_printf(sc->sc_dev, 1079cce63444SAdrian Chadd "%s: completed but frame size buckets mismatch " 1080cce63444SAdrian Chadd "(completed %d tx'ed %d)\n", 1081cce63444SAdrian Chadd __func__, frame_size, rc_framesize); 1082cce63444SAdrian Chadd #endif 1083cce63444SAdrian Chadd frame_size = rc_framesize; 1084cce63444SAdrian Chadd } 1085b2763056SSam Leffler 1086c1565b61SSam Leffler if (sn->ratemask == 0) { 1087b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1088b032f27cSSam Leffler &an->an_node, 1089b032f27cSSam Leffler "%s: size %d %s rate/try %d/%d no rates yet", 1090b032f27cSSam Leffler __func__, 109143e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1092eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 109343e9cf7cSSam Leffler short_tries, long_tries); 1094b2763056SSam Leffler return; 1095b2763056SSam Leffler } 1096af017101SAdrian Chadd mrr = sc->sc_mrretry; 1097af017101SAdrian Chadd /* XXX check HT protmode too */ 10989f579ef8SAdrian Chadd if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot)) 1099af017101SAdrian Chadd mrr = 0; 1100af017101SAdrian Chadd 1101f6cbf16aSSam Leffler if (!mrr || ts->ts_finaltsi == 0) { 1102c1565b61SSam Leffler if (!IS_RATE_DEFINED(sn, final_rix)) { 110376e6fd5dSGleb Smirnoff device_printf(sc->sc_dev, 110476e6fd5dSGleb Smirnoff "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", 110506c746edSAdrian Chadd __func__, ts->ts_rate, ts->ts_finaltsi, final_rix); 110676e6fd5dSGleb Smirnoff badrate(sc, 0, ts->ts_rate, long_tries, status); 1107ec9ee5e7SSam Leffler return; 1108ec9ee5e7SSam Leffler } 110965f9edeeSSam Leffler /* 111065f9edeeSSam Leffler * Only one rate was used; optimize work. 111165f9edeeSSam Leffler */ 1112b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1113f6fd8c7aSAdrian Chadd &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]", 1114b032f27cSSam Leffler __func__, 111543e9cf7cSSam Leffler bin_to_size(size_to_bin(frame_size)), 1116c4ac32a8SAdrian Chadd frame_size, 1117eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1118eb6f0de0SAdrian Chadd dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), 1119eb6f0de0SAdrian Chadd short_tries, long_tries, nframes, nbad); 1120b2763056SSam Leffler update_stats(sc, an, frame_size, 1121c1565b61SSam Leffler final_rix, long_tries, 1122eb6f0de0SAdrian Chadd short_tries, long_tries, status, 1123eb6f0de0SAdrian Chadd nframes, nbad); 1124eb6f0de0SAdrian Chadd 1125b2763056SSam Leffler } else { 112665f9edeeSSam Leffler int finalTSIdx = ts->ts_finaltsi; 1127bd97c52aSAdrian Chadd int i; 1128b2763056SSam Leffler 1129b2763056SSam Leffler /* 1130b2763056SSam Leffler * Process intermediate rates that failed. 1131b2763056SSam Leffler */ 1132ec9ee5e7SSam Leffler 1133b032f27cSSam Leffler IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, 1134b032f27cSSam Leffler &an->an_node, 1135f6fd8c7aSAdrian 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]", 1136b032f27cSSam Leffler __func__, 1137b2763056SSam Leffler bin_to_size(size_to_bin(frame_size)), 1138c4ac32a8SAdrian Chadd frame_size, 1139b2763056SSam Leffler finalTSIdx, 1140f6fd8c7aSAdrian Chadd short_tries, 1141b2763056SSam Leffler long_tries, 1142eb6f0de0SAdrian Chadd status ? "FAIL" : "OK", 1143eb6f0de0SAdrian Chadd dot11rate(rt, rc[0].rix), 1144eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[0].rix), rc[0].tries, 1145eb6f0de0SAdrian Chadd dot11rate(rt, rc[1].rix), 1146eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[1].rix), rc[1].tries, 1147eb6f0de0SAdrian Chadd dot11rate(rt, rc[2].rix), 1148eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[2].rix), rc[2].tries, 1149eb6f0de0SAdrian Chadd dot11rate(rt, rc[3].rix), 1150eb6f0de0SAdrian Chadd dot11rate_label(rt, rc[3].rix), rc[3].tries, 1151eb6f0de0SAdrian Chadd nframes, nbad); 1152c1565b61SSam Leffler 1153a6a308a4SAdrian Chadd for (i = 0; i < 4; i++) { 1154eb6f0de0SAdrian Chadd if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) 115576e6fd5dSGleb Smirnoff badrate(sc, 0, rc[i].ratecode, rc[i].tries, 1156eb6f0de0SAdrian Chadd status); 1157a6a308a4SAdrian Chadd } 1158b2763056SSam Leffler 115965f9edeeSSam Leffler /* 1160cce63444SAdrian Chadd * This used to not penalise other tries because loss 1161cce63444SAdrian Chadd * can be bursty, but it's then not accurately keeping 1162cce63444SAdrian Chadd * the avg TX time and EWMA updated. 116365f9edeeSSam Leffler */ 1164eb6f0de0SAdrian Chadd if (rc[0].tries) { 1165b2763056SSam Leffler update_stats(sc, an, frame_size, 1166eb6f0de0SAdrian Chadd rc[0].rix, rc[0].tries, 116765f9edeeSSam Leffler short_tries, long_tries, 1168eb6f0de0SAdrian Chadd long_tries > rc[0].tries, 1169eb6f0de0SAdrian Chadd nframes, nbad); 1170eb6f0de0SAdrian Chadd long_tries -= rc[0].tries; 1171b2763056SSam Leffler } 1172b2763056SSam Leffler 1173eb6f0de0SAdrian Chadd if (rc[1].tries && finalTSIdx > 0) { 1174b2763056SSam Leffler update_stats(sc, an, frame_size, 1175eb6f0de0SAdrian Chadd rc[1].rix, rc[1].tries, 117665f9edeeSSam Leffler short_tries, long_tries, 1177cce63444SAdrian Chadd long_tries > rc[1].tries, 1178eb6f0de0SAdrian Chadd nframes, nbad); 1179eb6f0de0SAdrian Chadd long_tries -= rc[1].tries; 1180b2763056SSam Leffler } 1181b2763056SSam Leffler 1182eb6f0de0SAdrian Chadd if (rc[2].tries && finalTSIdx > 1) { 1183b2763056SSam Leffler update_stats(sc, an, frame_size, 1184eb6f0de0SAdrian Chadd rc[2].rix, rc[2].tries, 118565f9edeeSSam Leffler short_tries, long_tries, 1186cce63444SAdrian Chadd long_tries > rc[2].tries, 1187eb6f0de0SAdrian Chadd nframes, nbad); 1188eb6f0de0SAdrian Chadd long_tries -= rc[2].tries; 1189b2763056SSam Leffler } 1190b2763056SSam Leffler 1191eb6f0de0SAdrian Chadd if (rc[3].tries && finalTSIdx > 2) { 1192b2763056SSam Leffler update_stats(sc, an, frame_size, 1193eb6f0de0SAdrian Chadd rc[3].rix, rc[3].tries, 119465f9edeeSSam Leffler short_tries, long_tries, 1195cce63444SAdrian Chadd long_tries > rc[3].tries, 1196eb6f0de0SAdrian Chadd nframes, nbad); 119738fda926SAdrian Chadd } 1198b2763056SSam Leffler } 1199fa20c234SSam Leffler } 1200fa20c234SSam Leffler 1201fa20c234SSam Leffler void 1202fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew) 1203fa20c234SSam Leffler { 1204fa20c234SSam Leffler if (isnew) 1205b2763056SSam Leffler ath_rate_ctl_reset(sc, &an->an_node); 1206fa20c234SSam Leffler } 1207fa20c234SSam Leffler 12087d450faaSAdrian Chadd void 12097d450faaSAdrian Chadd ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi) 12107d450faaSAdrian Chadd { 12117d450faaSAdrian Chadd } 12127d450faaSAdrian Chadd 12137d450faaSAdrian Chadd 1214c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = { 1215c1565b61SSam Leffler NULL, /* IEEE80211_MODE_AUTO */ 1216c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_11A */ 1217c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11B */ 1218c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_11G */ 1219c1565b61SSam Leffler NULL, /* IEEE80211_MODE_FH */ 1220c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_TURBO_A */ 1221c1565b61SSam Leffler series_11g, /* IEEE80211_MODE_TURBO_G */ 1222c1565b61SSam Leffler series_11a, /* IEEE80211_MODE_STURBO_A */ 1223a6a308a4SAdrian Chadd series_11na, /* IEEE80211_MODE_11NA */ 1224a6a308a4SAdrian Chadd series_11ng, /* IEEE80211_MODE_11NG */ 1225c1565b61SSam Leffler series_half, /* IEEE80211_MODE_HALF */ 1226c1565b61SSam Leffler series_quarter, /* IEEE80211_MODE_QUARTER */ 1227c1565b61SSam Leffler }; 1228c1565b61SSam Leffler 1229fa20c234SSam Leffler /* 1230fa20c234SSam Leffler * Initialize the tables for a node. 1231fa20c234SSam Leffler */ 1232fa20c234SSam Leffler static void 1233b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 1234fa20c234SSam Leffler { 1235fa20c234SSam Leffler #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) 1236c1565b61SSam Leffler #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) 1237a6a308a4SAdrian Chadd #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) 1238fa20c234SSam Leffler struct ath_node *an = ATH_NODE(ni); 1239fa20c234SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(an); 1240fa20c234SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1241c4ac32a8SAdrian Chadd int x, y, rix; 1242fa20c234SSam Leffler 1243fa20c234SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 1244c1565b61SSam Leffler 1245c1565b61SSam Leffler KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, 1246c1565b61SSam Leffler ("curmode %u", sc->sc_curmode)); 1247193bfa21SAdrian Chadd 1248c1565b61SSam Leffler sn->sched = mrr_schedules[sc->sc_curmode]; 1249c1565b61SSam Leffler KASSERT(sn->sched != NULL, 1250c1565b61SSam Leffler ("no mrr schedule for mode %u", sc->sc_curmode)); 1251c1565b61SSam Leffler 1252c1565b61SSam Leffler sn->static_rix = -1; 1253c4ac32a8SAdrian Chadd ath_rate_update_static_rix(sc, ni); 1254b2763056SSam Leffler 1255cc86f1eaSAdrian Chadd sn->currates = sc->sc_currates; 1256cc86f1eaSAdrian Chadd 1257c1565b61SSam Leffler /* 1258c1565b61SSam Leffler * Construct a bitmask of usable rates. This has all 1259c1565b61SSam Leffler * negotiated rates minus those marked by the hal as 1260c1565b61SSam Leffler * to be ignored for doing rate control. 1261c1565b61SSam Leffler */ 1262c1565b61SSam Leffler sn->ratemask = 0; 1263a6a308a4SAdrian Chadd /* MCS rates */ 1264a6a308a4SAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_HT) { 1265a6a308a4SAdrian Chadd for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { 1266a6a308a4SAdrian Chadd rix = sc->sc_rixmap[MCS(x)]; 1267a6a308a4SAdrian Chadd if (rix == 0xff) 1268a6a308a4SAdrian Chadd continue; 1269a6a308a4SAdrian Chadd /* skip rates marked broken by hal */ 1270a6a308a4SAdrian Chadd if (!rt->info[rix].valid) 1271a6a308a4SAdrian Chadd continue; 1272a6a308a4SAdrian Chadd KASSERT(rix < SAMPLE_MAXRATES, 1273a6a308a4SAdrian Chadd ("mcs %u has rix %d", MCS(x), rix)); 1274193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1275a6a308a4SAdrian Chadd } 1276a6a308a4SAdrian Chadd } 1277a6a308a4SAdrian Chadd 1278a6a308a4SAdrian Chadd /* Legacy rates */ 1279fa20c234SSam Leffler for (x = 0; x < ni->ni_rates.rs_nrates; x++) { 1280c1565b61SSam Leffler rix = sc->sc_rixmap[RATE(x)]; 1281c1565b61SSam Leffler if (rix == 0xff) 12820ae09ec5SSam Leffler continue; 1283c1565b61SSam Leffler /* skip rates marked broken by hal */ 1284c1565b61SSam Leffler if (!rt->info[rix].valid) 1285c1565b61SSam Leffler continue; 1286c1565b61SSam Leffler KASSERT(rix < SAMPLE_MAXRATES, 1287c1565b61SSam Leffler ("rate %u has rix %d", RATE(x), rix)); 1288193bfa21SAdrian Chadd sn->ratemask |= (uint64_t) 1<<rix; 1289b2763056SSam Leffler } 1290b032f27cSSam Leffler #ifdef IEEE80211_DEBUG 1291b032f27cSSam Leffler if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { 1292193bfa21SAdrian Chadd uint64_t mask; 1293c1565b61SSam Leffler 1294b032f27cSSam Leffler ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", 1295c1565b61SSam Leffler ni->ni_macaddr, ":", __func__); 1296c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1297c1565b61SSam Leffler if ((mask & 1) == 0) 1298b032f27cSSam Leffler continue; 1299ae0944b8SAdrian Chadd printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), 1300e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, 1600, rix, 0,0, 1301532f2442SAdrian Chadd (ni->ni_chw == 40))); 1302b032f27cSSam Leffler } 1303b032f27cSSam Leffler printf("\n"); 1304b032f27cSSam Leffler } 1305b032f27cSSam Leffler #endif 1306b2763056SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1307b2763056SSam Leffler int size = bin_to_size(y); 1308193bfa21SAdrian Chadd uint64_t mask; 1309c1565b61SSam Leffler 1310b2763056SSam Leffler sn->packets_sent[y] = 0; 1311c1565b61SSam Leffler sn->current_sample_rix[y] = -1; 1312c1565b61SSam Leffler sn->last_sample_rix[y] = 0; 1313c1565b61SSam Leffler /* XXX start with first valid rate */ 1314c1565b61SSam Leffler sn->current_rix[y] = ffs(sn->ratemask)-1; 1315b2763056SSam Leffler 1316c1565b61SSam Leffler /* 1317c1565b61SSam Leffler * Initialize the statistics buckets; these are 1318c1565b61SSam Leffler * indexed by the rate code index. 1319c1565b61SSam Leffler */ 1320c1565b61SSam Leffler for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) { 1321c1565b61SSam Leffler if ((mask & 1) == 0) /* not a valid rate */ 1322c1565b61SSam Leffler continue; 1323c1565b61SSam Leffler sn->stats[y][rix].successive_failures = 0; 1324c1565b61SSam Leffler sn->stats[y][rix].tries = 0; 1325c1565b61SSam Leffler sn->stats[y][rix].total_packets = 0; 1326c1565b61SSam Leffler sn->stats[y][rix].packets_acked = 0; 1327c1565b61SSam Leffler sn->stats[y][rix].last_tx = 0; 1328eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct = 0; 1329b2763056SSam Leffler 1330c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time = 1331e09c8c4cSAdrian Chadd calc_usecs_unicast_packet(sc, size, rix, 0, 0, 1332532f2442SAdrian Chadd (ni->ni_chw == 40)); 1333c1565b61SSam Leffler sn->stats[y][rix].average_tx_time = 1334c1565b61SSam Leffler sn->stats[y][rix].perfect_tx_time; 1335b2763056SSam Leffler } 1336b91bf513SSam Leffler } 1337c1565b61SSam Leffler #if 0 1338c1565b61SSam Leffler /* XXX 0, num_rates-1 are wrong */ 1339b032f27cSSam Leffler IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, 1340b032f27cSSam Leffler "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 1341b91bf513SSam Leffler sn->num_rates, 1342c1565b61SSam Leffler DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "", 1343b91bf513SSam Leffler sn->stats[1][0].perfect_tx_time, 1344c1565b61SSam Leffler DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "", 1345b91bf513SSam Leffler sn->stats[1][sn->num_rates-1].perfect_tx_time 1346b91bf513SSam Leffler ); 1347c1565b61SSam Leffler #endif 1348b032f27cSSam Leffler /* set the visible bit-rate */ 1349c1565b61SSam Leffler if (sn->static_rix != -1) 1350c1565b61SSam Leffler ni->ni_txrate = DOT11RATE(sn->static_rix); 1351d0d425bfSSam Leffler else 1352c1565b61SSam Leffler ni->ni_txrate = RATE(0); 1353fa20c234SSam Leffler #undef RATE 1354c1565b61SSam Leffler #undef DOT11RATE 1355fa20c234SSam Leffler } 1356fa20c234SSam Leffler 13572d20d655SAdrian Chadd /* 13582d20d655SAdrian Chadd * Fetch the statistics for the given node. 13592d20d655SAdrian Chadd * 13602d20d655SAdrian Chadd * The ieee80211 node must be referenced and unlocked, however the ath_node 13612d20d655SAdrian Chadd * must be locked. 13622d20d655SAdrian Chadd * 13632d20d655SAdrian Chadd * The main difference here is that we convert the rate indexes 13642d20d655SAdrian Chadd * to 802.11 rates, or the userland output won't make much sense 13652d20d655SAdrian Chadd * as it has no access to the rix table. 13662d20d655SAdrian Chadd */ 13672d20d655SAdrian Chadd int 13682d20d655SAdrian Chadd ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an, 13692d20d655SAdrian Chadd struct ath_rateioctl *rs) 13702d20d655SAdrian Chadd { 13712d20d655SAdrian Chadd struct sample_node *sn = ATH_NODE_SAMPLE(an); 13722d20d655SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates; 13732d20d655SAdrian Chadd struct ath_rateioctl_tlv av; 1374be4f96a6SAdrian Chadd struct ath_rateioctl_rt *tv; 13752d20d655SAdrian Chadd int y; 1376be4f96a6SAdrian Chadd int o = 0; 13772d20d655SAdrian Chadd 13782d20d655SAdrian Chadd ATH_NODE_LOCK_ASSERT(an); 13792d20d655SAdrian Chadd 13802d20d655SAdrian Chadd /* 13812d20d655SAdrian Chadd * Ensure there's enough space for the statistics. 13822d20d655SAdrian Chadd */ 13832d20d655SAdrian Chadd if (rs->len < 13842d20d655SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1385be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_rt) + 1386be4f96a6SAdrian Chadd sizeof(struct ath_rateioctl_tlv) + 1387be4f96a6SAdrian Chadd sizeof(struct sample_node)) { 1388be4f96a6SAdrian Chadd device_printf(sc->sc_dev, "%s: len=%d, too short\n", 1389be4f96a6SAdrian Chadd __func__, 1390be4f96a6SAdrian Chadd rs->len); 13912d20d655SAdrian Chadd return (EINVAL); 1392be4f96a6SAdrian Chadd } 13932d20d655SAdrian Chadd 13942d20d655SAdrian Chadd /* 13952d20d655SAdrian Chadd * Take a temporary copy of the sample node state so we can 13962d20d655SAdrian Chadd * modify it before we copy it. 13972d20d655SAdrian Chadd */ 1398be4f96a6SAdrian Chadd tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP, 1399be4f96a6SAdrian Chadd M_NOWAIT | M_ZERO); 1400be4f96a6SAdrian Chadd if (tv == NULL) { 14012d20d655SAdrian Chadd return (ENOMEM); 14022d20d655SAdrian Chadd } 14032d20d655SAdrian Chadd 14042d20d655SAdrian Chadd /* 1405be4f96a6SAdrian Chadd * Populate the rate table mapping TLV. 1406be4f96a6SAdrian Chadd */ 1407be4f96a6SAdrian Chadd tv->nentries = rt->rateCount; 1408be4f96a6SAdrian Chadd for (y = 0; y < rt->rateCount; y++) { 1409be4f96a6SAdrian Chadd tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL; 1410be4f96a6SAdrian Chadd if (rt->info[y].phy == IEEE80211_T_HT) 1411be4f96a6SAdrian Chadd tv->ratecode[y] |= IEEE80211_RATE_MCS; 1412be4f96a6SAdrian Chadd } 1413be4f96a6SAdrian Chadd 1414be4f96a6SAdrian Chadd o = 0; 1415be4f96a6SAdrian Chadd /* 1416be4f96a6SAdrian Chadd * First TLV - rate code mapping 1417be4f96a6SAdrian Chadd */ 1418be4f96a6SAdrian Chadd av.tlv_id = ATH_RATE_TLV_RATETABLE; 1419be4f96a6SAdrian Chadd av.tlv_len = sizeof(struct ath_rateioctl_rt); 1420be4f96a6SAdrian Chadd copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1421be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 1422be4f96a6SAdrian Chadd copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); 1423be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_rt); 1424be4f96a6SAdrian Chadd 1425be4f96a6SAdrian Chadd /* 1426be4f96a6SAdrian Chadd * Second TLV - sample node statistics 14272d20d655SAdrian Chadd */ 14282d20d655SAdrian Chadd av.tlv_id = ATH_RATE_TLV_SAMPLENODE; 14292d20d655SAdrian Chadd av.tlv_len = sizeof(struct sample_node); 1430be4f96a6SAdrian Chadd copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); 1431be4f96a6SAdrian Chadd o += sizeof(struct ath_rateioctl_tlv); 14322d20d655SAdrian Chadd 14332d20d655SAdrian Chadd /* 14342d20d655SAdrian Chadd * Copy the statistics over to the provided buffer. 14352d20d655SAdrian Chadd */ 1436be4f96a6SAdrian Chadd copyout(sn, rs->buf + o, sizeof(struct sample_node)); 1437be4f96a6SAdrian Chadd o += sizeof(struct sample_node); 14382d20d655SAdrian Chadd 1439be4f96a6SAdrian Chadd free(tv, M_TEMP); 14402d20d655SAdrian Chadd 14412d20d655SAdrian Chadd return (0); 14422d20d655SAdrian Chadd } 14432d20d655SAdrian Chadd 1444f0fd5e07SSam Leffler static void 1445c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni) 1446c1565b61SSam Leffler { 1447c1565b61SSam Leffler struct ath_softc *sc = arg; 1448c1565b61SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 1449c1565b61SSam Leffler struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni)); 1450193bfa21SAdrian Chadd uint64_t mask; 1451c1565b61SSam Leffler int rix, y; 1452c1565b61SSam Leffler 1453a055e7ceSKonstantin Belousov printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n", 1454c1565b61SSam Leffler ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni), 1455eb6f0de0SAdrian Chadd dot11rate(rt, sn->static_rix), 1456eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->static_rix), 1457a055e7ceSKonstantin Belousov (uintmax_t)sn->ratemask); 1458c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1459ae0944b8SAdrian Chadd printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n", 1460c1565b61SSam Leffler bin_to_size(y), sn->current_rix[y], 1461ae0944b8SAdrian Chadd dot11rate(rt, sn->current_rix[y]), 1462ae0944b8SAdrian Chadd dot11rate_label(rt, sn->current_rix[y]), 1463c1565b61SSam Leffler sn->packets_since_switch[y], sn->ticks_since_switch[y]); 1464eb6f0de0SAdrian Chadd printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n", 1465eb6f0de0SAdrian Chadd bin_to_size(y), 1466eb6f0de0SAdrian Chadd dot11rate(rt, sn->last_sample_rix[y]), 1467eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->last_sample_rix[y]), 1468eb6f0de0SAdrian Chadd dot11rate(rt, sn->current_sample_rix[y]), 1469eb6f0de0SAdrian Chadd dot11rate_label(rt, sn->current_sample_rix[y]), 1470eb6f0de0SAdrian Chadd sn->packets_sent[y]); 1471c1565b61SSam Leffler printf("[%4u] packets since sample %d sample tt %u\n", 1472c1565b61SSam Leffler bin_to_size(y), sn->packets_since_sample[y], 1473c1565b61SSam Leffler sn->sample_tt[y]); 1474c1565b61SSam Leffler } 1475c1565b61SSam Leffler for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 1476c1565b61SSam Leffler if ((mask & 1) == 0) 1477c1565b61SSam Leffler continue; 1478c1565b61SSam Leffler for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 1479c1565b61SSam Leffler if (sn->stats[y][rix].total_packets == 0) 1480c1565b61SSam Leffler continue; 1481eb6f0de0SAdrian Chadd printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n", 1482ae0944b8SAdrian Chadd dot11rate(rt, rix), dot11rate_label(rt, rix), 1483c1565b61SSam Leffler bin_to_size(y), 148487acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].total_packets, 148587acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].packets_acked, 148687acb7d5SAdrian Chadd (int) ((sn->stats[y][rix].packets_acked * 100ULL) / 148787acb7d5SAdrian Chadd sn->stats[y][rix].total_packets), 1488eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct / 10, 1489eb6f0de0SAdrian Chadd sn->stats[y][rix].ewma_pct % 10, 149087acb7d5SAdrian Chadd (uintmax_t) sn->stats[y][rix].tries, 1491c1565b61SSam Leffler sn->stats[y][rix].successive_failures, 1492c1565b61SSam Leffler sn->stats[y][rix].average_tx_time, 1493c1565b61SSam Leffler ticks - sn->stats[y][rix].last_tx); 1494c1565b61SSam Leffler } 1495c1565b61SSam Leffler } 1496c1565b61SSam Leffler } 1497c1565b61SSam Leffler 1498c1565b61SSam Leffler static int 1499c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS) 1500c1565b61SSam Leffler { 1501c1565b61SSam Leffler struct ath_softc *sc = arg1; 15027a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 1503c1565b61SSam Leffler int error, v; 1504c1565b61SSam Leffler 1505c1565b61SSam Leffler v = 0; 1506c1565b61SSam Leffler error = sysctl_handle_int(oidp, &v, 0, req); 1507c1565b61SSam Leffler if (error || !req->newptr) 1508c1565b61SSam Leffler return error; 1509c1565b61SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc); 1510c1565b61SSam Leffler return 0; 1511c1565b61SSam Leffler } 1512c1565b61SSam Leffler 1513c1565b61SSam Leffler static int 1514c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS) 1515c1565b61SSam Leffler { 1516c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1517c1565b61SSam Leffler int rate, error; 1518c1565b61SSam Leffler 1519c1565b61SSam Leffler rate = ssc->smoothing_rate; 1520c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1521c1565b61SSam Leffler if (error || !req->newptr) 1522c1565b61SSam Leffler return error; 1523c1565b61SSam Leffler if (!(0 <= rate && rate < 100)) 1524c1565b61SSam Leffler return EINVAL; 1525c1565b61SSam Leffler ssc->smoothing_rate = rate; 1526c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - rate); 1527c1565b61SSam Leffler return 0; 1528c1565b61SSam Leffler } 1529c1565b61SSam Leffler 1530c1565b61SSam Leffler static int 1531c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) 1532c1565b61SSam Leffler { 1533c1565b61SSam Leffler struct sample_softc *ssc = arg1; 1534c1565b61SSam Leffler int rate, error; 1535c1565b61SSam Leffler 1536c1565b61SSam Leffler rate = ssc->sample_rate; 1537c1565b61SSam Leffler error = sysctl_handle_int(oidp, &rate, 0, req); 1538c1565b61SSam Leffler if (error || !req->newptr) 1539c1565b61SSam Leffler return error; 1540c1565b61SSam Leffler if (!(2 <= rate && rate <= 100)) 1541c1565b61SSam Leffler return EINVAL; 1542c1565b61SSam Leffler ssc->sample_rate = rate; 1543c1565b61SSam Leffler return 0; 1544c1565b61SSam Leffler } 1545c1565b61SSam Leffler 1546c1565b61SSam Leffler static void 1547c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc) 1548fa20c234SSam Leffler { 1549fa20c234SSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 1550fa20c234SSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 1551fa20c234SSam Leffler 1552c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 155308f5e6bbSPawel Biernacki "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 155408f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_smoothing_rate, "I", 1555c1565b61SSam Leffler "sample: smoothing rate for avg tx time (%%)"); 1556c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 155708f5e6bbSPawel Biernacki "sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 155808f5e6bbSPawel Biernacki ssc, 0, ath_rate_sysctl_sample_rate, "I", 1559c1565b61SSam Leffler "sample: percent air time devoted to sampling new rates (%%)"); 1560c1565b61SSam Leffler /* XXX max_successive_failures, stale_failure_timeout, min_switch */ 1561c1565b61SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 156208f5e6bbSPawel Biernacki "sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 156308f5e6bbSPawel Biernacki sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics"); 1564fa20c234SSam Leffler } 1565fa20c234SSam Leffler 1566fa20c234SSam Leffler struct ath_ratectrl * 1567fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc) 1568fa20c234SSam Leffler { 1569c1565b61SSam Leffler struct sample_softc *ssc; 1570fa20c234SSam Leffler 1571c1565b61SSam Leffler ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO); 1572c1565b61SSam Leffler if (ssc == NULL) 1573fa20c234SSam Leffler return NULL; 1574c1565b61SSam Leffler ssc->arc.arc_space = sizeof(struct sample_node); 1575e69db8dfSAdrian Chadd ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */ 1576c1565b61SSam Leffler ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate); 1577c1565b61SSam Leffler ssc->sample_rate = 10; /* %time to try diff tx rates */ 1578c1565b61SSam Leffler ssc->max_successive_failures = 3; /* threshold for rate sampling*/ 1579c1565b61SSam Leffler ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */ 1580c1565b61SSam Leffler ssc->min_switch = hz; /* 1 second */ 1581c1565b61SSam Leffler ath_rate_sysctlattach(sc, ssc); 1582c1565b61SSam Leffler return &ssc->arc; 1583fa20c234SSam Leffler } 1584fa20c234SSam Leffler 1585fa20c234SSam Leffler void 1586fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc) 1587fa20c234SSam Leffler { 1588c1565b61SSam Leffler struct sample_softc *ssc = (struct sample_softc *) arc; 1589fa20c234SSam Leffler 1590c1565b61SSam Leffler free(ssc, M_DEVBUF); 1591fa20c234SSam Leffler } 1592