xref: /freebsd/sys/dev/ath/ath_rate/sample/sample.c (revision 8af1445957d479ac48dff629c28c68ca679cab49)
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.
168*8af14459SAdrian Chadd  *
169*8af14459SAdrian Chadd  * XXX TODO: this needs to be limited by the RTS/CTS AR5416 8KB bug limit!
170*8af14459SAdrian Chadd  * (by checking rts/cts flags and applying sc_rts_aggr_limit)
171*8af14459SAdrian Chadd  *
172*8af14459SAdrian Chadd  * XXX TODO: apply per-node max-ampdu size and driver ampdu size limits too.
173cce63444SAdrian Chadd  */
174cce63444SAdrian Chadd static int
175cce63444SAdrian Chadd ath_rate_sample_find_min_pktlength(struct ath_softc *sc,
176051ea90cSAdrian Chadd     struct ath_node *an, uint8_t rix0, int is_aggr)
177cce63444SAdrian Chadd {
178cce63444SAdrian Chadd #define	MCS_IDX(ix)		(rt->info[ix].dot11Rate)
179cce63444SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
180cce63444SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
181cce63444SAdrian Chadd 	const struct txschedule *sched = &sn->sched[rix0];
182cce63444SAdrian Chadd 	int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE
183cce63444SAdrian Chadd 	// Note: this may not be true in all cases; need to check?
184cce63444SAdrian Chadd 	int is_ht40 = (an->an_node.ni_chw == 40);
185cce63444SAdrian Chadd 	// Note: not great, but good enough..
186cce63444SAdrian Chadd 	int idx = is_ht40 ? MCS_HT40 : MCS_HT20;
187cce63444SAdrian Chadd 
188cce63444SAdrian Chadd 	if (rt->info[rix0].phy != IEEE80211_T_HT) {
189cce63444SAdrian Chadd 		return -1;
190cce63444SAdrian Chadd 	}
191cce63444SAdrian Chadd 
192cce63444SAdrian Chadd 	if (! sc->sc_mrretry) {
193cce63444SAdrian Chadd 		return -1;
194cce63444SAdrian Chadd 	}
195cce63444SAdrian Chadd 
196cce63444SAdrian Chadd 	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
197cce63444SAdrian Chadd 	    rix0, sched->r0));
198cce63444SAdrian Chadd 
199cce63444SAdrian Chadd 	/*
200cce63444SAdrian Chadd 	 * Update based on sched->r{0,1,2,3} if sched->t{0,1,2,3}
201cce63444SAdrian Chadd 	 * is not zero.
202cce63444SAdrian Chadd 	 *
203cce63444SAdrian Chadd 	 * Note: assuming all four PHYs are HT!
204051ea90cSAdrian Chadd 	 *
205051ea90cSAdrian Chadd 	 * XXX TODO: right now I hardcode here and in getxtxrates() that
206051ea90cSAdrian Chadd 	 * rates 2 and 3 in the tx schedule are ignored.  This is important
207051ea90cSAdrian Chadd 	 * for forming larger aggregates because right now (a) the tx schedule
208051ea90cSAdrian Chadd 	 * per rate is fixed, and (b) reliable packet transmission at those
209051ea90cSAdrian Chadd 	 * higher rates kinda needs a lower MCS rate in there somewhere.
210051ea90cSAdrian Chadd 	 * However, this means we can only form shorter aggregates.
211051ea90cSAdrian Chadd 	 * If we've negotiated aggregation then we can actually just
212051ea90cSAdrian Chadd 	 * rely on software retransmit rather than having things fall
213051ea90cSAdrian Chadd 	 * back to like MCS0/1 in hardware, and rate control will hopefully
214051ea90cSAdrian Chadd 	 * do the right thing.
215051ea90cSAdrian Chadd 	 *
216051ea90cSAdrian Chadd 	 * Once the whole rate schedule is passed into ath_rate_findrate(),
217051ea90cSAdrian Chadd 	 * the ath_rc_series is populated ,the fixed tx schedule stuff
218051ea90cSAdrian Chadd 	 * is removed AND getxtxrates() is removed then we can remove this
219051ea90cSAdrian Chadd 	 * check as it can just NOT populate t2/t3.  It also means
220051ea90cSAdrian Chadd 	 * probing can actually use rix0 for probeing and rix1 for the
221051ea90cSAdrian Chadd 	 * current best rate..
222cce63444SAdrian Chadd 	 */
223cce63444SAdrian Chadd 	if (sched->t0 != 0) {
224cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
225cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]);
226cce63444SAdrian Chadd 	}
227cce63444SAdrian Chadd 	if (sched->t1 != 0) {
228cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
229cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]);
230cce63444SAdrian Chadd 	}
231051ea90cSAdrian Chadd 	if (sched->t2 != 0 && (! is_aggr)) {
232cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
233cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]);
234cce63444SAdrian Chadd 	}
235051ea90cSAdrian Chadd 	if (sched->t3 != 0 && (! is_aggr)) {
236cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
237cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]);
238cce63444SAdrian Chadd 	}
239cce63444SAdrian Chadd 
240cce63444SAdrian Chadd 	return max_pkt_length;
241cce63444SAdrian Chadd #undef	MCS
242cce63444SAdrian Chadd }
243cce63444SAdrian Chadd 
244b2763056SSam Leffler static void	ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
245fa20c234SSam Leffler 
246b91bf513SSam Leffler static __inline int
247b91bf513SSam Leffler size_to_bin(int size)
248fa20c234SSam Leffler {
249c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1
250c1565b61SSam Leffler 	if (size <= packet_size_bins[0])
251c1565b61SSam Leffler 		return 0;
252c1565b61SSam Leffler #endif
253c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2
254c1565b61SSam Leffler 	if (size <= packet_size_bins[1])
255c1565b61SSam Leffler 		return 1;
256c1565b61SSam Leffler #endif
257c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3
258c1565b61SSam Leffler 	if (size <= packet_size_bins[2])
259c1565b61SSam Leffler 		return 2;
260c1565b61SSam Leffler #endif
261c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4
262cce63444SAdrian Chadd 	if (size <= packet_size_bins[3])
263cce63444SAdrian Chadd 		return 3;
264cce63444SAdrian Chadd #endif
265cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 5
266cce63444SAdrian Chadd 	if (size <= packet_size_bins[4])
267cce63444SAdrian Chadd 		return 4;
268cce63444SAdrian Chadd #endif
269cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 6
270cce63444SAdrian Chadd 	if (size <= packet_size_bins[5])
271cce63444SAdrian Chadd 		return 5;
272cce63444SAdrian Chadd #endif
273cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 7
274cce63444SAdrian Chadd 	if (size <= packet_size_bins[6])
275cce63444SAdrian Chadd 		return 6;
276cce63444SAdrian Chadd #endif
277cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 8
278c1565b61SSam Leffler #error "add support for more packet sizes"
279c1565b61SSam Leffler #endif
280fa20c234SSam Leffler 	return NUM_PACKET_SIZE_BINS-1;
281fa20c234SSam Leffler }
282fa20c234SSam Leffler 
283fa20c234SSam Leffler void
284fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
285fa20c234SSam Leffler {
286fa20c234SSam Leffler 	/* NB: assumed to be zero'd by caller */
287fa20c234SSam Leffler }
288fa20c234SSam Leffler 
289fa20c234SSam Leffler void
290fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
291fa20c234SSam Leffler {
292fa20c234SSam Leffler }
293fa20c234SSam Leffler 
294a6a308a4SAdrian Chadd static int
295a6a308a4SAdrian Chadd dot11rate(const HAL_RATE_TABLE *rt, int rix)
296a6a308a4SAdrian Chadd {
29787acb7d5SAdrian Chadd 	if (rix < 0)
29887acb7d5SAdrian Chadd 		return -1;
299a6a308a4SAdrian Chadd 	return rt->info[rix].phy == IEEE80211_T_HT ?
300a6a308a4SAdrian Chadd 	    rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;
301a6a308a4SAdrian Chadd }
302a6a308a4SAdrian Chadd 
303ae0944b8SAdrian Chadd static const char *
304ae0944b8SAdrian Chadd dot11rate_label(const HAL_RATE_TABLE *rt, int rix)
305ae0944b8SAdrian Chadd {
30687acb7d5SAdrian Chadd 	if (rix < 0)
30787acb7d5SAdrian Chadd 		return "";
308ae0944b8SAdrian Chadd 	return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";
309ae0944b8SAdrian Chadd }
310ae0944b8SAdrian Chadd 
311fa20c234SSam Leffler /*
312c1565b61SSam Leffler  * Return the rix with the lowest average_tx_time,
313fa20c234SSam Leffler  * or -1 if all the average_tx_times are 0.
314fa20c234SSam Leffler  */
315c1565b61SSam Leffler static __inline int
31636958948SAdrian Chadd pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt,
317c1565b61SSam Leffler     int size_bin, int require_acked_before)
318fa20c234SSam Leffler {
31936958948SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
320eb6f0de0SAdrian Chadd 	int best_rate_rix, best_rate_tt, best_rate_pct;
321193bfa21SAdrian Chadd 	uint64_t mask;
322eb6f0de0SAdrian Chadd 	int rix, tt, pct;
323b91bf513SSam Leffler 
324c1565b61SSam Leffler 	best_rate_rix = 0;
325c1565b61SSam Leffler 	best_rate_tt = 0;
326eb6f0de0SAdrian Chadd 	best_rate_pct = 0;
327c1565b61SSam Leffler 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
328c1565b61SSam Leffler 		if ((mask & 1) == 0)		/* not a supported rate */
329c1565b61SSam Leffler 			continue;
330c1565b61SSam Leffler 
33136958948SAdrian Chadd 		/* Don't pick a non-HT rate for a HT node */
33236958948SAdrian Chadd 		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
33336958948SAdrian Chadd 		    (rt->info[rix].phy != IEEE80211_T_HT)) {
33436958948SAdrian Chadd 			continue;
33536958948SAdrian Chadd 		}
33636958948SAdrian Chadd 
337c1565b61SSam Leffler 		tt = sn->stats[size_bin][rix].average_tx_time;
338c1565b61SSam Leffler 		if (tt <= 0 ||
339c1565b61SSam Leffler 		    (require_acked_before &&
340c1565b61SSam Leffler 		     !sn->stats[size_bin][rix].packets_acked))
341b91bf513SSam Leffler 			continue;
342b91bf513SSam Leffler 
343eb6f0de0SAdrian Chadd 		/* Calculate percentage if possible */
344eb6f0de0SAdrian Chadd 		if (sn->stats[size_bin][rix].total_packets > 0) {
345eb6f0de0SAdrian Chadd 			pct = sn->stats[size_bin][rix].ewma_pct;
346eb6f0de0SAdrian Chadd 		} else {
347cce63444SAdrian Chadd 			pct = -1; /* No percent yet to compare against! */
348eb6f0de0SAdrian Chadd 		}
349eb6f0de0SAdrian Chadd 
350b91bf513SSam Leffler 		/* don't use a bit-rate that has been failing */
351c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].successive_failures > 3)
352b91bf513SSam Leffler 			continue;
353b91bf513SSam Leffler 
354eb6f0de0SAdrian Chadd 		/*
355cce63444SAdrian Chadd 		 * For HT, Don't use a bit rate that is more
356cce63444SAdrian Chadd 		 * lossy than the best.  Give a bit of leeway.
357eb6f0de0SAdrian Chadd 		 *
358cce63444SAdrian Chadd 		 * Don't consider best rates that we haven't seen
359cce63444SAdrian Chadd 		 * packets for yet; let sampling start inflence that.
360eb6f0de0SAdrian Chadd 		 */
361eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
362cce63444SAdrian Chadd 			if (pct == -1)
363cce63444SAdrian Chadd 				continue;
364cce63444SAdrian Chadd #if 0
365cce63444SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
366cce63444SAdrian Chadd 			    IEEE80211_MSG_RATECTL,
367cce63444SAdrian Chadd 			    &an->an_node,
368cce63444SAdrian Chadd 			    "%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) "
369cce63444SAdrian Chadd 			    "to 0x%x pkts/ewma/tt (%ju/%d/%d)",
370cce63444SAdrian Chadd 			    __func__,
371cce63444SAdrian Chadd 			    bin_to_size(size_bin),
372cce63444SAdrian Chadd 			    rt->info[best_rate_rix].dot11Rate,
373cce63444SAdrian Chadd 			    sn->stats[size_bin][best_rate_rix].total_packets,
374cce63444SAdrian Chadd 			    best_rate_pct,
375cce63444SAdrian Chadd 			    best_rate_tt,
376cce63444SAdrian Chadd 			    rt->info[rix].dot11Rate,
377cce63444SAdrian Chadd 			    sn->stats[size_bin][rix].total_packets,
378cce63444SAdrian Chadd 			    pct,
379cce63444SAdrian Chadd 			    tt);
380cce63444SAdrian Chadd #endif
381eb6f0de0SAdrian Chadd 			if (best_rate_pct > (pct + 50))
382eb6f0de0SAdrian Chadd 				continue;
383eb6f0de0SAdrian Chadd 		}
384eb6f0de0SAdrian Chadd 		/*
385eb6f0de0SAdrian Chadd 		 * For non-MCS rates, use the current average txtime for
386eb6f0de0SAdrian Chadd 		 * comparison.
387eb6f0de0SAdrian Chadd 		 */
388eb6f0de0SAdrian Chadd 		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
389eb6f0de0SAdrian Chadd 			if (best_rate_tt == 0 || tt <= best_rate_tt) {
390fa20c234SSam Leffler 				best_rate_tt = tt;
391c1565b61SSam Leffler 				best_rate_rix = rix;
392eb6f0de0SAdrian Chadd 				best_rate_pct = pct;
393eb6f0de0SAdrian Chadd 			}
394eb6f0de0SAdrian Chadd 		}
395eb6f0de0SAdrian Chadd 
396eb6f0de0SAdrian Chadd 		/*
397cce63444SAdrian Chadd 		 * Since 2 and 3 stream rates have slightly higher TX times,
398eb6f0de0SAdrian Chadd 		 * allow a little bit of leeway. This should later
399eb6f0de0SAdrian Chadd 		 * be abstracted out and properly handled.
400eb6f0de0SAdrian Chadd 		 */
401eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
402cce63444SAdrian Chadd 			if (best_rate_tt == 0 || ((tt * 10) <= (best_rate_tt * 10))) {
403eb6f0de0SAdrian Chadd 				best_rate_tt = tt;
404eb6f0de0SAdrian Chadd 				best_rate_rix = rix;
405eb6f0de0SAdrian Chadd 				best_rate_pct = pct;
406eb6f0de0SAdrian Chadd 			}
407fa20c234SSam Leffler 		}
408fa20c234SSam Leffler 	}
409c1565b61SSam Leffler 	return (best_rate_tt ? best_rate_rix : -1);
410fa20c234SSam Leffler }
411fa20c234SSam Leffler 
412fa20c234SSam Leffler /*
413c1565b61SSam Leffler  * Pick a good "random" bit-rate to sample other than the current one.
414fa20c234SSam Leffler  */
415b91bf513SSam Leffler static __inline int
41636958948SAdrian Chadd pick_sample_rate(struct sample_softc *ssc , struct ath_node *an,
417c1565b61SSam Leffler     const HAL_RATE_TABLE *rt, int size_bin)
418fa20c234SSam Leffler {
419c1565b61SSam Leffler #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
420a6a308a4SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
42136958948SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
422c1565b61SSam Leffler 	int current_rix, rix;
423c1565b61SSam Leffler 	unsigned current_tt;
424193bfa21SAdrian Chadd 	uint64_t mask;
425fa20c234SSam Leffler 
426c1565b61SSam Leffler 	current_rix = sn->current_rix[size_bin];
427c1565b61SSam Leffler 	if (current_rix < 0) {
428fa20c234SSam Leffler 		/* no successes yet, send at the lowest bit-rate */
429cce63444SAdrian Chadd 		/* XXX TODO should return MCS0 if HT */
430fa20c234SSam Leffler 		return 0;
431fa20c234SSam Leffler 	}
432fa20c234SSam Leffler 
433c1565b61SSam Leffler 	current_tt = sn->stats[size_bin][current_rix].average_tx_time;
434fa20c234SSam Leffler 
435c1565b61SSam Leffler 	rix = sn->last_sample_rix[size_bin]+1;	/* next sample rate */
436193bfa21SAdrian Chadd 	mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
437c1565b61SSam Leffler 	while (mask != 0) {
438193bfa21SAdrian Chadd 		if ((mask & ((uint64_t) 1<<rix)) == 0) {	/* not a supported rate */
439c1565b61SSam Leffler 	nextrate:
440c1565b61SSam Leffler 			if (++rix >= rt->rateCount)
441c1565b61SSam Leffler 				rix = 0;
442b91bf513SSam Leffler 			continue;
443c1565b61SSam Leffler 		}
444b91bf513SSam Leffler 
445bf57b7b2SAdrian Chadd 		/*
446bf57b7b2SAdrian Chadd 		 * The following code stops trying to sample
447bf57b7b2SAdrian Chadd 		 * non-MCS rates when speaking to an MCS node.
448bf57b7b2SAdrian Chadd 		 * However, at least for CCK rates in 2.4GHz mode,
449bf57b7b2SAdrian Chadd 		 * the non-MCS rates MAY actually provide better
450bf57b7b2SAdrian Chadd 		 * PER at the very far edge of reception.
451bf57b7b2SAdrian Chadd 		 *
452bf57b7b2SAdrian Chadd 		 * However! Until ath_rate_form_aggr() grows
453bf57b7b2SAdrian Chadd 		 * some logic to not form aggregates if the
454bf57b7b2SAdrian Chadd 		 * selected rate is non-MCS, this won't work.
455bf57b7b2SAdrian Chadd 		 *
456bf57b7b2SAdrian Chadd 		 * So don't disable this code until you've taught
457bf57b7b2SAdrian Chadd 		 * ath_rate_form_aggr() to drop out if any of
458bf57b7b2SAdrian Chadd 		 * the selected rates are non-MCS.
459bf57b7b2SAdrian Chadd 		 */
460bf57b7b2SAdrian Chadd #if 1
46136958948SAdrian Chadd 		/* if the node is HT and the rate isn't HT, don't bother sample */
46236958948SAdrian Chadd 		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
46336958948SAdrian Chadd 		    (rt->info[rix].phy != IEEE80211_T_HT)) {
464193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
46536958948SAdrian Chadd 			goto nextrate;
46636958948SAdrian Chadd 		}
467bf57b7b2SAdrian Chadd #endif
46836958948SAdrian Chadd 
469b91bf513SSam Leffler 		/* this bit-rate is always worse than the current one */
470c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {
471193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
472c1565b61SSam Leffler 			goto nextrate;
473c1565b61SSam Leffler 		}
474b91bf513SSam Leffler 
475b91bf513SSam Leffler 		/* rarely sample bit-rates that fail a lot */
476c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
477c1565b61SSam Leffler 		    ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
478193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
479c1565b61SSam Leffler 			goto nextrate;
480fa20c234SSam Leffler 		}
481c1565b61SSam Leffler 
482eb6f0de0SAdrian Chadd 		/*
483e69db8dfSAdrian Chadd 		 * For HT, only sample a few rates on either side of the
484e69db8dfSAdrian Chadd 		 * current rix; there's quite likely a lot of them.
485cce63444SAdrian Chadd 		 *
486cce63444SAdrian Chadd 		 * This is limited to testing rate indexes on either side of
487cce63444SAdrian Chadd 		 * this MCS, but for all spatial streams.
488cce63444SAdrian Chadd 		 *
489cce63444SAdrian Chadd 		 * Otherwise we'll (a) never really sample higher MCS
490cce63444SAdrian Chadd 		 * rates if we're stuck low, and we'll make weird moves
491cce63444SAdrian Chadd 		 * like sample MCS8 if we're using MCS7.
492eb6f0de0SAdrian Chadd 		 */
493eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
494cce63444SAdrian Chadd 			uint8_t current_mcs, rix_mcs;
495cce63444SAdrian Chadd 
496cce63444SAdrian Chadd 			current_mcs = MCS(current_rix) & 0x7;
497cce63444SAdrian Chadd 			rix_mcs = MCS(rix) & 0x7;
498cce63444SAdrian Chadd 
499cce63444SAdrian Chadd 			if (rix_mcs < (current_mcs - 2) ||
500cce63444SAdrian Chadd 			    rix_mcs > (current_mcs + 2)) {
501193bfa21SAdrian Chadd 				mask &= ~((uint64_t) 1<<rix);
502eb6f0de0SAdrian Chadd 				goto nextrate;
503eb6f0de0SAdrian Chadd 			}
504eb6f0de0SAdrian Chadd 		}
505eb6f0de0SAdrian Chadd 
50636958948SAdrian Chadd 		/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
50736958948SAdrian Chadd 		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
508c1565b61SSam Leffler 			if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
509193bfa21SAdrian Chadd 				mask &= ~((uint64_t) 1<<rix);
510c1565b61SSam Leffler 				goto nextrate;
511c1565b61SSam Leffler 			}
51236958948SAdrian Chadd 		}
513c1565b61SSam Leffler 
514c1565b61SSam Leffler 		sn->last_sample_rix[size_bin] = rix;
515c1565b61SSam Leffler 		return rix;
516c1565b61SSam Leffler 	}
517c1565b61SSam Leffler 	return current_rix;
518c1565b61SSam Leffler #undef DOT11RATE
519a6a308a4SAdrian Chadd #undef	MCS
520fa20c234SSam Leffler }
521fa20c234SSam Leffler 
522c4ac32a8SAdrian Chadd static int
523c4ac32a8SAdrian Chadd ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni)
524c4ac32a8SAdrian Chadd {
525c4ac32a8SAdrian Chadd #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
526c4ac32a8SAdrian Chadd #define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
527c4ac32a8SAdrian Chadd #define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
528c4ac32a8SAdrian Chadd 	const struct ieee80211_txparam *tp = ni->ni_txparms;
529c4ac32a8SAdrian Chadd 	int srate;
530c4ac32a8SAdrian Chadd 
531c4ac32a8SAdrian Chadd 	/* Check MCS rates */
532c4ac32a8SAdrian Chadd 	for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) {
533c4ac32a8SAdrian Chadd 		if (MCS(srate) == tp->ucastrate)
534c4ac32a8SAdrian Chadd 			return sc->sc_rixmap[tp->ucastrate];
535c4ac32a8SAdrian Chadd 	}
536c4ac32a8SAdrian Chadd 
537c4ac32a8SAdrian Chadd 	/* Check legacy rates */
538c4ac32a8SAdrian Chadd 	for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) {
539c4ac32a8SAdrian Chadd 		if (RATE(srate) == tp->ucastrate)
540c4ac32a8SAdrian Chadd 			return sc->sc_rixmap[tp->ucastrate];
541c4ac32a8SAdrian Chadd 	}
542c4ac32a8SAdrian Chadd 	return -1;
543c4ac32a8SAdrian Chadd #undef	RATE
544c4ac32a8SAdrian Chadd #undef	DOT11RATE
545c4ac32a8SAdrian Chadd #undef	MCS
546c4ac32a8SAdrian Chadd }
547c4ac32a8SAdrian Chadd 
548c4ac32a8SAdrian Chadd static void
549c4ac32a8SAdrian Chadd ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni)
550c4ac32a8SAdrian Chadd {
551c4ac32a8SAdrian Chadd 	struct ath_node *an = ATH_NODE(ni);
552c4ac32a8SAdrian Chadd 	const struct ieee80211_txparam *tp = ni->ni_txparms;
553c4ac32a8SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
554c4ac32a8SAdrian Chadd 
555c4ac32a8SAdrian Chadd 	if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
556c4ac32a8SAdrian Chadd 		/*
557c4ac32a8SAdrian Chadd 		 * A fixed rate is to be used; ucastrate is the IEEE code
558c4ac32a8SAdrian Chadd 		 * for this rate (sans basic bit).  Check this against the
559c4ac32a8SAdrian Chadd 		 * negotiated rate set for the node.  Note the fixed rate
560c4ac32a8SAdrian Chadd 		 * may not be available for various reasons so we only
561c4ac32a8SAdrian Chadd 		 * setup the static rate index if the lookup is successful.
562c4ac32a8SAdrian Chadd 		 */
563c4ac32a8SAdrian Chadd 		sn->static_rix = ath_rate_get_static_rix(sc, ni);
564c4ac32a8SAdrian Chadd 	} else {
565c4ac32a8SAdrian Chadd 		sn->static_rix = -1;
566c4ac32a8SAdrian Chadd 	}
567c4ac32a8SAdrian Chadd }
568c4ac32a8SAdrian Chadd 
569eb6f0de0SAdrian Chadd /*
570eb6f0de0SAdrian Chadd  * Pick a non-HT rate to begin using.
571eb6f0de0SAdrian Chadd  */
572eb6f0de0SAdrian Chadd static int
573eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an,
574eb6f0de0SAdrian Chadd     int frameLen)
575eb6f0de0SAdrian Chadd {
576eb6f0de0SAdrian Chadd #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
577eb6f0de0SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
578eb6f0de0SAdrian Chadd #define	RATE(ix)	(DOT11RATE(ix) / 2)
579eb6f0de0SAdrian Chadd 	int rix = -1;
580eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
581eb6f0de0SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
582eb6f0de0SAdrian Chadd 	const int size_bin = size_to_bin(frameLen);
583eb6f0de0SAdrian Chadd 
584eb6f0de0SAdrian Chadd 	/* no packet has been sent successfully yet */
585eb6f0de0SAdrian Chadd 	for (rix = rt->rateCount-1; rix > 0; rix--) {
586193bfa21SAdrian Chadd 		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
587eb6f0de0SAdrian Chadd 			continue;
588eb6f0de0SAdrian Chadd 
589eb6f0de0SAdrian Chadd 		/* Skip HT rates */
590eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy == IEEE80211_T_HT)
591eb6f0de0SAdrian Chadd 			continue;
592eb6f0de0SAdrian Chadd 
593eb6f0de0SAdrian Chadd 		/*
594eb6f0de0SAdrian Chadd 		 * Pick the highest rate <= 36 Mbps
595eb6f0de0SAdrian Chadd 		 * that hasn't failed.
596eb6f0de0SAdrian Chadd 		 */
597eb6f0de0SAdrian Chadd 		if (DOT11RATE(rix) <= 72 &&
598eb6f0de0SAdrian Chadd 		    sn->stats[size_bin][rix].successive_failures == 0) {
599eb6f0de0SAdrian Chadd 			break;
600eb6f0de0SAdrian Chadd 		}
601eb6f0de0SAdrian Chadd 	}
602eb6f0de0SAdrian Chadd 	return rix;
603eb6f0de0SAdrian Chadd #undef	RATE
604eb6f0de0SAdrian Chadd #undef	MCS
605eb6f0de0SAdrian Chadd #undef	DOT11RATE
606eb6f0de0SAdrian Chadd }
607eb6f0de0SAdrian Chadd 
608eb6f0de0SAdrian Chadd /*
609eb6f0de0SAdrian Chadd  * Pick a HT rate to begin using.
610eb6f0de0SAdrian Chadd  *
611eb6f0de0SAdrian Chadd  * Don't use any non-HT rates; only consider HT rates.
612eb6f0de0SAdrian Chadd  */
613eb6f0de0SAdrian Chadd static int
614eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an,
615eb6f0de0SAdrian Chadd     int frameLen)
616eb6f0de0SAdrian Chadd {
617eb6f0de0SAdrian Chadd #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
618eb6f0de0SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
619eb6f0de0SAdrian Chadd #define	RATE(ix)	(DOT11RATE(ix) / 2)
620eb6f0de0SAdrian Chadd 	int rix = -1, ht_rix = -1;
621eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
622eb6f0de0SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
623eb6f0de0SAdrian Chadd 	const int size_bin = size_to_bin(frameLen);
624eb6f0de0SAdrian Chadd 
625eb6f0de0SAdrian Chadd 	/* no packet has been sent successfully yet */
626eb6f0de0SAdrian Chadd 	for (rix = rt->rateCount-1; rix > 0; rix--) {
627eb6f0de0SAdrian Chadd 		/* Skip rates we can't use */
628193bfa21SAdrian Chadd 		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
629eb6f0de0SAdrian Chadd 			continue;
630eb6f0de0SAdrian Chadd 
631eb6f0de0SAdrian Chadd 		/* Keep a copy of the last seen HT rate index */
632eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy == IEEE80211_T_HT)
633eb6f0de0SAdrian Chadd 			ht_rix = rix;
634eb6f0de0SAdrian Chadd 
635eb6f0de0SAdrian Chadd 		/* Skip non-HT rates */
636eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy != IEEE80211_T_HT)
637eb6f0de0SAdrian Chadd 			continue;
638eb6f0de0SAdrian Chadd 
639eb6f0de0SAdrian Chadd 		/*
640cce63444SAdrian Chadd 		 * Pick a medium-speed rate at 1 spatial stream
641cce63444SAdrian Chadd 		 * which has not seen any failures.
642cce63444SAdrian Chadd 		 * Higher rates may fail; we'll try them later.
643eb6f0de0SAdrian Chadd 		 */
644cce63444SAdrian Chadd 		if (((MCS(rix)& 0x7f) <= 4) &&
645eb6f0de0SAdrian Chadd 		    sn->stats[size_bin][rix].successive_failures == 0) {
646eb6f0de0SAdrian Chadd 			break;
647eb6f0de0SAdrian Chadd 		}
648eb6f0de0SAdrian Chadd 	}
649eb6f0de0SAdrian Chadd 
650eb6f0de0SAdrian Chadd 	/*
651eb6f0de0SAdrian Chadd 	 * If all the MCS rates have successive failures, rix should be
652eb6f0de0SAdrian Chadd 	 * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)
653eb6f0de0SAdrian Chadd 	 */
654eb6f0de0SAdrian Chadd 	return MAX(rix, ht_rix);
655eb6f0de0SAdrian Chadd #undef	RATE
656eb6f0de0SAdrian Chadd #undef	MCS
657eb6f0de0SAdrian Chadd #undef	DOT11RATE
658eb6f0de0SAdrian Chadd }
659c4ac32a8SAdrian Chadd 
660c4ac32a8SAdrian Chadd 
661fa20c234SSam Leffler void
662fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
66384f950a5SAdrian Chadd 		  int shortPreamble, size_t frameLen, int tid,
664cce63444SAdrian Chadd 		  int is_aggr, u_int8_t *rix0, int *try0,
665cce63444SAdrian Chadd 		  u_int8_t *txrate, int *maxdur, int *maxpktlen)
666fa20c234SSam Leffler {
667c1565b61SSam Leffler #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
668a6a308a4SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
669c1565b61SSam Leffler #define	RATE(ix)	(DOT11RATE(ix) / 2)
670fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
671fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
6727a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
673c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
674cce63444SAdrian Chadd 	int size_bin = size_to_bin(frameLen);
675c1565b61SSam Leffler 	int rix, mrr, best_rix, change_rates;
676b2763056SSam Leffler 	unsigned average_tx_time;
677cce63444SAdrian Chadd 	int max_pkt_len;
678fa20c234SSam Leffler 
679c4ac32a8SAdrian Chadd 	ath_rate_update_static_rix(sc, &an->an_node);
680c4ac32a8SAdrian Chadd 
68184f950a5SAdrian Chadd 	/* For now don't take TID, is_aggr into account */
68284f950a5SAdrian Chadd 	/* Also for now don't calculate a max duration; that'll come later */
68384f950a5SAdrian Chadd 	*maxdur = -1;
68484f950a5SAdrian Chadd 
685cce63444SAdrian Chadd 	/*
686cce63444SAdrian Chadd 	 * For now just set it to the frame length; we'll optimise it later.
687cce63444SAdrian Chadd 	 */
688cce63444SAdrian Chadd 	*maxpktlen = frameLen;
689cce63444SAdrian Chadd 
690cc86f1eaSAdrian Chadd 	if (sn->currates != sc->sc_currates) {
691cc86f1eaSAdrian Chadd 		device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",
692cc86f1eaSAdrian Chadd 		    __func__);
693cc86f1eaSAdrian Chadd 		rix = 0;
694cc86f1eaSAdrian Chadd 		*try0 = ATH_TXMAXTRY;
695cc86f1eaSAdrian Chadd 		goto done;
696cc86f1eaSAdrian Chadd 	}
697cc86f1eaSAdrian Chadd 
698c1565b61SSam Leffler 	if (sn->static_rix != -1) {
699c1565b61SSam Leffler 		rix = sn->static_rix;
700c1565b61SSam Leffler 		*try0 = ATH_TXMAXTRY;
701*8af14459SAdrian Chadd 
702*8af14459SAdrian Chadd 		/*
703*8af14459SAdrian Chadd 		 * Ensure we limit max packet length here too!
704*8af14459SAdrian Chadd 		 */
705*8af14459SAdrian Chadd 		max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an,
706*8af14459SAdrian Chadd 		    sn->static_rix,
707*8af14459SAdrian Chadd 		    is_aggr);
708*8af14459SAdrian Chadd 		if (max_pkt_len > 0) {
709*8af14459SAdrian Chadd 			*maxpktlen = frameLen = MIN(frameLen, max_pkt_len);
710*8af14459SAdrian Chadd 			size_bin = size_to_bin(frameLen);
711*8af14459SAdrian Chadd 		}
712c1565b61SSam Leffler 		goto done;
713c1565b61SSam Leffler 	}
714fa20c234SSam Leffler 
715af017101SAdrian Chadd 	mrr = sc->sc_mrretry;
716af017101SAdrian Chadd 	/* XXX check HT protmode too */
717cce63444SAdrian Chadd 	/* XXX turn into a cap; 11n MACs support MRR+RTSCTS */
7189f579ef8SAdrian Chadd 	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
719af017101SAdrian Chadd 		mrr = 0;
720c1565b61SSam Leffler 
72136958948SAdrian Chadd 	best_rix = pick_best_rate(an, rt, size_bin, !mrr);
722cce63444SAdrian Chadd 
723cce63444SAdrian Chadd 	/*
724cce63444SAdrian Chadd 	 * At this point we've chosen the best rix, so now we
725cce63444SAdrian Chadd 	 * need to potentially update our maximum packet length
726cce63444SAdrian Chadd 	 * and size_bin if we're doing 11n rates.
727cce63444SAdrian Chadd 	 */
728051ea90cSAdrian Chadd 	max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix,
729051ea90cSAdrian Chadd 	    is_aggr);
730cce63444SAdrian Chadd 	if (max_pkt_len > 0) {
731cce63444SAdrian Chadd #if 0
732cce63444SAdrian Chadd 		device_printf(sc->sc_dev,
733cce63444SAdrian Chadd 		    "Limiting maxpktlen from %d to %d bytes\n",
734cce63444SAdrian Chadd 		    (int) frameLen, max_pkt_len);
735cce63444SAdrian Chadd #endif
736cce63444SAdrian Chadd 		*maxpktlen = frameLen = MIN(frameLen, max_pkt_len);
737cce63444SAdrian Chadd 		size_bin = size_to_bin(frameLen);
738cce63444SAdrian Chadd 	}
739cce63444SAdrian Chadd 
740c1565b61SSam Leffler 	if (best_rix >= 0) {
741c1565b61SSam Leffler 		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
742fa20c234SSam Leffler 	} else {
743b2763056SSam Leffler 		average_tx_time = 0;
744b2763056SSam Leffler 	}
745cce63444SAdrian Chadd 
746fa20c234SSam Leffler 	/*
747c1565b61SSam Leffler 	 * Limit the time measuring the performance of other tx
748c1565b61SSam Leffler 	 * rates to sample_rate% of the total transmission time.
749fa20c234SSam Leffler 	 */
7505add7017SAdrian Chadd 	if (sn->sample_tt[size_bin] <
7515add7017SAdrian Chadd 	    average_tx_time *
7525add7017SAdrian Chadd 	    (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
75336958948SAdrian Chadd 		rix = pick_sample_rate(ssc, an, rt, size_bin);
754c1565b61SSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
7555add7017SAdrian Chadd 		     &an->an_node, "att %d sample_tt %d size %u "
7565add7017SAdrian Chadd 		     "sample rate %d %s current rate %d %s",
757eb6f0de0SAdrian Chadd 		     average_tx_time,
758eb6f0de0SAdrian Chadd 		     sn->sample_tt[size_bin],
759eb6f0de0SAdrian Chadd 		     bin_to_size(size_bin),
760eb6f0de0SAdrian Chadd 		     dot11rate(rt, rix),
761eb6f0de0SAdrian Chadd 		     dot11rate_label(rt, rix),
762eb6f0de0SAdrian Chadd 		     dot11rate(rt, sn->current_rix[size_bin]),
763eb6f0de0SAdrian Chadd 		     dot11rate_label(rt, sn->current_rix[size_bin]));
764c1565b61SSam Leffler 		if (rix != sn->current_rix[size_bin]) {
765c1565b61SSam Leffler 			sn->current_sample_rix[size_bin] = rix;
766b2763056SSam Leffler 		} else {
767c1565b61SSam Leffler 			sn->current_sample_rix[size_bin] = -1;
768b2763056SSam Leffler 		}
769b2763056SSam Leffler 		sn->packets_since_sample[size_bin] = 0;
770b2763056SSam Leffler 	} else {
771b91bf513SSam Leffler 		change_rates = 0;
772c1565b61SSam Leffler 		if (!sn->packets_sent[size_bin] || best_rix == -1) {
773b91bf513SSam Leffler 			/* no packet has been sent successfully yet */
774b91bf513SSam Leffler 			change_rates = 1;
775eb6f0de0SAdrian Chadd 			if (an->an_node.ni_flags & IEEE80211_NODE_HT)
776eb6f0de0SAdrian Chadd 				best_rix =
777eb6f0de0SAdrian Chadd 				    ath_rate_pick_seed_rate_ht(sc, an, frameLen);
778eb6f0de0SAdrian Chadd 			else
779eb6f0de0SAdrian Chadd 				best_rix =
780eb6f0de0SAdrian Chadd 				    ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
781b91bf513SSam Leffler 		} else if (sn->packets_sent[size_bin] < 20) {
782b91bf513SSam Leffler 			/* let the bit-rate switch quickly during the first few packets */
783eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
784eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
785eb6f0de0SAdrian Chadd 			    "%s: switching quickly..", __func__);
786b91bf513SSam Leffler 			change_rates = 1;
787c1565b61SSam Leffler 		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
788c1565b61SSam Leffler 			/* min_switch seconds have gone by */
789eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
790eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
791eb6f0de0SAdrian Chadd 			    "%s: min_switch %d > ticks_since_switch %d..",
792eb6f0de0SAdrian Chadd 			    __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
793b91bf513SSam Leffler 			change_rates = 1;
794eb6f0de0SAdrian Chadd 		} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
795eb6f0de0SAdrian Chadd 		    (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
796b91bf513SSam Leffler 			/* the current bit-rate is twice as slow as the best one */
797eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
798eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
799eb6f0de0SAdrian Chadd 			    "%s: 2x att (= %d) < cur_rix att %d",
800eb6f0de0SAdrian Chadd 			    __func__,
801eb6f0de0SAdrian Chadd 			    2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
802b91bf513SSam Leffler 			change_rates = 1;
803eb6f0de0SAdrian Chadd 		} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
804eb6f0de0SAdrian Chadd 			int cur_rix = sn->current_rix[size_bin];
805eb6f0de0SAdrian Chadd 			int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
806eb6f0de0SAdrian Chadd 			/*
807051ea90cSAdrian Chadd 			 * If the node is HT, it if the rate isn't the
808051ea90cSAdrian Chadd 			 * same and the average tx time is within 10%
809051ea90cSAdrian Chadd 			 * of the current rate. It can fail a little.
810eb6f0de0SAdrian Chadd 			 *
811eb6f0de0SAdrian Chadd 			 * This is likely not optimal!
812eb6f0de0SAdrian Chadd 			 */
813eb6f0de0SAdrian Chadd #if 0
814eb6f0de0SAdrian Chadd 			printf("cur rix/att %x/%d, best rix/att %x/%d\n",
815eb6f0de0SAdrian Chadd 			    MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
816eb6f0de0SAdrian Chadd #endif
8175add7017SAdrian Chadd 			if ((best_rix != cur_rix) &&
8185add7017SAdrian Chadd 			    (average_tx_time * 9) <= (cur_att * 10)) {
819eb6f0de0SAdrian Chadd 				IEEE80211_NOTE(an->an_node.ni_vap,
820eb6f0de0SAdrian Chadd 				    IEEE80211_MSG_RATECTL, &an->an_node,
821cce63444SAdrian Chadd 				    "%s: HT: size %d best_rix 0x%x > "
822cce63444SAdrian Chadd 				    " cur_rix 0x%x, average_tx_time %d,"
823cce63444SAdrian Chadd 				    " cur_att %d",
824cce63444SAdrian Chadd 				    __func__, bin_to_size(size_bin),
825cce63444SAdrian Chadd 				    MCS(best_rix), MCS(cur_rix),
826cce63444SAdrian Chadd 				    average_tx_time, cur_att);
827eb6f0de0SAdrian Chadd 				change_rates = 1;
828eb6f0de0SAdrian Chadd 			}
829b91bf513SSam Leffler 		}
830b91bf513SSam Leffler 
831b91bf513SSam Leffler 		sn->packets_since_sample[size_bin]++;
832b91bf513SSam Leffler 
833b91bf513SSam Leffler 		if (change_rates) {
834c1565b61SSam Leffler 			if (best_rix != sn->current_rix[size_bin]) {
835b032f27cSSam Leffler 				IEEE80211_NOTE(an->an_node.ni_vap,
836b032f27cSSam Leffler 				    IEEE80211_MSG_RATECTL,
837b032f27cSSam Leffler 				    &an->an_node,
838cce63444SAdrian Chadd "%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d",
839b2763056SSam Leffler 				    __func__,
840c1565b61SSam Leffler 				    bin_to_size(size_bin),
841cce63444SAdrian Chadd 				    dot11rate(rt, sn->current_rix[size_bin]),
842cce63444SAdrian Chadd 				    dot11rate_label(rt, sn->current_rix[size_bin]),
843c1565b61SSam Leffler 				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
844c1565b61SSam Leffler 				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
845cce63444SAdrian Chadd 				    sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct,
846cce63444SAdrian Chadd 				    dot11rate(rt, best_rix),
847cce63444SAdrian Chadd 				    dot11rate_label(rt, best_rix),
848c1565b61SSam Leffler 				    sn->stats[size_bin][best_rix].average_tx_time,
849c1565b61SSam Leffler 				    sn->stats[size_bin][best_rix].perfect_tx_time,
850cce63444SAdrian Chadd 				    sn->stats[size_bin][best_rix].ewma_pct,
851b2763056SSam Leffler 				    sn->packets_since_switch[size_bin],
852b2763056SSam Leffler 				    mrr);
853b2763056SSam Leffler 			}
854b2763056SSam Leffler 			sn->packets_since_switch[size_bin] = 0;
855c1565b61SSam Leffler 			sn->current_rix[size_bin] = best_rix;
856b91bf513SSam Leffler 			sn->ticks_since_switch[size_bin] = ticks;
857b032f27cSSam Leffler 			/*
858b032f27cSSam Leffler 			 * Set the visible txrate for this node.
859b032f27cSSam Leffler 			 */
8605add7017SAdrian Chadd 			an->an_node.ni_txrate =
8615add7017SAdrian Chadd 			    (rt->info[best_rix].phy == IEEE80211_T_HT) ?
8625add7017SAdrian Chadd 			     MCS(best_rix) : DOT11RATE(best_rix);
863b2763056SSam Leffler 		}
864c1565b61SSam Leffler 		rix = sn->current_rix[size_bin];
865b2763056SSam Leffler 		sn->packets_since_switch[size_bin]++;
866b91bf513SSam Leffler 	}
867c1565b61SSam Leffler 	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
868c1565b61SSam Leffler done:
869cc86f1eaSAdrian Chadd 
870cc86f1eaSAdrian Chadd 	/*
871cc86f1eaSAdrian Chadd 	 * This bug totally sucks and should be fixed.
872cc86f1eaSAdrian Chadd 	 *
873cc86f1eaSAdrian Chadd 	 * For now though, let's not panic, so we can start to figure
874cc86f1eaSAdrian Chadd 	 * out how to better reproduce it.
875cc86f1eaSAdrian Chadd 	 */
876cc86f1eaSAdrian Chadd 	if (rix < 0 || rix >= rt->rateCount) {
877cc86f1eaSAdrian Chadd 		printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
878cc86f1eaSAdrian Chadd 		    __func__,
879cc86f1eaSAdrian Chadd 		    rix,
880cc86f1eaSAdrian Chadd 		    rt->rateCount);
881cc86f1eaSAdrian Chadd 		    rix = 0;	/* XXX just default for now */
882cc86f1eaSAdrian Chadd 	}
883c1565b61SSam Leffler 	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));
884fa20c234SSam Leffler 
885c1565b61SSam Leffler 	*rix0 = rix;
886c1565b61SSam Leffler 	*txrate = rt->info[rix].rateCode
887c1565b61SSam Leffler 		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
888fa20c234SSam Leffler 	sn->packets_sent[size_bin]++;
889cce63444SAdrian Chadd 
890c1565b61SSam Leffler #undef DOT11RATE
891a6a308a4SAdrian Chadd #undef MCS
892c1565b61SSam Leffler #undef RATE
893fa20c234SSam Leffler }
894fa20c234SSam Leffler 
895710c3778SAdrian Chadd /*
896710c3778SAdrian Chadd  * Get the TX rates. Don't fiddle with short preamble flags for them;
897710c3778SAdrian Chadd  * the caller can do that.
898710c3778SAdrian Chadd  */
899710c3778SAdrian Chadd void
900710c3778SAdrian Chadd ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
901051ea90cSAdrian Chadd     uint8_t rix0, int is_aggr, struct ath_rc_series *rc)
902710c3778SAdrian Chadd {
903710c3778SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
904710c3778SAdrian Chadd 	const struct txschedule *sched = &sn->sched[rix0];
905710c3778SAdrian Chadd 
906193bfa21SAdrian Chadd 	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
907193bfa21SAdrian Chadd 	    rix0, sched->r0));
908710c3778SAdrian Chadd 
909eb6f0de0SAdrian Chadd 	rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
910710c3778SAdrian Chadd 
911eb6f0de0SAdrian Chadd 	rc[0].rix = sched->r0;
912eb6f0de0SAdrian Chadd 	rc[1].rix = sched->r1;
913eb6f0de0SAdrian Chadd 	rc[2].rix = sched->r2;
914eb6f0de0SAdrian Chadd 	rc[3].rix = sched->r3;
915eb6f0de0SAdrian Chadd 
916eb6f0de0SAdrian Chadd 	rc[0].tries = sched->t0;
917eb6f0de0SAdrian Chadd 	rc[1].tries = sched->t1;
918051ea90cSAdrian Chadd 
919051ea90cSAdrian Chadd 	if (is_aggr) {
920051ea90cSAdrian Chadd 		rc[2].tries = rc[3].tries = 0;
921051ea90cSAdrian Chadd 	} else {
922eb6f0de0SAdrian Chadd 		rc[2].tries = sched->t2;
923eb6f0de0SAdrian Chadd 		rc[3].tries = sched->t3;
924710c3778SAdrian Chadd 	}
925051ea90cSAdrian Chadd }
926710c3778SAdrian Chadd 
927fa20c234SSam Leffler void
928fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
929a4d8dd10SSam Leffler 		      struct ath_desc *ds, int shortPreamble, u_int8_t rix)
930fa20c234SSam Leffler {
931fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
932c1565b61SSam Leffler 	const struct txschedule *sched = &sn->sched[rix];
933c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
934c1565b61SSam Leffler 	uint8_t rix1, s1code, rix2, s2code, rix3, s3code;
935fa20c234SSam Leffler 
936c1565b61SSam Leffler 	/* XXX precalculate short preamble tables */
937c1565b61SSam Leffler 	rix1 = sched->r1;
938c1565b61SSam Leffler 	s1code = rt->info[rix1].rateCode
939c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix1].shortPreamble : 0);
940c1565b61SSam Leffler 	rix2 = sched->r2;
941c1565b61SSam Leffler 	s2code = rt->info[rix2].rateCode
942c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix2].shortPreamble : 0);
943c1565b61SSam Leffler 	rix3 = sched->r3;
944c1565b61SSam Leffler 	s3code = rt->info[rix3].rateCode
945c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix3].shortPreamble : 0);
946c1565b61SSam Leffler 	ath_hal_setupxtxdesc(sc->sc_ah, ds,
947c1565b61SSam Leffler 	    s1code, sched->t1,		/* series 1 */
948c1565b61SSam Leffler 	    s2code, sched->t2,		/* series 2 */
949c1565b61SSam Leffler 	    s3code, sched->t3);		/* series 3 */
950fa20c234SSam Leffler }
951fa20c234SSam Leffler 
952cf431555SAdrian Chadd /*
953cf431555SAdrian Chadd  * Update the current statistics.
954cf431555SAdrian Chadd  *
955cf431555SAdrian Chadd  * Note that status is for the FINAL transmit status, not this
956cf431555SAdrian Chadd  * particular attempt.  So, check if tries > tries0 and if so
957cf431555SAdrian Chadd  * assume this status failed.
958cf431555SAdrian Chadd  *
959cf431555SAdrian Chadd  * This is important because some failures are due to both
960cf431555SAdrian Chadd  * short AND long retries; if the final issue was a short
961cf431555SAdrian Chadd  * retry failure then we still want to account for the
962cf431555SAdrian Chadd  * bad long retry attempts.
963cf431555SAdrian Chadd  */
964b2763056SSam Leffler static void
965b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an,
966b2763056SSam Leffler 		  int frame_size,
967c1565b61SSam Leffler 		  int rix0, int tries0,
968eb6f0de0SAdrian Chadd 		  int short_tries, int tries, int status,
969eb6f0de0SAdrian Chadd 		  int nframes, int nbad)
970fa20c234SSam Leffler {
971fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
972fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
973ec3dec2fSAdrian Chadd #ifdef IEEE80211_DEBUG
974eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
975ec3dec2fSAdrian Chadd #endif
976c1565b61SSam Leffler 	const int size_bin = size_to_bin(frame_size);
977c1565b61SSam Leffler 	const int size = bin_to_size(size_bin);
978cf431555SAdrian Chadd 	int tt;
979532f2442SAdrian Chadd 	int is_ht40 = (an->an_node.ni_chw == 40);
980ee563d63SAdrian Chadd 	int pct;
981fa20c234SSam Leffler 
982c1565b61SSam Leffler 	if (!IS_RATE_DEFINED(sn, rix0))
98365f9edeeSSam Leffler 		return;
984cce63444SAdrian Chadd 
985cce63444SAdrian Chadd 	/*
986cf431555SAdrian Chadd 	 * Treat long retries as us exceeding retries, even
987cf431555SAdrian Chadd 	 * if the eventual attempt at some other MRR schedule
988cf431555SAdrian Chadd 	 * succeeded.
989cf431555SAdrian Chadd 	 */
990cf431555SAdrian Chadd 	if (tries > tries0) {
991cf431555SAdrian Chadd 		status = HAL_TXERR_XRETRY;
992cf431555SAdrian Chadd 	}
993cf431555SAdrian Chadd 
994cf431555SAdrian Chadd 	/*
995cce63444SAdrian Chadd 	 * If status is FAIL then we treat all frames as bad.
996cce63444SAdrian Chadd 	 * This better accurately tracks EWMA and average TX time
997cce63444SAdrian Chadd 	 * because even if the eventual transmission succeeded,
998cce63444SAdrian Chadd 	 * transmission at this rate did not.
999cce63444SAdrian Chadd 	 */
1000cce63444SAdrian Chadd 	if (status != 0)
1001cce63444SAdrian Chadd 		nbad = nframes;
1002cce63444SAdrian Chadd 
1003051ea90cSAdrian Chadd 	/*
1004051ea90cSAdrian Chadd 	 * Ignore short tries count as contributing to failure.
1005051ea90cSAdrian Chadd 	 * Right now there's no way to know if it's part of any
1006051ea90cSAdrian Chadd 	 * given rate attempt, and outside of the RTS/CTS management
1007051ea90cSAdrian Chadd 	 * rate, it doesn't /really/ help.
1008051ea90cSAdrian Chadd 	 */
1009051ea90cSAdrian Chadd 	tt = calc_usecs_unicast_packet(sc, size, rix0,
1010051ea90cSAdrian Chadd 	    0 /* short_tries */, MIN(tries0, tries) - 1, is_ht40);
1011c1565b61SSam Leffler 
1012c1565b61SSam Leffler 	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
1013fa20c234SSam Leffler 		/* just average the first few packets */
1014c1565b61SSam Leffler 		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
1015c1565b61SSam Leffler 		int packets = sn->stats[size_bin][rix0].total_packets;
1016eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
1017fa20c234SSam Leffler 	} else {
1018fa20c234SSam Leffler 		/* use a ewma */
1019c1565b61SSam Leffler 		sn->stats[size_bin][rix0].average_tx_time =
1020c1565b61SSam Leffler 			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) +
1021c1565b61SSam Leffler 			 (tt * (100 - ssc->smoothing_rate))) / 100;
1022fa20c234SSam Leffler 	}
1023fa20c234SSam Leffler 
1024eb6f0de0SAdrian Chadd 	if (nframes == nbad) {
1025eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].successive_failures += nbad;
1026fa20c234SSam Leffler 	} else {
1027eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
1028c1565b61SSam Leffler 		sn->stats[size_bin][rix0].successive_failures = 0;
1029fa20c234SSam Leffler 	}
1030c1565b61SSam Leffler 	sn->stats[size_bin][rix0].tries += tries;
1031c1565b61SSam Leffler 	sn->stats[size_bin][rix0].last_tx = ticks;
1032eb6f0de0SAdrian Chadd 	sn->stats[size_bin][rix0].total_packets += nframes;
1033b2763056SSam Leffler 
1034ee563d63SAdrian Chadd 	/* update EWMA for this rix */
1035ee563d63SAdrian Chadd 
1036ee563d63SAdrian Chadd 	/* Calculate percentage based on current rate */
1037ee563d63SAdrian Chadd 	if (nframes == 0)
1038ee563d63SAdrian Chadd 		nframes = nbad = 1;
1039ee563d63SAdrian Chadd 	pct = ((nframes - nbad) * 1000) / nframes;
1040ee563d63SAdrian Chadd 
1041ee563d63SAdrian Chadd 	if (sn->stats[size_bin][rix0].total_packets <
1042ee563d63SAdrian Chadd 	    ssc->smoothing_minpackets) {
1043ee563d63SAdrian Chadd 		/* just average the first few packets */
1044ee563d63SAdrian Chadd 		int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /
1045ee563d63SAdrian Chadd 		    (sn->stats[size_bin][rix0].total_packets);
1046ee563d63SAdrian Chadd 		sn->stats[size_bin][rix0].ewma_pct = a_pct;
1047ee563d63SAdrian Chadd 	} else {
1048ee563d63SAdrian Chadd 		/* use a ewma */
1049ee563d63SAdrian Chadd 		sn->stats[size_bin][rix0].ewma_pct =
1050ee563d63SAdrian Chadd 			((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +
1051ee563d63SAdrian Chadd 			 (pct * (100 - ssc->smoothing_rate))) / 100;
1052ee563d63SAdrian Chadd 	}
1053ee563d63SAdrian Chadd 
1054cce63444SAdrian Chadd 	/*
1055cce63444SAdrian Chadd 	 * Only update the sample time for the initial sample rix.
1056cce63444SAdrian Chadd 	 * We've updated the statistics on each of the other retries
1057cce63444SAdrian Chadd 	 * fine, but we should only update the sample_tt with what
1058cce63444SAdrian Chadd 	 * was actually sampled.
1059cce63444SAdrian Chadd 	 *
1060cce63444SAdrian Chadd 	 * However, to aide in debugging, log all the failures for
1061cce63444SAdrian Chadd 	 * each of the buckets
1062cce63444SAdrian Chadd 	 */
1063b032f27cSSam Leffler 	IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1064b032f27cSSam Leffler 	   &an->an_node,
1065cce63444SAdrian Chadd 	    "%s: size %d %s %s rate %d %s tries (%d/%d) tt %d "
1066cce63444SAdrian Chadd 	    "avg_tt (%d/%d) nfrm %d nbad %d",
1067b032f27cSSam Leffler 	    __func__,
106865f9edeeSSam Leffler 	    size,
106965f9edeeSSam Leffler 	    status ? "FAIL" : "OK",
1070cce63444SAdrian Chadd 	    rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr",
1071eb6f0de0SAdrian Chadd 	    dot11rate(rt, rix0),
1072eb6f0de0SAdrian Chadd 	    dot11rate_label(rt, rix0),
1073eb6f0de0SAdrian Chadd 	    short_tries, tries, tt,
1074c1565b61SSam Leffler 	    sn->stats[size_bin][rix0].average_tx_time,
1075eb6f0de0SAdrian Chadd 	    sn->stats[size_bin][rix0].perfect_tx_time,
1076eb6f0de0SAdrian Chadd 	    nframes, nbad);
1077cce63444SAdrian Chadd 
1078cce63444SAdrian Chadd 	if (rix0 == sn->current_sample_rix[size_bin]) {
1079b2763056SSam Leffler 		sn->sample_tt[size_bin] = tt;
1080c1565b61SSam Leffler 		sn->current_sample_rix[size_bin] = -1;
1081b2763056SSam Leffler 	}
1082b2763056SSam Leffler }
1083b2763056SSam Leffler 
1084ec9ee5e7SSam Leffler static void
108576e6fd5dSGleb Smirnoff badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status)
1086ec9ee5e7SSam Leffler {
108776e6fd5dSGleb Smirnoff 
108876e6fd5dSGleb Smirnoff 	device_printf(sc->sc_dev,
108976e6fd5dSGleb Smirnoff 	    "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n",
1090ec9ee5e7SSam Leffler 	    series, hwrate, tries, status);
1091ec9ee5e7SSam Leffler }
1092ec9ee5e7SSam Leffler 
1093b2763056SSam Leffler void
109443e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
1095eb6f0de0SAdrian Chadd 	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
1096cce63444SAdrian Chadd 	int frame_size, int rc_framesize, int nframes, int nbad)
1097b2763056SSam Leffler {
10987a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
1099b2763056SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1100eb6f0de0SAdrian Chadd 	int final_rix, short_tries, long_tries;
110146d4d74cSSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1102eb6f0de0SAdrian Chadd 	int status = ts->ts_status;
11031bb9a085SSam Leffler 	int mrr;
1104b2763056SSam Leffler 
1105f6cbf16aSSam Leffler 	final_rix = rt->rateCodeToIndex[ts->ts_rate];
110665f9edeeSSam Leffler 	short_tries = ts->ts_shortretry;
110765f9edeeSSam Leffler 	long_tries = ts->ts_longretry + 1;
1108eb6f0de0SAdrian Chadd 
1109ee563d63SAdrian Chadd 	if (nframes == 0) {
1110ee563d63SAdrian Chadd 		device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);
1111ee563d63SAdrian Chadd 		return;
1112ee563d63SAdrian Chadd 	}
1113ee563d63SAdrian Chadd 
111443e9cf7cSSam Leffler 	if (frame_size == 0)		    /* NB: should not happen */
1115b2763056SSam Leffler 		frame_size = 1500;
1116cce63444SAdrian Chadd 	if (rc_framesize == 0)		    /* NB: should not happen */
1117cce63444SAdrian Chadd 		rc_framesize = 1500;
1118cce63444SAdrian Chadd 
1119cce63444SAdrian Chadd 	/*
1120cce63444SAdrian Chadd 	 * There are still some places where what rate control set as
1121cce63444SAdrian Chadd 	 * a limit but the hardware decided, for some reason, to transmit
1122cce63444SAdrian Chadd 	 * at a smaller size that fell into a different bucket.
1123cce63444SAdrian Chadd 	 *
1124cce63444SAdrian Chadd 	 * The eternal question here is - which size_bin should it go in?
1125cce63444SAdrian Chadd 	 * The one that was requested, or the one that was transmitted?
1126cce63444SAdrian Chadd 	 *
1127cce63444SAdrian Chadd 	 * Here's the problem - if we use the one that was transmitted,
1128cce63444SAdrian Chadd 	 * we may continue to hit corner cases where we make a rate
1129cce63444SAdrian Chadd 	 * selection using a higher bin but only update the smaller bin;
1130cce63444SAdrian Chadd 	 * thus never really "adapting".
1131cce63444SAdrian Chadd 	 *
1132cce63444SAdrian Chadd 	 * If however we update the larger bin, we're not accurately
1133cce63444SAdrian Chadd 	 * representing the channel state at that frame/aggregate size.
1134cce63444SAdrian Chadd 	 * However if we keep hitting the larger request but completing
1135cce63444SAdrian Chadd 	 * a smaller size, we at least updates based on what the
1136cce63444SAdrian Chadd 	 * request was /for/.
1137cce63444SAdrian Chadd 	 *
1138cce63444SAdrian Chadd 	 * I'm going to err on the side of caution and choose the
1139cce63444SAdrian Chadd 	 * latter.
1140cce63444SAdrian Chadd 	 */
1141cce63444SAdrian Chadd 	if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) {
1142cce63444SAdrian Chadd #if 0
1143cce63444SAdrian Chadd 		device_printf(sc->sc_dev,
1144cce63444SAdrian Chadd 		    "%s: completed but frame size buckets mismatch "
1145cce63444SAdrian Chadd 		    "(completed %d tx'ed %d)\n",
1146cce63444SAdrian Chadd 		    __func__, frame_size, rc_framesize);
1147cce63444SAdrian Chadd #endif
1148cce63444SAdrian Chadd 		frame_size = rc_framesize;
1149cce63444SAdrian Chadd 	}
1150b2763056SSam Leffler 
1151c1565b61SSam Leffler 	if (sn->ratemask == 0) {
1152b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1153b032f27cSSam Leffler 		    &an->an_node,
1154b032f27cSSam Leffler 		    "%s: size %d %s rate/try %d/%d no rates yet",
1155b032f27cSSam Leffler 		    __func__,
115643e9cf7cSSam Leffler 		    bin_to_size(size_to_bin(frame_size)),
1157eb6f0de0SAdrian Chadd 		    status ? "FAIL" : "OK",
115843e9cf7cSSam Leffler 		    short_tries, long_tries);
1159b2763056SSam Leffler 		return;
1160b2763056SSam Leffler 	}
1161af017101SAdrian Chadd 	mrr = sc->sc_mrretry;
1162af017101SAdrian Chadd 	/* XXX check HT protmode too */
11639f579ef8SAdrian Chadd 	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
1164af017101SAdrian Chadd 		mrr = 0;
1165af017101SAdrian Chadd 
1166f6cbf16aSSam Leffler 	if (!mrr || ts->ts_finaltsi == 0) {
1167c1565b61SSam Leffler 		if (!IS_RATE_DEFINED(sn, final_rix)) {
116876e6fd5dSGleb Smirnoff 			device_printf(sc->sc_dev,
116976e6fd5dSGleb Smirnoff 			    "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n",
117006c746edSAdrian Chadd 			    __func__, ts->ts_rate, ts->ts_finaltsi, final_rix);
117176e6fd5dSGleb Smirnoff 			badrate(sc, 0, ts->ts_rate, long_tries, status);
1172ec9ee5e7SSam Leffler 			return;
1173ec9ee5e7SSam Leffler 		}
117465f9edeeSSam Leffler 		/*
117565f9edeeSSam Leffler 		 * Only one rate was used; optimize work.
117665f9edeeSSam Leffler 		 */
1177b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1178f6fd8c7aSAdrian Chadd 		     &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",
1179b032f27cSSam Leffler 		     __func__,
118043e9cf7cSSam Leffler 		     bin_to_size(size_to_bin(frame_size)),
1181c4ac32a8SAdrian Chadd 		     frame_size,
1182eb6f0de0SAdrian Chadd 		     status ? "FAIL" : "OK",
1183eb6f0de0SAdrian Chadd 		     dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
1184eb6f0de0SAdrian Chadd 		     short_tries, long_tries, nframes, nbad);
1185b2763056SSam Leffler 		update_stats(sc, an, frame_size,
1186c1565b61SSam Leffler 			     final_rix, long_tries,
1187eb6f0de0SAdrian Chadd 			     short_tries, long_tries, status,
1188eb6f0de0SAdrian Chadd 			     nframes, nbad);
1189eb6f0de0SAdrian Chadd 
1190b2763056SSam Leffler 	} else {
119165f9edeeSSam Leffler 		int finalTSIdx = ts->ts_finaltsi;
1192bd97c52aSAdrian Chadd 		int i;
1193b2763056SSam Leffler 
1194b2763056SSam Leffler 		/*
1195b2763056SSam Leffler 		 * Process intermediate rates that failed.
1196b2763056SSam Leffler 		 */
1197ec9ee5e7SSam Leffler 
1198b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1199b032f27cSSam Leffler 		    &an->an_node,
1200f6fd8c7aSAdrian 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]",
1201b032f27cSSam Leffler 		     __func__,
1202b2763056SSam Leffler 		     bin_to_size(size_to_bin(frame_size)),
1203c4ac32a8SAdrian Chadd 		     frame_size,
1204b2763056SSam Leffler 		     finalTSIdx,
1205f6fd8c7aSAdrian Chadd 		     short_tries,
1206b2763056SSam Leffler 		     long_tries,
1207eb6f0de0SAdrian Chadd 		     status ? "FAIL" : "OK",
1208eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[0].rix),
1209eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[0].rix), rc[0].tries,
1210eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[1].rix),
1211eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[1].rix), rc[1].tries,
1212eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[2].rix),
1213eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[2].rix), rc[2].tries,
1214eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[3].rix),
1215eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[3].rix), rc[3].tries,
1216eb6f0de0SAdrian Chadd 		     nframes, nbad);
1217c1565b61SSam Leffler 
1218a6a308a4SAdrian Chadd 		for (i = 0; i < 4; i++) {
1219eb6f0de0SAdrian Chadd 			if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
122076e6fd5dSGleb Smirnoff 				badrate(sc, 0, rc[i].ratecode, rc[i].tries,
1221eb6f0de0SAdrian Chadd 				    status);
1222a6a308a4SAdrian Chadd 		}
1223b2763056SSam Leffler 
122465f9edeeSSam Leffler 		/*
1225cce63444SAdrian Chadd 		 * This used to not penalise other tries because loss
1226cce63444SAdrian Chadd 		 * can be bursty, but it's then not accurately keeping
1227cce63444SAdrian Chadd 		 * the avg TX time and EWMA updated.
122865f9edeeSSam Leffler 		 */
1229eb6f0de0SAdrian Chadd 		if (rc[0].tries) {
1230b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1231eb6f0de0SAdrian Chadd 				     rc[0].rix, rc[0].tries,
123265f9edeeSSam Leffler 				     short_tries, long_tries,
1233cf431555SAdrian Chadd 				     status,
1234eb6f0de0SAdrian Chadd 				     nframes, nbad);
1235eb6f0de0SAdrian Chadd 			long_tries -= rc[0].tries;
1236b2763056SSam Leffler 		}
1237b2763056SSam Leffler 
1238eb6f0de0SAdrian Chadd 		if (rc[1].tries && finalTSIdx > 0) {
1239b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1240eb6f0de0SAdrian Chadd 				     rc[1].rix, rc[1].tries,
124165f9edeeSSam Leffler 				     short_tries, long_tries,
1242cf431555SAdrian Chadd 				     status,
1243eb6f0de0SAdrian Chadd 				     nframes, nbad);
1244eb6f0de0SAdrian Chadd 			long_tries -= rc[1].tries;
1245b2763056SSam Leffler 		}
1246b2763056SSam Leffler 
1247eb6f0de0SAdrian Chadd 		if (rc[2].tries && finalTSIdx > 1) {
1248b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1249eb6f0de0SAdrian Chadd 				     rc[2].rix, rc[2].tries,
125065f9edeeSSam Leffler 				     short_tries, long_tries,
1251cf431555SAdrian Chadd 				     status,
1252eb6f0de0SAdrian Chadd 				     nframes, nbad);
1253eb6f0de0SAdrian Chadd 			long_tries -= rc[2].tries;
1254b2763056SSam Leffler 		}
1255b2763056SSam Leffler 
1256eb6f0de0SAdrian Chadd 		if (rc[3].tries && finalTSIdx > 2) {
1257b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1258eb6f0de0SAdrian Chadd 				     rc[3].rix, rc[3].tries,
125965f9edeeSSam Leffler 				     short_tries, long_tries,
1260cf431555SAdrian Chadd 				     status,
1261eb6f0de0SAdrian Chadd 				     nframes, nbad);
126238fda926SAdrian Chadd 		}
1263b2763056SSam Leffler 	}
1264fa20c234SSam Leffler }
1265fa20c234SSam Leffler 
1266fa20c234SSam Leffler void
1267fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
1268fa20c234SSam Leffler {
1269fa20c234SSam Leffler 	if (isnew)
1270b2763056SSam Leffler 		ath_rate_ctl_reset(sc, &an->an_node);
1271fa20c234SSam Leffler }
1272fa20c234SSam Leffler 
12737d450faaSAdrian Chadd void
12747d450faaSAdrian Chadd ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
12757d450faaSAdrian Chadd {
12767d450faaSAdrian Chadd }
12777d450faaSAdrian Chadd 
12787d450faaSAdrian Chadd 
1279c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {
1280c1565b61SSam Leffler 	NULL,		/* IEEE80211_MODE_AUTO */
1281c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_11A */
1282c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_11B */
1283c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_11G */
1284c1565b61SSam Leffler 	NULL,		/* IEEE80211_MODE_FH */
1285c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_TURBO_A */
1286c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_TURBO_G */
1287c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_STURBO_A */
1288a6a308a4SAdrian Chadd 	series_11na,	/* IEEE80211_MODE_11NA */
1289a6a308a4SAdrian Chadd 	series_11ng,	/* IEEE80211_MODE_11NG */
1290c1565b61SSam Leffler 	series_half,	/* IEEE80211_MODE_HALF */
1291c1565b61SSam Leffler 	series_quarter,	/* IEEE80211_MODE_QUARTER */
1292c1565b61SSam Leffler };
1293c1565b61SSam Leffler 
1294fa20c234SSam Leffler /*
1295fa20c234SSam Leffler  * Initialize the tables for a node.
1296fa20c234SSam Leffler  */
1297fa20c234SSam Leffler static void
1298b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
1299fa20c234SSam Leffler {
1300fa20c234SSam Leffler #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
1301c1565b61SSam Leffler #define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
1302a6a308a4SAdrian Chadd #define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
1303fa20c234SSam Leffler 	struct ath_node *an = ATH_NODE(ni);
1304fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1305fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1306c4ac32a8SAdrian Chadd 	int x, y, rix;
1307fa20c234SSam Leffler 
1308fa20c234SSam Leffler 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
1309c1565b61SSam Leffler 
1310c1565b61SSam Leffler 	KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
1311c1565b61SSam Leffler 	    ("curmode %u", sc->sc_curmode));
1312193bfa21SAdrian Chadd 
1313c1565b61SSam Leffler 	sn->sched = mrr_schedules[sc->sc_curmode];
1314c1565b61SSam Leffler 	KASSERT(sn->sched != NULL,
1315c1565b61SSam Leffler 	    ("no mrr schedule for mode %u", sc->sc_curmode));
1316c1565b61SSam Leffler 
1317c1565b61SSam Leffler         sn->static_rix = -1;
1318c4ac32a8SAdrian Chadd 	ath_rate_update_static_rix(sc, ni);
1319b2763056SSam Leffler 
1320cc86f1eaSAdrian Chadd 	sn->currates = sc->sc_currates;
1321cc86f1eaSAdrian Chadd 
1322c1565b61SSam Leffler 	/*
1323c1565b61SSam Leffler 	 * Construct a bitmask of usable rates.  This has all
1324c1565b61SSam Leffler 	 * negotiated rates minus those marked by the hal as
1325c1565b61SSam Leffler 	 * to be ignored for doing rate control.
1326c1565b61SSam Leffler 	 */
1327c1565b61SSam Leffler 	sn->ratemask = 0;
1328a6a308a4SAdrian Chadd 	/* MCS rates */
1329a6a308a4SAdrian Chadd 	if (ni->ni_flags & IEEE80211_NODE_HT) {
1330a6a308a4SAdrian Chadd 		for (x = 0; x < ni->ni_htrates.rs_nrates; x++) {
1331a6a308a4SAdrian Chadd 			rix = sc->sc_rixmap[MCS(x)];
1332a6a308a4SAdrian Chadd 			if (rix == 0xff)
1333a6a308a4SAdrian Chadd 				continue;
1334a6a308a4SAdrian Chadd 			/* skip rates marked broken by hal */
1335a6a308a4SAdrian Chadd 			if (!rt->info[rix].valid)
1336a6a308a4SAdrian Chadd 				continue;
1337a6a308a4SAdrian Chadd 			KASSERT(rix < SAMPLE_MAXRATES,
1338a6a308a4SAdrian Chadd 			    ("mcs %u has rix %d", MCS(x), rix));
1339193bfa21SAdrian Chadd 			sn->ratemask |= (uint64_t) 1<<rix;
1340a6a308a4SAdrian Chadd 		}
1341a6a308a4SAdrian Chadd 	}
1342a6a308a4SAdrian Chadd 
1343a6a308a4SAdrian Chadd 	/* Legacy rates */
1344fa20c234SSam Leffler 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
1345c1565b61SSam Leffler 		rix = sc->sc_rixmap[RATE(x)];
1346c1565b61SSam Leffler 		if (rix == 0xff)
13470ae09ec5SSam Leffler 			continue;
1348c1565b61SSam Leffler 		/* skip rates marked broken by hal */
1349c1565b61SSam Leffler 		if (!rt->info[rix].valid)
1350c1565b61SSam Leffler 			continue;
1351c1565b61SSam Leffler 		KASSERT(rix < SAMPLE_MAXRATES,
1352c1565b61SSam Leffler 		    ("rate %u has rix %d", RATE(x), rix));
1353193bfa21SAdrian Chadd 		sn->ratemask |= (uint64_t) 1<<rix;
1354b2763056SSam Leffler 	}
1355b032f27cSSam Leffler #ifdef IEEE80211_DEBUG
1356b032f27cSSam Leffler 	if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
1357193bfa21SAdrian Chadd 		uint64_t mask;
1358c1565b61SSam Leffler 
1359b032f27cSSam Leffler 		ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",
1360c1565b61SSam Leffler 		    ni->ni_macaddr, ":", __func__);
1361c1565b61SSam Leffler 		for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1362c1565b61SSam Leffler 			if ((mask & 1) == 0)
1363b032f27cSSam Leffler 				continue;
1364ae0944b8SAdrian Chadd 			printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix),
1365e09c8c4cSAdrian Chadd 			    calc_usecs_unicast_packet(sc, 1600, rix, 0,0,
1366532f2442SAdrian Chadd 			        (ni->ni_chw == 40)));
1367b032f27cSSam Leffler 		}
1368b032f27cSSam Leffler 		printf("\n");
1369b032f27cSSam Leffler 	}
1370b032f27cSSam Leffler #endif
1371b2763056SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1372b2763056SSam Leffler 		int size = bin_to_size(y);
1373193bfa21SAdrian Chadd 		uint64_t mask;
1374c1565b61SSam Leffler 
1375b2763056SSam Leffler 		sn->packets_sent[y] = 0;
1376c1565b61SSam Leffler 		sn->current_sample_rix[y] = -1;
1377c1565b61SSam Leffler 		sn->last_sample_rix[y] = 0;
1378c1565b61SSam Leffler 		/* XXX start with first valid rate */
1379c1565b61SSam Leffler 		sn->current_rix[y] = ffs(sn->ratemask)-1;
1380b2763056SSam Leffler 
1381c1565b61SSam Leffler 		/*
1382c1565b61SSam Leffler 		 * Initialize the statistics buckets; these are
1383c1565b61SSam Leffler 		 * indexed by the rate code index.
1384c1565b61SSam Leffler 		 */
1385c1565b61SSam Leffler 		for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) {
1386c1565b61SSam Leffler 			if ((mask & 1) == 0)		/* not a valid rate */
1387c1565b61SSam Leffler 				continue;
1388c1565b61SSam Leffler 			sn->stats[y][rix].successive_failures = 0;
1389c1565b61SSam Leffler 			sn->stats[y][rix].tries = 0;
1390c1565b61SSam Leffler 			sn->stats[y][rix].total_packets = 0;
1391c1565b61SSam Leffler 			sn->stats[y][rix].packets_acked = 0;
1392c1565b61SSam Leffler 			sn->stats[y][rix].last_tx = 0;
1393eb6f0de0SAdrian Chadd 			sn->stats[y][rix].ewma_pct = 0;
1394b2763056SSam Leffler 
1395c1565b61SSam Leffler 			sn->stats[y][rix].perfect_tx_time =
1396e09c8c4cSAdrian Chadd 			    calc_usecs_unicast_packet(sc, size, rix, 0, 0,
1397532f2442SAdrian Chadd 			    (ni->ni_chw == 40));
1398c1565b61SSam Leffler 			sn->stats[y][rix].average_tx_time =
1399c1565b61SSam Leffler 			    sn->stats[y][rix].perfect_tx_time;
1400b2763056SSam Leffler 		}
1401b91bf513SSam Leffler 	}
1402c1565b61SSam Leffler #if 0
1403c1565b61SSam Leffler 	/* XXX 0, num_rates-1 are wrong */
1404b032f27cSSam Leffler 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
1405b032f27cSSam Leffler 	    "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__,
1406b91bf513SSam Leffler 	    sn->num_rates,
1407c1565b61SSam Leffler 	    DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "",
1408b91bf513SSam Leffler 	    sn->stats[1][0].perfect_tx_time,
1409c1565b61SSam Leffler 	    DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "",
1410b91bf513SSam Leffler 	    sn->stats[1][sn->num_rates-1].perfect_tx_time
1411b91bf513SSam Leffler 	);
1412c1565b61SSam Leffler #endif
1413b032f27cSSam Leffler 	/* set the visible bit-rate */
1414c1565b61SSam Leffler 	if (sn->static_rix != -1)
1415c1565b61SSam Leffler 		ni->ni_txrate = DOT11RATE(sn->static_rix);
1416d0d425bfSSam Leffler 	else
1417c1565b61SSam Leffler 		ni->ni_txrate = RATE(0);
1418fa20c234SSam Leffler #undef RATE
1419c1565b61SSam Leffler #undef DOT11RATE
1420fa20c234SSam Leffler }
1421fa20c234SSam Leffler 
14222d20d655SAdrian Chadd /*
14232d20d655SAdrian Chadd  * Fetch the statistics for the given node.
14242d20d655SAdrian Chadd  *
14252d20d655SAdrian Chadd  * The ieee80211 node must be referenced and unlocked, however the ath_node
14262d20d655SAdrian Chadd  * must be locked.
14272d20d655SAdrian Chadd  *
14282d20d655SAdrian Chadd  * The main difference here is that we convert the rate indexes
14292d20d655SAdrian Chadd  * to 802.11 rates, or the userland output won't make much sense
14302d20d655SAdrian Chadd  * as it has no access to the rix table.
14312d20d655SAdrian Chadd  */
14322d20d655SAdrian Chadd int
14332d20d655SAdrian Chadd ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
14342d20d655SAdrian Chadd     struct ath_rateioctl *rs)
14352d20d655SAdrian Chadd {
14362d20d655SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
14372d20d655SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
14382d20d655SAdrian Chadd 	struct ath_rateioctl_tlv av;
1439be4f96a6SAdrian Chadd 	struct ath_rateioctl_rt *tv;
14402d20d655SAdrian Chadd 	int y;
1441be4f96a6SAdrian Chadd 	int o = 0;
14422d20d655SAdrian Chadd 
14432d20d655SAdrian Chadd 	ATH_NODE_LOCK_ASSERT(an);
14442d20d655SAdrian Chadd 
14452d20d655SAdrian Chadd 	/*
14462d20d655SAdrian Chadd 	 * Ensure there's enough space for the statistics.
14472d20d655SAdrian Chadd 	 */
14482d20d655SAdrian Chadd 	if (rs->len <
14492d20d655SAdrian Chadd 	    sizeof(struct ath_rateioctl_tlv) +
1450be4f96a6SAdrian Chadd 	    sizeof(struct ath_rateioctl_rt) +
1451be4f96a6SAdrian Chadd 	    sizeof(struct ath_rateioctl_tlv) +
1452be4f96a6SAdrian Chadd 	    sizeof(struct sample_node)) {
1453be4f96a6SAdrian Chadd 		device_printf(sc->sc_dev, "%s: len=%d, too short\n",
1454be4f96a6SAdrian Chadd 		    __func__,
1455be4f96a6SAdrian Chadd 		    rs->len);
14562d20d655SAdrian Chadd 		return (EINVAL);
1457be4f96a6SAdrian Chadd 	}
14582d20d655SAdrian Chadd 
14592d20d655SAdrian Chadd 	/*
14602d20d655SAdrian Chadd 	 * Take a temporary copy of the sample node state so we can
14612d20d655SAdrian Chadd 	 * modify it before we copy it.
14622d20d655SAdrian Chadd 	 */
1463be4f96a6SAdrian Chadd 	tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,
1464be4f96a6SAdrian Chadd 	    M_NOWAIT | M_ZERO);
1465be4f96a6SAdrian Chadd 	if (tv == NULL) {
14662d20d655SAdrian Chadd 		return (ENOMEM);
14672d20d655SAdrian Chadd 	}
14682d20d655SAdrian Chadd 
14692d20d655SAdrian Chadd 	/*
1470be4f96a6SAdrian Chadd 	 * Populate the rate table mapping TLV.
1471be4f96a6SAdrian Chadd 	 */
1472be4f96a6SAdrian Chadd 	tv->nentries = rt->rateCount;
1473be4f96a6SAdrian Chadd 	for (y = 0; y < rt->rateCount; y++) {
1474be4f96a6SAdrian Chadd 		tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;
1475be4f96a6SAdrian Chadd 		if (rt->info[y].phy == IEEE80211_T_HT)
1476be4f96a6SAdrian Chadd 			tv->ratecode[y] |= IEEE80211_RATE_MCS;
1477be4f96a6SAdrian Chadd 	}
1478be4f96a6SAdrian Chadd 
1479be4f96a6SAdrian Chadd 	o = 0;
1480be4f96a6SAdrian Chadd 	/*
1481be4f96a6SAdrian Chadd 	 * First TLV - rate code mapping
1482be4f96a6SAdrian Chadd 	 */
1483be4f96a6SAdrian Chadd 	av.tlv_id = ATH_RATE_TLV_RATETABLE;
1484be4f96a6SAdrian Chadd 	av.tlv_len = sizeof(struct ath_rateioctl_rt);
1485be4f96a6SAdrian Chadd 	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1486be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_tlv);
1487be4f96a6SAdrian Chadd 	copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));
1488be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_rt);
1489be4f96a6SAdrian Chadd 
1490be4f96a6SAdrian Chadd 	/*
1491be4f96a6SAdrian Chadd 	 * Second TLV - sample node statistics
14922d20d655SAdrian Chadd 	 */
14932d20d655SAdrian Chadd 	av.tlv_id = ATH_RATE_TLV_SAMPLENODE;
14942d20d655SAdrian Chadd 	av.tlv_len = sizeof(struct sample_node);
1495be4f96a6SAdrian Chadd 	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1496be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_tlv);
14972d20d655SAdrian Chadd 
14982d20d655SAdrian Chadd 	/*
14992d20d655SAdrian Chadd 	 * Copy the statistics over to the provided buffer.
15002d20d655SAdrian Chadd 	 */
1501be4f96a6SAdrian Chadd 	copyout(sn, rs->buf + o, sizeof(struct sample_node));
1502be4f96a6SAdrian Chadd 	o += sizeof(struct sample_node);
15032d20d655SAdrian Chadd 
1504be4f96a6SAdrian Chadd 	free(tv, M_TEMP);
15052d20d655SAdrian Chadd 
15062d20d655SAdrian Chadd 	return (0);
15072d20d655SAdrian Chadd }
15082d20d655SAdrian Chadd 
1509f0fd5e07SSam Leffler static void
1510c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni)
1511c1565b61SSam Leffler {
1512c1565b61SSam Leffler 	struct ath_softc *sc = arg;
1513c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1514c1565b61SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));
1515193bfa21SAdrian Chadd 	uint64_t mask;
1516c1565b61SSam Leffler 	int rix, y;
1517c1565b61SSam Leffler 
1518a055e7ceSKonstantin Belousov 	printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",
1519c1565b61SSam Leffler 	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
1520eb6f0de0SAdrian Chadd 	    dot11rate(rt, sn->static_rix),
1521eb6f0de0SAdrian Chadd 	    dot11rate_label(rt, sn->static_rix),
1522a055e7ceSKonstantin Belousov 	    (uintmax_t)sn->ratemask);
1523c1565b61SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1524ae0944b8SAdrian Chadd 		printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",
1525c1565b61SSam Leffler 		    bin_to_size(y), sn->current_rix[y],
1526ae0944b8SAdrian Chadd 		    dot11rate(rt, sn->current_rix[y]),
1527ae0944b8SAdrian Chadd 		    dot11rate_label(rt, sn->current_rix[y]),
1528c1565b61SSam Leffler 		    sn->packets_since_switch[y], sn->ticks_since_switch[y]);
1529eb6f0de0SAdrian Chadd 		printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",
1530eb6f0de0SAdrian Chadd 		    bin_to_size(y),
1531eb6f0de0SAdrian Chadd 		    dot11rate(rt, sn->last_sample_rix[y]),
1532eb6f0de0SAdrian Chadd 		    dot11rate_label(rt, sn->last_sample_rix[y]),
1533eb6f0de0SAdrian Chadd 		    dot11rate(rt, sn->current_sample_rix[y]),
1534eb6f0de0SAdrian Chadd 		    dot11rate_label(rt, sn->current_sample_rix[y]),
1535eb6f0de0SAdrian Chadd 		    sn->packets_sent[y]);
1536c1565b61SSam Leffler 		printf("[%4u] packets since sample %d sample tt %u\n",
1537c1565b61SSam Leffler 		    bin_to_size(y), sn->packets_since_sample[y],
1538c1565b61SSam Leffler 		    sn->sample_tt[y]);
1539c1565b61SSam Leffler 	}
1540c1565b61SSam Leffler 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1541c1565b61SSam Leffler 		if ((mask & 1) == 0)
1542c1565b61SSam Leffler 				continue;
1543c1565b61SSam Leffler 		for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1544c1565b61SSam Leffler 			if (sn->stats[y][rix].total_packets == 0)
1545c1565b61SSam Leffler 				continue;
1546eb6f0de0SAdrian Chadd 			printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",
1547ae0944b8SAdrian Chadd 			    dot11rate(rt, rix), dot11rate_label(rt, rix),
1548c1565b61SSam Leffler 			    bin_to_size(y),
154987acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].total_packets,
155087acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].packets_acked,
155187acb7d5SAdrian Chadd 			    (int) ((sn->stats[y][rix].packets_acked * 100ULL) /
155287acb7d5SAdrian Chadd 			     sn->stats[y][rix].total_packets),
1553eb6f0de0SAdrian Chadd 			    sn->stats[y][rix].ewma_pct / 10,
1554eb6f0de0SAdrian Chadd 			    sn->stats[y][rix].ewma_pct % 10,
155587acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].tries,
1556c1565b61SSam Leffler 			    sn->stats[y][rix].successive_failures,
1557c1565b61SSam Leffler 			    sn->stats[y][rix].average_tx_time,
1558c1565b61SSam Leffler 			    ticks - sn->stats[y][rix].last_tx);
1559c1565b61SSam Leffler 		}
1560c1565b61SSam Leffler 	}
1561c1565b61SSam Leffler }
1562c1565b61SSam Leffler 
1563c1565b61SSam Leffler static int
1564c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS)
1565c1565b61SSam Leffler {
1566c1565b61SSam Leffler 	struct ath_softc *sc = arg1;
15677a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
1568c1565b61SSam Leffler 	int error, v;
1569c1565b61SSam Leffler 
1570c1565b61SSam Leffler 	v = 0;
1571c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &v, 0, req);
1572c1565b61SSam Leffler 	if (error || !req->newptr)
1573c1565b61SSam Leffler 		return error;
1574c1565b61SSam Leffler 	ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc);
1575c1565b61SSam Leffler 	return 0;
1576c1565b61SSam Leffler }
1577c1565b61SSam Leffler 
1578c1565b61SSam Leffler static int
1579c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)
1580c1565b61SSam Leffler {
1581c1565b61SSam Leffler 	struct sample_softc *ssc = arg1;
1582c1565b61SSam Leffler 	int rate, error;
1583c1565b61SSam Leffler 
1584c1565b61SSam Leffler 	rate = ssc->smoothing_rate;
1585c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &rate, 0, req);
1586c1565b61SSam Leffler 	if (error || !req->newptr)
1587c1565b61SSam Leffler 		return error;
1588c1565b61SSam Leffler 	if (!(0 <= rate && rate < 100))
1589c1565b61SSam Leffler 		return EINVAL;
1590c1565b61SSam Leffler 	ssc->smoothing_rate = rate;
1591c1565b61SSam Leffler 	ssc->smoothing_minpackets = 100 / (100 - rate);
1592c1565b61SSam Leffler 	return 0;
1593c1565b61SSam Leffler }
1594c1565b61SSam Leffler 
1595c1565b61SSam Leffler static int
1596c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
1597c1565b61SSam Leffler {
1598c1565b61SSam Leffler 	struct sample_softc *ssc = arg1;
1599c1565b61SSam Leffler 	int rate, error;
1600c1565b61SSam Leffler 
1601c1565b61SSam Leffler 	rate = ssc->sample_rate;
1602c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &rate, 0, req);
1603c1565b61SSam Leffler 	if (error || !req->newptr)
1604c1565b61SSam Leffler 		return error;
1605c1565b61SSam Leffler 	if (!(2 <= rate && rate <= 100))
1606c1565b61SSam Leffler 		return EINVAL;
1607c1565b61SSam Leffler 	ssc->sample_rate = rate;
1608c1565b61SSam Leffler 	return 0;
1609c1565b61SSam Leffler }
1610c1565b61SSam Leffler 
1611c1565b61SSam Leffler static void
1612c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc)
1613fa20c234SSam Leffler {
1614fa20c234SSam Leffler 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
1615fa20c234SSam Leffler 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
1616fa20c234SSam Leffler 
1617c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
161808f5e6bbSPawel Biernacki 	    "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
161908f5e6bbSPawel Biernacki 	    ssc, 0, ath_rate_sysctl_smoothing_rate, "I",
1620c1565b61SSam Leffler 	    "sample: smoothing rate for avg tx time (%%)");
1621c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
162208f5e6bbSPawel Biernacki 	    "sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
162308f5e6bbSPawel Biernacki 	    ssc, 0, ath_rate_sysctl_sample_rate, "I",
1624c1565b61SSam Leffler 	    "sample: percent air time devoted to sampling new rates (%%)");
1625c1565b61SSam Leffler 	/* XXX max_successive_failures, stale_failure_timeout, min_switch */
1626c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
162708f5e6bbSPawel Biernacki 	    "sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
162808f5e6bbSPawel Biernacki 	    sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics");
1629fa20c234SSam Leffler }
1630fa20c234SSam Leffler 
1631fa20c234SSam Leffler struct ath_ratectrl *
1632fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc)
1633fa20c234SSam Leffler {
1634c1565b61SSam Leffler 	struct sample_softc *ssc;
1635fa20c234SSam Leffler 
1636c1565b61SSam Leffler 	ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
1637c1565b61SSam Leffler 	if (ssc == NULL)
1638fa20c234SSam Leffler 		return NULL;
1639c1565b61SSam Leffler 	ssc->arc.arc_space = sizeof(struct sample_node);
1640e69db8dfSAdrian Chadd 	ssc->smoothing_rate = 75;		/* ewma percentage ([0..99]) */
1641c1565b61SSam Leffler 	ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);
1642c1565b61SSam Leffler 	ssc->sample_rate = 10;			/* %time to try diff tx rates */
1643c1565b61SSam Leffler 	ssc->max_successive_failures = 3;	/* threshold for rate sampling*/
1644c1565b61SSam Leffler 	ssc->stale_failure_timeout = 10 * hz;	/* 10 seconds */
1645c1565b61SSam Leffler 	ssc->min_switch = hz;			/* 1 second */
1646c1565b61SSam Leffler 	ath_rate_sysctlattach(sc, ssc);
1647c1565b61SSam Leffler 	return &ssc->arc;
1648fa20c234SSam Leffler }
1649fa20c234SSam Leffler 
1650fa20c234SSam Leffler void
1651fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc)
1652fa20c234SSam Leffler {
1653c1565b61SSam Leffler 	struct sample_softc *ssc = (struct sample_softc *) arc;
1654fa20c234SSam Leffler 
1655c1565b61SSam Leffler 	free(ssc, M_DEVBUF);
1656fa20c234SSam Leffler }
1657