Path: blob/main/sys/dev/ath/ath_rate/sample/sample.c
39565 views
/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 2005 John Bicket4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer,11* without modification.12* 2. Redistributions in binary form must reproduce at minimum a disclaimer13* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any14* redistribution must be conditioned upon including a substantially15* similar Disclaimer requirement for further binary redistribution.16* 3. Neither the names of the above-listed copyright holders nor the names17* of any contributors may be used to endorse or promote products derived18* from this software without specific prior written permission.19*20* Alternatively, this software may be distributed under the terms of the21* GNU General Public License ("GPL") version 2 as published by the Free22* Software Foundation.23*24* NO WARRANTY25* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS26* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT27* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY28* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL29* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,30* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF31* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS32* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER33* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)34* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF35* THE POSSIBILITY OF SUCH DAMAGES.36*37*/3839#include <sys/cdefs.h>40/*41* John Bicket's SampleRate control algorithm.42*/43#include "opt_ath.h"44#include "opt_inet.h"45#include "opt_wlan.h"46#include "opt_ah.h"4748#include <sys/param.h>49#include <sys/systm.h>50#include <sys/sysctl.h>51#include <sys/kernel.h>52#include <sys/lock.h>53#include <sys/malloc.h>54#include <sys/mutex.h>55#include <sys/errno.h>5657#include <machine/bus.h>58#include <machine/resource.h>59#include <sys/bus.h>6061#include <sys/socket.h>6263#include <net/if.h>64#include <net/if_var.h>65#include <net/if_media.h>66#include <net/if_arp.h>67#include <net/ethernet.h> /* XXX for ether_sprintf */6869#include <net80211/ieee80211_var.h>7071#include <net/bpf.h>7273#ifdef INET74#include <netinet/in.h>75#include <netinet/if_ether.h>76#endif7778#include <dev/ath/if_athvar.h>79#include <dev/ath/ath_rate/sample/sample.h>80#include <dev/ath/ath_hal/ah_desc.h>81#include <dev/ath/ath_rate/sample/tx_schedules.h>8283/*84* This file is an implementation of the SampleRate algorithm85* in "Bit-rate Selection in Wireless Networks"86* (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)87*88* SampleRate chooses the bit-rate it predicts will provide the most89* throughput based on estimates of the expected per-packet90* transmission time for each bit-rate. SampleRate periodically sends91* packets at bit-rates other than the current one to estimate when92* another bit-rate will provide better performance. SampleRate93* switches to another bit-rate when its estimated per-packet94* transmission time becomes smaller than the current bit-rate's.95* SampleRate reduces the number of bit-rates it must sample by96* eliminating those that could not perform better than the one97* currently being used. SampleRate also stops probing at a bit-rate98* if it experiences several successive losses.99*100* The difference between the algorithm in the thesis and the one in this101* file is that the one in this file uses a ewma instead of a window.102*103* Also, this implementation tracks the average transmission time for104* a few different packet sizes independently for each link.105*/106107/* XXX TODO: move this into ath_hal/net80211 so it can be shared */108109#define MCS_HT20 0110#define MCS_HT20_SGI 1111#define MCS_HT40 2112#define MCS_HT40_SGI 3113114/*115* This is currently a copy/paste from the 11n tx code.116*117* It's used to determine the maximum frame length allowed for the118* given rate. For now this ignores SGI/LGI and will assume long-GI.119* This only matters for lower rates that can't fill a full 64k A-MPDU.120*121* (But it's also important because right now rate control doesn't set122* flags like SGI/LGI, STBC, LDPC, TX power, etc.)123*124* When selecting a set of rates the rate control code will iterate125* over the HT20/HT40 max frame length and tell the caller the maximum126* length (@ LGI.) It will also choose a bucket that's the minimum127* of this value and the provided aggregate length. That way the128* rate selection will closely match what the eventual formed aggregate129* will be rather than "not at all".130*/131132static int ath_rate_sample_max_4ms_framelen[4][32] = {133[MCS_HT20] = {1343212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,1356424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,1369628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,13712828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,138},139[MCS_HT20_SGI] = {1403572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,1417140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,14210700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,14314256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,144},145[MCS_HT40] = {1466680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,14713348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,14820004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,14926644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,150},151[MCS_HT40_SGI] = {1527420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,15314832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,15422232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,15529616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,156}157};158159/*160* Given the (potentially MRR) transmit schedule, calculate the maximum161* allowed packet size for forming aggregates based on the lowest162* MCS rate in the transmit schedule.163*164* Returns -1 if it's a legacy rate or no MRR.165*166* XXX TODO: this needs to be limited by the RTS/CTS AR5416 8KB bug limit!167* (by checking rts/cts flags and applying sc_rts_aggr_limit)168*169* XXX TODO: apply per-node max-ampdu size and driver ampdu size limits too.170*/171static int172ath_rate_sample_find_min_pktlength(struct ath_softc *sc,173struct ath_node *an, uint8_t rix0, int is_aggr)174{175#define MCS_IDX(ix) (rt->info[ix].dot11Rate)176const HAL_RATE_TABLE *rt = sc->sc_currates;177struct sample_node *sn = ATH_NODE_SAMPLE(an);178const struct txschedule *sched = &sn->sched[rix0];179int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE180// Note: this may not be true in all cases; need to check?181int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40);182// Note: not great, but good enough..183int idx = is_ht40 ? MCS_HT40 : MCS_HT20;184185if (rt->info[rix0].phy != IEEE80211_T_HT) {186return -1;187}188189if (! sc->sc_mrretry) {190return -1;191}192193KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",194rix0, sched->r0));195196/*197* Update based on sched->r{0,1,2,3} if sched->t{0,1,2,3}198* is not zero.199*200* Note: assuming all four PHYs are HT!201*202* XXX TODO: right now I hardcode here and in getxtxrates() that203* rates 2 and 3 in the tx schedule are ignored. This is important204* for forming larger aggregates because right now (a) the tx schedule205* per rate is fixed, and (b) reliable packet transmission at those206* higher rates kinda needs a lower MCS rate in there somewhere.207* However, this means we can only form shorter aggregates.208* If we've negotiated aggregation then we can actually just209* rely on software retransmit rather than having things fall210* back to like MCS0/1 in hardware, and rate control will hopefully211* do the right thing.212*213* Once the whole rate schedule is passed into ath_rate_findrate(),214* the ath_rc_series is populated ,the fixed tx schedule stuff215* is removed AND getxtxrates() is removed then we can remove this216* check as it can just NOT populate t2/t3. It also means217* probing can actually use rix0 for probeing and rix1 for the218* current best rate..219*/220if (sched->t0 != 0) {221max_pkt_length = MIN(max_pkt_length,222ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]);223}224if (sched->t1 != 0) {225max_pkt_length = MIN(max_pkt_length,226ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]);227}228if (sched->t2 != 0 && (! is_aggr)) {229max_pkt_length = MIN(max_pkt_length,230ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]);231}232if (sched->t3 != 0 && (! is_aggr)) {233max_pkt_length = MIN(max_pkt_length,234ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]);235}236237return max_pkt_length;238#undef MCS239}240241static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);242243static __inline int244size_to_bin(int size)245{246#if NUM_PACKET_SIZE_BINS > 1247if (size <= packet_size_bins[0])248return 0;249#endif250#if NUM_PACKET_SIZE_BINS > 2251if (size <= packet_size_bins[1])252return 1;253#endif254#if NUM_PACKET_SIZE_BINS > 3255if (size <= packet_size_bins[2])256return 2;257#endif258#if NUM_PACKET_SIZE_BINS > 4259if (size <= packet_size_bins[3])260return 3;261#endif262#if NUM_PACKET_SIZE_BINS > 5263if (size <= packet_size_bins[4])264return 4;265#endif266#if NUM_PACKET_SIZE_BINS > 6267if (size <= packet_size_bins[5])268return 5;269#endif270#if NUM_PACKET_SIZE_BINS > 7271if (size <= packet_size_bins[6])272return 6;273#endif274#if NUM_PACKET_SIZE_BINS > 8275#error "add support for more packet sizes"276#endif277return NUM_PACKET_SIZE_BINS-1;278}279280void281ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)282{283/* NB: assumed to be zero'd by caller */284}285286void287ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)288{289}290291static int292dot11rate(const HAL_RATE_TABLE *rt, int rix)293{294if (rix < 0)295return -1;296return rt->info[rix].phy == IEEE80211_T_HT ?297rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;298}299300static const char *301dot11rate_label(const HAL_RATE_TABLE *rt, int rix)302{303if (rix < 0)304return "";305return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";306}307308/*309* Return the rix with the lowest average_tx_time,310* or -1 if all the average_tx_times are 0.311*/312static __inline int313pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt,314int size_bin, int require_acked_before)315{316struct sample_node *sn = ATH_NODE_SAMPLE(an);317int best_rate_rix, best_rate_tt, best_rate_pct;318uint64_t mask;319int rix, tt, pct;320321best_rate_rix = 0;322best_rate_tt = 0;323best_rate_pct = 0;324for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {325if ((mask & 1) == 0) /* not a supported rate */326continue;327328/* Don't pick a non-HT rate for a HT node */329if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&330(rt->info[rix].phy != IEEE80211_T_HT)) {331continue;332}333334tt = sn->stats[size_bin][rix].average_tx_time;335if (tt <= 0 ||336(require_acked_before &&337!sn->stats[size_bin][rix].packets_acked))338continue;339340/* Calculate percentage if possible */341if (sn->stats[size_bin][rix].total_packets > 0) {342pct = sn->stats[size_bin][rix].ewma_pct;343} else {344pct = -1; /* No percent yet to compare against! */345}346347/* don't use a bit-rate that has been failing */348if (sn->stats[size_bin][rix].successive_failures > 3)349continue;350351/*352* For HT, Don't use a bit rate that is more353* lossy than the best. Give a bit of leeway.354*355* Don't consider best rates that we haven't seen356* packets for yet; let sampling start inflence that.357*/358if (an->an_node.ni_flags & IEEE80211_NODE_HT) {359if (pct == -1)360continue;361#if 0362IEEE80211_NOTE(an->an_node.ni_vap,363IEEE80211_MSG_RATECTL,364&an->an_node,365"%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) "366"to 0x%x pkts/ewma/tt (%ju/%d/%d)",367__func__,368bin_to_size(size_bin),369rt->info[best_rate_rix].dot11Rate,370sn->stats[size_bin][best_rate_rix].total_packets,371best_rate_pct,372best_rate_tt,373rt->info[rix].dot11Rate,374sn->stats[size_bin][rix].total_packets,375pct,376tt);377#endif378if (best_rate_pct > (pct + 50))379continue;380}381/*382* For non-MCS rates, use the current average txtime for383* comparison.384*/385if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {386if (best_rate_tt == 0 || tt <= best_rate_tt) {387best_rate_tt = tt;388best_rate_rix = rix;389best_rate_pct = pct;390}391}392393/*394* Since 2 and 3 stream rates have slightly higher TX times,395* allow a little bit of leeway. This should later396* be abstracted out and properly handled.397*/398if (an->an_node.ni_flags & IEEE80211_NODE_HT) {399if (best_rate_tt == 0 ||400((tt * 9) <= (best_rate_tt * 10))) {401best_rate_tt = tt;402best_rate_rix = rix;403best_rate_pct = pct;404}405}406}407return (best_rate_tt ? best_rate_rix : -1);408}409410/*411* Pick a good "random" bit-rate to sample other than the current one.412*/413static __inline int414pick_sample_rate(struct sample_softc *ssc , struct ath_node *an,415const HAL_RATE_TABLE *rt, int size_bin)416{417#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)418#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)419struct sample_node *sn = ATH_NODE_SAMPLE(an);420int current_rix, rix;421unsigned current_tt;422uint64_t mask;423424current_rix = sn->current_rix[size_bin];425if (current_rix < 0) {426/* no successes yet, send at the lowest bit-rate */427/* XXX TODO should return MCS0 if HT */428return 0;429}430431current_tt = sn->stats[size_bin][current_rix].average_tx_time;432433rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */434mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */435while (mask != 0) {436if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */437nextrate:438if (++rix >= rt->rateCount)439rix = 0;440continue;441}442443/*444* The following code stops trying to sample445* non-MCS rates when speaking to an MCS node.446* However, at least for CCK rates in 2.4GHz mode,447* the non-MCS rates MAY actually provide better448* PER at the very far edge of reception.449*450* However! Until ath_rate_form_aggr() grows451* some logic to not form aggregates if the452* selected rate is non-MCS, this won't work.453*454* So don't disable this code until you've taught455* ath_rate_form_aggr() to drop out if any of456* the selected rates are non-MCS.457*/458#if 1459/* if the node is HT and the rate isn't HT, don't bother sample */460if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&461(rt->info[rix].phy != IEEE80211_T_HT)) {462mask &= ~((uint64_t) 1<<rix);463goto nextrate;464}465#endif466467/* this bit-rate is always worse than the current one */468if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {469mask &= ~((uint64_t) 1<<rix);470goto nextrate;471}472473/* rarely sample bit-rates that fail a lot */474if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&475ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {476mask &= ~((uint64_t) 1<<rix);477goto nextrate;478}479480/*481* For HT, only sample a few rates on either side of the482* current rix; there's quite likely a lot of them.483*484* This is limited to testing rate indexes on either side of485* this MCS, but for all spatial streams.486*487* Otherwise we'll (a) never really sample higher MCS488* rates if we're stuck low, and we'll make weird moves489* like sample MCS8 if we're using MCS7.490*/491if (an->an_node.ni_flags & IEEE80211_NODE_HT) {492uint8_t current_mcs, rix_mcs;493494current_mcs = MCS(current_rix) & 0x7;495rix_mcs = MCS(rix) & 0x7;496497if (rix_mcs < (current_mcs - 2) ||498rix_mcs > (current_mcs + 2)) {499mask &= ~((uint64_t) 1<<rix);500goto nextrate;501}502}503504/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */505if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {506if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {507mask &= ~((uint64_t) 1<<rix);508goto nextrate;509}510}511512sn->last_sample_rix[size_bin] = rix;513return rix;514}515return current_rix;516#undef DOT11RATE517#undef MCS518}519520static int521ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni)522{523#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)524#define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)525#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)526const struct ieee80211_txparam *tp = ni->ni_txparms;527int srate;528529/* Check MCS rates */530for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) {531if (MCS(srate) == tp->ucastrate)532return sc->sc_rixmap[tp->ucastrate];533}534535/* Check legacy rates */536for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) {537if (RATE(srate) == tp->ucastrate)538return sc->sc_rixmap[tp->ucastrate];539}540return -1;541#undef RATE542#undef DOT11RATE543#undef MCS544}545546static void547ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni)548{549struct ath_node *an = ATH_NODE(ni);550const struct ieee80211_txparam *tp = ni->ni_txparms;551struct sample_node *sn = ATH_NODE_SAMPLE(an);552553if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {554/*555* A fixed rate is to be used; ucastrate is the IEEE code556* for this rate (sans basic bit). Check this against the557* negotiated rate set for the node. Note the fixed rate558* may not be available for various reasons so we only559* setup the static rate index if the lookup is successful.560*/561sn->static_rix = ath_rate_get_static_rix(sc, ni);562} else {563sn->static_rix = -1;564}565}566567/*568* Pick a non-HT rate to begin using.569*/570static int571ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an,572int frameLen)573{574#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)575#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)576#define RATE(ix) (DOT11RATE(ix) / 2)577int rix = -1;578const HAL_RATE_TABLE *rt = sc->sc_currates;579struct sample_node *sn = ATH_NODE_SAMPLE(an);580const int size_bin = size_to_bin(frameLen);581582/* no packet has been sent successfully yet */583for (rix = rt->rateCount-1; rix > 0; rix--) {584if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)585continue;586587/* Skip HT rates */588if (rt->info[rix].phy == IEEE80211_T_HT)589continue;590591/*592* Pick the highest rate <= 36 Mbps593* that hasn't failed.594*/595if (DOT11RATE(rix) <= 72 &&596sn->stats[size_bin][rix].successive_failures == 0) {597break;598}599}600return rix;601#undef RATE602#undef MCS603#undef DOT11RATE604}605606/*607* Pick a HT rate to begin using.608*609* Don't use any non-HT rates; only consider HT rates.610*/611static int612ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an,613int frameLen)614{615#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)616#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)617#define RATE(ix) (DOT11RATE(ix) / 2)618int rix = -1, ht_rix = -1;619const HAL_RATE_TABLE *rt = sc->sc_currates;620struct sample_node *sn = ATH_NODE_SAMPLE(an);621const int size_bin = size_to_bin(frameLen);622623/* no packet has been sent successfully yet */624for (rix = rt->rateCount-1; rix > 0; rix--) {625/* Skip rates we can't use */626if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)627continue;628629/* Keep a copy of the last seen HT rate index */630if (rt->info[rix].phy == IEEE80211_T_HT)631ht_rix = rix;632633/* Skip non-HT rates */634if (rt->info[rix].phy != IEEE80211_T_HT)635continue;636637/*638* Pick a medium-speed rate at 1 spatial stream639* which has not seen any failures.640* Higher rates may fail; we'll try them later.641*/642if (((MCS(rix)& 0x7f) <= 4) &&643sn->stats[size_bin][rix].successive_failures == 0) {644break;645}646}647648/*649* If all the MCS rates have successive failures, rix should be650* > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)651*/652return MAX(rix, ht_rix);653#undef RATE654#undef MCS655#undef DOT11RATE656}657658void659ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,660int shortPreamble, size_t frameLen, int tid,661int is_aggr, u_int8_t *rix0, int *try0,662u_int8_t *txrate, int *maxdur, int *maxpktlen)663{664#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)665#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)666#define RATE(ix) (DOT11RATE(ix) / 2)667struct sample_node *sn = ATH_NODE_SAMPLE(an);668struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);669struct ieee80211com *ic = &sc->sc_ic;670const HAL_RATE_TABLE *rt = sc->sc_currates;671int size_bin = size_to_bin(frameLen);672int rix, mrr, best_rix, change_rates;673unsigned average_tx_time;674int max_pkt_len;675676ath_rate_update_static_rix(sc, &an->an_node);677678/* For now don't take TID, is_aggr into account */679/* Also for now don't calculate a max duration; that'll come later */680*maxdur = -1;681682/*683* For now just set it to the frame length; we'll optimise it later.684*/685*maxpktlen = frameLen;686687if (sn->currates != sc->sc_currates) {688device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",689__func__);690rix = 0;691*try0 = ATH_TXMAXTRY;692goto done;693}694695if (sn->static_rix != -1) {696rix = sn->static_rix;697*try0 = ATH_TXMAXTRY;698699/*700* Ensure we limit max packet length here too!701*/702max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an,703sn->static_rix,704is_aggr);705if (max_pkt_len > 0) {706*maxpktlen = frameLen = MIN(frameLen, max_pkt_len);707size_bin = size_to_bin(frameLen);708}709goto done;710}711712mrr = sc->sc_mrretry;713/* XXX check HT protmode too */714/* XXX turn into a cap; 11n MACs support MRR+RTSCTS */715if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))716mrr = 0;717718best_rix = pick_best_rate(an, rt, size_bin, !mrr);719720/*721* At this point we've chosen the best rix, so now we722* need to potentially update our maximum packet length723* and size_bin if we're doing 11n rates.724*/725max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix,726is_aggr);727if (max_pkt_len > 0) {728#if 0729device_printf(sc->sc_dev,730"Limiting maxpktlen from %d to %d bytes\n",731(int) frameLen, max_pkt_len);732#endif733*maxpktlen = frameLen = MIN(frameLen, max_pkt_len);734size_bin = size_to_bin(frameLen);735}736737if (best_rix >= 0) {738average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;739} else {740average_tx_time = 0;741}742743/*744* Limit the time measuring the performance of other tx745* rates to sample_rate% of the total transmission time.746*/747if (sn->sample_tt[size_bin] <748average_tx_time *749(sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {750rix = pick_sample_rate(ssc, an, rt, size_bin);751IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,752&an->an_node, "att %d sample_tt %d size %u "753"sample rate %d %s current rate %d %s",754average_tx_time,755sn->sample_tt[size_bin],756bin_to_size(size_bin),757dot11rate(rt, rix),758dot11rate_label(rt, rix),759dot11rate(rt, sn->current_rix[size_bin]),760dot11rate_label(rt, sn->current_rix[size_bin]));761if (rix != sn->current_rix[size_bin]) {762sn->current_sample_rix[size_bin] = rix;763} else {764sn->current_sample_rix[size_bin] = -1;765}766sn->packets_since_sample[size_bin] = 0;767} else {768change_rates = 0;769if (!sn->packets_sent[size_bin] || best_rix == -1) {770/* no packet has been sent successfully yet */771change_rates = 1;772if (an->an_node.ni_flags & IEEE80211_NODE_HT)773best_rix =774ath_rate_pick_seed_rate_ht(sc, an, frameLen);775else776best_rix =777ath_rate_pick_seed_rate_legacy(sc, an, frameLen);778} else if (sn->packets_sent[size_bin] < 20) {779/* let the bit-rate switch quickly during the first few packets */780IEEE80211_NOTE(an->an_node.ni_vap,781IEEE80211_MSG_RATECTL, &an->an_node,782"%s: switching quickly..", __func__);783change_rates = 1;784} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {785/* min_switch seconds have gone by */786IEEE80211_NOTE(an->an_node.ni_vap,787IEEE80211_MSG_RATECTL, &an->an_node,788"%s: min_switch %d > ticks_since_switch %d..",789__func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);790change_rates = 1;791} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&792(2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {793/* the current bit-rate is twice as slow as the best one */794IEEE80211_NOTE(an->an_node.ni_vap,795IEEE80211_MSG_RATECTL, &an->an_node,796"%s: 2x att (= %d) < cur_rix att %d",797__func__,7982 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);799change_rates = 1;800} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {801int cur_rix = sn->current_rix[size_bin];802int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;803/*804* If the node is HT, it if the rate isn't the805* same and the average tx time is within 10%806* of the current rate. It can fail a little.807*808* This is likely not optimal!809*/810#if 0811printf("cur rix/att %x/%d, best rix/att %x/%d\n",812MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);813#endif814if ((best_rix != cur_rix) &&815(average_tx_time * 9) <= (cur_att * 10)) {816IEEE80211_NOTE(an->an_node.ni_vap,817IEEE80211_MSG_RATECTL, &an->an_node,818"%s: HT: size %d best_rix 0x%x > "819" cur_rix 0x%x, average_tx_time %d,"820" cur_att %d",821__func__, bin_to_size(size_bin),822MCS(best_rix), MCS(cur_rix),823average_tx_time, cur_att);824change_rates = 1;825}826}827828sn->packets_since_sample[size_bin]++;829830if (change_rates) {831if (best_rix != sn->current_rix[size_bin]) {832IEEE80211_NOTE(an->an_node.ni_vap,833IEEE80211_MSG_RATECTL,834&an->an_node,835"%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d",836__func__,837bin_to_size(size_bin),838dot11rate(rt, sn->current_rix[size_bin]),839dot11rate_label(rt, sn->current_rix[size_bin]),840sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,841sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,842sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct,843dot11rate(rt, best_rix),844dot11rate_label(rt, best_rix),845sn->stats[size_bin][best_rix].average_tx_time,846sn->stats[size_bin][best_rix].perfect_tx_time,847sn->stats[size_bin][best_rix].ewma_pct,848sn->packets_since_switch[size_bin],849mrr);850}851sn->packets_since_switch[size_bin] = 0;852sn->current_rix[size_bin] = best_rix;853sn->ticks_since_switch[size_bin] = ticks;854/*855* Set the visible txrate for this node.856*/857if (rt->info[best_rix].phy == IEEE80211_T_HT)858ieee80211_node_set_txrate_ht_mcsrate(859&an->an_node,860MCS(best_rix) & IEEE80211_RATE_VAL);861else862ieee80211_node_set_txrate_dot11rate(863&an->an_node,864DOT11RATE(best_rix));865}866rix = sn->current_rix[size_bin];867sn->packets_since_switch[size_bin]++;868}869*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;870done:871872/*873* This bug totally sucks and should be fixed.874*875* For now though, let's not panic, so we can start to figure876* out how to better reproduce it.877*/878if (rix < 0 || rix >= rt->rateCount) {879printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",880__func__,881rix,882rt->rateCount);883rix = 0; /* XXX just default for now */884}885KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));886887*rix0 = rix;888*txrate = rt->info[rix].rateCode889| (shortPreamble ? rt->info[rix].shortPreamble : 0);890sn->packets_sent[size_bin]++;891892#undef DOT11RATE893#undef MCS894#undef RATE895}896897/*898* Get the TX rates. Don't fiddle with short preamble flags for them;899* the caller can do that.900*/901void902ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,903uint8_t rix0, int is_aggr, struct ath_rc_series *rc)904{905struct sample_node *sn = ATH_NODE_SAMPLE(an);906const struct txschedule *sched = &sn->sched[rix0];907908KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",909rix0, sched->r0));910911rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;912913rc[0].rix = sched->r0;914rc[1].rix = sched->r1;915rc[2].rix = sched->r2;916rc[3].rix = sched->r3;917918rc[0].tries = sched->t0;919rc[1].tries = sched->t1;920921if (is_aggr) {922rc[2].tries = rc[3].tries = 0;923} else {924rc[2].tries = sched->t2;925rc[3].tries = sched->t3;926}927}928929void930ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,931struct ath_desc *ds, int shortPreamble, u_int8_t rix)932{933struct sample_node *sn = ATH_NODE_SAMPLE(an);934const struct txschedule *sched = &sn->sched[rix];935const HAL_RATE_TABLE *rt = sc->sc_currates;936uint8_t rix1, s1code, rix2, s2code, rix3, s3code;937938/* XXX precalculate short preamble tables */939rix1 = sched->r1;940s1code = rt->info[rix1].rateCode941| (shortPreamble ? rt->info[rix1].shortPreamble : 0);942rix2 = sched->r2;943s2code = rt->info[rix2].rateCode944| (shortPreamble ? rt->info[rix2].shortPreamble : 0);945rix3 = sched->r3;946s3code = rt->info[rix3].rateCode947| (shortPreamble ? rt->info[rix3].shortPreamble : 0);948ath_hal_setupxtxdesc(sc->sc_ah, ds,949s1code, sched->t1, /* series 1 */950s2code, sched->t2, /* series 2 */951s3code, sched->t3); /* series 3 */952}953954/*955* Update the current statistics.956*957* Note that status is for the FINAL transmit status, not this958* particular attempt. So, check if tries > tries0 and if so959* assume this status failed.960*961* This is important because some failures are due to both962* short AND long retries; if the final issue was a short963* retry failure then we still want to account for the964* bad long retry attempts.965*/966static void967update_stats(struct ath_softc *sc, struct ath_node *an,968int frame_size,969int rix0, int tries0,970int short_tries, int tries, int status,971int nframes, int nbad)972{973struct sample_node *sn = ATH_NODE_SAMPLE(an);974struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);975#ifdef IEEE80211_DEBUG976const HAL_RATE_TABLE *rt = sc->sc_currates;977#endif978const int size_bin = size_to_bin(frame_size);979const int size = bin_to_size(size_bin);980int tt;981int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40);982int pct;983984if (!IS_RATE_DEFINED(sn, rix0))985return;986987/*988* Treat long retries as us exceeding retries, even989* if the eventual attempt at some other MRR schedule990* succeeded.991*/992if (tries > tries0) {993status = HAL_TXERR_XRETRY;994}995996/*997* If status is FAIL then we treat all frames as bad.998* This better accurately tracks EWMA and average TX time999* because even if the eventual transmission succeeded,1000* transmission at this rate did not.1001*/1002if (status != 0)1003nbad = nframes;10041005/*1006* Ignore short tries count as contributing to failure.1007* Right now there's no way to know if it's part of any1008* given rate attempt, and outside of the RTS/CTS management1009* rate, it doesn't /really/ help.1010*/1011tt = calc_usecs_unicast_packet(sc, size, rix0,10120 /* short_tries */, MIN(tries0, tries) - 1, is_ht40);10131014if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {1015/* just average the first few packets */1016int avg_tx = sn->stats[size_bin][rix0].average_tx_time;1017int packets = sn->stats[size_bin][rix0].total_packets;1018sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);1019} else {1020/* use a ewma */1021sn->stats[size_bin][rix0].average_tx_time =1022((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) +1023(tt * (100 - ssc->smoothing_rate))) / 100;1024}10251026if (nframes == nbad) {1027sn->stats[size_bin][rix0].successive_failures += nbad;1028} else {1029sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);1030sn->stats[size_bin][rix0].successive_failures = 0;1031}1032sn->stats[size_bin][rix0].tries += tries;1033sn->stats[size_bin][rix0].last_tx = ticks;1034sn->stats[size_bin][rix0].total_packets += nframes;10351036/* update EWMA for this rix */10371038/* Calculate percentage based on current rate */1039if (nframes == 0)1040nframes = nbad = 1;1041pct = ((nframes - nbad) * 1000) / nframes;10421043if (sn->stats[size_bin][rix0].total_packets <1044ssc->smoothing_minpackets) {1045/* just average the first few packets */1046int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /1047(sn->stats[size_bin][rix0].total_packets);1048sn->stats[size_bin][rix0].ewma_pct = a_pct;1049} else {1050/* use a ewma */1051sn->stats[size_bin][rix0].ewma_pct =1052((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +1053(pct * (100 - ssc->smoothing_rate))) / 100;1054}10551056/*1057* Only update the sample time for the initial sample rix.1058* We've updated the statistics on each of the other retries1059* fine, but we should only update the sample_tt with what1060* was actually sampled.1061*1062* However, to aide in debugging, log all the failures for1063* each of the buckets1064*/1065IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,1066&an->an_node,1067"%s: size %d %s %s rate %d %s tries (%d/%d) tt %d "1068"avg_tt (%d/%d) nfrm %d nbad %d",1069__func__,1070size,1071status ? "FAIL" : "OK",1072rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr",1073dot11rate(rt, rix0),1074dot11rate_label(rt, rix0),1075short_tries, tries, tt,1076sn->stats[size_bin][rix0].average_tx_time,1077sn->stats[size_bin][rix0].perfect_tx_time,1078nframes, nbad);10791080if (rix0 == sn->current_sample_rix[size_bin]) {1081sn->sample_tt[size_bin] = tt;1082sn->current_sample_rix[size_bin] = -1;1083}1084}10851086static void1087badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status)1088{10891090device_printf(sc->sc_dev,1091"bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n",1092series, hwrate, tries, status);1093}10941095void1096ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,1097const struct ath_rc_series *rc, const struct ath_tx_status *ts,1098int frame_size, int rc_framesize, int nframes, int nbad)1099{1100struct ieee80211com *ic = &sc->sc_ic;1101struct sample_node *sn = ATH_NODE_SAMPLE(an);1102int final_rix, short_tries, long_tries;1103const HAL_RATE_TABLE *rt = sc->sc_currates;1104int status = ts->ts_status;1105int mrr;11061107final_rix = rt->rateCodeToIndex[ts->ts_rate];1108short_tries = ts->ts_shortretry;1109long_tries = ts->ts_longretry + 1;11101111if (nframes == 0) {1112device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);1113return;1114}11151116if (frame_size == 0) /* NB: should not happen */1117frame_size = 1500;1118if (rc_framesize == 0) /* NB: should not happen */1119rc_framesize = 1500;11201121/*1122* There are still some places where what rate control set as1123* a limit but the hardware decided, for some reason, to transmit1124* at a smaller size that fell into a different bucket.1125*1126* The eternal question here is - which size_bin should it go in?1127* The one that was requested, or the one that was transmitted?1128*1129* Here's the problem - if we use the one that was transmitted,1130* we may continue to hit corner cases where we make a rate1131* selection using a higher bin but only update the smaller bin;1132* thus never really "adapting".1133*1134* If however we update the larger bin, we're not accurately1135* representing the channel state at that frame/aggregate size.1136* However if we keep hitting the larger request but completing1137* a smaller size, we at least updates based on what the1138* request was /for/.1139*1140* I'm going to err on the side of caution and choose the1141* latter.1142*/1143if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) {1144#if 01145device_printf(sc->sc_dev,1146"%s: completed but frame size buckets mismatch "1147"(completed %d tx'ed %d)\n",1148__func__, frame_size, rc_framesize);1149#endif1150frame_size = rc_framesize;1151}11521153if (sn->ratemask == 0) {1154IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,1155&an->an_node,1156"%s: size %d %s rate/try %d/%d no rates yet",1157__func__,1158bin_to_size(size_to_bin(frame_size)),1159status ? "FAIL" : "OK",1160short_tries, long_tries);1161return;1162}1163mrr = sc->sc_mrretry;1164/* XXX check HT protmode too */1165if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))1166mrr = 0;11671168if (!mrr || ts->ts_finaltsi == 0) {1169if (!IS_RATE_DEFINED(sn, final_rix)) {1170device_printf(sc->sc_dev,1171"%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n",1172__func__, ts->ts_rate, ts->ts_finaltsi, final_rix);1173badrate(sc, 0, ts->ts_rate, long_tries, status);1174return;1175}1176/*1177* Only one rate was used; optimize work.1178*/1179IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,1180&an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",1181__func__,1182bin_to_size(size_to_bin(frame_size)),1183frame_size,1184status ? "FAIL" : "OK",1185dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),1186short_tries, long_tries, nframes, nbad);1187update_stats(sc, an, frame_size,1188final_rix, long_tries,1189short_tries, long_tries, status,1190nframes, nbad);11911192} else {1193int finalTSIdx = ts->ts_finaltsi;1194int i;11951196/*1197* Process intermediate rates that failed.1198*/11991200IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,1201&an->an_node,1202"%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]",1203__func__,1204bin_to_size(size_to_bin(frame_size)),1205frame_size,1206finalTSIdx,1207short_tries,1208long_tries,1209status ? "FAIL" : "OK",1210dot11rate(rt, rc[0].rix),1211dot11rate_label(rt, rc[0].rix), rc[0].tries,1212dot11rate(rt, rc[1].rix),1213dot11rate_label(rt, rc[1].rix), rc[1].tries,1214dot11rate(rt, rc[2].rix),1215dot11rate_label(rt, rc[2].rix), rc[2].tries,1216dot11rate(rt, rc[3].rix),1217dot11rate_label(rt, rc[3].rix), rc[3].tries,1218nframes, nbad);12191220for (i = 0; i < 4; i++) {1221if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))1222badrate(sc, 0, rc[i].ratecode, rc[i].tries,1223status);1224}12251226/*1227* This used to not penalise other tries because loss1228* can be bursty, but it's then not accurately keeping1229* the avg TX time and EWMA updated.1230*/1231if (rc[0].tries) {1232update_stats(sc, an, frame_size,1233rc[0].rix, rc[0].tries,1234short_tries, long_tries,1235status,1236nframes, nbad);1237long_tries -= rc[0].tries;1238}12391240if (rc[1].tries && finalTSIdx > 0) {1241update_stats(sc, an, frame_size,1242rc[1].rix, rc[1].tries,1243short_tries, long_tries,1244status,1245nframes, nbad);1246long_tries -= rc[1].tries;1247}12481249if (rc[2].tries && finalTSIdx > 1) {1250update_stats(sc, an, frame_size,1251rc[2].rix, rc[2].tries,1252short_tries, long_tries,1253status,1254nframes, nbad);1255long_tries -= rc[2].tries;1256}12571258if (rc[3].tries && finalTSIdx > 2) {1259update_stats(sc, an, frame_size,1260rc[3].rix, rc[3].tries,1261short_tries, long_tries,1262status,1263nframes, nbad);1264}1265}1266}12671268void1269ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)1270{1271if (isnew)1272ath_rate_ctl_reset(sc, &an->an_node);1273}12741275void1276ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)1277{1278}12791280static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {1281NULL, /* IEEE80211_MODE_AUTO */1282series_11a, /* IEEE80211_MODE_11A */1283series_11g, /* IEEE80211_MODE_11B */1284series_11g, /* IEEE80211_MODE_11G */1285NULL, /* IEEE80211_MODE_FH */1286series_11a, /* IEEE80211_MODE_TURBO_A */1287series_11g, /* IEEE80211_MODE_TURBO_G */1288series_11a, /* IEEE80211_MODE_STURBO_A */1289series_11na, /* IEEE80211_MODE_11NA */1290series_11ng, /* IEEE80211_MODE_11NG */1291series_half, /* IEEE80211_MODE_HALF */1292series_quarter, /* IEEE80211_MODE_QUARTER */1293};12941295/*1296* Initialize the tables for a node.1297*/1298static void1299ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)1300{1301#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)1302#define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)1303#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)1304struct ath_node *an = ATH_NODE(ni);1305struct sample_node *sn = ATH_NODE_SAMPLE(an);1306const HAL_RATE_TABLE *rt = sc->sc_currates;1307int x, y, rix;13081309KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));13101311KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,1312("curmode %u", sc->sc_curmode));13131314sn->sched = mrr_schedules[sc->sc_curmode];1315KASSERT(sn->sched != NULL,1316("no mrr schedule for mode %u", sc->sc_curmode));13171318sn->static_rix = -1;1319ath_rate_update_static_rix(sc, ni);13201321sn->currates = sc->sc_currates;13221323/*1324* Construct a bitmask of usable rates. This has all1325* negotiated rates minus those marked by the hal as1326* to be ignored for doing rate control.1327*/1328sn->ratemask = 0;1329/* MCS rates */1330if (ni->ni_flags & IEEE80211_NODE_HT) {1331for (x = 0; x < ni->ni_htrates.rs_nrates; x++) {1332rix = sc->sc_rixmap[MCS(x)];1333if (rix == 0xff)1334continue;1335/* skip rates marked broken by hal */1336if (!rt->info[rix].valid)1337continue;1338KASSERT(rix < SAMPLE_MAXRATES,1339("mcs %u has rix %d", MCS(x), rix));1340sn->ratemask |= (uint64_t) 1<<rix;1341}1342}13431344/* Legacy rates */1345for (x = 0; x < ni->ni_rates.rs_nrates; x++) {1346rix = sc->sc_rixmap[RATE(x)];1347if (rix == 0xff)1348continue;1349/* skip rates marked broken by hal */1350if (!rt->info[rix].valid)1351continue;1352KASSERT(rix < SAMPLE_MAXRATES,1353("rate %u has rix %d", RATE(x), rix));1354sn->ratemask |= (uint64_t) 1<<rix;1355}1356#ifdef IEEE80211_DEBUG1357if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {1358uint64_t mask;13591360ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",1361ni->ni_macaddr, ":", __func__);1362for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {1363if ((mask & 1) == 0)1364continue;1365printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix),1366calc_usecs_unicast_packet(sc, 1600, rix, 0,0,1367(ni->ni_chw == NET80211_STA_RX_BW_40)));1368}1369printf("\n");1370}1371#endif1372for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {1373int size = bin_to_size(y);1374uint64_t mask;13751376sn->packets_sent[y] = 0;1377sn->current_sample_rix[y] = -1;1378sn->last_sample_rix[y] = 0;1379/* XXX start with first valid rate */1380sn->current_rix[y] = ffs(sn->ratemask)-1;13811382/*1383* Initialize the statistics buckets; these are1384* indexed by the rate code index.1385*/1386for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) {1387if ((mask & 1) == 0) /* not a valid rate */1388continue;1389sn->stats[y][rix].successive_failures = 0;1390sn->stats[y][rix].tries = 0;1391sn->stats[y][rix].total_packets = 0;1392sn->stats[y][rix].packets_acked = 0;1393sn->stats[y][rix].last_tx = 0;1394sn->stats[y][rix].ewma_pct = 0;13951396sn->stats[y][rix].perfect_tx_time =1397calc_usecs_unicast_packet(sc, size, rix, 0, 0,1398(ni->ni_chw == NET80211_STA_RX_BW_40));1399sn->stats[y][rix].average_tx_time =1400sn->stats[y][rix].perfect_tx_time;1401}1402}1403#if 01404/* XXX 0, num_rates-1 are wrong */1405IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,1406"%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__,1407sn->num_rates,1408DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "",1409sn->stats[1][0].perfect_tx_time,1410DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "",1411sn->stats[1][sn->num_rates-1].perfect_tx_time1412);1413#endif1414/* set the visible bit-rate */1415if (sn->static_rix != -1)1416ieee80211_node_set_txrate_dot11rate(ni,1417DOT11RATE(sn->static_rix));1418else1419ieee80211_node_set_txrate_dot11rate(ni, RATE(0));1420#undef RATE1421#undef DOT11RATE1422}14231424/*1425* Fetch the statistics for the given node.1426*1427* The ieee80211 node must be referenced and unlocked, however the ath_node1428* must be locked.1429*1430* The main difference here is that we convert the rate indexes1431* to 802.11 rates, or the userland output won't make much sense1432* as it has no access to the rix table.1433*/1434int1435ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,1436struct ath_rateioctl *rs)1437{1438struct sample_node *sn = ATH_NODE_SAMPLE(an);1439const HAL_RATE_TABLE *rt = sc->sc_currates;1440struct ath_rateioctl_tlv av;1441struct ath_rateioctl_rt *tv;1442int error, y;1443int o = 0;14441445ATH_NODE_LOCK_ASSERT(an);14461447error = 0;14481449/*1450* Ensure there's enough space for the statistics.1451*/1452if (rs->len <1453sizeof(struct ath_rateioctl_tlv) +1454sizeof(struct ath_rateioctl_rt) +1455sizeof(struct ath_rateioctl_tlv) +1456sizeof(struct sample_node)) {1457device_printf(sc->sc_dev, "%s: len=%d, too short\n",1458__func__,1459rs->len);1460return (EINVAL);1461}14621463/*1464* Take a temporary copy of the sample node state so we can1465* modify it before we copy it.1466*/1467tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,1468M_NOWAIT | M_ZERO);1469if (tv == NULL) {1470return (ENOMEM);1471}14721473/*1474* Populate the rate table mapping TLV.1475*/1476tv->nentries = rt->rateCount;1477for (y = 0; y < rt->rateCount; y++) {1478tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;1479if (rt->info[y].phy == IEEE80211_T_HT)1480tv->ratecode[y] |= IEEE80211_RATE_MCS;1481}14821483o = 0;1484/*1485* First TLV - rate code mapping1486*/1487av.tlv_id = ATH_RATE_TLV_RATETABLE;1488av.tlv_len = sizeof(struct ath_rateioctl_rt);1489error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));1490if (error != 0)1491goto out;1492o += sizeof(struct ath_rateioctl_tlv);1493error = copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));1494if (error != 0)1495goto out;1496o += sizeof(struct ath_rateioctl_rt);14971498/*1499* Second TLV - sample node statistics1500*/1501av.tlv_id = ATH_RATE_TLV_SAMPLENODE;1502av.tlv_len = sizeof(struct sample_node);1503error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));1504if (error != 0)1505goto out;1506o += sizeof(struct ath_rateioctl_tlv);15071508/*1509* Copy the statistics over to the provided buffer.1510*/1511error = copyout(sn, rs->buf + o, sizeof(struct sample_node));1512if (error != 0)1513goto out;1514o += sizeof(struct sample_node);15151516out:1517free(tv, M_TEMP);1518return (error);1519}15201521static void1522sample_stats(void *arg, struct ieee80211_node *ni)1523{1524struct ath_softc *sc = arg;1525const HAL_RATE_TABLE *rt = sc->sc_currates;1526struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));1527uint64_t mask;1528int rix, y;15291530printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",1531ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),1532dot11rate(rt, sn->static_rix),1533dot11rate_label(rt, sn->static_rix),1534(uintmax_t)sn->ratemask);1535for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {1536printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",1537bin_to_size(y), sn->current_rix[y],1538dot11rate(rt, sn->current_rix[y]),1539dot11rate_label(rt, sn->current_rix[y]),1540sn->packets_since_switch[y], sn->ticks_since_switch[y]);1541printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",1542bin_to_size(y),1543dot11rate(rt, sn->last_sample_rix[y]),1544dot11rate_label(rt, sn->last_sample_rix[y]),1545dot11rate(rt, sn->current_sample_rix[y]),1546dot11rate_label(rt, sn->current_sample_rix[y]),1547sn->packets_sent[y]);1548printf("[%4u] packets since sample %d sample tt %u\n",1549bin_to_size(y), sn->packets_since_sample[y],1550sn->sample_tt[y]);1551}1552for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {1553if ((mask & 1) == 0)1554continue;1555for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {1556if (sn->stats[y][rix].total_packets == 0)1557continue;1558printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",1559dot11rate(rt, rix), dot11rate_label(rt, rix),1560bin_to_size(y),1561(uintmax_t) sn->stats[y][rix].total_packets,1562(uintmax_t) sn->stats[y][rix].packets_acked,1563(int) ((sn->stats[y][rix].packets_acked * 100ULL) /1564sn->stats[y][rix].total_packets),1565sn->stats[y][rix].ewma_pct / 10,1566sn->stats[y][rix].ewma_pct % 10,1567(uintmax_t) sn->stats[y][rix].tries,1568sn->stats[y][rix].successive_failures,1569sn->stats[y][rix].average_tx_time,1570ticks - sn->stats[y][rix].last_tx);1571}1572}1573}15741575static int1576ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS)1577{1578struct ath_softc *sc = arg1;1579struct ieee80211com *ic = &sc->sc_ic;1580int error, v;15811582v = 0;1583error = sysctl_handle_int(oidp, &v, 0, req);1584if (error || !req->newptr)1585return error;1586ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc);1587return 0;1588}15891590static int1591ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)1592{1593struct sample_softc *ssc = arg1;1594int rate, error;15951596rate = ssc->smoothing_rate;1597error = sysctl_handle_int(oidp, &rate, 0, req);1598if (error || !req->newptr)1599return error;1600if (!(0 <= rate && rate < 100))1601return EINVAL;1602ssc->smoothing_rate = rate;1603ssc->smoothing_minpackets = 100 / (100 - rate);1604return 0;1605}16061607static int1608ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)1609{1610struct sample_softc *ssc = arg1;1611int rate, error;16121613rate = ssc->sample_rate;1614error = sysctl_handle_int(oidp, &rate, 0, req);1615if (error || !req->newptr)1616return error;1617if (!(2 <= rate && rate <= 100))1618return EINVAL;1619ssc->sample_rate = rate;1620return 0;1621}16221623static void1624ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc)1625{1626struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);1627struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);16281629SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,1630"smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,1631ssc, 0, ath_rate_sysctl_smoothing_rate, "I",1632"sample: smoothing rate for avg tx time (%%)");1633SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,1634"sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,1635ssc, 0, ath_rate_sysctl_sample_rate, "I",1636"sample: percent air time devoted to sampling new rates (%%)");1637/* XXX max_successive_failures, stale_failure_timeout, min_switch */1638SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,1639"sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,1640sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics");1641}16421643struct ath_ratectrl *1644ath_rate_attach(struct ath_softc *sc)1645{1646struct sample_softc *ssc;16471648ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);1649if (ssc == NULL)1650return NULL;1651ssc->arc.arc_space = sizeof(struct sample_node);1652ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */1653ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);1654ssc->sample_rate = 10; /* %time to try diff tx rates */1655ssc->max_successive_failures = 3; /* threshold for rate sampling*/1656ssc->stale_failure_timeout = 10 * hz; /* 10 seconds */1657ssc->min_switch = hz; /* 1 second */1658ath_rate_sysctlattach(sc, ssc);1659return &ssc->arc;1660}16611662void1663ath_rate_detach(struct ath_ratectrl *arc)1664{1665struct sample_softc *ssc = (struct sample_softc *) arc;16661667free(ssc, M_DEVBUF);1668}166916701671