xref: /freebsd/sys/dev/ath/ath_rate/sample/sample.c (revision 5add701776232903532062c48930bb8a7ab65c1b)
1fa20c234SSam Leffler /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3718cf2ccSPedro F. Giffuni  *
4fa20c234SSam Leffler  * Copyright (c) 2005 John Bicket
5fa20c234SSam Leffler  * All rights reserved.
6fa20c234SSam Leffler  *
7fa20c234SSam Leffler  * Redistribution and use in source and binary forms, with or without
8fa20c234SSam Leffler  * modification, are permitted provided that the following conditions
9fa20c234SSam Leffler  * are met:
10fa20c234SSam Leffler  * 1. Redistributions of source code must retain the above copyright
11fa20c234SSam Leffler  *    notice, this list of conditions and the following disclaimer,
12fa20c234SSam Leffler  *    without modification.
13fa20c234SSam Leffler  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14fa20c234SSam Leffler  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15fa20c234SSam Leffler  *    redistribution must be conditioned upon including a substantially
16fa20c234SSam Leffler  *    similar Disclaimer requirement for further binary redistribution.
17fa20c234SSam Leffler  * 3. Neither the names of the above-listed copyright holders nor the names
18fa20c234SSam Leffler  *    of any contributors may be used to endorse or promote products derived
19fa20c234SSam Leffler  *    from this software without specific prior written permission.
20fa20c234SSam Leffler  *
21fa20c234SSam Leffler  * Alternatively, this software may be distributed under the terms of the
22fa20c234SSam Leffler  * GNU General Public License ("GPL") version 2 as published by the Free
23fa20c234SSam Leffler  * Software Foundation.
24fa20c234SSam Leffler  *
25fa20c234SSam Leffler  * NO WARRANTY
26fa20c234SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27fa20c234SSam Leffler  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28fa20c234SSam Leffler  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
29fa20c234SSam Leffler  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
30fa20c234SSam Leffler  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
31fa20c234SSam Leffler  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32fa20c234SSam Leffler  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33fa20c234SSam Leffler  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34fa20c234SSam Leffler  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35fa20c234SSam Leffler  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36fa20c234SSam Leffler  * THE POSSIBILITY OF SUCH DAMAGES.
3768e8e04eSSam Leffler  *
38fa20c234SSam Leffler  */
39fa20c234SSam Leffler 
40fa20c234SSam Leffler #include <sys/cdefs.h>
41fa20c234SSam Leffler __FBSDID("$FreeBSD$");
42fa20c234SSam Leffler 
43fa20c234SSam Leffler /*
44fa20c234SSam Leffler  * John Bicket's SampleRate control algorithm.
45fa20c234SSam Leffler  */
46c312fb4aSAdrian Chadd #include "opt_ath.h"
47fa20c234SSam Leffler #include "opt_inet.h"
48b032f27cSSam Leffler #include "opt_wlan.h"
4987acb7d5SAdrian Chadd #include "opt_ah.h"
50fa20c234SSam Leffler 
51fa20c234SSam Leffler #include <sys/param.h>
52fa20c234SSam Leffler #include <sys/systm.h>
53fa20c234SSam Leffler #include <sys/sysctl.h>
54fa20c234SSam Leffler #include <sys/kernel.h>
55fa20c234SSam Leffler #include <sys/lock.h>
5676039bc8SGleb Smirnoff #include <sys/malloc.h>
57fa20c234SSam Leffler #include <sys/mutex.h>
58fa20c234SSam Leffler #include <sys/errno.h>
59fa20c234SSam Leffler 
60fa20c234SSam Leffler #include <machine/bus.h>
61fa20c234SSam Leffler #include <machine/resource.h>
62fa20c234SSam Leffler #include <sys/bus.h>
63fa20c234SSam Leffler 
64fa20c234SSam Leffler #include <sys/socket.h>
65fa20c234SSam Leffler 
66fa20c234SSam Leffler #include <net/if.h>
6776039bc8SGleb Smirnoff #include <net/if_var.h>
68fa20c234SSam Leffler #include <net/if_media.h>
69fa20c234SSam Leffler #include <net/if_arp.h>
70c1565b61SSam Leffler #include <net/ethernet.h>		/* XXX for ether_sprintf */
71fa20c234SSam Leffler 
72fa20c234SSam Leffler #include <net80211/ieee80211_var.h>
73fa20c234SSam Leffler 
74fa20c234SSam Leffler #include <net/bpf.h>
75fa20c234SSam Leffler 
76fa20c234SSam Leffler #ifdef INET
77fa20c234SSam Leffler #include <netinet/in.h>
78fa20c234SSam Leffler #include <netinet/if_ether.h>
79fa20c234SSam Leffler #endif
80fa20c234SSam Leffler 
81fa20c234SSam Leffler #include <dev/ath/if_athvar.h>
82fa20c234SSam Leffler #include <dev/ath/ath_rate/sample/sample.h>
8333644623SSam Leffler #include <dev/ath/ath_hal/ah_desc.h>
84a6a308a4SAdrian Chadd #include <dev/ath/ath_rate/sample/tx_schedules.h>
85fa20c234SSam Leffler 
86fa20c234SSam Leffler /*
87fa20c234SSam Leffler  * This file is an implementation of the SampleRate algorithm
88fa20c234SSam Leffler  * in "Bit-rate Selection in Wireless Networks"
89fa20c234SSam Leffler  * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
90fa20c234SSam Leffler  *
91fa20c234SSam Leffler  * SampleRate chooses the bit-rate it predicts will provide the most
92fa20c234SSam Leffler  * throughput based on estimates of the expected per-packet
93fa20c234SSam Leffler  * transmission time for each bit-rate.  SampleRate periodically sends
94fa20c234SSam Leffler  * packets at bit-rates other than the current one to estimate when
95fa20c234SSam Leffler  * another bit-rate will provide better performance. SampleRate
96fa20c234SSam Leffler  * switches to another bit-rate when its estimated per-packet
97fa20c234SSam Leffler  * transmission time becomes smaller than the current bit-rate's.
98fa20c234SSam Leffler  * SampleRate reduces the number of bit-rates it must sample by
99fa20c234SSam Leffler  * eliminating those that could not perform better than the one
100fa20c234SSam Leffler  * currently being used.  SampleRate also stops probing at a bit-rate
101fa20c234SSam Leffler  * if it experiences several successive losses.
102fa20c234SSam Leffler  *
103fa20c234SSam Leffler  * The difference between the algorithm in the thesis and the one in this
104fa20c234SSam Leffler  * file is that the one in this file uses a ewma instead of a window.
105fa20c234SSam Leffler  *
106b91bf513SSam Leffler  * Also, this implementation tracks the average transmission time for
107b91bf513SSam Leffler  * a few different packet sizes independently for each link.
108fa20c234SSam Leffler  */
109fa20c234SSam Leffler 
110cce63444SAdrian Chadd /* XXX TODO: move this into ath_hal/net80211 so it can be shared */
111cce63444SAdrian Chadd 
112cce63444SAdrian Chadd #define	MCS_HT20	0
113cce63444SAdrian Chadd #define	MCS_HT20_SGI	1
114cce63444SAdrian Chadd #define	MCS_HT40	2
115cce63444SAdrian Chadd #define	MCS_HT40_SGI	3
116cce63444SAdrian Chadd 
117cce63444SAdrian Chadd /*
118cce63444SAdrian Chadd  * This is currently a copy/paste from the 11n tx code.
119cce63444SAdrian Chadd  *
120cce63444SAdrian Chadd  * It's used to determine the maximum frame length allowed for the
121cce63444SAdrian Chadd  * given rate.  For now this ignores SGI/LGI and will assume long-GI.
122cce63444SAdrian Chadd  * This only matters for lower rates that can't fill a full 64k A-MPDU.
123cce63444SAdrian Chadd  *
124cce63444SAdrian Chadd  * (But it's also important because right now rate control doesn't set
125cce63444SAdrian Chadd  * flags like SGI/LGI, STBC, LDPC, TX power, etc.)
126cce63444SAdrian Chadd  *
127cce63444SAdrian Chadd  * When selecting a set of rates the rate control code will iterate
128cce63444SAdrian Chadd  * over the HT20/HT40 max frame length and tell the caller the maximum
129cce63444SAdrian Chadd  * length (@ LGI.)  It will also choose a bucket that's the minimum
130cce63444SAdrian Chadd  * of this value and the provided aggregate length.  That way the
131cce63444SAdrian Chadd  * rate selection will closely match what the eventual formed aggregate
132cce63444SAdrian Chadd  * will be rather than "not at all".
133cce63444SAdrian Chadd  */
134cce63444SAdrian Chadd 
135cce63444SAdrian Chadd static int ath_rate_sample_max_4ms_framelen[4][32] = {
136cce63444SAdrian Chadd         [MCS_HT20] = {
137cce63444SAdrian Chadd                 3212,  6432,  9648,  12864,  19300,  25736,  28952,  32172,
138cce63444SAdrian Chadd                 6424,  12852, 19280, 25708,  38568,  51424,  57852,  64280,
139cce63444SAdrian Chadd                 9628,  19260, 28896, 38528,  57792,  65532,  65532,  65532,
140cce63444SAdrian Chadd                 12828, 25656, 38488, 51320,  65532,  65532,  65532,  65532,
141cce63444SAdrian Chadd         },
142cce63444SAdrian Chadd         [MCS_HT20_SGI] = {
143cce63444SAdrian Chadd                 3572,  7144,  10720,  14296,  21444,  28596,  32172,  35744,
144cce63444SAdrian Chadd                 7140,  14284, 21428,  28568,  42856,  57144,  64288,  65532,
145cce63444SAdrian Chadd                 10700, 21408, 32112,  42816,  64228,  65532,  65532,  65532,
146cce63444SAdrian Chadd                 14256, 28516, 42780,  57040,  65532,  65532,  65532,  65532,
147cce63444SAdrian Chadd         },
148cce63444SAdrian Chadd         [MCS_HT40] = {
149cce63444SAdrian Chadd                 6680,  13360,  20044,  26724,  40092,  53456,  60140,  65532,
150cce63444SAdrian Chadd                 13348, 26700,  40052,  53400,  65532,  65532,  65532,  65532,
151cce63444SAdrian Chadd                 20004, 40008,  60016,  65532,  65532,  65532,  65532,  65532,
152cce63444SAdrian Chadd                 26644, 53292,  65532,  65532,  65532,  65532,  65532,  65532,
153cce63444SAdrian Chadd         },
154cce63444SAdrian Chadd         [MCS_HT40_SGI] = {
155cce63444SAdrian Chadd                 7420,  14844,  22272,  29696,  44544,  59396,  65532,  65532,
156cce63444SAdrian Chadd                 14832, 29668,  44504,  59340,  65532,  65532,  65532,  65532,
157cce63444SAdrian Chadd                 22232, 44464,  65532,  65532,  65532,  65532,  65532,  65532,
158cce63444SAdrian Chadd                 29616, 59232,  65532,  65532,  65532,  65532,  65532,  65532,
159cce63444SAdrian Chadd         }
160cce63444SAdrian Chadd };
161cce63444SAdrian Chadd 
162cce63444SAdrian Chadd /*
163cce63444SAdrian Chadd  * Given the (potentially MRR) transmit schedule, calculate the maximum
164cce63444SAdrian Chadd  * allowed packet size for forming aggregates based on the lowest
165cce63444SAdrian Chadd  * MCS rate in the transmit schedule.
166cce63444SAdrian Chadd  *
167cce63444SAdrian Chadd  * Returns -1 if it's a legacy rate or no MRR.
168cce63444SAdrian Chadd  */
169cce63444SAdrian Chadd static int
170cce63444SAdrian Chadd ath_rate_sample_find_min_pktlength(struct ath_softc *sc,
171cce63444SAdrian Chadd     struct ath_node *an, uint8_t rix0)
172cce63444SAdrian Chadd {
173cce63444SAdrian Chadd #define	MCS_IDX(ix)		(rt->info[ix].dot11Rate)
174cce63444SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
175cce63444SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
176cce63444SAdrian Chadd 	const struct txschedule *sched = &sn->sched[rix0];
177cce63444SAdrian Chadd 	int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE
178cce63444SAdrian Chadd 	// Note: this may not be true in all cases; need to check?
179cce63444SAdrian Chadd 	int is_ht40 = (an->an_node.ni_chw == 40);
180cce63444SAdrian Chadd 	// Note: not great, but good enough..
181cce63444SAdrian Chadd 	int idx = is_ht40 ? MCS_HT40 : MCS_HT20;
182cce63444SAdrian Chadd 
183cce63444SAdrian Chadd 	if (rt->info[rix0].phy != IEEE80211_T_HT) {
184cce63444SAdrian Chadd 		return -1;
185cce63444SAdrian Chadd 	}
186cce63444SAdrian Chadd 
187cce63444SAdrian Chadd 	if (! sc->sc_mrretry) {
188cce63444SAdrian Chadd 		return -1;
189cce63444SAdrian Chadd 	}
190cce63444SAdrian Chadd 
191cce63444SAdrian Chadd 	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
192cce63444SAdrian Chadd 	    rix0, sched->r0));
193cce63444SAdrian Chadd 
194cce63444SAdrian Chadd 	/*
195cce63444SAdrian Chadd 	 * Update based on sched->r{0,1,2,3} if sched->t{0,1,2,3}
196cce63444SAdrian Chadd 	 * is not zero.
197cce63444SAdrian Chadd 	 *
198cce63444SAdrian Chadd 	 * Note: assuming all four PHYs are HT!
199cce63444SAdrian Chadd 	 */
200cce63444SAdrian Chadd 	if (sched->t0 != 0) {
201cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
202cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r0)]);
203cce63444SAdrian Chadd 	}
204cce63444SAdrian Chadd 	if (sched->t1 != 0) {
205cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
206cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r1)]);
207cce63444SAdrian Chadd 	}
208cce63444SAdrian Chadd 	if (sched->t2 != 0) {
209cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
210cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r2)]);
211cce63444SAdrian Chadd 	}
212cce63444SAdrian Chadd 	if (sched->t3 != 0) {
213cce63444SAdrian Chadd 		max_pkt_length = MIN(max_pkt_length,
214cce63444SAdrian Chadd 		    ath_rate_sample_max_4ms_framelen[idx][MCS_IDX(sched->r3)]);
215cce63444SAdrian Chadd 	}
216cce63444SAdrian Chadd 
217cce63444SAdrian Chadd 	return max_pkt_length;
218cce63444SAdrian Chadd #undef	MCS
219cce63444SAdrian Chadd }
220cce63444SAdrian Chadd 
221b2763056SSam Leffler static void	ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
222fa20c234SSam Leffler 
223b91bf513SSam Leffler static __inline int
224b91bf513SSam Leffler size_to_bin(int size)
225fa20c234SSam Leffler {
226c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 1
227c1565b61SSam Leffler 	if (size <= packet_size_bins[0])
228c1565b61SSam Leffler 		return 0;
229c1565b61SSam Leffler #endif
230c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 2
231c1565b61SSam Leffler 	if (size <= packet_size_bins[1])
232c1565b61SSam Leffler 		return 1;
233c1565b61SSam Leffler #endif
234c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 3
235c1565b61SSam Leffler 	if (size <= packet_size_bins[2])
236c1565b61SSam Leffler 		return 2;
237c1565b61SSam Leffler #endif
238c1565b61SSam Leffler #if NUM_PACKET_SIZE_BINS > 4
239cce63444SAdrian Chadd 	if (size <= packet_size_bins[3])
240cce63444SAdrian Chadd 		return 3;
241cce63444SAdrian Chadd #endif
242cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 5
243cce63444SAdrian Chadd 	if (size <= packet_size_bins[4])
244cce63444SAdrian Chadd 		return 4;
245cce63444SAdrian Chadd #endif
246cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 6
247cce63444SAdrian Chadd 	if (size <= packet_size_bins[5])
248cce63444SAdrian Chadd 		return 5;
249cce63444SAdrian Chadd #endif
250cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 7
251cce63444SAdrian Chadd 	if (size <= packet_size_bins[6])
252cce63444SAdrian Chadd 		return 6;
253cce63444SAdrian Chadd #endif
254cce63444SAdrian Chadd #if NUM_PACKET_SIZE_BINS > 8
255c1565b61SSam Leffler #error "add support for more packet sizes"
256c1565b61SSam Leffler #endif
257fa20c234SSam Leffler 	return NUM_PACKET_SIZE_BINS-1;
258fa20c234SSam Leffler }
259fa20c234SSam Leffler 
260fa20c234SSam Leffler void
261fa20c234SSam Leffler ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
262fa20c234SSam Leffler {
263fa20c234SSam Leffler 	/* NB: assumed to be zero'd by caller */
264fa20c234SSam Leffler }
265fa20c234SSam Leffler 
266fa20c234SSam Leffler void
267fa20c234SSam Leffler ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
268fa20c234SSam Leffler {
269fa20c234SSam Leffler }
270fa20c234SSam Leffler 
271a6a308a4SAdrian Chadd static int
272a6a308a4SAdrian Chadd dot11rate(const HAL_RATE_TABLE *rt, int rix)
273a6a308a4SAdrian Chadd {
27487acb7d5SAdrian Chadd 	if (rix < 0)
27587acb7d5SAdrian Chadd 		return -1;
276a6a308a4SAdrian Chadd 	return rt->info[rix].phy == IEEE80211_T_HT ?
277a6a308a4SAdrian Chadd 	    rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;
278a6a308a4SAdrian Chadd }
279a6a308a4SAdrian Chadd 
280ae0944b8SAdrian Chadd static const char *
281ae0944b8SAdrian Chadd dot11rate_label(const HAL_RATE_TABLE *rt, int rix)
282ae0944b8SAdrian Chadd {
28387acb7d5SAdrian Chadd 	if (rix < 0)
28487acb7d5SAdrian Chadd 		return "";
285ae0944b8SAdrian Chadd 	return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";
286ae0944b8SAdrian Chadd }
287ae0944b8SAdrian Chadd 
288fa20c234SSam Leffler /*
289c1565b61SSam Leffler  * Return the rix with the lowest average_tx_time,
290fa20c234SSam Leffler  * or -1 if all the average_tx_times are 0.
291fa20c234SSam Leffler  */
292c1565b61SSam Leffler static __inline int
29336958948SAdrian Chadd pick_best_rate(struct ath_node *an, const HAL_RATE_TABLE *rt,
294c1565b61SSam Leffler     int size_bin, int require_acked_before)
295fa20c234SSam Leffler {
29636958948SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
297eb6f0de0SAdrian Chadd 	int best_rate_rix, best_rate_tt, best_rate_pct;
298193bfa21SAdrian Chadd 	uint64_t mask;
299eb6f0de0SAdrian Chadd 	int rix, tt, pct;
300b91bf513SSam Leffler 
301c1565b61SSam Leffler 	best_rate_rix = 0;
302c1565b61SSam Leffler 	best_rate_tt = 0;
303eb6f0de0SAdrian Chadd 	best_rate_pct = 0;
304c1565b61SSam Leffler 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
305c1565b61SSam Leffler 		if ((mask & 1) == 0)		/* not a supported rate */
306c1565b61SSam Leffler 			continue;
307c1565b61SSam Leffler 
30836958948SAdrian Chadd 		/* Don't pick a non-HT rate for a HT node */
30936958948SAdrian Chadd 		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
31036958948SAdrian Chadd 		    (rt->info[rix].phy != IEEE80211_T_HT)) {
31136958948SAdrian Chadd 			continue;
31236958948SAdrian Chadd 		}
31336958948SAdrian Chadd 
314c1565b61SSam Leffler 		tt = sn->stats[size_bin][rix].average_tx_time;
315c1565b61SSam Leffler 		if (tt <= 0 ||
316c1565b61SSam Leffler 		    (require_acked_before &&
317c1565b61SSam Leffler 		     !sn->stats[size_bin][rix].packets_acked))
318b91bf513SSam Leffler 			continue;
319b91bf513SSam Leffler 
320eb6f0de0SAdrian Chadd 		/* Calculate percentage if possible */
321eb6f0de0SAdrian Chadd 		if (sn->stats[size_bin][rix].total_packets > 0) {
322eb6f0de0SAdrian Chadd 			pct = sn->stats[size_bin][rix].ewma_pct;
323eb6f0de0SAdrian Chadd 		} else {
324cce63444SAdrian Chadd 			pct = -1; /* No percent yet to compare against! */
325eb6f0de0SAdrian Chadd 		}
326eb6f0de0SAdrian Chadd 
327b91bf513SSam Leffler 		/* don't use a bit-rate that has been failing */
328c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].successive_failures > 3)
329b91bf513SSam Leffler 			continue;
330b91bf513SSam Leffler 
331eb6f0de0SAdrian Chadd 		/*
332cce63444SAdrian Chadd 		 * For HT, Don't use a bit rate that is more
333cce63444SAdrian Chadd 		 * lossy than the best.  Give a bit of leeway.
334eb6f0de0SAdrian Chadd 		 *
335cce63444SAdrian Chadd 		 * Don't consider best rates that we haven't seen
336cce63444SAdrian Chadd 		 * packets for yet; let sampling start inflence that.
337eb6f0de0SAdrian Chadd 		 */
338eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
339cce63444SAdrian Chadd 			if (pct == -1)
340cce63444SAdrian Chadd 				continue;
341cce63444SAdrian Chadd #if 0
342cce63444SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
343cce63444SAdrian Chadd 			    IEEE80211_MSG_RATECTL,
344cce63444SAdrian Chadd 			    &an->an_node,
345cce63444SAdrian Chadd 			    "%s: size %d comparing best rate 0x%x pkts/ewma/tt (%ju/%d/%d) "
346cce63444SAdrian Chadd 			    "to 0x%x pkts/ewma/tt (%ju/%d/%d)",
347cce63444SAdrian Chadd 			    __func__,
348cce63444SAdrian Chadd 			    bin_to_size(size_bin),
349cce63444SAdrian Chadd 			    rt->info[best_rate_rix].dot11Rate,
350cce63444SAdrian Chadd 			    sn->stats[size_bin][best_rate_rix].total_packets,
351cce63444SAdrian Chadd 			    best_rate_pct,
352cce63444SAdrian Chadd 			    best_rate_tt,
353cce63444SAdrian Chadd 			    rt->info[rix].dot11Rate,
354cce63444SAdrian Chadd 			    sn->stats[size_bin][rix].total_packets,
355cce63444SAdrian Chadd 			    pct,
356cce63444SAdrian Chadd 			    tt);
357cce63444SAdrian Chadd #endif
358eb6f0de0SAdrian Chadd 			if (best_rate_pct > (pct + 50))
359eb6f0de0SAdrian Chadd 				continue;
360eb6f0de0SAdrian Chadd 		}
361eb6f0de0SAdrian Chadd 		/*
362eb6f0de0SAdrian Chadd 		 * For non-MCS rates, use the current average txtime for
363eb6f0de0SAdrian Chadd 		 * comparison.
364eb6f0de0SAdrian Chadd 		 */
365eb6f0de0SAdrian Chadd 		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
366eb6f0de0SAdrian Chadd 			if (best_rate_tt == 0 || tt <= best_rate_tt) {
367fa20c234SSam Leffler 				best_rate_tt = tt;
368c1565b61SSam Leffler 				best_rate_rix = rix;
369eb6f0de0SAdrian Chadd 				best_rate_pct = pct;
370eb6f0de0SAdrian Chadd 			}
371eb6f0de0SAdrian Chadd 		}
372eb6f0de0SAdrian Chadd 
373eb6f0de0SAdrian Chadd 		/*
374cce63444SAdrian Chadd 		 * Since 2 and 3 stream rates have slightly higher TX times,
375eb6f0de0SAdrian Chadd 		 * allow a little bit of leeway. This should later
376eb6f0de0SAdrian Chadd 		 * be abstracted out and properly handled.
377eb6f0de0SAdrian Chadd 		 */
378eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
379cce63444SAdrian Chadd 			if (best_rate_tt == 0 || ((tt * 10) <= (best_rate_tt * 10))) {
380eb6f0de0SAdrian Chadd 				best_rate_tt = tt;
381eb6f0de0SAdrian Chadd 				best_rate_rix = rix;
382eb6f0de0SAdrian Chadd 				best_rate_pct = pct;
383eb6f0de0SAdrian Chadd 			}
384fa20c234SSam Leffler 		}
385fa20c234SSam Leffler 	}
386c1565b61SSam Leffler 	return (best_rate_tt ? best_rate_rix : -1);
387fa20c234SSam Leffler }
388fa20c234SSam Leffler 
389fa20c234SSam Leffler /*
390c1565b61SSam Leffler  * Pick a good "random" bit-rate to sample other than the current one.
391fa20c234SSam Leffler  */
392b91bf513SSam Leffler static __inline int
39336958948SAdrian Chadd pick_sample_rate(struct sample_softc *ssc , struct ath_node *an,
394c1565b61SSam Leffler     const HAL_RATE_TABLE *rt, int size_bin)
395fa20c234SSam Leffler {
396c1565b61SSam Leffler #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
397a6a308a4SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
39836958948SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
399c1565b61SSam Leffler 	int current_rix, rix;
400c1565b61SSam Leffler 	unsigned current_tt;
401193bfa21SAdrian Chadd 	uint64_t mask;
402fa20c234SSam Leffler 
403c1565b61SSam Leffler 	current_rix = sn->current_rix[size_bin];
404c1565b61SSam Leffler 	if (current_rix < 0) {
405fa20c234SSam Leffler 		/* no successes yet, send at the lowest bit-rate */
406cce63444SAdrian Chadd 		/* XXX TODO should return MCS0 if HT */
407fa20c234SSam Leffler 		return 0;
408fa20c234SSam Leffler 	}
409fa20c234SSam Leffler 
410c1565b61SSam Leffler 	current_tt = sn->stats[size_bin][current_rix].average_tx_time;
411fa20c234SSam Leffler 
412c1565b61SSam Leffler 	rix = sn->last_sample_rix[size_bin]+1;	/* next sample rate */
413193bfa21SAdrian Chadd 	mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
414c1565b61SSam Leffler 	while (mask != 0) {
415193bfa21SAdrian Chadd 		if ((mask & ((uint64_t) 1<<rix)) == 0) {	/* not a supported rate */
416c1565b61SSam Leffler 	nextrate:
417c1565b61SSam Leffler 			if (++rix >= rt->rateCount)
418c1565b61SSam Leffler 				rix = 0;
419b91bf513SSam Leffler 			continue;
420c1565b61SSam Leffler 		}
421b91bf513SSam Leffler 
422bf57b7b2SAdrian Chadd 		/*
423bf57b7b2SAdrian Chadd 		 * The following code stops trying to sample
424bf57b7b2SAdrian Chadd 		 * non-MCS rates when speaking to an MCS node.
425bf57b7b2SAdrian Chadd 		 * However, at least for CCK rates in 2.4GHz mode,
426bf57b7b2SAdrian Chadd 		 * the non-MCS rates MAY actually provide better
427bf57b7b2SAdrian Chadd 		 * PER at the very far edge of reception.
428bf57b7b2SAdrian Chadd 		 *
429bf57b7b2SAdrian Chadd 		 * However! Until ath_rate_form_aggr() grows
430bf57b7b2SAdrian Chadd 		 * some logic to not form aggregates if the
431bf57b7b2SAdrian Chadd 		 * selected rate is non-MCS, this won't work.
432bf57b7b2SAdrian Chadd 		 *
433bf57b7b2SAdrian Chadd 		 * So don't disable this code until you've taught
434bf57b7b2SAdrian Chadd 		 * ath_rate_form_aggr() to drop out if any of
435bf57b7b2SAdrian Chadd 		 * the selected rates are non-MCS.
436bf57b7b2SAdrian Chadd 		 */
437bf57b7b2SAdrian Chadd #if 1
43836958948SAdrian Chadd 		/* if the node is HT and the rate isn't HT, don't bother sample */
43936958948SAdrian Chadd 		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
44036958948SAdrian Chadd 		    (rt->info[rix].phy != IEEE80211_T_HT)) {
441193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
44236958948SAdrian Chadd 			goto nextrate;
44336958948SAdrian Chadd 		}
444bf57b7b2SAdrian Chadd #endif
44536958948SAdrian Chadd 
446b91bf513SSam Leffler 		/* this bit-rate is always worse than the current one */
447c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {
448193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
449c1565b61SSam Leffler 			goto nextrate;
450c1565b61SSam Leffler 		}
451b91bf513SSam Leffler 
452b91bf513SSam Leffler 		/* rarely sample bit-rates that fail a lot */
453c1565b61SSam Leffler 		if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
454c1565b61SSam Leffler 		    ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
455193bfa21SAdrian Chadd 			mask &= ~((uint64_t) 1<<rix);
456c1565b61SSam Leffler 			goto nextrate;
457fa20c234SSam Leffler 		}
458c1565b61SSam Leffler 
459eb6f0de0SAdrian Chadd 		/*
460e69db8dfSAdrian Chadd 		 * For HT, only sample a few rates on either side of the
461e69db8dfSAdrian Chadd 		 * current rix; there's quite likely a lot of them.
462cce63444SAdrian Chadd 		 *
463cce63444SAdrian Chadd 		 * This is limited to testing rate indexes on either side of
464cce63444SAdrian Chadd 		 * this MCS, but for all spatial streams.
465cce63444SAdrian Chadd 		 *
466cce63444SAdrian Chadd 		 * Otherwise we'll (a) never really sample higher MCS
467cce63444SAdrian Chadd 		 * rates if we're stuck low, and we'll make weird moves
468cce63444SAdrian Chadd 		 * like sample MCS8 if we're using MCS7.
469eb6f0de0SAdrian Chadd 		 */
470eb6f0de0SAdrian Chadd 		if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
471cce63444SAdrian Chadd 			uint8_t current_mcs, rix_mcs;
472cce63444SAdrian Chadd 
473cce63444SAdrian Chadd 			current_mcs = MCS(current_rix) & 0x7;
474cce63444SAdrian Chadd 			rix_mcs = MCS(rix) & 0x7;
475cce63444SAdrian Chadd 
476cce63444SAdrian Chadd 			if (rix_mcs < (current_mcs - 2) ||
477cce63444SAdrian Chadd 			    rix_mcs > (current_mcs + 2)) {
478193bfa21SAdrian Chadd 				mask &= ~((uint64_t) 1<<rix);
479eb6f0de0SAdrian Chadd 				goto nextrate;
480eb6f0de0SAdrian Chadd 			}
481eb6f0de0SAdrian Chadd 		}
482eb6f0de0SAdrian Chadd 
48336958948SAdrian Chadd 		/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
48436958948SAdrian Chadd 		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
485c1565b61SSam Leffler 			if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
486193bfa21SAdrian Chadd 				mask &= ~((uint64_t) 1<<rix);
487c1565b61SSam Leffler 				goto nextrate;
488c1565b61SSam Leffler 			}
48936958948SAdrian Chadd 		}
490c1565b61SSam Leffler 
491c1565b61SSam Leffler 		sn->last_sample_rix[size_bin] = rix;
492c1565b61SSam Leffler 		return rix;
493c1565b61SSam Leffler 	}
494c1565b61SSam Leffler 	return current_rix;
495c1565b61SSam Leffler #undef DOT11RATE
496a6a308a4SAdrian Chadd #undef	MCS
497fa20c234SSam Leffler }
498fa20c234SSam Leffler 
499c4ac32a8SAdrian Chadd static int
500c4ac32a8SAdrian Chadd ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni)
501c4ac32a8SAdrian Chadd {
502c4ac32a8SAdrian Chadd #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
503c4ac32a8SAdrian Chadd #define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
504c4ac32a8SAdrian Chadd #define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
505c4ac32a8SAdrian Chadd 	const struct ieee80211_txparam *tp = ni->ni_txparms;
506c4ac32a8SAdrian Chadd 	int srate;
507c4ac32a8SAdrian Chadd 
508c4ac32a8SAdrian Chadd 	/* Check MCS rates */
509c4ac32a8SAdrian Chadd 	for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) {
510c4ac32a8SAdrian Chadd 		if (MCS(srate) == tp->ucastrate)
511c4ac32a8SAdrian Chadd 			return sc->sc_rixmap[tp->ucastrate];
512c4ac32a8SAdrian Chadd 	}
513c4ac32a8SAdrian Chadd 
514c4ac32a8SAdrian Chadd 	/* Check legacy rates */
515c4ac32a8SAdrian Chadd 	for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) {
516c4ac32a8SAdrian Chadd 		if (RATE(srate) == tp->ucastrate)
517c4ac32a8SAdrian Chadd 			return sc->sc_rixmap[tp->ucastrate];
518c4ac32a8SAdrian Chadd 	}
519c4ac32a8SAdrian Chadd 	return -1;
520c4ac32a8SAdrian Chadd #undef	RATE
521c4ac32a8SAdrian Chadd #undef	DOT11RATE
522c4ac32a8SAdrian Chadd #undef	MCS
523c4ac32a8SAdrian Chadd }
524c4ac32a8SAdrian Chadd 
525c4ac32a8SAdrian Chadd static void
526c4ac32a8SAdrian Chadd ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni)
527c4ac32a8SAdrian Chadd {
528c4ac32a8SAdrian Chadd 	struct ath_node *an = ATH_NODE(ni);
529c4ac32a8SAdrian Chadd 	const struct ieee80211_txparam *tp = ni->ni_txparms;
530c4ac32a8SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
531c4ac32a8SAdrian Chadd 
532c4ac32a8SAdrian Chadd 	if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
533c4ac32a8SAdrian Chadd 		/*
534c4ac32a8SAdrian Chadd 		 * A fixed rate is to be used; ucastrate is the IEEE code
535c4ac32a8SAdrian Chadd 		 * for this rate (sans basic bit).  Check this against the
536c4ac32a8SAdrian Chadd 		 * negotiated rate set for the node.  Note the fixed rate
537c4ac32a8SAdrian Chadd 		 * may not be available for various reasons so we only
538c4ac32a8SAdrian Chadd 		 * setup the static rate index if the lookup is successful.
539c4ac32a8SAdrian Chadd 		 */
540c4ac32a8SAdrian Chadd 		sn->static_rix = ath_rate_get_static_rix(sc, ni);
541c4ac32a8SAdrian Chadd 	} else {
542c4ac32a8SAdrian Chadd 		sn->static_rix = -1;
543c4ac32a8SAdrian Chadd 	}
544c4ac32a8SAdrian Chadd }
545c4ac32a8SAdrian Chadd 
546eb6f0de0SAdrian Chadd /*
547eb6f0de0SAdrian Chadd  * Pick a non-HT rate to begin using.
548eb6f0de0SAdrian Chadd  */
549eb6f0de0SAdrian Chadd static int
550eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an,
551eb6f0de0SAdrian Chadd     int frameLen)
552eb6f0de0SAdrian Chadd {
553eb6f0de0SAdrian Chadd #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
554eb6f0de0SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
555eb6f0de0SAdrian Chadd #define	RATE(ix)	(DOT11RATE(ix) / 2)
556eb6f0de0SAdrian Chadd 	int rix = -1;
557eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
558eb6f0de0SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
559eb6f0de0SAdrian Chadd 	const int size_bin = size_to_bin(frameLen);
560eb6f0de0SAdrian Chadd 
561eb6f0de0SAdrian Chadd 	/* no packet has been sent successfully yet */
562eb6f0de0SAdrian Chadd 	for (rix = rt->rateCount-1; rix > 0; rix--) {
563193bfa21SAdrian Chadd 		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
564eb6f0de0SAdrian Chadd 			continue;
565eb6f0de0SAdrian Chadd 
566eb6f0de0SAdrian Chadd 		/* Skip HT rates */
567eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy == IEEE80211_T_HT)
568eb6f0de0SAdrian Chadd 			continue;
569eb6f0de0SAdrian Chadd 
570eb6f0de0SAdrian Chadd 		/*
571eb6f0de0SAdrian Chadd 		 * Pick the highest rate <= 36 Mbps
572eb6f0de0SAdrian Chadd 		 * that hasn't failed.
573eb6f0de0SAdrian Chadd 		 */
574eb6f0de0SAdrian Chadd 		if (DOT11RATE(rix) <= 72 &&
575eb6f0de0SAdrian Chadd 		    sn->stats[size_bin][rix].successive_failures == 0) {
576eb6f0de0SAdrian Chadd 			break;
577eb6f0de0SAdrian Chadd 		}
578eb6f0de0SAdrian Chadd 	}
579eb6f0de0SAdrian Chadd 	return rix;
580eb6f0de0SAdrian Chadd #undef	RATE
581eb6f0de0SAdrian Chadd #undef	MCS
582eb6f0de0SAdrian Chadd #undef	DOT11RATE
583eb6f0de0SAdrian Chadd }
584eb6f0de0SAdrian Chadd 
585eb6f0de0SAdrian Chadd /*
586eb6f0de0SAdrian Chadd  * Pick a HT rate to begin using.
587eb6f0de0SAdrian Chadd  *
588eb6f0de0SAdrian Chadd  * Don't use any non-HT rates; only consider HT rates.
589eb6f0de0SAdrian Chadd  */
590eb6f0de0SAdrian Chadd static int
591eb6f0de0SAdrian Chadd ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an,
592eb6f0de0SAdrian Chadd     int frameLen)
593eb6f0de0SAdrian Chadd {
594eb6f0de0SAdrian Chadd #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
595eb6f0de0SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
596eb6f0de0SAdrian Chadd #define	RATE(ix)	(DOT11RATE(ix) / 2)
597eb6f0de0SAdrian Chadd 	int rix = -1, ht_rix = -1;
598eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
599eb6f0de0SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
600eb6f0de0SAdrian Chadd 	const int size_bin = size_to_bin(frameLen);
601eb6f0de0SAdrian Chadd 
602eb6f0de0SAdrian Chadd 	/* no packet has been sent successfully yet */
603eb6f0de0SAdrian Chadd 	for (rix = rt->rateCount-1; rix > 0; rix--) {
604eb6f0de0SAdrian Chadd 		/* Skip rates we can't use */
605193bfa21SAdrian Chadd 		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
606eb6f0de0SAdrian Chadd 			continue;
607eb6f0de0SAdrian Chadd 
608eb6f0de0SAdrian Chadd 		/* Keep a copy of the last seen HT rate index */
609eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy == IEEE80211_T_HT)
610eb6f0de0SAdrian Chadd 			ht_rix = rix;
611eb6f0de0SAdrian Chadd 
612eb6f0de0SAdrian Chadd 		/* Skip non-HT rates */
613eb6f0de0SAdrian Chadd 		if (rt->info[rix].phy != IEEE80211_T_HT)
614eb6f0de0SAdrian Chadd 			continue;
615eb6f0de0SAdrian Chadd 
616eb6f0de0SAdrian Chadd 		/*
617cce63444SAdrian Chadd 		 * Pick a medium-speed rate at 1 spatial stream
618cce63444SAdrian Chadd 		 * which has not seen any failures.
619cce63444SAdrian Chadd 		 * Higher rates may fail; we'll try them later.
620eb6f0de0SAdrian Chadd 		 */
621cce63444SAdrian Chadd 		if (((MCS(rix)& 0x7f) <= 4) &&
622eb6f0de0SAdrian Chadd 		    sn->stats[size_bin][rix].successive_failures == 0) {
623eb6f0de0SAdrian Chadd 			break;
624eb6f0de0SAdrian Chadd 		}
625eb6f0de0SAdrian Chadd 	}
626eb6f0de0SAdrian Chadd 
627eb6f0de0SAdrian Chadd 	/*
628eb6f0de0SAdrian Chadd 	 * If all the MCS rates have successive failures, rix should be
629eb6f0de0SAdrian Chadd 	 * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)
630eb6f0de0SAdrian Chadd 	 */
631eb6f0de0SAdrian Chadd 	return MAX(rix, ht_rix);
632eb6f0de0SAdrian Chadd #undef	RATE
633eb6f0de0SAdrian Chadd #undef	MCS
634eb6f0de0SAdrian Chadd #undef	DOT11RATE
635eb6f0de0SAdrian Chadd }
636c4ac32a8SAdrian Chadd 
637c4ac32a8SAdrian Chadd 
638fa20c234SSam Leffler void
639fa20c234SSam Leffler ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
64084f950a5SAdrian Chadd 		  int shortPreamble, size_t frameLen, int tid,
641cce63444SAdrian Chadd 		  int is_aggr, u_int8_t *rix0, int *try0,
642cce63444SAdrian Chadd 		  u_int8_t *txrate, int *maxdur, int *maxpktlen)
643fa20c234SSam Leffler {
644c1565b61SSam Leffler #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
645a6a308a4SAdrian Chadd #define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
646c1565b61SSam Leffler #define	RATE(ix)	(DOT11RATE(ix) / 2)
647fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
648fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
6497a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
650c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
651cce63444SAdrian Chadd 	int size_bin = size_to_bin(frameLen);
652c1565b61SSam Leffler 	int rix, mrr, best_rix, change_rates;
653b2763056SSam Leffler 	unsigned average_tx_time;
654cce63444SAdrian Chadd 	int max_pkt_len;
655fa20c234SSam Leffler 
656c4ac32a8SAdrian Chadd 	ath_rate_update_static_rix(sc, &an->an_node);
657c4ac32a8SAdrian Chadd 
65884f950a5SAdrian Chadd 	/* For now don't take TID, is_aggr into account */
65984f950a5SAdrian Chadd 	/* Also for now don't calculate a max duration; that'll come later */
66084f950a5SAdrian Chadd 	*maxdur = -1;
66184f950a5SAdrian Chadd 
662cce63444SAdrian Chadd 	/*
663cce63444SAdrian Chadd 	 * For now just set it to the frame length; we'll optimise it later.
664cce63444SAdrian Chadd 	 */
665cce63444SAdrian Chadd 	*maxpktlen = frameLen;
666cce63444SAdrian Chadd 
667cc86f1eaSAdrian Chadd 	if (sn->currates != sc->sc_currates) {
668cc86f1eaSAdrian Chadd 		device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",
669cc86f1eaSAdrian Chadd 		    __func__);
670cc86f1eaSAdrian Chadd 		rix = 0;
671cc86f1eaSAdrian Chadd 		*try0 = ATH_TXMAXTRY;
672cc86f1eaSAdrian Chadd 		goto done;
673cc86f1eaSAdrian Chadd 	}
674cc86f1eaSAdrian Chadd 
675c1565b61SSam Leffler 	if (sn->static_rix != -1) {
676c1565b61SSam Leffler 		rix = sn->static_rix;
677c1565b61SSam Leffler 		*try0 = ATH_TXMAXTRY;
678c1565b61SSam Leffler 		goto done;
679c1565b61SSam Leffler 	}
680fa20c234SSam Leffler 
681af017101SAdrian Chadd 	mrr = sc->sc_mrretry;
682af017101SAdrian Chadd 	/* XXX check HT protmode too */
683cce63444SAdrian Chadd 	/* XXX turn into a cap; 11n MACs support MRR+RTSCTS */
6849f579ef8SAdrian Chadd 	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
685af017101SAdrian Chadd 		mrr = 0;
686c1565b61SSam Leffler 
68736958948SAdrian Chadd 	best_rix = pick_best_rate(an, rt, size_bin, !mrr);
688cce63444SAdrian Chadd 
689cce63444SAdrian Chadd 	/*
690cce63444SAdrian Chadd 	 * At this point we've chosen the best rix, so now we
691cce63444SAdrian Chadd 	 * need to potentially update our maximum packet length
692cce63444SAdrian Chadd 	 * and size_bin if we're doing 11n rates.
693cce63444SAdrian Chadd 	 */
694cce63444SAdrian Chadd 	max_pkt_len = ath_rate_sample_find_min_pktlength(sc, an, best_rix);
695cce63444SAdrian Chadd 	if (max_pkt_len > 0) {
696cce63444SAdrian Chadd #if 0
697cce63444SAdrian Chadd 		device_printf(sc->sc_dev,
698cce63444SAdrian Chadd 		    "Limiting maxpktlen from %d to %d bytes\n",
699cce63444SAdrian Chadd 		    (int) frameLen, max_pkt_len);
700cce63444SAdrian Chadd #endif
701cce63444SAdrian Chadd 		*maxpktlen = frameLen = MIN(frameLen, max_pkt_len);
702cce63444SAdrian Chadd 		size_bin = size_to_bin(frameLen);
703cce63444SAdrian Chadd 	}
704cce63444SAdrian Chadd 
705c1565b61SSam Leffler 	if (best_rix >= 0) {
706c1565b61SSam Leffler 		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
707fa20c234SSam Leffler 	} else {
708b2763056SSam Leffler 		average_tx_time = 0;
709b2763056SSam Leffler 	}
710cce63444SAdrian Chadd 
711fa20c234SSam Leffler 	/*
712c1565b61SSam Leffler 	 * Limit the time measuring the performance of other tx
713c1565b61SSam Leffler 	 * rates to sample_rate% of the total transmission time.
714fa20c234SSam Leffler 	 */
715*5add7017SAdrian Chadd 	if (sn->sample_tt[size_bin] <
716*5add7017SAdrian Chadd 	    average_tx_time *
717*5add7017SAdrian Chadd 	    (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
71836958948SAdrian Chadd 		rix = pick_sample_rate(ssc, an, rt, size_bin);
719c1565b61SSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
720*5add7017SAdrian Chadd 		     &an->an_node, "att %d sample_tt %d size %u "
721*5add7017SAdrian Chadd 		     "sample rate %d %s current rate %d %s",
722eb6f0de0SAdrian Chadd 		     average_tx_time,
723eb6f0de0SAdrian Chadd 		     sn->sample_tt[size_bin],
724eb6f0de0SAdrian Chadd 		     bin_to_size(size_bin),
725eb6f0de0SAdrian Chadd 		     dot11rate(rt, rix),
726eb6f0de0SAdrian Chadd 		     dot11rate_label(rt, rix),
727eb6f0de0SAdrian Chadd 		     dot11rate(rt, sn->current_rix[size_bin]),
728eb6f0de0SAdrian Chadd 		     dot11rate_label(rt, sn->current_rix[size_bin]));
729c1565b61SSam Leffler 		if (rix != sn->current_rix[size_bin]) {
730c1565b61SSam Leffler 			sn->current_sample_rix[size_bin] = rix;
731b2763056SSam Leffler 		} else {
732c1565b61SSam Leffler 			sn->current_sample_rix[size_bin] = -1;
733b2763056SSam Leffler 		}
734b2763056SSam Leffler 		sn->packets_since_sample[size_bin] = 0;
735b2763056SSam Leffler 	} else {
736b91bf513SSam Leffler 		change_rates = 0;
737c1565b61SSam Leffler 		if (!sn->packets_sent[size_bin] || best_rix == -1) {
738b91bf513SSam Leffler 			/* no packet has been sent successfully yet */
739b91bf513SSam Leffler 			change_rates = 1;
740eb6f0de0SAdrian Chadd 			if (an->an_node.ni_flags & IEEE80211_NODE_HT)
741eb6f0de0SAdrian Chadd 				best_rix =
742eb6f0de0SAdrian Chadd 				    ath_rate_pick_seed_rate_ht(sc, an, frameLen);
743eb6f0de0SAdrian Chadd 			else
744eb6f0de0SAdrian Chadd 				best_rix =
745eb6f0de0SAdrian Chadd 				    ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
746b91bf513SSam Leffler 		} else if (sn->packets_sent[size_bin] < 20) {
747b91bf513SSam Leffler 			/* let the bit-rate switch quickly during the first few packets */
748eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
749eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
750eb6f0de0SAdrian Chadd 			    "%s: switching quickly..", __func__);
751b91bf513SSam Leffler 			change_rates = 1;
752c1565b61SSam Leffler 		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
753c1565b61SSam Leffler 			/* min_switch seconds have gone by */
754eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
755eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
756eb6f0de0SAdrian Chadd 			    "%s: min_switch %d > ticks_since_switch %d..",
757eb6f0de0SAdrian Chadd 			    __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
758b91bf513SSam Leffler 			change_rates = 1;
759eb6f0de0SAdrian Chadd 		} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
760eb6f0de0SAdrian Chadd 		    (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
761b91bf513SSam Leffler 			/* the current bit-rate is twice as slow as the best one */
762eb6f0de0SAdrian Chadd 			IEEE80211_NOTE(an->an_node.ni_vap,
763eb6f0de0SAdrian Chadd 			    IEEE80211_MSG_RATECTL, &an->an_node,
764eb6f0de0SAdrian Chadd 			    "%s: 2x att (= %d) < cur_rix att %d",
765eb6f0de0SAdrian Chadd 			    __func__,
766eb6f0de0SAdrian Chadd 			    2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
767b91bf513SSam Leffler 			change_rates = 1;
768eb6f0de0SAdrian Chadd 		} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
769eb6f0de0SAdrian Chadd 			int cur_rix = sn->current_rix[size_bin];
770eb6f0de0SAdrian Chadd 			int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
771eb6f0de0SAdrian Chadd 			/*
772cce63444SAdrian Chadd 			 * If the node is HT, upgrade it if the MCS rate without
773cce63444SAdrian Chadd 			 * the stream is higher and the average tx time is
774cce63444SAdrian Chadd 			 * within 10% of the current rate. It can fail a little.
775eb6f0de0SAdrian Chadd 			 *
776eb6f0de0SAdrian Chadd 			 * This is likely not optimal!
777eb6f0de0SAdrian Chadd 			 */
778eb6f0de0SAdrian Chadd #if 0
779eb6f0de0SAdrian Chadd 			printf("cur rix/att %x/%d, best rix/att %x/%d\n",
780eb6f0de0SAdrian Chadd 			    MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
781eb6f0de0SAdrian Chadd #endif
782*5add7017SAdrian Chadd 			if ((best_rix != cur_rix) &&
783*5add7017SAdrian Chadd 			    ((MCS(best_rix) & 0x7) >= (MCS(cur_rix) & 0x7)) &&
784*5add7017SAdrian Chadd 			    (average_tx_time * 9) <= (cur_att * 10)) {
785eb6f0de0SAdrian Chadd 				IEEE80211_NOTE(an->an_node.ni_vap,
786eb6f0de0SAdrian Chadd 				    IEEE80211_MSG_RATECTL, &an->an_node,
787cce63444SAdrian Chadd 				    "%s: HT: size %d best_rix 0x%x > "
788cce63444SAdrian Chadd 				    " cur_rix 0x%x, average_tx_time %d,"
789cce63444SAdrian Chadd 				    " cur_att %d",
790cce63444SAdrian Chadd 				    __func__, bin_to_size(size_bin),
791cce63444SAdrian Chadd 				    MCS(best_rix), MCS(cur_rix),
792cce63444SAdrian Chadd 				    average_tx_time, cur_att);
793eb6f0de0SAdrian Chadd 				change_rates = 1;
794eb6f0de0SAdrian Chadd 			}
795b91bf513SSam Leffler 		}
796b91bf513SSam Leffler 
797b91bf513SSam Leffler 		sn->packets_since_sample[size_bin]++;
798b91bf513SSam Leffler 
799b91bf513SSam Leffler 		if (change_rates) {
800c1565b61SSam Leffler 			if (best_rix != sn->current_rix[size_bin]) {
801b032f27cSSam Leffler 				IEEE80211_NOTE(an->an_node.ni_vap,
802b032f27cSSam Leffler 				    IEEE80211_MSG_RATECTL,
803b032f27cSSam Leffler 				    &an->an_node,
804cce63444SAdrian Chadd "%s: size %d switch rate %d %s (%d/%d) EWMA %d -> %d %s (%d/%d) EWMA %d after %d packets mrr %d",
805b2763056SSam Leffler 				    __func__,
806c1565b61SSam Leffler 				    bin_to_size(size_bin),
807cce63444SAdrian Chadd 				    dot11rate(rt, sn->current_rix[size_bin]),
808cce63444SAdrian Chadd 				    dot11rate_label(rt, sn->current_rix[size_bin]),
809c1565b61SSam Leffler 				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
810c1565b61SSam Leffler 				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
811cce63444SAdrian Chadd 				    sn->stats[size_bin][sn->current_rix[size_bin]].ewma_pct,
812cce63444SAdrian Chadd 				    dot11rate(rt, best_rix),
813cce63444SAdrian Chadd 				    dot11rate_label(rt, best_rix),
814c1565b61SSam Leffler 				    sn->stats[size_bin][best_rix].average_tx_time,
815c1565b61SSam Leffler 				    sn->stats[size_bin][best_rix].perfect_tx_time,
816cce63444SAdrian Chadd 				    sn->stats[size_bin][best_rix].ewma_pct,
817b2763056SSam Leffler 				    sn->packets_since_switch[size_bin],
818b2763056SSam Leffler 				    mrr);
819b2763056SSam Leffler 			}
820b2763056SSam Leffler 			sn->packets_since_switch[size_bin] = 0;
821c1565b61SSam Leffler 			sn->current_rix[size_bin] = best_rix;
822b91bf513SSam Leffler 			sn->ticks_since_switch[size_bin] = ticks;
823b032f27cSSam Leffler 			/*
824b032f27cSSam Leffler 			 * Set the visible txrate for this node.
825b032f27cSSam Leffler 			 */
826*5add7017SAdrian Chadd 			an->an_node.ni_txrate =
827*5add7017SAdrian Chadd 			    (rt->info[best_rix].phy == IEEE80211_T_HT) ?
828*5add7017SAdrian Chadd 			     MCS(best_rix) : DOT11RATE(best_rix);
829b2763056SSam Leffler 		}
830c1565b61SSam Leffler 		rix = sn->current_rix[size_bin];
831b2763056SSam Leffler 		sn->packets_since_switch[size_bin]++;
832b91bf513SSam Leffler 	}
833c1565b61SSam Leffler 	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
834c1565b61SSam Leffler done:
835cc86f1eaSAdrian Chadd 
836cc86f1eaSAdrian Chadd 	/*
837cc86f1eaSAdrian Chadd 	 * This bug totally sucks and should be fixed.
838cc86f1eaSAdrian Chadd 	 *
839cc86f1eaSAdrian Chadd 	 * For now though, let's not panic, so we can start to figure
840cc86f1eaSAdrian Chadd 	 * out how to better reproduce it.
841cc86f1eaSAdrian Chadd 	 */
842cc86f1eaSAdrian Chadd 	if (rix < 0 || rix >= rt->rateCount) {
843cc86f1eaSAdrian Chadd 		printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
844cc86f1eaSAdrian Chadd 		    __func__,
845cc86f1eaSAdrian Chadd 		    rix,
846cc86f1eaSAdrian Chadd 		    rt->rateCount);
847cc86f1eaSAdrian Chadd 		    rix = 0;	/* XXX just default for now */
848cc86f1eaSAdrian Chadd 	}
849c1565b61SSam Leffler 	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));
850fa20c234SSam Leffler 
851c1565b61SSam Leffler 	*rix0 = rix;
852c1565b61SSam Leffler 	*txrate = rt->info[rix].rateCode
853c1565b61SSam Leffler 		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
854fa20c234SSam Leffler 	sn->packets_sent[size_bin]++;
855cce63444SAdrian Chadd 
856c1565b61SSam Leffler #undef DOT11RATE
857a6a308a4SAdrian Chadd #undef MCS
858c1565b61SSam Leffler #undef RATE
859fa20c234SSam Leffler }
860fa20c234SSam Leffler 
861710c3778SAdrian Chadd /*
862710c3778SAdrian Chadd  * Get the TX rates. Don't fiddle with short preamble flags for them;
863710c3778SAdrian Chadd  * the caller can do that.
864710c3778SAdrian Chadd  */
865710c3778SAdrian Chadd void
866710c3778SAdrian Chadd ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
867eb6f0de0SAdrian Chadd     uint8_t rix0, struct ath_rc_series *rc)
868710c3778SAdrian Chadd {
869710c3778SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
870710c3778SAdrian Chadd 	const struct txschedule *sched = &sn->sched[rix0];
871710c3778SAdrian Chadd 
872193bfa21SAdrian Chadd 	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
873193bfa21SAdrian Chadd 	    rix0, sched->r0));
874710c3778SAdrian Chadd 
875eb6f0de0SAdrian Chadd 	rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
876710c3778SAdrian Chadd 
877eb6f0de0SAdrian Chadd 	rc[0].rix = sched->r0;
878eb6f0de0SAdrian Chadd 	rc[1].rix = sched->r1;
879eb6f0de0SAdrian Chadd 	rc[2].rix = sched->r2;
880eb6f0de0SAdrian Chadd 	rc[3].rix = sched->r3;
881eb6f0de0SAdrian Chadd 
882eb6f0de0SAdrian Chadd 	rc[0].tries = sched->t0;
883eb6f0de0SAdrian Chadd 	rc[1].tries = sched->t1;
884eb6f0de0SAdrian Chadd 	rc[2].tries = sched->t2;
885eb6f0de0SAdrian Chadd 	rc[3].tries = sched->t3;
886710c3778SAdrian Chadd }
887710c3778SAdrian Chadd 
888fa20c234SSam Leffler void
889fa20c234SSam Leffler ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
890a4d8dd10SSam Leffler 		      struct ath_desc *ds, int shortPreamble, u_int8_t rix)
891fa20c234SSam Leffler {
892fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
893c1565b61SSam Leffler 	const struct txschedule *sched = &sn->sched[rix];
894c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
895c1565b61SSam Leffler 	uint8_t rix1, s1code, rix2, s2code, rix3, s3code;
896fa20c234SSam Leffler 
897c1565b61SSam Leffler 	/* XXX precalculate short preamble tables */
898c1565b61SSam Leffler 	rix1 = sched->r1;
899c1565b61SSam Leffler 	s1code = rt->info[rix1].rateCode
900c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix1].shortPreamble : 0);
901c1565b61SSam Leffler 	rix2 = sched->r2;
902c1565b61SSam Leffler 	s2code = rt->info[rix2].rateCode
903c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix2].shortPreamble : 0);
904c1565b61SSam Leffler 	rix3 = sched->r3;
905c1565b61SSam Leffler 	s3code = rt->info[rix3].rateCode
906c1565b61SSam Leffler 	       | (shortPreamble ? rt->info[rix3].shortPreamble : 0);
907c1565b61SSam Leffler 	ath_hal_setupxtxdesc(sc->sc_ah, ds,
908c1565b61SSam Leffler 	    s1code, sched->t1,		/* series 1 */
909c1565b61SSam Leffler 	    s2code, sched->t2,		/* series 2 */
910c1565b61SSam Leffler 	    s3code, sched->t3);		/* series 3 */
911fa20c234SSam Leffler }
912fa20c234SSam Leffler 
913b2763056SSam Leffler static void
914b2763056SSam Leffler update_stats(struct ath_softc *sc, struct ath_node *an,
915b2763056SSam Leffler 		  int frame_size,
916c1565b61SSam Leffler 		  int rix0, int tries0,
917eb6f0de0SAdrian Chadd 		  int short_tries, int tries, int status,
918eb6f0de0SAdrian Chadd 		  int nframes, int nbad)
919fa20c234SSam Leffler {
920fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
921fa20c234SSam Leffler 	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
922ec3dec2fSAdrian Chadd #ifdef IEEE80211_DEBUG
923eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
924ec3dec2fSAdrian Chadd #endif
925c1565b61SSam Leffler 	const int size_bin = size_to_bin(frame_size);
926c1565b61SSam Leffler 	const int size = bin_to_size(size_bin);
927c1565b61SSam Leffler 	int tt, tries_so_far;
928532f2442SAdrian Chadd 	int is_ht40 = (an->an_node.ni_chw == 40);
929ee563d63SAdrian Chadd 	int pct;
930fa20c234SSam Leffler 
931c1565b61SSam Leffler 	if (!IS_RATE_DEFINED(sn, rix0))
93265f9edeeSSam Leffler 		return;
933cce63444SAdrian Chadd 
934cce63444SAdrian Chadd 	/*
935cce63444SAdrian Chadd 	 * If status is FAIL then we treat all frames as bad.
936cce63444SAdrian Chadd 	 * This better accurately tracks EWMA and average TX time
937cce63444SAdrian Chadd 	 * because even if the eventual transmission succeeded,
938cce63444SAdrian Chadd 	 * transmission at this rate did not.
939cce63444SAdrian Chadd 	 */
940cce63444SAdrian Chadd 	if (status != 0)
941cce63444SAdrian Chadd 		nbad = nframes;
942cce63444SAdrian Chadd 
943c1565b61SSam Leffler 	tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
944e09c8c4cSAdrian Chadd 		MIN(tries0, tries) - 1, is_ht40);
945c1565b61SSam Leffler 	tries_so_far = tries0;
946c1565b61SSam Leffler 
947c1565b61SSam Leffler 	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
948fa20c234SSam Leffler 		/* just average the first few packets */
949c1565b61SSam Leffler 		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
950c1565b61SSam Leffler 		int packets = sn->stats[size_bin][rix0].total_packets;
951eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
952fa20c234SSam Leffler 	} else {
953fa20c234SSam Leffler 		/* use a ewma */
954c1565b61SSam Leffler 		sn->stats[size_bin][rix0].average_tx_time =
955c1565b61SSam Leffler 			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) +
956c1565b61SSam Leffler 			 (tt * (100 - ssc->smoothing_rate))) / 100;
957fa20c234SSam Leffler 	}
958fa20c234SSam Leffler 
959eb6f0de0SAdrian Chadd 	if (nframes == nbad) {
960eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].successive_failures += nbad;
961fa20c234SSam Leffler 	} else {
962eb6f0de0SAdrian Chadd 		sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
963c1565b61SSam Leffler 		sn->stats[size_bin][rix0].successive_failures = 0;
964fa20c234SSam Leffler 	}
965c1565b61SSam Leffler 	sn->stats[size_bin][rix0].tries += tries;
966c1565b61SSam Leffler 	sn->stats[size_bin][rix0].last_tx = ticks;
967eb6f0de0SAdrian Chadd 	sn->stats[size_bin][rix0].total_packets += nframes;
968b2763056SSam Leffler 
969ee563d63SAdrian Chadd 	/* update EWMA for this rix */
970ee563d63SAdrian Chadd 
971ee563d63SAdrian Chadd 	/* Calculate percentage based on current rate */
972ee563d63SAdrian Chadd 	if (nframes == 0)
973ee563d63SAdrian Chadd 		nframes = nbad = 1;
974ee563d63SAdrian Chadd 	pct = ((nframes - nbad) * 1000) / nframes;
975ee563d63SAdrian Chadd 
976ee563d63SAdrian Chadd 	if (sn->stats[size_bin][rix0].total_packets <
977ee563d63SAdrian Chadd 	    ssc->smoothing_minpackets) {
978ee563d63SAdrian Chadd 		/* just average the first few packets */
979ee563d63SAdrian Chadd 		int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /
980ee563d63SAdrian Chadd 		    (sn->stats[size_bin][rix0].total_packets);
981ee563d63SAdrian Chadd 		sn->stats[size_bin][rix0].ewma_pct = a_pct;
982ee563d63SAdrian Chadd 	} else {
983ee563d63SAdrian Chadd 		/* use a ewma */
984ee563d63SAdrian Chadd 		sn->stats[size_bin][rix0].ewma_pct =
985ee563d63SAdrian Chadd 			((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +
986ee563d63SAdrian Chadd 			 (pct * (100 - ssc->smoothing_rate))) / 100;
987ee563d63SAdrian Chadd 	}
988ee563d63SAdrian Chadd 
989cce63444SAdrian Chadd 	/*
990cce63444SAdrian Chadd 	 * Only update the sample time for the initial sample rix.
991cce63444SAdrian Chadd 	 * We've updated the statistics on each of the other retries
992cce63444SAdrian Chadd 	 * fine, but we should only update the sample_tt with what
993cce63444SAdrian Chadd 	 * was actually sampled.
994cce63444SAdrian Chadd 	 *
995cce63444SAdrian Chadd 	 * However, to aide in debugging, log all the failures for
996cce63444SAdrian Chadd 	 * each of the buckets
997cce63444SAdrian Chadd 	 */
998b032f27cSSam Leffler 	IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
999b032f27cSSam Leffler 	   &an->an_node,
1000cce63444SAdrian Chadd 	    "%s: size %d %s %s rate %d %s tries (%d/%d) tt %d "
1001cce63444SAdrian Chadd 	    "avg_tt (%d/%d) nfrm %d nbad %d",
1002b032f27cSSam Leffler 	    __func__,
100365f9edeeSSam Leffler 	    size,
100465f9edeeSSam Leffler 	    status ? "FAIL" : "OK",
1005cce63444SAdrian Chadd 	    rix0 == sn->current_sample_rix[size_bin] ? "sample" : "mrr",
1006eb6f0de0SAdrian Chadd 	    dot11rate(rt, rix0),
1007eb6f0de0SAdrian Chadd 	    dot11rate_label(rt, rix0),
1008eb6f0de0SAdrian Chadd 	    short_tries, tries, tt,
1009c1565b61SSam Leffler 	    sn->stats[size_bin][rix0].average_tx_time,
1010eb6f0de0SAdrian Chadd 	    sn->stats[size_bin][rix0].perfect_tx_time,
1011eb6f0de0SAdrian Chadd 	    nframes, nbad);
1012cce63444SAdrian Chadd 
1013cce63444SAdrian Chadd 	if (rix0 == sn->current_sample_rix[size_bin]) {
1014b2763056SSam Leffler 		sn->sample_tt[size_bin] = tt;
1015c1565b61SSam Leffler 		sn->current_sample_rix[size_bin] = -1;
1016b2763056SSam Leffler 	}
1017b2763056SSam Leffler }
1018b2763056SSam Leffler 
1019ec9ee5e7SSam Leffler static void
102076e6fd5dSGleb Smirnoff badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status)
1021ec9ee5e7SSam Leffler {
102276e6fd5dSGleb Smirnoff 
102376e6fd5dSGleb Smirnoff 	device_printf(sc->sc_dev,
102476e6fd5dSGleb Smirnoff 	    "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n",
1025ec9ee5e7SSam Leffler 	    series, hwrate, tries, status);
1026ec9ee5e7SSam Leffler }
1027ec9ee5e7SSam Leffler 
1028b2763056SSam Leffler void
102943e9cf7cSSam Leffler ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
1030eb6f0de0SAdrian Chadd 	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
1031cce63444SAdrian Chadd 	int frame_size, int rc_framesize, int nframes, int nbad)
1032b2763056SSam Leffler {
10337a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
1034b2763056SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1035eb6f0de0SAdrian Chadd 	int final_rix, short_tries, long_tries;
103646d4d74cSSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1037eb6f0de0SAdrian Chadd 	int status = ts->ts_status;
10381bb9a085SSam Leffler 	int mrr;
1039b2763056SSam Leffler 
1040f6cbf16aSSam Leffler 	final_rix = rt->rateCodeToIndex[ts->ts_rate];
104165f9edeeSSam Leffler 	short_tries = ts->ts_shortretry;
104265f9edeeSSam Leffler 	long_tries = ts->ts_longretry + 1;
1043eb6f0de0SAdrian Chadd 
1044ee563d63SAdrian Chadd 	if (nframes == 0) {
1045ee563d63SAdrian Chadd 		device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);
1046ee563d63SAdrian Chadd 		return;
1047ee563d63SAdrian Chadd 	}
1048ee563d63SAdrian Chadd 
104943e9cf7cSSam Leffler 	if (frame_size == 0)		    /* NB: should not happen */
1050b2763056SSam Leffler 		frame_size = 1500;
1051cce63444SAdrian Chadd 	if (rc_framesize == 0)		    /* NB: should not happen */
1052cce63444SAdrian Chadd 		rc_framesize = 1500;
1053cce63444SAdrian Chadd 
1054cce63444SAdrian Chadd 	/*
1055cce63444SAdrian Chadd 	 * There are still some places where what rate control set as
1056cce63444SAdrian Chadd 	 * a limit but the hardware decided, for some reason, to transmit
1057cce63444SAdrian Chadd 	 * at a smaller size that fell into a different bucket.
1058cce63444SAdrian Chadd 	 *
1059cce63444SAdrian Chadd 	 * The eternal question here is - which size_bin should it go in?
1060cce63444SAdrian Chadd 	 * The one that was requested, or the one that was transmitted?
1061cce63444SAdrian Chadd 	 *
1062cce63444SAdrian Chadd 	 * Here's the problem - if we use the one that was transmitted,
1063cce63444SAdrian Chadd 	 * we may continue to hit corner cases where we make a rate
1064cce63444SAdrian Chadd 	 * selection using a higher bin but only update the smaller bin;
1065cce63444SAdrian Chadd 	 * thus never really "adapting".
1066cce63444SAdrian Chadd 	 *
1067cce63444SAdrian Chadd 	 * If however we update the larger bin, we're not accurately
1068cce63444SAdrian Chadd 	 * representing the channel state at that frame/aggregate size.
1069cce63444SAdrian Chadd 	 * However if we keep hitting the larger request but completing
1070cce63444SAdrian Chadd 	 * a smaller size, we at least updates based on what the
1071cce63444SAdrian Chadd 	 * request was /for/.
1072cce63444SAdrian Chadd 	 *
1073cce63444SAdrian Chadd 	 * I'm going to err on the side of caution and choose the
1074cce63444SAdrian Chadd 	 * latter.
1075cce63444SAdrian Chadd 	 */
1076cce63444SAdrian Chadd 	if (size_to_bin(frame_size) != size_to_bin(rc_framesize)) {
1077cce63444SAdrian Chadd #if 0
1078cce63444SAdrian Chadd 		device_printf(sc->sc_dev,
1079cce63444SAdrian Chadd 		    "%s: completed but frame size buckets mismatch "
1080cce63444SAdrian Chadd 		    "(completed %d tx'ed %d)\n",
1081cce63444SAdrian Chadd 		    __func__, frame_size, rc_framesize);
1082cce63444SAdrian Chadd #endif
1083cce63444SAdrian Chadd 		frame_size = rc_framesize;
1084cce63444SAdrian Chadd 	}
1085b2763056SSam Leffler 
1086c1565b61SSam Leffler 	if (sn->ratemask == 0) {
1087b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1088b032f27cSSam Leffler 		    &an->an_node,
1089b032f27cSSam Leffler 		    "%s: size %d %s rate/try %d/%d no rates yet",
1090b032f27cSSam Leffler 		    __func__,
109143e9cf7cSSam Leffler 		    bin_to_size(size_to_bin(frame_size)),
1092eb6f0de0SAdrian Chadd 		    status ? "FAIL" : "OK",
109343e9cf7cSSam Leffler 		    short_tries, long_tries);
1094b2763056SSam Leffler 		return;
1095b2763056SSam Leffler 	}
1096af017101SAdrian Chadd 	mrr = sc->sc_mrretry;
1097af017101SAdrian Chadd 	/* XXX check HT protmode too */
10989f579ef8SAdrian Chadd 	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
1099af017101SAdrian Chadd 		mrr = 0;
1100af017101SAdrian Chadd 
1101f6cbf16aSSam Leffler 	if (!mrr || ts->ts_finaltsi == 0) {
1102c1565b61SSam Leffler 		if (!IS_RATE_DEFINED(sn, final_rix)) {
110376e6fd5dSGleb Smirnoff 			device_printf(sc->sc_dev,
110476e6fd5dSGleb Smirnoff 			    "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n",
110506c746edSAdrian Chadd 			    __func__, ts->ts_rate, ts->ts_finaltsi, final_rix);
110676e6fd5dSGleb Smirnoff 			badrate(sc, 0, ts->ts_rate, long_tries, status);
1107ec9ee5e7SSam Leffler 			return;
1108ec9ee5e7SSam Leffler 		}
110965f9edeeSSam Leffler 		/*
111065f9edeeSSam Leffler 		 * Only one rate was used; optimize work.
111165f9edeeSSam Leffler 		 */
1112b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1113f6fd8c7aSAdrian Chadd 		     &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",
1114b032f27cSSam Leffler 		     __func__,
111543e9cf7cSSam Leffler 		     bin_to_size(size_to_bin(frame_size)),
1116c4ac32a8SAdrian Chadd 		     frame_size,
1117eb6f0de0SAdrian Chadd 		     status ? "FAIL" : "OK",
1118eb6f0de0SAdrian Chadd 		     dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
1119eb6f0de0SAdrian Chadd 		     short_tries, long_tries, nframes, nbad);
1120b2763056SSam Leffler 		update_stats(sc, an, frame_size,
1121c1565b61SSam Leffler 			     final_rix, long_tries,
1122eb6f0de0SAdrian Chadd 			     short_tries, long_tries, status,
1123eb6f0de0SAdrian Chadd 			     nframes, nbad);
1124eb6f0de0SAdrian Chadd 
1125b2763056SSam Leffler 	} else {
112665f9edeeSSam Leffler 		int finalTSIdx = ts->ts_finaltsi;
1127bd97c52aSAdrian Chadd 		int i;
1128b2763056SSam Leffler 
1129b2763056SSam Leffler 		/*
1130b2763056SSam Leffler 		 * Process intermediate rates that failed.
1131b2763056SSam Leffler 		 */
1132ec9ee5e7SSam Leffler 
1133b032f27cSSam Leffler 		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
1134b032f27cSSam Leffler 		    &an->an_node,
1135f6fd8c7aSAdrian 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]",
1136b032f27cSSam Leffler 		     __func__,
1137b2763056SSam Leffler 		     bin_to_size(size_to_bin(frame_size)),
1138c4ac32a8SAdrian Chadd 		     frame_size,
1139b2763056SSam Leffler 		     finalTSIdx,
1140f6fd8c7aSAdrian Chadd 		     short_tries,
1141b2763056SSam Leffler 		     long_tries,
1142eb6f0de0SAdrian Chadd 		     status ? "FAIL" : "OK",
1143eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[0].rix),
1144eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[0].rix), rc[0].tries,
1145eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[1].rix),
1146eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[1].rix), rc[1].tries,
1147eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[2].rix),
1148eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[2].rix), rc[2].tries,
1149eb6f0de0SAdrian Chadd 		     dot11rate(rt, rc[3].rix),
1150eb6f0de0SAdrian Chadd 		      dot11rate_label(rt, rc[3].rix), rc[3].tries,
1151eb6f0de0SAdrian Chadd 		     nframes, nbad);
1152c1565b61SSam Leffler 
1153a6a308a4SAdrian Chadd 		for (i = 0; i < 4; i++) {
1154eb6f0de0SAdrian Chadd 			if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
115576e6fd5dSGleb Smirnoff 				badrate(sc, 0, rc[i].ratecode, rc[i].tries,
1156eb6f0de0SAdrian Chadd 				    status);
1157a6a308a4SAdrian Chadd 		}
1158b2763056SSam Leffler 
115965f9edeeSSam Leffler 		/*
1160cce63444SAdrian Chadd 		 * This used to not penalise other tries because loss
1161cce63444SAdrian Chadd 		 * can be bursty, but it's then not accurately keeping
1162cce63444SAdrian Chadd 		 * the avg TX time and EWMA updated.
116365f9edeeSSam Leffler 		 */
1164eb6f0de0SAdrian Chadd 		if (rc[0].tries) {
1165b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1166eb6f0de0SAdrian Chadd 				     rc[0].rix, rc[0].tries,
116765f9edeeSSam Leffler 				     short_tries, long_tries,
1168eb6f0de0SAdrian Chadd 				     long_tries > rc[0].tries,
1169eb6f0de0SAdrian Chadd 				     nframes, nbad);
1170eb6f0de0SAdrian Chadd 			long_tries -= rc[0].tries;
1171b2763056SSam Leffler 		}
1172b2763056SSam Leffler 
1173eb6f0de0SAdrian Chadd 		if (rc[1].tries && finalTSIdx > 0) {
1174b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1175eb6f0de0SAdrian Chadd 				     rc[1].rix, rc[1].tries,
117665f9edeeSSam Leffler 				     short_tries, long_tries,
1177cce63444SAdrian Chadd 				     long_tries > rc[1].tries,
1178eb6f0de0SAdrian Chadd 				     nframes, nbad);
1179eb6f0de0SAdrian Chadd 			long_tries -= rc[1].tries;
1180b2763056SSam Leffler 		}
1181b2763056SSam Leffler 
1182eb6f0de0SAdrian Chadd 		if (rc[2].tries && finalTSIdx > 1) {
1183b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1184eb6f0de0SAdrian Chadd 				     rc[2].rix, rc[2].tries,
118565f9edeeSSam Leffler 				     short_tries, long_tries,
1186cce63444SAdrian Chadd 				     long_tries > rc[2].tries,
1187eb6f0de0SAdrian Chadd 				     nframes, nbad);
1188eb6f0de0SAdrian Chadd 			long_tries -= rc[2].tries;
1189b2763056SSam Leffler 		}
1190b2763056SSam Leffler 
1191eb6f0de0SAdrian Chadd 		if (rc[3].tries && finalTSIdx > 2) {
1192b2763056SSam Leffler 			update_stats(sc, an, frame_size,
1193eb6f0de0SAdrian Chadd 				     rc[3].rix, rc[3].tries,
119465f9edeeSSam Leffler 				     short_tries, long_tries,
1195cce63444SAdrian Chadd 				     long_tries > rc[3].tries,
1196eb6f0de0SAdrian Chadd 				     nframes, nbad);
119738fda926SAdrian Chadd 		}
1198b2763056SSam Leffler 	}
1199fa20c234SSam Leffler }
1200fa20c234SSam Leffler 
1201fa20c234SSam Leffler void
1202fa20c234SSam Leffler ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
1203fa20c234SSam Leffler {
1204fa20c234SSam Leffler 	if (isnew)
1205b2763056SSam Leffler 		ath_rate_ctl_reset(sc, &an->an_node);
1206fa20c234SSam Leffler }
1207fa20c234SSam Leffler 
12087d450faaSAdrian Chadd void
12097d450faaSAdrian Chadd ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
12107d450faaSAdrian Chadd {
12117d450faaSAdrian Chadd }
12127d450faaSAdrian Chadd 
12137d450faaSAdrian Chadd 
1214c1565b61SSam Leffler static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {
1215c1565b61SSam Leffler 	NULL,		/* IEEE80211_MODE_AUTO */
1216c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_11A */
1217c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_11B */
1218c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_11G */
1219c1565b61SSam Leffler 	NULL,		/* IEEE80211_MODE_FH */
1220c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_TURBO_A */
1221c1565b61SSam Leffler 	series_11g,	/* IEEE80211_MODE_TURBO_G */
1222c1565b61SSam Leffler 	series_11a,	/* IEEE80211_MODE_STURBO_A */
1223a6a308a4SAdrian Chadd 	series_11na,	/* IEEE80211_MODE_11NA */
1224a6a308a4SAdrian Chadd 	series_11ng,	/* IEEE80211_MODE_11NG */
1225c1565b61SSam Leffler 	series_half,	/* IEEE80211_MODE_HALF */
1226c1565b61SSam Leffler 	series_quarter,	/* IEEE80211_MODE_QUARTER */
1227c1565b61SSam Leffler };
1228c1565b61SSam Leffler 
1229fa20c234SSam Leffler /*
1230fa20c234SSam Leffler  * Initialize the tables for a node.
1231fa20c234SSam Leffler  */
1232fa20c234SSam Leffler static void
1233b2763056SSam Leffler ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
1234fa20c234SSam Leffler {
1235fa20c234SSam Leffler #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
1236c1565b61SSam Leffler #define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
1237a6a308a4SAdrian Chadd #define	MCS(_ix)	(ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
1238fa20c234SSam Leffler 	struct ath_node *an = ATH_NODE(ni);
1239fa20c234SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
1240fa20c234SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1241c4ac32a8SAdrian Chadd 	int x, y, rix;
1242fa20c234SSam Leffler 
1243fa20c234SSam Leffler 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
1244c1565b61SSam Leffler 
1245c1565b61SSam Leffler 	KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
1246c1565b61SSam Leffler 	    ("curmode %u", sc->sc_curmode));
1247193bfa21SAdrian Chadd 
1248c1565b61SSam Leffler 	sn->sched = mrr_schedules[sc->sc_curmode];
1249c1565b61SSam Leffler 	KASSERT(sn->sched != NULL,
1250c1565b61SSam Leffler 	    ("no mrr schedule for mode %u", sc->sc_curmode));
1251c1565b61SSam Leffler 
1252c1565b61SSam Leffler         sn->static_rix = -1;
1253c4ac32a8SAdrian Chadd 	ath_rate_update_static_rix(sc, ni);
1254b2763056SSam Leffler 
1255cc86f1eaSAdrian Chadd 	sn->currates = sc->sc_currates;
1256cc86f1eaSAdrian Chadd 
1257c1565b61SSam Leffler 	/*
1258c1565b61SSam Leffler 	 * Construct a bitmask of usable rates.  This has all
1259c1565b61SSam Leffler 	 * negotiated rates minus those marked by the hal as
1260c1565b61SSam Leffler 	 * to be ignored for doing rate control.
1261c1565b61SSam Leffler 	 */
1262c1565b61SSam Leffler 	sn->ratemask = 0;
1263a6a308a4SAdrian Chadd 	/* MCS rates */
1264a6a308a4SAdrian Chadd 	if (ni->ni_flags & IEEE80211_NODE_HT) {
1265a6a308a4SAdrian Chadd 		for (x = 0; x < ni->ni_htrates.rs_nrates; x++) {
1266a6a308a4SAdrian Chadd 			rix = sc->sc_rixmap[MCS(x)];
1267a6a308a4SAdrian Chadd 			if (rix == 0xff)
1268a6a308a4SAdrian Chadd 				continue;
1269a6a308a4SAdrian Chadd 			/* skip rates marked broken by hal */
1270a6a308a4SAdrian Chadd 			if (!rt->info[rix].valid)
1271a6a308a4SAdrian Chadd 				continue;
1272a6a308a4SAdrian Chadd 			KASSERT(rix < SAMPLE_MAXRATES,
1273a6a308a4SAdrian Chadd 			    ("mcs %u has rix %d", MCS(x), rix));
1274193bfa21SAdrian Chadd 			sn->ratemask |= (uint64_t) 1<<rix;
1275a6a308a4SAdrian Chadd 		}
1276a6a308a4SAdrian Chadd 	}
1277a6a308a4SAdrian Chadd 
1278a6a308a4SAdrian Chadd 	/* Legacy rates */
1279fa20c234SSam Leffler 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
1280c1565b61SSam Leffler 		rix = sc->sc_rixmap[RATE(x)];
1281c1565b61SSam Leffler 		if (rix == 0xff)
12820ae09ec5SSam Leffler 			continue;
1283c1565b61SSam Leffler 		/* skip rates marked broken by hal */
1284c1565b61SSam Leffler 		if (!rt->info[rix].valid)
1285c1565b61SSam Leffler 			continue;
1286c1565b61SSam Leffler 		KASSERT(rix < SAMPLE_MAXRATES,
1287c1565b61SSam Leffler 		    ("rate %u has rix %d", RATE(x), rix));
1288193bfa21SAdrian Chadd 		sn->ratemask |= (uint64_t) 1<<rix;
1289b2763056SSam Leffler 	}
1290b032f27cSSam Leffler #ifdef IEEE80211_DEBUG
1291b032f27cSSam Leffler 	if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
1292193bfa21SAdrian Chadd 		uint64_t mask;
1293c1565b61SSam Leffler 
1294b032f27cSSam Leffler 		ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",
1295c1565b61SSam Leffler 		    ni->ni_macaddr, ":", __func__);
1296c1565b61SSam Leffler 		for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1297c1565b61SSam Leffler 			if ((mask & 1) == 0)
1298b032f27cSSam Leffler 				continue;
1299ae0944b8SAdrian Chadd 			printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix),
1300e09c8c4cSAdrian Chadd 			    calc_usecs_unicast_packet(sc, 1600, rix, 0,0,
1301532f2442SAdrian Chadd 			        (ni->ni_chw == 40)));
1302b032f27cSSam Leffler 		}
1303b032f27cSSam Leffler 		printf("\n");
1304b032f27cSSam Leffler 	}
1305b032f27cSSam Leffler #endif
1306b2763056SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1307b2763056SSam Leffler 		int size = bin_to_size(y);
1308193bfa21SAdrian Chadd 		uint64_t mask;
1309c1565b61SSam Leffler 
1310b2763056SSam Leffler 		sn->packets_sent[y] = 0;
1311c1565b61SSam Leffler 		sn->current_sample_rix[y] = -1;
1312c1565b61SSam Leffler 		sn->last_sample_rix[y] = 0;
1313c1565b61SSam Leffler 		/* XXX start with first valid rate */
1314c1565b61SSam Leffler 		sn->current_rix[y] = ffs(sn->ratemask)-1;
1315b2763056SSam Leffler 
1316c1565b61SSam Leffler 		/*
1317c1565b61SSam Leffler 		 * Initialize the statistics buckets; these are
1318c1565b61SSam Leffler 		 * indexed by the rate code index.
1319c1565b61SSam Leffler 		 */
1320c1565b61SSam Leffler 		for (rix = 0, mask = sn->ratemask; mask != 0; rix++, mask >>= 1) {
1321c1565b61SSam Leffler 			if ((mask & 1) == 0)		/* not a valid rate */
1322c1565b61SSam Leffler 				continue;
1323c1565b61SSam Leffler 			sn->stats[y][rix].successive_failures = 0;
1324c1565b61SSam Leffler 			sn->stats[y][rix].tries = 0;
1325c1565b61SSam Leffler 			sn->stats[y][rix].total_packets = 0;
1326c1565b61SSam Leffler 			sn->stats[y][rix].packets_acked = 0;
1327c1565b61SSam Leffler 			sn->stats[y][rix].last_tx = 0;
1328eb6f0de0SAdrian Chadd 			sn->stats[y][rix].ewma_pct = 0;
1329b2763056SSam Leffler 
1330c1565b61SSam Leffler 			sn->stats[y][rix].perfect_tx_time =
1331e09c8c4cSAdrian Chadd 			    calc_usecs_unicast_packet(sc, size, rix, 0, 0,
1332532f2442SAdrian Chadd 			    (ni->ni_chw == 40));
1333c1565b61SSam Leffler 			sn->stats[y][rix].average_tx_time =
1334c1565b61SSam Leffler 			    sn->stats[y][rix].perfect_tx_time;
1335b2763056SSam Leffler 		}
1336b91bf513SSam Leffler 	}
1337c1565b61SSam Leffler #if 0
1338c1565b61SSam Leffler 	/* XXX 0, num_rates-1 are wrong */
1339b032f27cSSam Leffler 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
1340b032f27cSSam Leffler 	    "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__,
1341b91bf513SSam Leffler 	    sn->num_rates,
1342c1565b61SSam Leffler 	    DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "",
1343b91bf513SSam Leffler 	    sn->stats[1][0].perfect_tx_time,
1344c1565b61SSam Leffler 	    DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "",
1345b91bf513SSam Leffler 	    sn->stats[1][sn->num_rates-1].perfect_tx_time
1346b91bf513SSam Leffler 	);
1347c1565b61SSam Leffler #endif
1348b032f27cSSam Leffler 	/* set the visible bit-rate */
1349c1565b61SSam Leffler 	if (sn->static_rix != -1)
1350c1565b61SSam Leffler 		ni->ni_txrate = DOT11RATE(sn->static_rix);
1351d0d425bfSSam Leffler 	else
1352c1565b61SSam Leffler 		ni->ni_txrate = RATE(0);
1353fa20c234SSam Leffler #undef RATE
1354c1565b61SSam Leffler #undef DOT11RATE
1355fa20c234SSam Leffler }
1356fa20c234SSam Leffler 
13572d20d655SAdrian Chadd /*
13582d20d655SAdrian Chadd  * Fetch the statistics for the given node.
13592d20d655SAdrian Chadd  *
13602d20d655SAdrian Chadd  * The ieee80211 node must be referenced and unlocked, however the ath_node
13612d20d655SAdrian Chadd  * must be locked.
13622d20d655SAdrian Chadd  *
13632d20d655SAdrian Chadd  * The main difference here is that we convert the rate indexes
13642d20d655SAdrian Chadd  * to 802.11 rates, or the userland output won't make much sense
13652d20d655SAdrian Chadd  * as it has no access to the rix table.
13662d20d655SAdrian Chadd  */
13672d20d655SAdrian Chadd int
13682d20d655SAdrian Chadd ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
13692d20d655SAdrian Chadd     struct ath_rateioctl *rs)
13702d20d655SAdrian Chadd {
13712d20d655SAdrian Chadd 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
13722d20d655SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
13732d20d655SAdrian Chadd 	struct ath_rateioctl_tlv av;
1374be4f96a6SAdrian Chadd 	struct ath_rateioctl_rt *tv;
13752d20d655SAdrian Chadd 	int y;
1376be4f96a6SAdrian Chadd 	int o = 0;
13772d20d655SAdrian Chadd 
13782d20d655SAdrian Chadd 	ATH_NODE_LOCK_ASSERT(an);
13792d20d655SAdrian Chadd 
13802d20d655SAdrian Chadd 	/*
13812d20d655SAdrian Chadd 	 * Ensure there's enough space for the statistics.
13822d20d655SAdrian Chadd 	 */
13832d20d655SAdrian Chadd 	if (rs->len <
13842d20d655SAdrian Chadd 	    sizeof(struct ath_rateioctl_tlv) +
1385be4f96a6SAdrian Chadd 	    sizeof(struct ath_rateioctl_rt) +
1386be4f96a6SAdrian Chadd 	    sizeof(struct ath_rateioctl_tlv) +
1387be4f96a6SAdrian Chadd 	    sizeof(struct sample_node)) {
1388be4f96a6SAdrian Chadd 		device_printf(sc->sc_dev, "%s: len=%d, too short\n",
1389be4f96a6SAdrian Chadd 		    __func__,
1390be4f96a6SAdrian Chadd 		    rs->len);
13912d20d655SAdrian Chadd 		return (EINVAL);
1392be4f96a6SAdrian Chadd 	}
13932d20d655SAdrian Chadd 
13942d20d655SAdrian Chadd 	/*
13952d20d655SAdrian Chadd 	 * Take a temporary copy of the sample node state so we can
13962d20d655SAdrian Chadd 	 * modify it before we copy it.
13972d20d655SAdrian Chadd 	 */
1398be4f96a6SAdrian Chadd 	tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,
1399be4f96a6SAdrian Chadd 	    M_NOWAIT | M_ZERO);
1400be4f96a6SAdrian Chadd 	if (tv == NULL) {
14012d20d655SAdrian Chadd 		return (ENOMEM);
14022d20d655SAdrian Chadd 	}
14032d20d655SAdrian Chadd 
14042d20d655SAdrian Chadd 	/*
1405be4f96a6SAdrian Chadd 	 * Populate the rate table mapping TLV.
1406be4f96a6SAdrian Chadd 	 */
1407be4f96a6SAdrian Chadd 	tv->nentries = rt->rateCount;
1408be4f96a6SAdrian Chadd 	for (y = 0; y < rt->rateCount; y++) {
1409be4f96a6SAdrian Chadd 		tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;
1410be4f96a6SAdrian Chadd 		if (rt->info[y].phy == IEEE80211_T_HT)
1411be4f96a6SAdrian Chadd 			tv->ratecode[y] |= IEEE80211_RATE_MCS;
1412be4f96a6SAdrian Chadd 	}
1413be4f96a6SAdrian Chadd 
1414be4f96a6SAdrian Chadd 	o = 0;
1415be4f96a6SAdrian Chadd 	/*
1416be4f96a6SAdrian Chadd 	 * First TLV - rate code mapping
1417be4f96a6SAdrian Chadd 	 */
1418be4f96a6SAdrian Chadd 	av.tlv_id = ATH_RATE_TLV_RATETABLE;
1419be4f96a6SAdrian Chadd 	av.tlv_len = sizeof(struct ath_rateioctl_rt);
1420be4f96a6SAdrian Chadd 	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1421be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_tlv);
1422be4f96a6SAdrian Chadd 	copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));
1423be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_rt);
1424be4f96a6SAdrian Chadd 
1425be4f96a6SAdrian Chadd 	/*
1426be4f96a6SAdrian Chadd 	 * Second TLV - sample node statistics
14272d20d655SAdrian Chadd 	 */
14282d20d655SAdrian Chadd 	av.tlv_id = ATH_RATE_TLV_SAMPLENODE;
14292d20d655SAdrian Chadd 	av.tlv_len = sizeof(struct sample_node);
1430be4f96a6SAdrian Chadd 	copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
1431be4f96a6SAdrian Chadd 	o += sizeof(struct ath_rateioctl_tlv);
14322d20d655SAdrian Chadd 
14332d20d655SAdrian Chadd 	/*
14342d20d655SAdrian Chadd 	 * Copy the statistics over to the provided buffer.
14352d20d655SAdrian Chadd 	 */
1436be4f96a6SAdrian Chadd 	copyout(sn, rs->buf + o, sizeof(struct sample_node));
1437be4f96a6SAdrian Chadd 	o += sizeof(struct sample_node);
14382d20d655SAdrian Chadd 
1439be4f96a6SAdrian Chadd 	free(tv, M_TEMP);
14402d20d655SAdrian Chadd 
14412d20d655SAdrian Chadd 	return (0);
14422d20d655SAdrian Chadd }
14432d20d655SAdrian Chadd 
1444f0fd5e07SSam Leffler static void
1445c1565b61SSam Leffler sample_stats(void *arg, struct ieee80211_node *ni)
1446c1565b61SSam Leffler {
1447c1565b61SSam Leffler 	struct ath_softc *sc = arg;
1448c1565b61SSam Leffler 	const HAL_RATE_TABLE *rt = sc->sc_currates;
1449c1565b61SSam Leffler 	struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));
1450193bfa21SAdrian Chadd 	uint64_t mask;
1451c1565b61SSam Leffler 	int rix, y;
1452c1565b61SSam Leffler 
1453a055e7ceSKonstantin Belousov 	printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",
1454c1565b61SSam Leffler 	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
1455eb6f0de0SAdrian Chadd 	    dot11rate(rt, sn->static_rix),
1456eb6f0de0SAdrian Chadd 	    dot11rate_label(rt, sn->static_rix),
1457a055e7ceSKonstantin Belousov 	    (uintmax_t)sn->ratemask);
1458c1565b61SSam Leffler 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1459ae0944b8SAdrian Chadd 		printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",
1460c1565b61SSam Leffler 		    bin_to_size(y), sn->current_rix[y],
1461ae0944b8SAdrian Chadd 		    dot11rate(rt, sn->current_rix[y]),
1462ae0944b8SAdrian Chadd 		    dot11rate_label(rt, sn->current_rix[y]),
1463c1565b61SSam Leffler 		    sn->packets_since_switch[y], sn->ticks_since_switch[y]);
1464eb6f0de0SAdrian Chadd 		printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",
1465eb6f0de0SAdrian Chadd 		    bin_to_size(y),
1466eb6f0de0SAdrian Chadd 		    dot11rate(rt, sn->last_sample_rix[y]),
1467eb6f0de0SAdrian Chadd 		    dot11rate_label(rt, sn->last_sample_rix[y]),
1468eb6f0de0SAdrian Chadd 		    dot11rate(rt, sn->current_sample_rix[y]),
1469eb6f0de0SAdrian Chadd 		    dot11rate_label(rt, sn->current_sample_rix[y]),
1470eb6f0de0SAdrian Chadd 		    sn->packets_sent[y]);
1471c1565b61SSam Leffler 		printf("[%4u] packets since sample %d sample tt %u\n",
1472c1565b61SSam Leffler 		    bin_to_size(y), sn->packets_since_sample[y],
1473c1565b61SSam Leffler 		    sn->sample_tt[y]);
1474c1565b61SSam Leffler 	}
1475c1565b61SSam Leffler 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
1476c1565b61SSam Leffler 		if ((mask & 1) == 0)
1477c1565b61SSam Leffler 				continue;
1478c1565b61SSam Leffler 		for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1479c1565b61SSam Leffler 			if (sn->stats[y][rix].total_packets == 0)
1480c1565b61SSam Leffler 				continue;
1481eb6f0de0SAdrian Chadd 			printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",
1482ae0944b8SAdrian Chadd 			    dot11rate(rt, rix), dot11rate_label(rt, rix),
1483c1565b61SSam Leffler 			    bin_to_size(y),
148487acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].total_packets,
148587acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].packets_acked,
148687acb7d5SAdrian Chadd 			    (int) ((sn->stats[y][rix].packets_acked * 100ULL) /
148787acb7d5SAdrian Chadd 			     sn->stats[y][rix].total_packets),
1488eb6f0de0SAdrian Chadd 			    sn->stats[y][rix].ewma_pct / 10,
1489eb6f0de0SAdrian Chadd 			    sn->stats[y][rix].ewma_pct % 10,
149087acb7d5SAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].tries,
1491c1565b61SSam Leffler 			    sn->stats[y][rix].successive_failures,
1492c1565b61SSam Leffler 			    sn->stats[y][rix].average_tx_time,
1493c1565b61SSam Leffler 			    ticks - sn->stats[y][rix].last_tx);
1494c1565b61SSam Leffler 		}
1495c1565b61SSam Leffler 	}
1496c1565b61SSam Leffler }
1497c1565b61SSam Leffler 
1498c1565b61SSam Leffler static int
1499c1565b61SSam Leffler ath_rate_sysctl_stats(SYSCTL_HANDLER_ARGS)
1500c1565b61SSam Leffler {
1501c1565b61SSam Leffler 	struct ath_softc *sc = arg1;
15027a79cebfSGleb Smirnoff 	struct ieee80211com *ic = &sc->sc_ic;
1503c1565b61SSam Leffler 	int error, v;
1504c1565b61SSam Leffler 
1505c1565b61SSam Leffler 	v = 0;
1506c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &v, 0, req);
1507c1565b61SSam Leffler 	if (error || !req->newptr)
1508c1565b61SSam Leffler 		return error;
1509c1565b61SSam Leffler 	ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, sc);
1510c1565b61SSam Leffler 	return 0;
1511c1565b61SSam Leffler }
1512c1565b61SSam Leffler 
1513c1565b61SSam Leffler static int
1514c1565b61SSam Leffler ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)
1515c1565b61SSam Leffler {
1516c1565b61SSam Leffler 	struct sample_softc *ssc = arg1;
1517c1565b61SSam Leffler 	int rate, error;
1518c1565b61SSam Leffler 
1519c1565b61SSam Leffler 	rate = ssc->smoothing_rate;
1520c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &rate, 0, req);
1521c1565b61SSam Leffler 	if (error || !req->newptr)
1522c1565b61SSam Leffler 		return error;
1523c1565b61SSam Leffler 	if (!(0 <= rate && rate < 100))
1524c1565b61SSam Leffler 		return EINVAL;
1525c1565b61SSam Leffler 	ssc->smoothing_rate = rate;
1526c1565b61SSam Leffler 	ssc->smoothing_minpackets = 100 / (100 - rate);
1527c1565b61SSam Leffler 	return 0;
1528c1565b61SSam Leffler }
1529c1565b61SSam Leffler 
1530c1565b61SSam Leffler static int
1531c1565b61SSam Leffler ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
1532c1565b61SSam Leffler {
1533c1565b61SSam Leffler 	struct sample_softc *ssc = arg1;
1534c1565b61SSam Leffler 	int rate, error;
1535c1565b61SSam Leffler 
1536c1565b61SSam Leffler 	rate = ssc->sample_rate;
1537c1565b61SSam Leffler 	error = sysctl_handle_int(oidp, &rate, 0, req);
1538c1565b61SSam Leffler 	if (error || !req->newptr)
1539c1565b61SSam Leffler 		return error;
1540c1565b61SSam Leffler 	if (!(2 <= rate && rate <= 100))
1541c1565b61SSam Leffler 		return EINVAL;
1542c1565b61SSam Leffler 	ssc->sample_rate = rate;
1543c1565b61SSam Leffler 	return 0;
1544c1565b61SSam Leffler }
1545c1565b61SSam Leffler 
1546c1565b61SSam Leffler static void
1547c1565b61SSam Leffler ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc)
1548fa20c234SSam Leffler {
1549fa20c234SSam Leffler 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
1550fa20c234SSam Leffler 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
1551fa20c234SSam Leffler 
1552c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
155308f5e6bbSPawel Biernacki 	    "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
155408f5e6bbSPawel Biernacki 	    ssc, 0, ath_rate_sysctl_smoothing_rate, "I",
1555c1565b61SSam Leffler 	    "sample: smoothing rate for avg tx time (%%)");
1556c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
155708f5e6bbSPawel Biernacki 	    "sample_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
155808f5e6bbSPawel Biernacki 	    ssc, 0, ath_rate_sysctl_sample_rate, "I",
1559c1565b61SSam Leffler 	    "sample: percent air time devoted to sampling new rates (%%)");
1560c1565b61SSam Leffler 	/* XXX max_successive_failures, stale_failure_timeout, min_switch */
1561c1565b61SSam Leffler 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
156208f5e6bbSPawel Biernacki 	    "sample_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
156308f5e6bbSPawel Biernacki 	    sc, 0, ath_rate_sysctl_stats, "I", "sample: print statistics");
1564fa20c234SSam Leffler }
1565fa20c234SSam Leffler 
1566fa20c234SSam Leffler struct ath_ratectrl *
1567fa20c234SSam Leffler ath_rate_attach(struct ath_softc *sc)
1568fa20c234SSam Leffler {
1569c1565b61SSam Leffler 	struct sample_softc *ssc;
1570fa20c234SSam Leffler 
1571c1565b61SSam Leffler 	ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
1572c1565b61SSam Leffler 	if (ssc == NULL)
1573fa20c234SSam Leffler 		return NULL;
1574c1565b61SSam Leffler 	ssc->arc.arc_space = sizeof(struct sample_node);
1575e69db8dfSAdrian Chadd 	ssc->smoothing_rate = 75;		/* ewma percentage ([0..99]) */
1576c1565b61SSam Leffler 	ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);
1577c1565b61SSam Leffler 	ssc->sample_rate = 10;			/* %time to try diff tx rates */
1578c1565b61SSam Leffler 	ssc->max_successive_failures = 3;	/* threshold for rate sampling*/
1579c1565b61SSam Leffler 	ssc->stale_failure_timeout = 10 * hz;	/* 10 seconds */
1580c1565b61SSam Leffler 	ssc->min_switch = hz;			/* 1 second */
1581c1565b61SSam Leffler 	ath_rate_sysctlattach(sc, ssc);
1582c1565b61SSam Leffler 	return &ssc->arc;
1583fa20c234SSam Leffler }
1584fa20c234SSam Leffler 
1585fa20c234SSam Leffler void
1586fa20c234SSam Leffler ath_rate_detach(struct ath_ratectrl *arc)
1587fa20c234SSam Leffler {
1588c1565b61SSam Leffler 	struct sample_softc *ssc = (struct sample_softc *) arc;
1589fa20c234SSam Leffler 
1590c1565b61SSam Leffler 	free(ssc, M_DEVBUF);
1591fa20c234SSam Leffler }
1592