xref: /haiku/src/libs/compat/openbsd_wlan/net80211/ieee80211_ra_vht.c (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
1*04171cfcSAugustin Cavalier /*	$OpenBSD: ieee80211_ra_vht.c,v 1.3 2022/03/23 09:21:47 stsp Exp $	*/
2*04171cfcSAugustin Cavalier 
3*04171cfcSAugustin Cavalier /*
4*04171cfcSAugustin Cavalier  * Copyright (c) 2021 Christian Ehrhardt <ehrhardt@genua.de>
5*04171cfcSAugustin Cavalier  * Copyright (c) 2016, 2021, 2022 Stefan Sperling <stsp@openbsd.org>
6*04171cfcSAugustin Cavalier  * Copyright (c) 2016 Theo Buehler <tb@openbsd.org>
7*04171cfcSAugustin Cavalier  *
8*04171cfcSAugustin Cavalier  * Permission to use, copy, modify, and distribute this software for any
9*04171cfcSAugustin Cavalier  * purpose with or without fee is hereby granted, provided that the above
10*04171cfcSAugustin Cavalier  * copyright notice and this permission notice appear in all copies.
11*04171cfcSAugustin Cavalier  *
12*04171cfcSAugustin Cavalier  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13*04171cfcSAugustin Cavalier  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14*04171cfcSAugustin Cavalier  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15*04171cfcSAugustin Cavalier  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16*04171cfcSAugustin Cavalier  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17*04171cfcSAugustin Cavalier  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18*04171cfcSAugustin Cavalier  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19*04171cfcSAugustin Cavalier  */
20*04171cfcSAugustin Cavalier 
21*04171cfcSAugustin Cavalier #include <sys/param.h>
22*04171cfcSAugustin Cavalier #include <sys/systm.h>
23*04171cfcSAugustin Cavalier #include <sys/socket.h>
24*04171cfcSAugustin Cavalier 
25*04171cfcSAugustin Cavalier #include <net/if.h>
26*04171cfcSAugustin Cavalier #include <net/if_media.h>
27*04171cfcSAugustin Cavalier 
28*04171cfcSAugustin Cavalier #include <netinet/in.h>
29*04171cfcSAugustin Cavalier #include <netinet/if_ether.h>
30*04171cfcSAugustin Cavalier 
31*04171cfcSAugustin Cavalier #include <net80211/ieee80211_var.h>
32*04171cfcSAugustin Cavalier #include <net80211/ieee80211_ra_vht.h>
33*04171cfcSAugustin Cavalier 
34*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *,
35*04171cfcSAugustin Cavalier 	    struct ieee80211_node *);
36*04171cfcSAugustin Cavalier const struct ieee80211_vht_rateset * ieee80211_ra_vht_next_rateset(
37*04171cfcSAugustin Cavalier 		    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
38*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *,
39*04171cfcSAugustin Cavalier 	    const struct ieee80211_vht_rateset *);
40*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *,
41*04171cfcSAugustin Cavalier 	    struct ieee80211_node *, const struct ieee80211_vht_rateset *);
42*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *,
43*04171cfcSAugustin Cavalier 	    struct ieee80211_node *);
44*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *, int);
45*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_intra_mode_ra_finished(
46*04171cfcSAugustin Cavalier 	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
47*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *,
48*04171cfcSAugustin Cavalier 	    struct ieee80211_node *);
49*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_inter_mode_ra_finished(
50*04171cfcSAugustin Cavalier 	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
51*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *,
52*04171cfcSAugustin Cavalier 	    struct ieee80211_node *);
53*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *,
54*04171cfcSAugustin Cavalier 	    struct ieee80211_node *);
55*04171cfcSAugustin Cavalier void	ieee80211_ra_vht_init_valid_rates(struct ieee80211com *,
56*04171cfcSAugustin Cavalier 	    struct ieee80211_node *, struct ieee80211_ra_vht_node *);
57*04171cfcSAugustin Cavalier int	ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *);
58*04171cfcSAugustin Cavalier 
59*04171cfcSAugustin Cavalier /* We use fixed point arithmetic with 64 bit integers. */
60*04171cfcSAugustin Cavalier #define RA_FP_SHIFT	21
61*04171cfcSAugustin Cavalier #define RA_FP_INT(x)	(x ## ULL << RA_FP_SHIFT) /* the integer x */
62*04171cfcSAugustin Cavalier #define RA_FP_1	RA_FP_INT(1)
63*04171cfcSAugustin Cavalier 
64*04171cfcSAugustin Cavalier /* Multiply two fixed point numbers. */
65*04171cfcSAugustin Cavalier #define RA_FP_MUL(a, b) \
66*04171cfcSAugustin Cavalier 	(((a) * (b)) >> RA_FP_SHIFT)
67*04171cfcSAugustin Cavalier 
68*04171cfcSAugustin Cavalier /* Divide two fixed point numbers. */
69*04171cfcSAugustin Cavalier #define RA_FP_DIV(a, b) \
70*04171cfcSAugustin Cavalier 	(b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b)))
71*04171cfcSAugustin Cavalier 
72*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
73*04171cfcSAugustin Cavalier #define DPRINTF(x)	do { if (ra_vht_debug > 0) printf x; } while (0)
74*04171cfcSAugustin Cavalier #define DPRINTFN(n, x)	do { if (ra_vht_debug >= (n)) printf x; } while (0)
75*04171cfcSAugustin Cavalier int ra_vht_debug = 0;
76*04171cfcSAugustin Cavalier #else
77*04171cfcSAugustin Cavalier #define DPRINTF(x)	do { ; } while (0)
78*04171cfcSAugustin Cavalier #define DPRINTFN(n, x)	do { ; } while (0)
79*04171cfcSAugustin Cavalier #endif
80*04171cfcSAugustin Cavalier 
81*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
82*04171cfcSAugustin Cavalier void
ra_vht_fixedp_split(uint32_t * i,uint32_t * f,uint64_t fp)83*04171cfcSAugustin Cavalier ra_vht_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp)
84*04171cfcSAugustin Cavalier {
85*04171cfcSAugustin Cavalier 	uint64_t tmp;
86*04171cfcSAugustin Cavalier 
87*04171cfcSAugustin Cavalier 	/* integer part */
88*04171cfcSAugustin Cavalier 	*i = (fp >> RA_FP_SHIFT);
89*04171cfcSAugustin Cavalier 
90*04171cfcSAugustin Cavalier  	/* fractional part */
91*04171cfcSAugustin Cavalier 	tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT)));
92*04171cfcSAugustin Cavalier 	tmp *= 100;
93*04171cfcSAugustin Cavalier 	*f = (uint32_t)(tmp >> RA_FP_SHIFT);
94*04171cfcSAugustin Cavalier }
95*04171cfcSAugustin Cavalier 
96*04171cfcSAugustin Cavalier char *
ra_vht_fp_sprintf(uint64_t fp)97*04171cfcSAugustin Cavalier ra_vht_fp_sprintf(uint64_t fp)
98*04171cfcSAugustin Cavalier {
99*04171cfcSAugustin Cavalier 	uint32_t i, f;
100*04171cfcSAugustin Cavalier 	static char buf[64];
101*04171cfcSAugustin Cavalier 	int ret;
102*04171cfcSAugustin Cavalier 
103*04171cfcSAugustin Cavalier 	ra_vht_fixedp_split(&i, &f, fp);
104*04171cfcSAugustin Cavalier 	ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f);
105*04171cfcSAugustin Cavalier 	if (ret == -1 || ret >= sizeof(buf))
106*04171cfcSAugustin Cavalier 		return "ERR";
107*04171cfcSAugustin Cavalier 
108*04171cfcSAugustin Cavalier 	return buf;
109*04171cfcSAugustin Cavalier }
110*04171cfcSAugustin Cavalier #endif /* RA_DEBUG */
111*04171cfcSAugustin Cavalier 
112*04171cfcSAugustin Cavalier const struct ieee80211_vht_rateset *
ieee80211_ra_vht_get_rateset(int mcs,int nss,int chan40,int chan80,int sgi)113*04171cfcSAugustin Cavalier ieee80211_ra_vht_get_rateset(int mcs, int nss, int chan40, int chan80, int sgi)
114*04171cfcSAugustin Cavalier {
115*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
116*04171cfcSAugustin Cavalier 	int i;
117*04171cfcSAugustin Cavalier 
118*04171cfcSAugustin Cavalier 	for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
119*04171cfcSAugustin Cavalier 		rs = &ieee80211_std_ratesets_11ac[i];
120*04171cfcSAugustin Cavalier 		if (mcs < rs->nrates && rs->num_ss == nss &&
121*04171cfcSAugustin Cavalier 		    chan40 == rs->chan40 && chan80 == rs->chan80 &&
122*04171cfcSAugustin Cavalier 		    sgi == rs->sgi)
123*04171cfcSAugustin Cavalier 			return rs;
124*04171cfcSAugustin Cavalier 	}
125*04171cfcSAugustin Cavalier 
126*04171cfcSAugustin Cavalier 	panic("MCS %d NSS %d is not part of any rateset", mcs, nss);
127*04171cfcSAugustin Cavalier }
128*04171cfcSAugustin Cavalier 
129*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_use_sgi(struct ieee80211_node * ni)130*04171cfcSAugustin Cavalier ieee80211_ra_vht_use_sgi(struct ieee80211_node *ni)
131*04171cfcSAugustin Cavalier {
132*04171cfcSAugustin Cavalier 	if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_160MHZ) &&
133*04171cfcSAugustin Cavalier 	    ieee80211_node_supports_vht_chan160(ni)) {
134*04171cfcSAugustin Cavalier 		if (ni->ni_flags & IEEE80211_NODE_VHT_SGI160)
135*04171cfcSAugustin Cavalier 			return 1;
136*04171cfcSAugustin Cavalier 	}
137*04171cfcSAugustin Cavalier 
138*04171cfcSAugustin Cavalier 	if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_80MHZ) &&
139*04171cfcSAugustin Cavalier 	    ieee80211_node_supports_vht_chan80(ni)) {
140*04171cfcSAugustin Cavalier 		if (ni->ni_flags & IEEE80211_NODE_VHT_SGI80)
141*04171cfcSAugustin Cavalier 			return 1;
142*04171cfcSAugustin Cavalier 	}
143*04171cfcSAugustin Cavalier 
144*04171cfcSAugustin Cavalier 	return 0;
145*04171cfcSAugustin Cavalier }
146*04171cfcSAugustin Cavalier 
147*04171cfcSAugustin Cavalier /*
148*04171cfcSAugustin Cavalier  * Update goodput statistics.
149*04171cfcSAugustin Cavalier  */
150*04171cfcSAugustin Cavalier 
151*04171cfcSAugustin Cavalier uint64_t
ieee80211_ra_vht_get_txrate(int mcs,int nss,int chan40,int chan80,int sgi)152*04171cfcSAugustin Cavalier ieee80211_ra_vht_get_txrate(int mcs, int nss, int chan40, int chan80, int sgi)
153*04171cfcSAugustin Cavalier {
154*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
155*04171cfcSAugustin Cavalier 	uint64_t txrate;
156*04171cfcSAugustin Cavalier 
157*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, chan40, chan80, sgi);
158*04171cfcSAugustin Cavalier 	txrate = rs->rates[mcs];
159*04171cfcSAugustin Cavalier 	txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
160*04171cfcSAugustin Cavalier 	txrate *= 500; /* convert to kbit/s */
161*04171cfcSAugustin Cavalier 	txrate /= 1000; /* convert to mbit/s */
162*04171cfcSAugustin Cavalier 
163*04171cfcSAugustin Cavalier 	return txrate;
164*04171cfcSAugustin Cavalier }
165*04171cfcSAugustin Cavalier 
166*04171cfcSAugustin Cavalier /*
167*04171cfcSAugustin Cavalier  * Rate selection.
168*04171cfcSAugustin Cavalier  */
169*04171cfcSAugustin Cavalier 
170*04171cfcSAugustin Cavalier /* A rate's goodput has to be at least this much larger to be "better". */
171*04171cfcSAugustin Cavalier #define IEEE80211_RA_RATE_THRESHOLD	(RA_FP_1 / 64) /* ~ 0.015 */
172*04171cfcSAugustin Cavalier 
173*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_next_lower_intra_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)174*04171cfcSAugustin Cavalier ieee80211_ra_vht_next_lower_intra_rate(struct ieee80211_ra_vht_node *rn,
175*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
176*04171cfcSAugustin Cavalier {
177*04171cfcSAugustin Cavalier 	if (ni->ni_txmcs <= 0)
178*04171cfcSAugustin Cavalier 		return 0;
179*04171cfcSAugustin Cavalier 
180*04171cfcSAugustin Cavalier 	return ni->ni_txmcs - 1;
181*04171cfcSAugustin Cavalier }
182*04171cfcSAugustin Cavalier 
183*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_get_max_mcs(int vht_mcs,int nss,int chan40)184*04171cfcSAugustin Cavalier ieee80211_ra_vht_get_max_mcs(int vht_mcs, int nss, int chan40)
185*04171cfcSAugustin Cavalier {
186*04171cfcSAugustin Cavalier 	int supp_mcs = (vht_mcs & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >>
187*04171cfcSAugustin Cavalier 	    IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss);
188*04171cfcSAugustin Cavalier 	int max_mcs = -1;
189*04171cfcSAugustin Cavalier 
190*04171cfcSAugustin Cavalier 	switch (supp_mcs) {
191*04171cfcSAugustin Cavalier 	case IEEE80211_VHT_MCS_SS_NOT_SUPP:
192*04171cfcSAugustin Cavalier 		break;
193*04171cfcSAugustin Cavalier 	case IEEE80211_VHT_MCS_0_7:
194*04171cfcSAugustin Cavalier 		max_mcs = 7;
195*04171cfcSAugustin Cavalier 		break;
196*04171cfcSAugustin Cavalier 	case IEEE80211_VHT_MCS_0_8:
197*04171cfcSAugustin Cavalier 		max_mcs = 8;
198*04171cfcSAugustin Cavalier 		break;
199*04171cfcSAugustin Cavalier 	case IEEE80211_VHT_MCS_0_9:
200*04171cfcSAugustin Cavalier 		/* Disable VHT MCS 9 for 20MHz-only stations. */
201*04171cfcSAugustin Cavalier 		if (!chan40)
202*04171cfcSAugustin Cavalier 			max_mcs = 8;
203*04171cfcSAugustin Cavalier 		else
204*04171cfcSAugustin Cavalier 			max_mcs = 9;
205*04171cfcSAugustin Cavalier 		break;
206*04171cfcSAugustin Cavalier 	default:
207*04171cfcSAugustin Cavalier 		/* Should not happen; Values above cover the possible range. */
208*04171cfcSAugustin Cavalier 		panic("invalid VHT Rx MCS value %u", supp_mcs);
209*04171cfcSAugustin Cavalier 	}
210*04171cfcSAugustin Cavalier 
211*04171cfcSAugustin Cavalier 	return max_mcs;
212*04171cfcSAugustin Cavalier }
213*04171cfcSAugustin Cavalier 
214*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)215*04171cfcSAugustin Cavalier ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *rn,
216*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
217*04171cfcSAugustin Cavalier {
218*04171cfcSAugustin Cavalier 	int max_mcs;
219*04171cfcSAugustin Cavalier 
220*04171cfcSAugustin Cavalier 	max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs,
221*04171cfcSAugustin Cavalier 	    ni->ni_vht_ss, ieee80211_node_supports_ht_chan40(ni));
222*04171cfcSAugustin Cavalier 	if (max_mcs != 7 && max_mcs != 8 && max_mcs != 9)
223*04171cfcSAugustin Cavalier 		panic("ni->ni_vht_ss invalid: %u", ni->ni_vht_ss);
224*04171cfcSAugustin Cavalier 
225*04171cfcSAugustin Cavalier 	if (ni->ni_txmcs >= max_mcs)
226*04171cfcSAugustin Cavalier 		return max_mcs;
227*04171cfcSAugustin Cavalier 
228*04171cfcSAugustin Cavalier 	return ni->ni_txmcs + 1;
229*04171cfcSAugustin Cavalier }
230*04171cfcSAugustin Cavalier 
231*04171cfcSAugustin Cavalier const struct ieee80211_vht_rateset *
ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)232*04171cfcSAugustin Cavalier ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node *rn,
233*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
234*04171cfcSAugustin Cavalier {
235*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs, *rsnext;
236*04171cfcSAugustin Cavalier 	int next;
237*04171cfcSAugustin Cavalier 	int sgi = ieee80211_ra_vht_use_sgi(ni);
238*04171cfcSAugustin Cavalier 	int mcs = ni->ni_txmcs;
239*04171cfcSAugustin Cavalier 	int nss = ni->ni_vht_ss;
240*04171cfcSAugustin Cavalier 
241*04171cfcSAugustin Cavalier 	/*
242*04171cfcSAugustin Cavalier 	 * We only probe 80MHz ratesets.
243*04171cfcSAugustin Cavalier 	 * Drivers handle retries on slower rates if needed.
244*04171cfcSAugustin Cavalier 	 */
245*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1, sgi);
246*04171cfcSAugustin Cavalier 	if (rn->probing & IEEE80211_RA_PROBING_UP) {
247*04171cfcSAugustin Cavalier 		switch (rs->idx) {
248*04171cfcSAugustin Cavalier 		case IEEE80211_VHT_RATESET_SISO_80:
249*04171cfcSAugustin Cavalier 			next = IEEE80211_VHT_RATESET_MIMO2_80;
250*04171cfcSAugustin Cavalier 			break;
251*04171cfcSAugustin Cavalier 		case IEEE80211_VHT_RATESET_SISO_80_SGI:
252*04171cfcSAugustin Cavalier 			next = IEEE80211_VHT_RATESET_MIMO2_80_SGI;
253*04171cfcSAugustin Cavalier 			break;
254*04171cfcSAugustin Cavalier 		default:
255*04171cfcSAugustin Cavalier 			return NULL;
256*04171cfcSAugustin Cavalier 		}
257*04171cfcSAugustin Cavalier 	} else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
258*04171cfcSAugustin Cavalier 		switch (rs->idx) {
259*04171cfcSAugustin Cavalier 		case IEEE80211_VHT_RATESET_MIMO2_80:
260*04171cfcSAugustin Cavalier 			next = IEEE80211_VHT_RATESET_SISO_80;
261*04171cfcSAugustin Cavalier 			break;
262*04171cfcSAugustin Cavalier 		case IEEE80211_VHT_RATESET_MIMO2_80_SGI:
263*04171cfcSAugustin Cavalier 			next = IEEE80211_VHT_RATESET_SISO_80_SGI;
264*04171cfcSAugustin Cavalier 			break;
265*04171cfcSAugustin Cavalier 		default:
266*04171cfcSAugustin Cavalier 			return NULL;
267*04171cfcSAugustin Cavalier 		}
268*04171cfcSAugustin Cavalier 	} else
269*04171cfcSAugustin Cavalier 		panic("%s: invalid probing mode %d", __func__, rn->probing);
270*04171cfcSAugustin Cavalier 
271*04171cfcSAugustin Cavalier 	rsnext = &ieee80211_std_ratesets_11ac[next];
272*04171cfcSAugustin Cavalier 	if (rn->valid_rates[rsnext->num_ss - 1] == 0)
273*04171cfcSAugustin Cavalier 		return NULL;
274*04171cfcSAugustin Cavalier 
275*04171cfcSAugustin Cavalier 	return rsnext;
276*04171cfcSAugustin Cavalier }
277*04171cfcSAugustin Cavalier 
278*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node * rn,const struct ieee80211_vht_rateset * rs)279*04171cfcSAugustin Cavalier ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *rn,
280*04171cfcSAugustin Cavalier     const struct ieee80211_vht_rateset *rs)
281*04171cfcSAugustin Cavalier {
282*04171cfcSAugustin Cavalier 	uint64_t gmax = 0;
283*04171cfcSAugustin Cavalier 	int mcs, best_mcs = 0;
284*04171cfcSAugustin Cavalier 
285*04171cfcSAugustin Cavalier 	for (mcs = 0; mcs < rs->nrates; mcs++) {
286*04171cfcSAugustin Cavalier 		struct ieee80211_ra_vht_goodput_stats *g = &rn->g[rs->idx][mcs];
287*04171cfcSAugustin Cavalier 		if (((1 << mcs) & rn->valid_rates[rs->num_ss - 1]) == 0)
288*04171cfcSAugustin Cavalier 			continue;
289*04171cfcSAugustin Cavalier 		if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
290*04171cfcSAugustin Cavalier 			gmax = g->measured;
291*04171cfcSAugustin Cavalier 			best_mcs = mcs;
292*04171cfcSAugustin Cavalier 		}
293*04171cfcSAugustin Cavalier 	}
294*04171cfcSAugustin Cavalier 
295*04171cfcSAugustin Cavalier 	return best_mcs;
296*04171cfcSAugustin Cavalier }
297*04171cfcSAugustin Cavalier 
298*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni,const struct ieee80211_vht_rateset * rsnext)299*04171cfcSAugustin Cavalier ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *rn,
300*04171cfcSAugustin Cavalier     struct ieee80211_node *ni, const struct ieee80211_vht_rateset *rsnext)
301*04171cfcSAugustin Cavalier {
302*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
303*04171cfcSAugustin Cavalier 	struct ieee80211_ra_vht_goodput_stats *g;
304*04171cfcSAugustin Cavalier 	int best_mcs, mcs;
305*04171cfcSAugustin Cavalier 
306*04171cfcSAugustin Cavalier 	/* Find most recently measured best MCS from the current rateset. */
307*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, ni->ni_vht_ss, 0, 1,
308*04171cfcSAugustin Cavalier 	    ieee80211_ra_vht_use_sgi(ni));
309*04171cfcSAugustin Cavalier 	best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs);
310*04171cfcSAugustin Cavalier 
311*04171cfcSAugustin Cavalier 	/* Switch to the next rateset. */
312*04171cfcSAugustin Cavalier 	ni->ni_txmcs = 0;
313*04171cfcSAugustin Cavalier 	ni->ni_vht_ss = rsnext->num_ss;
314*04171cfcSAugustin Cavalier 
315*04171cfcSAugustin Cavalier 	/* Select the lowest rate from the next rateset with loss-free
316*04171cfcSAugustin Cavalier 	 * goodput close to the current best measurement. */
317*04171cfcSAugustin Cavalier 	g = &rn->g[rs->idx][best_mcs];
318*04171cfcSAugustin Cavalier 	for (mcs = 0; mcs < rsnext->nrates; mcs++) {
319*04171cfcSAugustin Cavalier 		uint64_t txrate = rsnext->rates[mcs];
320*04171cfcSAugustin Cavalier 
321*04171cfcSAugustin Cavalier 		if ((rn->valid_rates[rsnext->num_ss - 1] & (1 << mcs)) == 0)
322*04171cfcSAugustin Cavalier 			continue;
323*04171cfcSAugustin Cavalier 
324*04171cfcSAugustin Cavalier 		txrate = txrate * 500; /* convert to kbit/s */
325*04171cfcSAugustin Cavalier 		txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
326*04171cfcSAugustin Cavalier 		txrate /= 1000; /* convert to mbit/s */
327*04171cfcSAugustin Cavalier 
328*04171cfcSAugustin Cavalier 		if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) {
329*04171cfcSAugustin Cavalier 			ni->ni_txmcs = mcs;
330*04171cfcSAugustin Cavalier 			break;
331*04171cfcSAugustin Cavalier 		}
332*04171cfcSAugustin Cavalier 	}
333*04171cfcSAugustin Cavalier 	/* If all rates are lower then the best rate is the closest match. */
334*04171cfcSAugustin Cavalier 	if (mcs == rsnext->nrates)
335*04171cfcSAugustin Cavalier 		ni->ni_txmcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rsnext);
336*04171cfcSAugustin Cavalier 
337*04171cfcSAugustin Cavalier 	/* Add rates from the next rateset as candidates. */
338*04171cfcSAugustin Cavalier 	rn->candidate_rates[rsnext->num_ss - 1] |= (1 << ni->ni_txmcs);
339*04171cfcSAugustin Cavalier 	if (rn->probing & IEEE80211_RA_PROBING_UP) {
340*04171cfcSAugustin Cavalier 		rn->candidate_rates[rsnext->num_ss - 1] |=
341*04171cfcSAugustin Cavalier 		  (1 << ieee80211_ra_vht_next_intra_rate(rn, ni));
342*04171cfcSAugustin Cavalier 	} else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
343*04171cfcSAugustin Cavalier 		rn->candidate_rates[rsnext->num_ss - 1] |=
344*04171cfcSAugustin Cavalier 		    (1 << ieee80211_ra_vht_next_lower_intra_rate(rn, ni));
345*04171cfcSAugustin Cavalier 	} else
346*04171cfcSAugustin Cavalier 		panic("%s: invalid probing mode %d", __func__, rn->probing);
347*04171cfcSAugustin Cavalier }
348*04171cfcSAugustin Cavalier 
349*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)350*04171cfcSAugustin Cavalier ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *rn,
351*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
352*04171cfcSAugustin Cavalier {
353*04171cfcSAugustin Cavalier 	int next;
354*04171cfcSAugustin Cavalier 
355*04171cfcSAugustin Cavalier 	if (rn->probing & IEEE80211_RA_PROBING_DOWN)
356*04171cfcSAugustin Cavalier 		next = ieee80211_ra_vht_next_lower_intra_rate(rn, ni);
357*04171cfcSAugustin Cavalier 	else if (rn->probing & IEEE80211_RA_PROBING_UP)
358*04171cfcSAugustin Cavalier 		next = ieee80211_ra_vht_next_intra_rate(rn, ni);
359*04171cfcSAugustin Cavalier 	else
360*04171cfcSAugustin Cavalier 		panic("%s: invalid probing mode %d", __func__, rn->probing);
361*04171cfcSAugustin Cavalier 
362*04171cfcSAugustin Cavalier 	return next;
363*04171cfcSAugustin Cavalier }
364*04171cfcSAugustin Cavalier 
365*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats * g)366*04171cfcSAugustin Cavalier ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats *g)
367*04171cfcSAugustin Cavalier {
368*04171cfcSAugustin Cavalier 	g->nprobe_pkts = 0;
369*04171cfcSAugustin Cavalier 	g->nprobe_fail = 0;
370*04171cfcSAugustin Cavalier }
371*04171cfcSAugustin Cavalier 
372*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node * rn,int nss)373*04171cfcSAugustin Cavalier ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *rn, int nss)
374*04171cfcSAugustin Cavalier {
375*04171cfcSAugustin Cavalier 	rn->probing = IEEE80211_RA_NOT_PROBING;
376*04171cfcSAugustin Cavalier 	rn->probed_rates[nss - 1] = 0;
377*04171cfcSAugustin Cavalier 	rn->valid_probes[nss - 1] = 0;
378*04171cfcSAugustin Cavalier 	rn->candidate_rates[nss - 1] = 0;
379*04171cfcSAugustin Cavalier }
380*04171cfcSAugustin Cavalier 
381*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_intra_mode_ra_finished(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)382*04171cfcSAugustin Cavalier ieee80211_ra_vht_intra_mode_ra_finished(struct ieee80211_ra_vht_node *rn,
383*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
384*04171cfcSAugustin Cavalier {
385*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
386*04171cfcSAugustin Cavalier 	struct ieee80211_ra_vht_goodput_stats *g;
387*04171cfcSAugustin Cavalier 	int next_mcs, best_mcs;
388*04171cfcSAugustin Cavalier 	uint64_t next_rate;
389*04171cfcSAugustin Cavalier 	int nss = ni->ni_vht_ss;
390*04171cfcSAugustin Cavalier 	int sgi = ieee80211_ra_vht_use_sgi(ni);
391*04171cfcSAugustin Cavalier 
392*04171cfcSAugustin Cavalier 	rn->probed_rates[nss - 1] = (rn->probed_rates[nss - 1] |
393*04171cfcSAugustin Cavalier 	    (1 << ni->ni_txmcs));
394*04171cfcSAugustin Cavalier 
395*04171cfcSAugustin Cavalier 	/* Check if the min/max MCS in this rateset has been probed. */
396*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
397*04171cfcSAugustin Cavalier 	if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
398*04171cfcSAugustin Cavalier 		if (ni->ni_txmcs == 0 ||
399*04171cfcSAugustin Cavalier 		    rn->probed_rates[nss - 1] & (1 << 0)) {
400*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
401*04171cfcSAugustin Cavalier 			return 1;
402*04171cfcSAugustin Cavalier 		}
403*04171cfcSAugustin Cavalier 	} else if (rn->probing & IEEE80211_RA_PROBING_UP) {
404*04171cfcSAugustin Cavalier 		if (ni->ni_txmcs == rn->max_mcs[nss - 1] ||
405*04171cfcSAugustin Cavalier 		    rn->probed_rates[nss - 1] & (1 << rn->max_mcs[nss - 1])) {
406*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
407*04171cfcSAugustin Cavalier 			return 1;
408*04171cfcSAugustin Cavalier 		}
409*04171cfcSAugustin Cavalier 	}
410*04171cfcSAugustin Cavalier 
411*04171cfcSAugustin Cavalier 	/*
412*04171cfcSAugustin Cavalier 	 * Check if the measured goodput is loss-free and better than the
413*04171cfcSAugustin Cavalier 	 * loss-free goodput of the candidate rate.
414*04171cfcSAugustin Cavalier 	 */
415*04171cfcSAugustin Cavalier 	next_mcs = ieee80211_ra_vht_next_mcs(rn, ni);
416*04171cfcSAugustin Cavalier 	if (next_mcs == ni->ni_txmcs) {
417*04171cfcSAugustin Cavalier 		ieee80211_ra_vht_trigger_next_rateset(rn, ni);
418*04171cfcSAugustin Cavalier 		return 1;
419*04171cfcSAugustin Cavalier 	}
420*04171cfcSAugustin Cavalier 	next_rate = ieee80211_ra_vht_get_txrate(next_mcs, nss, 0, 1, sgi);
421*04171cfcSAugustin Cavalier 	g = &rn->g[rs->idx][ni->ni_txmcs];
422*04171cfcSAugustin Cavalier 	if (g->loss == 0 &&
423*04171cfcSAugustin Cavalier 	    g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) {
424*04171cfcSAugustin Cavalier 		ieee80211_ra_vht_trigger_next_rateset(rn, ni);
425*04171cfcSAugustin Cavalier 		return 1;
426*04171cfcSAugustin Cavalier 	}
427*04171cfcSAugustin Cavalier 
428*04171cfcSAugustin Cavalier 	/* Check if we had a better measurement at a previously probed MCS. */
429*04171cfcSAugustin Cavalier 	best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs);
430*04171cfcSAugustin Cavalier 	if (best_mcs != ni->ni_txmcs) {
431*04171cfcSAugustin Cavalier 		if ((rn->probing & IEEE80211_RA_PROBING_UP) &&
432*04171cfcSAugustin Cavalier 		    best_mcs < ni->ni_txmcs) {
433*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
434*04171cfcSAugustin Cavalier 			return 1;
435*04171cfcSAugustin Cavalier 		}
436*04171cfcSAugustin Cavalier 		if ((rn->probing & IEEE80211_RA_PROBING_DOWN) &&
437*04171cfcSAugustin Cavalier 		    best_mcs > ni->ni_txmcs) {
438*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
439*04171cfcSAugustin Cavalier 			return 1;
440*04171cfcSAugustin Cavalier 		}
441*04171cfcSAugustin Cavalier 	}
442*04171cfcSAugustin Cavalier 
443*04171cfcSAugustin Cavalier 	/* Check if all rates in the set of candidate rates have been probed. */
444*04171cfcSAugustin Cavalier 	if ((rn->candidate_rates[nss - 1] & rn->probed_rates[nss - 1]) ==
445*04171cfcSAugustin Cavalier 	    rn->candidate_rates[nss - 1]) {
446*04171cfcSAugustin Cavalier 		/* Remain in the current rateset until above checks trigger. */
447*04171cfcSAugustin Cavalier 		rn->probing &= ~IEEE80211_RA_PROBING_INTER;
448*04171cfcSAugustin Cavalier 		return 1;
449*04171cfcSAugustin Cavalier 	}
450*04171cfcSAugustin Cavalier 
451*04171cfcSAugustin Cavalier 	return 0;
452*04171cfcSAugustin Cavalier }
453*04171cfcSAugustin Cavalier 
454*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)455*04171cfcSAugustin Cavalier ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *rn,
456*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
457*04171cfcSAugustin Cavalier {
458*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rsnext;
459*04171cfcSAugustin Cavalier 
460*04171cfcSAugustin Cavalier 	rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
461*04171cfcSAugustin Cavalier 	if (rsnext) {
462*04171cfcSAugustin Cavalier 		ieee80211_ra_vht_probe_next_rateset(rn, ni, rsnext);
463*04171cfcSAugustin Cavalier 		rn->probing |= IEEE80211_RA_PROBING_INTER;
464*04171cfcSAugustin Cavalier 	} else
465*04171cfcSAugustin Cavalier 		rn->probing &= ~IEEE80211_RA_PROBING_INTER;
466*04171cfcSAugustin Cavalier }
467*04171cfcSAugustin Cavalier 
468*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_inter_mode_ra_finished(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)469*04171cfcSAugustin Cavalier ieee80211_ra_vht_inter_mode_ra_finished(struct ieee80211_ra_vht_node *rn,
470*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
471*04171cfcSAugustin Cavalier {
472*04171cfcSAugustin Cavalier 	return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0);
473*04171cfcSAugustin Cavalier }
474*04171cfcSAugustin Cavalier 
475*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)476*04171cfcSAugustin Cavalier ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *rn,
477*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
478*04171cfcSAugustin Cavalier {
479*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
480*04171cfcSAugustin Cavalier 	int i, j, best_mcs = rn->best_mcs, best_nss = rn->best_nss;
481*04171cfcSAugustin Cavalier 	uint64_t gmax;
482*04171cfcSAugustin Cavalier 
483*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(best_mcs, best_nss, 0, 1,
484*04171cfcSAugustin Cavalier 	    ieee80211_ra_vht_use_sgi(ni));
485*04171cfcSAugustin Cavalier 	gmax = rn->g[rs->idx][best_mcs].measured;
486*04171cfcSAugustin Cavalier 
487*04171cfcSAugustin Cavalier 	for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
488*04171cfcSAugustin Cavalier 		rs = &ieee80211_std_ratesets_11ac[i];
489*04171cfcSAugustin Cavalier 		for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) {
490*04171cfcSAugustin Cavalier 			struct ieee80211_ra_vht_goodput_stats *g = &rn->g[i][j];
491*04171cfcSAugustin Cavalier 			if (((1 << i) & rn->valid_rates[rs->num_ss - 1]) == 0)
492*04171cfcSAugustin Cavalier 				continue;
493*04171cfcSAugustin Cavalier 			if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
494*04171cfcSAugustin Cavalier 				gmax = g->measured;
495*04171cfcSAugustin Cavalier 				best_mcs = j;
496*04171cfcSAugustin Cavalier 				best_nss = rs->num_ss;
497*04171cfcSAugustin Cavalier 			}
498*04171cfcSAugustin Cavalier 		}
499*04171cfcSAugustin Cavalier 	}
500*04171cfcSAugustin Cavalier 
501*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
502*04171cfcSAugustin Cavalier 	if (rn->best_mcs != best_mcs || rn->best_nss != best_nss) {
503*04171cfcSAugustin Cavalier 		DPRINTF(("MCS,NSS %d,%d is best; MCS,NSS{cur|avg|loss}:",
504*04171cfcSAugustin Cavalier 		    best_mcs, best_nss));
505*04171cfcSAugustin Cavalier 		for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
506*04171cfcSAugustin Cavalier 			rs = &ieee80211_std_ratesets_11ac[i];
507*04171cfcSAugustin Cavalier 			if (rs->chan80 == 0 ||
508*04171cfcSAugustin Cavalier 			    rs->sgi != ieee80211_ra_vht_use_sgi(ni))
509*04171cfcSAugustin Cavalier 				continue;
510*04171cfcSAugustin Cavalier 			for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) {
511*04171cfcSAugustin Cavalier 				struct ieee80211_ra_vht_goodput_stats *g;
512*04171cfcSAugustin Cavalier 				g = &rn->g[i][j];
513*04171cfcSAugustin Cavalier 				if ((rn->valid_rates[rs->num_ss - 1] &
514*04171cfcSAugustin Cavalier 				    (1 << j)) == 0)
515*04171cfcSAugustin Cavalier 					continue;
516*04171cfcSAugustin Cavalier 				DPRINTF((" %d,%d{%s|", j, rs->num_ss,
517*04171cfcSAugustin Cavalier 				    ra_vht_fp_sprintf(g->measured)));
518*04171cfcSAugustin Cavalier 				DPRINTF(("%s|", ra_vht_fp_sprintf(g->average)));
519*04171cfcSAugustin Cavalier 				DPRINTF(("%s%%}", ra_vht_fp_sprintf(g->loss)));
520*04171cfcSAugustin Cavalier 			}
521*04171cfcSAugustin Cavalier 		}
522*04171cfcSAugustin Cavalier 		DPRINTF(("\n"));
523*04171cfcSAugustin Cavalier 	}
524*04171cfcSAugustin Cavalier #endif
525*04171cfcSAugustin Cavalier 	rn->best_mcs = best_mcs;
526*04171cfcSAugustin Cavalier 	rn->best_nss = best_nss;
527*04171cfcSAugustin Cavalier }
528*04171cfcSAugustin Cavalier 
529*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)530*04171cfcSAugustin Cavalier ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *rn,
531*04171cfcSAugustin Cavalier     struct ieee80211_node *ni)
532*04171cfcSAugustin Cavalier {
533*04171cfcSAugustin Cavalier 	/* Select the next rate to probe. */
534*04171cfcSAugustin Cavalier 	rn->probed_rates[ni->ni_vht_ss - 1] |= (1 << ni->ni_txmcs);
535*04171cfcSAugustin Cavalier 	ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
536*04171cfcSAugustin Cavalier }
537*04171cfcSAugustin Cavalier 
538*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_init_valid_rates(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_ra_vht_node * rn)539*04171cfcSAugustin Cavalier ieee80211_ra_vht_init_valid_rates(struct ieee80211com *ic,
540*04171cfcSAugustin Cavalier     struct ieee80211_node *ni, struct ieee80211_ra_vht_node *rn)
541*04171cfcSAugustin Cavalier {
542*04171cfcSAugustin Cavalier 	int nss, ic_max_mcs, ni_max_mcs, max_mcs;
543*04171cfcSAugustin Cavalier 
544*04171cfcSAugustin Cavalier 	memset(rn->max_mcs, 0, sizeof(rn->max_mcs));
545*04171cfcSAugustin Cavalier 	memset(rn->valid_rates, 0, sizeof(rn->valid_rates));
546*04171cfcSAugustin Cavalier 
547*04171cfcSAugustin Cavalier 	for (nss = 1; nss <= IEEE80211_VHT_NUM_SS; nss++) {
548*04171cfcSAugustin Cavalier 		ic_max_mcs = ieee80211_ra_vht_get_max_mcs(ic->ic_vht_txmcs,
549*04171cfcSAugustin Cavalier 		    nss, IEEE80211_CHAN_40MHZ_ALLOWED(ic->ic_bss->ni_chan));
550*04171cfcSAugustin Cavalier 		ni_max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs,
551*04171cfcSAugustin Cavalier 		    nss, ieee80211_node_supports_ht_chan40(ni));
552*04171cfcSAugustin Cavalier 		if ((ic_max_mcs != 7 && ic_max_mcs != 8 && ic_max_mcs != 9) ||
553*04171cfcSAugustin Cavalier 		    (ni_max_mcs != 7 && ni_max_mcs != 8 && ni_max_mcs != 9))
554*04171cfcSAugustin Cavalier 			continue;
555*04171cfcSAugustin Cavalier 
556*04171cfcSAugustin Cavalier 		max_mcs = MIN(ic_max_mcs, ni_max_mcs);
557*04171cfcSAugustin Cavalier 		rn->max_mcs[nss - 1] = max_mcs;
558*04171cfcSAugustin Cavalier 		rn->valid_rates[nss - 1] = ((1 << (max_mcs + 1)) - 1);
559*04171cfcSAugustin Cavalier 	}
560*04171cfcSAugustin Cavalier }
561*04171cfcSAugustin Cavalier 
562*04171cfcSAugustin Cavalier int
ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats * g)563*04171cfcSAugustin Cavalier ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *g)
564*04171cfcSAugustin Cavalier {
565*04171cfcSAugustin Cavalier 	/* 128 packets make up a valid probe in any case. */
566*04171cfcSAugustin Cavalier 	if (g->nprobe_pkts >= 128)
567*04171cfcSAugustin Cavalier 		return 1;
568*04171cfcSAugustin Cavalier 
569*04171cfcSAugustin Cavalier 	/* 8 packets with > 75% loss make a valid probe, too. */
570*04171cfcSAugustin Cavalier 	if (g->nprobe_pkts >= 8 &&
571*04171cfcSAugustin Cavalier 	    g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4)
572*04171cfcSAugustin Cavalier 		return 1;
573*04171cfcSAugustin Cavalier 
574*04171cfcSAugustin Cavalier 	return 0;
575*04171cfcSAugustin Cavalier }
576*04171cfcSAugustin Cavalier 
577*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_add_stats(struct ieee80211_ra_vht_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni,int mcs,int nss,uint32_t total,uint32_t fail)578*04171cfcSAugustin Cavalier ieee80211_ra_vht_add_stats(struct ieee80211_ra_vht_node *rn,
579*04171cfcSAugustin Cavalier     struct ieee80211com *ic, struct ieee80211_node *ni,
580*04171cfcSAugustin Cavalier     int mcs, int nss, uint32_t total, uint32_t fail)
581*04171cfcSAugustin Cavalier {
582*04171cfcSAugustin Cavalier 	static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */
583*04171cfcSAugustin Cavalier 	static const uint64_t beta =  RA_FP_1 / 4; /* 1/4 = 0.25 */
584*04171cfcSAugustin Cavalier 	int s;
585*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs;
586*04171cfcSAugustin Cavalier 	struct ieee80211_ra_vht_goodput_stats *g;
587*04171cfcSAugustin Cavalier 	uint64_t sfer, rate, delta;
588*04171cfcSAugustin Cavalier 
589*04171cfcSAugustin Cavalier 	/*
590*04171cfcSAugustin Cavalier 	 * Ignore invalid values. These values may come from hardware
591*04171cfcSAugustin Cavalier 	 * so asserting valid values via panic is not appropriate.
592*04171cfcSAugustin Cavalier 	 */
593*04171cfcSAugustin Cavalier 	if (mcs < 0 || mcs >= IEEE80211_VHT_RATESET_MAX_NRATES)
594*04171cfcSAugustin Cavalier 		return;
595*04171cfcSAugustin Cavalier 	if (nss <= 0 || nss > IEEE80211_VHT_NUM_SS)
596*04171cfcSAugustin Cavalier 		return;
597*04171cfcSAugustin Cavalier 	if (total == 0)
598*04171cfcSAugustin Cavalier 		return;
599*04171cfcSAugustin Cavalier 
600*04171cfcSAugustin Cavalier 	s = splnet();
601*04171cfcSAugustin Cavalier 
602*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1,
603*04171cfcSAugustin Cavalier 	    ieee80211_ra_vht_use_sgi(ni));
604*04171cfcSAugustin Cavalier 	g = &rn->g[rs->idx][mcs];
605*04171cfcSAugustin Cavalier 	g->nprobe_pkts += total;
606*04171cfcSAugustin Cavalier 	g->nprobe_fail += fail;
607*04171cfcSAugustin Cavalier 
608*04171cfcSAugustin Cavalier 	if (!ieee80211_ra_vht_probe_valid(g)) {
609*04171cfcSAugustin Cavalier 		splx(s);
610*04171cfcSAugustin Cavalier 		return;
611*04171cfcSAugustin Cavalier 	}
612*04171cfcSAugustin Cavalier 	rn->valid_probes[nss - 1] |= 1U << mcs;
613*04171cfcSAugustin Cavalier 
614*04171cfcSAugustin Cavalier 	if (g->nprobe_fail > g->nprobe_pkts) {
615*04171cfcSAugustin Cavalier 		DPRINTF(("%s fail %u > pkts %u\n",
616*04171cfcSAugustin Cavalier 		    ether_sprintf(ni->ni_macaddr),
617*04171cfcSAugustin Cavalier 		    g->nprobe_fail, g->nprobe_pkts));
618*04171cfcSAugustin Cavalier 		g->nprobe_fail = g->nprobe_pkts;
619*04171cfcSAugustin Cavalier 	}
620*04171cfcSAugustin Cavalier 
621*04171cfcSAugustin Cavalier 	sfer = g->nprobe_fail << RA_FP_SHIFT;
622*04171cfcSAugustin Cavalier 	sfer /= g->nprobe_pkts;
623*04171cfcSAugustin Cavalier 	g->nprobe_fail = 0;
624*04171cfcSAugustin Cavalier 	g->nprobe_pkts = 0;
625*04171cfcSAugustin Cavalier 
626*04171cfcSAugustin Cavalier 	rate = ieee80211_ra_vht_get_txrate(mcs, nss, 0, 1,
627*04171cfcSAugustin Cavalier 	    ieee80211_ra_vht_use_sgi(ni));
628*04171cfcSAugustin Cavalier 
629*04171cfcSAugustin Cavalier 	g->loss = sfer * 100;
630*04171cfcSAugustin Cavalier 	g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate);
631*04171cfcSAugustin Cavalier 	g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average);
632*04171cfcSAugustin Cavalier 	g->average += RA_FP_MUL(alpha, g->measured);
633*04171cfcSAugustin Cavalier 
634*04171cfcSAugustin Cavalier 	g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation);
635*04171cfcSAugustin Cavalier 	if (g->average > g->measured)
636*04171cfcSAugustin Cavalier 		delta = g->average - g->measured;
637*04171cfcSAugustin Cavalier 	else
638*04171cfcSAugustin Cavalier 		delta = g->measured - g->average;
639*04171cfcSAugustin Cavalier 	g->stddeviation += RA_FP_MUL(beta, delta);
640*04171cfcSAugustin Cavalier 
641*04171cfcSAugustin Cavalier 	splx(s);
642*04171cfcSAugustin Cavalier }
643*04171cfcSAugustin Cavalier 
644*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni)645*04171cfcSAugustin Cavalier ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node *rn,
646*04171cfcSAugustin Cavalier     struct ieee80211com *ic, struct ieee80211_node *ni)
647*04171cfcSAugustin Cavalier {
648*04171cfcSAugustin Cavalier 	struct ieee80211_ra_vht_goodput_stats *g;
649*04171cfcSAugustin Cavalier 	int s;
650*04171cfcSAugustin Cavalier 	int sgi = ieee80211_ra_vht_use_sgi(ni);
651*04171cfcSAugustin Cavalier 	const struct ieee80211_vht_rateset *rs, *rsnext;
652*04171cfcSAugustin Cavalier 	int nss = ni->ni_vht_ss;
653*04171cfcSAugustin Cavalier 
654*04171cfcSAugustin Cavalier 	s = splnet();
655*04171cfcSAugustin Cavalier 
656*04171cfcSAugustin Cavalier 	if (rn->valid_rates[0] == 0) {
657*04171cfcSAugustin Cavalier 		ieee80211_ra_vht_init_valid_rates(ic, ni, rn);
658*04171cfcSAugustin Cavalier 		if (rn->valid_rates[0] == 0)
659*04171cfcSAugustin Cavalier 			panic("VHT not supported");
660*04171cfcSAugustin Cavalier 	}
661*04171cfcSAugustin Cavalier 
662*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
663*04171cfcSAugustin Cavalier 	g = &rn->g[rs->idx][ni->ni_txmcs];
664*04171cfcSAugustin Cavalier 
665*04171cfcSAugustin Cavalier 	if (rn->probing) {
666*04171cfcSAugustin Cavalier 		/* Probe another rate or settle at the best rate. */
667*04171cfcSAugustin Cavalier 		if (!(rn->valid_probes[nss - 1] & (1UL << ni->ni_txmcs))) {
668*04171cfcSAugustin Cavalier 			splx(s);
669*04171cfcSAugustin Cavalier 			return;
670*04171cfcSAugustin Cavalier 		}
671*04171cfcSAugustin Cavalier 		ieee80211_ra_vht_probe_clear(g);
672*04171cfcSAugustin Cavalier 		if (!ieee80211_ra_vht_intra_mode_ra_finished(rn, ni)) {
673*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_probe_next_rate(rn, ni);
674*04171cfcSAugustin Cavalier 			DPRINTFN(3, ("probing MCS,NSS %d,%d\n",
675*04171cfcSAugustin Cavalier 			    ni->ni_txmcs, ni->ni_vht_ss));
676*04171cfcSAugustin Cavalier 		} else if (ieee80211_ra_vht_inter_mode_ra_finished(rn, ni)) {
677*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_best_rate(rn, ni);
678*04171cfcSAugustin Cavalier 			ni->ni_txmcs = rn->best_mcs;
679*04171cfcSAugustin Cavalier 			ni->ni_vht_ss = rn->best_nss;
680*04171cfcSAugustin Cavalier 			ieee80211_ra_vht_probe_done(rn, nss);
681*04171cfcSAugustin Cavalier 		}
682*04171cfcSAugustin Cavalier 
683*04171cfcSAugustin Cavalier 		splx(s);
684*04171cfcSAugustin Cavalier 		return;
685*04171cfcSAugustin Cavalier 	} else {
686*04171cfcSAugustin Cavalier 		rn->valid_probes[nss - 1] = 0;
687*04171cfcSAugustin Cavalier 	}
688*04171cfcSAugustin Cavalier 
689*04171cfcSAugustin Cavalier 
690*04171cfcSAugustin Cavalier 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
691*04171cfcSAugustin Cavalier 	if ((g->measured >> RA_FP_SHIFT) == 0LL ||
692*04171cfcSAugustin Cavalier 	    (g->average >= 3 * g->stddeviation &&
693*04171cfcSAugustin Cavalier 	    g->measured < g->average - 3 * g->stddeviation)) {
694*04171cfcSAugustin Cavalier 		/* Channel becomes bad. Probe downwards. */
695*04171cfcSAugustin Cavalier 		rn->probing = IEEE80211_RA_PROBING_DOWN;
696*04171cfcSAugustin Cavalier 		rn->probed_rates[nss - 1] = 0;
697*04171cfcSAugustin Cavalier 		if (ni->ni_txmcs == 0) {
698*04171cfcSAugustin Cavalier 			rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
699*04171cfcSAugustin Cavalier 			if (rsnext) {
700*04171cfcSAugustin Cavalier 				ieee80211_ra_vht_probe_next_rateset(rn, ni,
701*04171cfcSAugustin Cavalier 				    rsnext);
702*04171cfcSAugustin Cavalier 			} else {
703*04171cfcSAugustin Cavalier 				/* Cannot probe further down. */
704*04171cfcSAugustin Cavalier 				rn->probing = IEEE80211_RA_NOT_PROBING;
705*04171cfcSAugustin Cavalier 			}
706*04171cfcSAugustin Cavalier 		} else {
707*04171cfcSAugustin Cavalier 			ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
708*04171cfcSAugustin Cavalier 			rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs);
709*04171cfcSAugustin Cavalier 		}
710*04171cfcSAugustin Cavalier 	} else if (g->loss < 2 * RA_FP_1 ||
711*04171cfcSAugustin Cavalier 	    g->measured > g->average + 3 * g->stddeviation) {
712*04171cfcSAugustin Cavalier 		/* Channel becomes good. */
713*04171cfcSAugustin Cavalier 		rn->probing = IEEE80211_RA_PROBING_UP;
714*04171cfcSAugustin Cavalier 		rn->probed_rates[nss - 1] = 0;
715*04171cfcSAugustin Cavalier 		if (ni->ni_txmcs == rn->max_mcs[nss - 1]) {
716*04171cfcSAugustin Cavalier 			rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
717*04171cfcSAugustin Cavalier 			if (rsnext) {
718*04171cfcSAugustin Cavalier 				ieee80211_ra_vht_probe_next_rateset(rn, ni,
719*04171cfcSAugustin Cavalier 				    rsnext);
720*04171cfcSAugustin Cavalier 			} else {
721*04171cfcSAugustin Cavalier 				/* Cannot probe further up. */
722*04171cfcSAugustin Cavalier 				rn->probing = IEEE80211_RA_NOT_PROBING;
723*04171cfcSAugustin Cavalier 			}
724*04171cfcSAugustin Cavalier 		} else {
725*04171cfcSAugustin Cavalier 			ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
726*04171cfcSAugustin Cavalier 			rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs);
727*04171cfcSAugustin Cavalier 		}
728*04171cfcSAugustin Cavalier 	} else {
729*04171cfcSAugustin Cavalier 		/* Remain at current rate. */
730*04171cfcSAugustin Cavalier 		rn->probing = IEEE80211_RA_NOT_PROBING;
731*04171cfcSAugustin Cavalier 		rn->probed_rates[nss - 1] = 0;
732*04171cfcSAugustin Cavalier 		rn->candidate_rates[nss - 1] = 0;
733*04171cfcSAugustin Cavalier 	}
734*04171cfcSAugustin Cavalier 
735*04171cfcSAugustin Cavalier 	splx(s);
736*04171cfcSAugustin Cavalier 
737*04171cfcSAugustin Cavalier 	if (rn->probing) {
738*04171cfcSAugustin Cavalier 		if (rn->probing & IEEE80211_RA_PROBING_UP)
739*04171cfcSAugustin Cavalier 			DPRINTFN(2, ("channel becomes good; probe up\n"));
740*04171cfcSAugustin Cavalier 		else
741*04171cfcSAugustin Cavalier 			DPRINTFN(2, ("channel becomes bad; probe down\n"));
742*04171cfcSAugustin Cavalier 
743*04171cfcSAugustin Cavalier 		DPRINTFN(3, ("measured: %s Mbit/s\n",
744*04171cfcSAugustin Cavalier 		    ra_vht_fp_sprintf(g->measured)));
745*04171cfcSAugustin Cavalier 		DPRINTFN(3, ("average: %s Mbit/s\n",
746*04171cfcSAugustin Cavalier 		    ra_vht_fp_sprintf(g->average)));
747*04171cfcSAugustin Cavalier 		DPRINTFN(3, ("stddeviation: %s\n",
748*04171cfcSAugustin Cavalier 		    ra_vht_fp_sprintf(g->stddeviation)));
749*04171cfcSAugustin Cavalier 		DPRINTFN(3, ("loss: %s%%\n", ra_vht_fp_sprintf(g->loss)));
750*04171cfcSAugustin Cavalier 	}
751*04171cfcSAugustin Cavalier }
752*04171cfcSAugustin Cavalier 
753*04171cfcSAugustin Cavalier void
ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node * rn)754*04171cfcSAugustin Cavalier ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node *rn)
755*04171cfcSAugustin Cavalier {
756*04171cfcSAugustin Cavalier 	memset(rn, 0, sizeof(*rn));
757*04171cfcSAugustin Cavalier 	rn->best_nss = 1;
758*04171cfcSAugustin Cavalier }
759