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