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