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