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