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