.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org> |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
| 4 | + * Copyright (C) 2019-2020 Intel Corporation |
---|
7 | 5 | */ |
---|
8 | 6 | #include <linux/netdevice.h> |
---|
9 | 7 | #include <linux/types.h> |
---|
.. | .. |
---|
20 | 18 | |
---|
21 | 19 | #define AVG_AMPDU_SIZE 16 |
---|
22 | 20 | #define AVG_PKT_SIZE 1200 |
---|
| 21 | + |
---|
| 22 | +#define SAMPLE_SWITCH_THR 100 |
---|
23 | 23 | |
---|
24 | 24 | /* Number of bits for an average sized packet */ |
---|
25 | 25 | #define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3) |
---|
.. | .. |
---|
51 | 51 | MINSTREL_MAX_STREAMS * _sgi + \ |
---|
52 | 52 | _streams - 1 |
---|
53 | 53 | |
---|
| 54 | +#define _MAX(a, b) (((a)>(b))?(a):(b)) |
---|
| 55 | + |
---|
| 56 | +#define GROUP_SHIFT(duration) \ |
---|
| 57 | + _MAX(0, 16 - __builtin_clz(duration)) |
---|
| 58 | + |
---|
54 | 59 | /* MCS rate information for an MCS group */ |
---|
55 | | -#define MCS_GROUP(_streams, _sgi, _ht40) \ |
---|
| 60 | +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ |
---|
56 | 61 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ |
---|
57 | 62 | .streams = _streams, \ |
---|
| 63 | + .shift = _s, \ |
---|
| 64 | + .bw = _ht40, \ |
---|
58 | 65 | .flags = \ |
---|
59 | 66 | IEEE80211_TX_RC_MCS | \ |
---|
60 | 67 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
---|
61 | 68 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ |
---|
62 | 69 | .duration = { \ |
---|
63 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \ |
---|
64 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \ |
---|
65 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \ |
---|
66 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \ |
---|
67 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \ |
---|
68 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \ |
---|
69 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \ |
---|
70 | | - MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \ |
---|
| 70 | + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ |
---|
| 71 | + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ |
---|
| 72 | + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ |
---|
| 73 | + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ |
---|
| 74 | + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ |
---|
| 75 | + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ |
---|
| 76 | + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ |
---|
| 77 | + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ |
---|
71 | 78 | } \ |
---|
72 | 79 | } |
---|
| 80 | + |
---|
| 81 | +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ |
---|
| 82 | + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) |
---|
| 83 | + |
---|
| 84 | +#define MCS_GROUP(_streams, _sgi, _ht40) \ |
---|
| 85 | + __MCS_GROUP(_streams, _sgi, _ht40, \ |
---|
| 86 | + MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) |
---|
73 | 87 | |
---|
74 | 88 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ |
---|
75 | 89 | (MINSTREL_VHT_GROUP_0 + \ |
---|
.. | .. |
---|
80 | 94 | #define BW2VBPS(_bw, r3, r2, r1) \ |
---|
81 | 95 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) |
---|
82 | 96 | |
---|
83 | | -#define VHT_GROUP(_streams, _sgi, _bw) \ |
---|
| 97 | +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ |
---|
84 | 98 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ |
---|
85 | 99 | .streams = _streams, \ |
---|
| 100 | + .shift = _s, \ |
---|
| 101 | + .bw = _bw, \ |
---|
86 | 102 | .flags = \ |
---|
87 | 103 | IEEE80211_TX_RC_VHT_MCS | \ |
---|
88 | 104 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
---|
.. | .. |
---|
90 | 106 | _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ |
---|
91 | 107 | .duration = { \ |
---|
92 | 108 | MCS_DURATION(_streams, _sgi, \ |
---|
93 | | - BW2VBPS(_bw, 117, 54, 26)), \ |
---|
| 109 | + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ |
---|
94 | 110 | MCS_DURATION(_streams, _sgi, \ |
---|
95 | | - BW2VBPS(_bw, 234, 108, 52)), \ |
---|
| 111 | + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ |
---|
96 | 112 | MCS_DURATION(_streams, _sgi, \ |
---|
97 | | - BW2VBPS(_bw, 351, 162, 78)), \ |
---|
| 113 | + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ |
---|
98 | 114 | MCS_DURATION(_streams, _sgi, \ |
---|
99 | | - BW2VBPS(_bw, 468, 216, 104)), \ |
---|
| 115 | + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ |
---|
100 | 116 | MCS_DURATION(_streams, _sgi, \ |
---|
101 | | - BW2VBPS(_bw, 702, 324, 156)), \ |
---|
| 117 | + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ |
---|
102 | 118 | MCS_DURATION(_streams, _sgi, \ |
---|
103 | | - BW2VBPS(_bw, 936, 432, 208)), \ |
---|
| 119 | + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ |
---|
104 | 120 | MCS_DURATION(_streams, _sgi, \ |
---|
105 | | - BW2VBPS(_bw, 1053, 486, 234)), \ |
---|
| 121 | + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ |
---|
106 | 122 | MCS_DURATION(_streams, _sgi, \ |
---|
107 | | - BW2VBPS(_bw, 1170, 540, 260)), \ |
---|
| 123 | + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ |
---|
108 | 124 | MCS_DURATION(_streams, _sgi, \ |
---|
109 | | - BW2VBPS(_bw, 1404, 648, 312)), \ |
---|
| 125 | + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ |
---|
110 | 126 | MCS_DURATION(_streams, _sgi, \ |
---|
111 | | - BW2VBPS(_bw, 1560, 720, 346)) \ |
---|
| 127 | + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ |
---|
112 | 128 | } \ |
---|
113 | 129 | } |
---|
| 130 | + |
---|
| 131 | +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ |
---|
| 132 | + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ |
---|
| 133 | + BW2VBPS(_bw, 117, 54, 26))) |
---|
| 134 | + |
---|
| 135 | +#define VHT_GROUP(_streams, _sgi, _bw) \ |
---|
| 136 | + __VHT_GROUP(_streams, _sgi, _bw, \ |
---|
| 137 | + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) |
---|
114 | 138 | |
---|
115 | 139 | #define CCK_DURATION(_bitrate, _short, _len) \ |
---|
116 | 140 | (1000 * (10 /* SIFS */ + \ |
---|
.. | .. |
---|
121 | 145 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ |
---|
122 | 146 | CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) |
---|
123 | 147 | |
---|
124 | | -#define CCK_DURATION_LIST(_short) \ |
---|
125 | | - CCK_ACK_DURATION(10, _short), \ |
---|
126 | | - CCK_ACK_DURATION(20, _short), \ |
---|
127 | | - CCK_ACK_DURATION(55, _short), \ |
---|
128 | | - CCK_ACK_DURATION(110, _short) |
---|
| 148 | +#define CCK_DURATION_LIST(_short, _s) \ |
---|
| 149 | + CCK_ACK_DURATION(10, _short) >> _s, \ |
---|
| 150 | + CCK_ACK_DURATION(20, _short) >> _s, \ |
---|
| 151 | + CCK_ACK_DURATION(55, _short) >> _s, \ |
---|
| 152 | + CCK_ACK_DURATION(110, _short) >> _s |
---|
129 | 153 | |
---|
130 | | -#define CCK_GROUP \ |
---|
| 154 | +#define __CCK_GROUP(_s) \ |
---|
131 | 155 | [MINSTREL_CCK_GROUP] = { \ |
---|
132 | 156 | .streams = 1, \ |
---|
133 | 157 | .flags = 0, \ |
---|
| 158 | + .shift = _s, \ |
---|
134 | 159 | .duration = { \ |
---|
135 | | - CCK_DURATION_LIST(false), \ |
---|
136 | | - CCK_DURATION_LIST(true) \ |
---|
| 160 | + CCK_DURATION_LIST(false, _s), \ |
---|
| 161 | + CCK_DURATION_LIST(true, _s) \ |
---|
137 | 162 | } \ |
---|
138 | 163 | } |
---|
139 | 164 | |
---|
140 | | -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
---|
| 165 | +#define CCK_GROUP_SHIFT \ |
---|
| 166 | + GROUP_SHIFT(CCK_ACK_DURATION(10, false)) |
---|
| 167 | + |
---|
| 168 | +#define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) |
---|
| 169 | + |
---|
| 170 | + |
---|
141 | 171 | static bool minstrel_vht_only = true; |
---|
142 | 172 | module_param(minstrel_vht_only, bool, 0644); |
---|
143 | 173 | MODULE_PARM_DESC(minstrel_vht_only, |
---|
144 | 174 | "Use only VHT rates when VHT is supported by sta."); |
---|
145 | | -#endif |
---|
146 | 175 | |
---|
147 | 176 | /* |
---|
148 | 177 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
---|
.. | .. |
---|
156 | 185 | MCS_GROUP(1, 0, BW_20), |
---|
157 | 186 | MCS_GROUP(2, 0, BW_20), |
---|
158 | 187 | MCS_GROUP(3, 0, BW_20), |
---|
| 188 | + MCS_GROUP(4, 0, BW_20), |
---|
159 | 189 | |
---|
160 | 190 | MCS_GROUP(1, 1, BW_20), |
---|
161 | 191 | MCS_GROUP(2, 1, BW_20), |
---|
162 | 192 | MCS_GROUP(3, 1, BW_20), |
---|
| 193 | + MCS_GROUP(4, 1, BW_20), |
---|
163 | 194 | |
---|
164 | 195 | MCS_GROUP(1, 0, BW_40), |
---|
165 | 196 | MCS_GROUP(2, 0, BW_40), |
---|
166 | 197 | MCS_GROUP(3, 0, BW_40), |
---|
| 198 | + MCS_GROUP(4, 0, BW_40), |
---|
167 | 199 | |
---|
168 | 200 | MCS_GROUP(1, 1, BW_40), |
---|
169 | 201 | MCS_GROUP(2, 1, BW_40), |
---|
170 | 202 | MCS_GROUP(3, 1, BW_40), |
---|
| 203 | + MCS_GROUP(4, 1, BW_40), |
---|
171 | 204 | |
---|
172 | 205 | CCK_GROUP, |
---|
173 | 206 | |
---|
174 | | -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
---|
175 | 207 | VHT_GROUP(1, 0, BW_20), |
---|
176 | 208 | VHT_GROUP(2, 0, BW_20), |
---|
177 | 209 | VHT_GROUP(3, 0, BW_20), |
---|
| 210 | + VHT_GROUP(4, 0, BW_20), |
---|
178 | 211 | |
---|
179 | 212 | VHT_GROUP(1, 1, BW_20), |
---|
180 | 213 | VHT_GROUP(2, 1, BW_20), |
---|
181 | 214 | VHT_GROUP(3, 1, BW_20), |
---|
| 215 | + VHT_GROUP(4, 1, BW_20), |
---|
182 | 216 | |
---|
183 | 217 | VHT_GROUP(1, 0, BW_40), |
---|
184 | 218 | VHT_GROUP(2, 0, BW_40), |
---|
185 | 219 | VHT_GROUP(3, 0, BW_40), |
---|
| 220 | + VHT_GROUP(4, 0, BW_40), |
---|
186 | 221 | |
---|
187 | 222 | VHT_GROUP(1, 1, BW_40), |
---|
188 | 223 | VHT_GROUP(2, 1, BW_40), |
---|
189 | 224 | VHT_GROUP(3, 1, BW_40), |
---|
| 225 | + VHT_GROUP(4, 1, BW_40), |
---|
190 | 226 | |
---|
191 | 227 | VHT_GROUP(1, 0, BW_80), |
---|
192 | 228 | VHT_GROUP(2, 0, BW_80), |
---|
193 | 229 | VHT_GROUP(3, 0, BW_80), |
---|
| 230 | + VHT_GROUP(4, 0, BW_80), |
---|
194 | 231 | |
---|
195 | 232 | VHT_GROUP(1, 1, BW_80), |
---|
196 | 233 | VHT_GROUP(2, 1, BW_80), |
---|
197 | 234 | VHT_GROUP(3, 1, BW_80), |
---|
198 | | -#endif |
---|
| 235 | + VHT_GROUP(4, 1, BW_80), |
---|
199 | 236 | }; |
---|
200 | 237 | |
---|
201 | 238 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
---|
.. | .. |
---|
295 | 332 | return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; |
---|
296 | 333 | } |
---|
297 | 334 | |
---|
| 335 | +static unsigned int |
---|
| 336 | +minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) |
---|
| 337 | +{ |
---|
| 338 | + if (!mi->avg_ampdu_len) |
---|
| 339 | + return AVG_AMPDU_SIZE; |
---|
| 340 | + |
---|
| 341 | + return MINSTREL_TRUNC(mi->avg_ampdu_len); |
---|
| 342 | +} |
---|
| 343 | + |
---|
298 | 344 | /* |
---|
299 | 345 | * Return current throughput based on the average A-MPDU length, taking into |
---|
300 | 346 | * account the expected number of retransmissions and their expected length |
---|
301 | 347 | */ |
---|
302 | 348 | int |
---|
303 | 349 | minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, |
---|
304 | | - int prob_ewma) |
---|
| 350 | + int prob_avg) |
---|
305 | 351 | { |
---|
306 | 352 | unsigned int nsecs = 0; |
---|
307 | 353 | |
---|
308 | 354 | /* do not account throughput if sucess prob is below 10% */ |
---|
309 | | - if (prob_ewma < MINSTREL_FRAC(10, 100)) |
---|
| 355 | + if (prob_avg < MINSTREL_FRAC(10, 100)) |
---|
310 | 356 | return 0; |
---|
311 | 357 | |
---|
312 | 358 | if (group != MINSTREL_CCK_GROUP) |
---|
313 | | - nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); |
---|
| 359 | + nsecs = 1000 * mi->overhead / minstrel_ht_avg_ampdu_len(mi); |
---|
314 | 360 | |
---|
315 | | - nsecs += minstrel_mcs_groups[group].duration[rate]; |
---|
| 361 | + nsecs += minstrel_mcs_groups[group].duration[rate] << |
---|
| 362 | + minstrel_mcs_groups[group].shift; |
---|
316 | 363 | |
---|
317 | 364 | /* |
---|
318 | 365 | * For the throughput calculation, limit the probability value to 90% to |
---|
319 | 366 | * account for collision related packet error rate fluctuation |
---|
320 | 367 | * (prob is scaled - see MINSTREL_FRAC above) |
---|
321 | 368 | */ |
---|
322 | | - if (prob_ewma > MINSTREL_FRAC(90, 100)) |
---|
| 369 | + if (prob_avg > MINSTREL_FRAC(90, 100)) |
---|
323 | 370 | return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) |
---|
324 | 371 | / nsecs)); |
---|
325 | 372 | else |
---|
326 | | - return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs)); |
---|
| 373 | + return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs)); |
---|
327 | 374 | } |
---|
328 | 375 | |
---|
329 | 376 | /* |
---|
.. | .. |
---|
343 | 390 | |
---|
344 | 391 | cur_group = index / MCS_GROUP_RATES; |
---|
345 | 392 | cur_idx = index % MCS_GROUP_RATES; |
---|
346 | | - cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; |
---|
| 393 | + cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; |
---|
347 | 394 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); |
---|
348 | 395 | |
---|
349 | 396 | do { |
---|
350 | 397 | tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; |
---|
351 | 398 | tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; |
---|
352 | | - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
---|
| 399 | + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; |
---|
353 | 400 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, |
---|
354 | 401 | tmp_prob); |
---|
355 | 402 | if (cur_tp_avg < tmp_tp_avg || |
---|
.. | .. |
---|
386 | 433 | |
---|
387 | 434 | tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; |
---|
388 | 435 | tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; |
---|
389 | | - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
---|
| 436 | + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; |
---|
390 | 437 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); |
---|
391 | 438 | |
---|
392 | 439 | /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from |
---|
.. | .. |
---|
398 | 445 | |
---|
399 | 446 | max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; |
---|
400 | 447 | max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; |
---|
401 | | - max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; |
---|
| 448 | + max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; |
---|
402 | 449 | |
---|
403 | | - if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { |
---|
| 450 | + if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { |
---|
404 | 451 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, |
---|
405 | | - mrs->prob_ewma); |
---|
| 452 | + mrs->prob_avg); |
---|
406 | 453 | if (cur_tp_avg > tmp_tp_avg) |
---|
407 | 454 | mi->max_prob_rate = index; |
---|
408 | 455 | |
---|
.. | .. |
---|
412 | 459 | if (cur_tp_avg > max_gpr_tp_avg) |
---|
413 | 460 | mg->max_group_prob_rate = index; |
---|
414 | 461 | } else { |
---|
415 | | - if (mrs->prob_ewma > tmp_prob) |
---|
| 462 | + if (mrs->prob_avg > tmp_prob) |
---|
416 | 463 | mi->max_prob_rate = index; |
---|
417 | | - if (mrs->prob_ewma > max_gpr_prob) |
---|
| 464 | + if (mrs->prob_avg > max_gpr_prob) |
---|
418 | 465 | mg->max_group_prob_rate = index; |
---|
419 | 466 | } |
---|
420 | 467 | } |
---|
.. | .. |
---|
436 | 483 | |
---|
437 | 484 | tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; |
---|
438 | 485 | tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; |
---|
439 | | - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
---|
| 486 | + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; |
---|
440 | 487 | tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); |
---|
441 | 488 | |
---|
442 | 489 | tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; |
---|
443 | 490 | tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; |
---|
444 | | - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
---|
| 491 | + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; |
---|
445 | 492 | tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); |
---|
446 | 493 | |
---|
447 | 494 | if (tmp_cck_tp > tmp_mcs_tp) { |
---|
.. | .. |
---|
472 | 519 | continue; |
---|
473 | 520 | |
---|
474 | 521 | tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; |
---|
475 | | - tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma; |
---|
| 522 | + tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; |
---|
476 | 523 | |
---|
477 | 524 | if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && |
---|
478 | 525 | (minstrel_mcs_groups[group].streams < tmp_max_streams)) { |
---|
.. | .. |
---|
482 | 529 | tmp_prob); |
---|
483 | 530 | } |
---|
484 | 531 | } |
---|
| 532 | +} |
---|
| 533 | + |
---|
| 534 | +static inline int |
---|
| 535 | +minstrel_get_duration(int index) |
---|
| 536 | +{ |
---|
| 537 | + const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
---|
| 538 | + unsigned int duration = group->duration[index % MCS_GROUP_RATES]; |
---|
| 539 | + return duration << group->shift; |
---|
| 540 | +} |
---|
| 541 | + |
---|
| 542 | +static bool |
---|
| 543 | +minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group, |
---|
| 544 | + int tp_idx, const struct mcs_group *group) |
---|
| 545 | +{ |
---|
| 546 | + if (group->bw < tp_group->bw) |
---|
| 547 | + return false; |
---|
| 548 | + |
---|
| 549 | + if (group->streams == tp_group->streams) |
---|
| 550 | + return true; |
---|
| 551 | + |
---|
| 552 | + if (tp_idx < 4 && group->streams == tp_group->streams - 1) |
---|
| 553 | + return true; |
---|
| 554 | + |
---|
| 555 | + return group->streams == tp_group->streams + 1; |
---|
| 556 | +} |
---|
| 557 | + |
---|
| 558 | +static void |
---|
| 559 | +minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates, |
---|
| 560 | + bool faster_rate) |
---|
| 561 | +{ |
---|
| 562 | + const struct mcs_group *group, *tp_group; |
---|
| 563 | + int i, g, max_dur; |
---|
| 564 | + int tp_idx; |
---|
| 565 | + |
---|
| 566 | + tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES]; |
---|
| 567 | + tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; |
---|
| 568 | + |
---|
| 569 | + max_dur = minstrel_get_duration(mi->max_tp_rate[0]); |
---|
| 570 | + if (faster_rate) |
---|
| 571 | + max_dur -= max_dur / 16; |
---|
| 572 | + |
---|
| 573 | + for (g = 0; g < MINSTREL_GROUPS_NB; g++) { |
---|
| 574 | + u16 supported = mi->supported[g]; |
---|
| 575 | + |
---|
| 576 | + if (!supported) |
---|
| 577 | + continue; |
---|
| 578 | + |
---|
| 579 | + group = &minstrel_mcs_groups[g]; |
---|
| 580 | + if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group)) |
---|
| 581 | + continue; |
---|
| 582 | + |
---|
| 583 | + for (i = 0; supported; supported >>= 1, i++) { |
---|
| 584 | + int idx; |
---|
| 585 | + |
---|
| 586 | + if (!(supported & 1)) |
---|
| 587 | + continue; |
---|
| 588 | + |
---|
| 589 | + if ((group->duration[i] << group->shift) > max_dur) |
---|
| 590 | + continue; |
---|
| 591 | + |
---|
| 592 | + idx = g * MCS_GROUP_RATES + i; |
---|
| 593 | + if (idx == mi->max_tp_rate[0]) |
---|
| 594 | + continue; |
---|
| 595 | + |
---|
| 596 | + rates[(*n_rates)++] = idx; |
---|
| 597 | + break; |
---|
| 598 | + } |
---|
| 599 | + } |
---|
| 600 | +} |
---|
| 601 | + |
---|
| 602 | +static void |
---|
| 603 | +minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, |
---|
| 604 | + struct minstrel_ht_sta *mi) |
---|
| 605 | +{ |
---|
| 606 | + struct minstrel_rate_stats *mrs; |
---|
| 607 | + u16 rates[MINSTREL_GROUPS_NB]; |
---|
| 608 | + int n_rates = 0; |
---|
| 609 | + int probe_rate = 0; |
---|
| 610 | + bool faster_rate; |
---|
| 611 | + int i; |
---|
| 612 | + u8 random; |
---|
| 613 | + |
---|
| 614 | + /* |
---|
| 615 | + * Use rate switching instead of probing packets for devices with |
---|
| 616 | + * little control over retry fallback behavior |
---|
| 617 | + */ |
---|
| 618 | + if (mp->hw->max_rates > 1) |
---|
| 619 | + return; |
---|
| 620 | + |
---|
| 621 | + /* |
---|
| 622 | + * If the current EWMA prob is >75%, look for a rate that's 6.25% |
---|
| 623 | + * faster than the max tp rate. |
---|
| 624 | + * If that fails, look again for a rate that is at least as fast |
---|
| 625 | + */ |
---|
| 626 | + mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); |
---|
| 627 | + faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100); |
---|
| 628 | + minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate); |
---|
| 629 | + if (!n_rates && faster_rate) |
---|
| 630 | + minstrel_ht_find_probe_rates(mi, rates, &n_rates, false); |
---|
| 631 | + |
---|
| 632 | + /* If no suitable rate was found, try to pick the next one in the group */ |
---|
| 633 | + if (!n_rates) { |
---|
| 634 | + int g_idx = mi->max_tp_rate[0] / MCS_GROUP_RATES; |
---|
| 635 | + u16 supported = mi->supported[g_idx]; |
---|
| 636 | + |
---|
| 637 | + supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES; |
---|
| 638 | + for (i = 0; supported; supported >>= 1, i++) { |
---|
| 639 | + if (!(supported & 1)) |
---|
| 640 | + continue; |
---|
| 641 | + |
---|
| 642 | + probe_rate = mi->max_tp_rate[0] + i; |
---|
| 643 | + goto out; |
---|
| 644 | + } |
---|
| 645 | + |
---|
| 646 | + return; |
---|
| 647 | + } |
---|
| 648 | + |
---|
| 649 | + i = 0; |
---|
| 650 | + if (n_rates > 1) { |
---|
| 651 | + random = prandom_u32(); |
---|
| 652 | + i = random % n_rates; |
---|
| 653 | + } |
---|
| 654 | + probe_rate = rates[i]; |
---|
| 655 | + |
---|
| 656 | +out: |
---|
| 657 | + mi->sample_rate = probe_rate; |
---|
| 658 | + mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; |
---|
485 | 659 | } |
---|
486 | 660 | |
---|
487 | 661 | /* |
---|
.. | .. |
---|
494 | 668 | * higher throughput rates, even if the probablity is a bit lower |
---|
495 | 669 | */ |
---|
496 | 670 | static void |
---|
497 | | -minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) |
---|
| 671 | +minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
---|
| 672 | + bool sample) |
---|
498 | 673 | { |
---|
499 | 674 | struct minstrel_mcs_group_data *mg; |
---|
500 | 675 | struct minstrel_rate_stats *mrs; |
---|
.. | .. |
---|
502 | 677 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; |
---|
503 | 678 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; |
---|
504 | 679 | |
---|
| 680 | + mi->sample_mode = MINSTREL_SAMPLE_IDLE; |
---|
| 681 | + |
---|
| 682 | + if (sample) { |
---|
| 683 | + mi->total_packets_cur = mi->total_packets - |
---|
| 684 | + mi->total_packets_last; |
---|
| 685 | + mi->total_packets_last = mi->total_packets; |
---|
| 686 | + } |
---|
| 687 | + if (!mp->sample_switch) |
---|
| 688 | + sample = false; |
---|
| 689 | + if (mi->total_packets_cur < SAMPLE_SWITCH_THR && mp->sample_switch != 1) |
---|
| 690 | + sample = false; |
---|
| 691 | + |
---|
505 | 692 | if (mi->ampdu_packets > 0) { |
---|
506 | | - mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
---|
507 | | - MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL); |
---|
| 693 | + if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) |
---|
| 694 | + mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
---|
| 695 | + MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), |
---|
| 696 | + EWMA_LEVEL); |
---|
| 697 | + else |
---|
| 698 | + mi->avg_ampdu_len = 0; |
---|
508 | 699 | mi->ampdu_len = 0; |
---|
509 | 700 | mi->ampdu_packets = 0; |
---|
510 | 701 | } |
---|
.. | .. |
---|
512 | 703 | mi->sample_slow = 0; |
---|
513 | 704 | mi->sample_count = 0; |
---|
514 | 705 | |
---|
515 | | - /* Initialize global rate indexes */ |
---|
516 | | - for(j = 0; j < MAX_THR_RATES; j++){ |
---|
517 | | - tmp_mcs_tp_rate[j] = 0; |
---|
518 | | - tmp_cck_tp_rate[j] = 0; |
---|
519 | | - } |
---|
| 706 | + memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); |
---|
| 707 | + memset(tmp_cck_tp_rate, 0, sizeof(tmp_cck_tp_rate)); |
---|
| 708 | + if (mi->supported[MINSTREL_CCK_GROUP]) |
---|
| 709 | + for (j = 0; j < ARRAY_SIZE(tmp_cck_tp_rate); j++) |
---|
| 710 | + tmp_cck_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; |
---|
| 711 | + |
---|
| 712 | + if (mi->supported[MINSTREL_VHT_GROUP_0]) |
---|
| 713 | + index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES; |
---|
| 714 | + else |
---|
| 715 | + index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES; |
---|
| 716 | + |
---|
| 717 | + for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) |
---|
| 718 | + tmp_mcs_tp_rate[j] = index; |
---|
520 | 719 | |
---|
521 | 720 | /* Find best rate sets within all MCS groups*/ |
---|
522 | 721 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { |
---|
.. | .. |
---|
539 | 738 | |
---|
540 | 739 | mrs = &mg->rates[i]; |
---|
541 | 740 | mrs->retry_updated = false; |
---|
542 | | - minstrel_calc_rate_stats(mrs); |
---|
543 | | - cur_prob = mrs->prob_ewma; |
---|
| 741 | + minstrel_calc_rate_stats(mp, mrs); |
---|
| 742 | + cur_prob = mrs->prob_avg; |
---|
544 | 743 | |
---|
545 | 744 | if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) |
---|
546 | 745 | continue; |
---|
.. | .. |
---|
575 | 774 | |
---|
576 | 775 | /* try to sample all available rates during each interval */ |
---|
577 | 776 | mi->sample_count *= 8; |
---|
| 777 | + if (mp->new_avg) |
---|
| 778 | + mi->sample_count /= 2; |
---|
| 779 | + |
---|
| 780 | + if (sample) |
---|
| 781 | + minstrel_ht_rate_sample_switch(mp, mi); |
---|
578 | 782 | |
---|
579 | 783 | #ifdef CONFIG_MAC80211_DEBUGFS |
---|
580 | 784 | /* use fixed index if set */ |
---|
.. | .. |
---|
582 | 786 | for (i = 0; i < 4; i++) |
---|
583 | 787 | mi->max_tp_rate[i] = mp->fixed_rate_idx; |
---|
584 | 788 | mi->max_prob_rate = mp->fixed_rate_idx; |
---|
| 789 | + mi->sample_mode = MINSTREL_SAMPLE_IDLE; |
---|
585 | 790 | } |
---|
586 | 791 | #endif |
---|
587 | 792 | |
---|
.. | .. |
---|
685 | 890 | struct minstrel_ht_sta_priv *msp = priv_sta; |
---|
686 | 891 | struct minstrel_ht_sta *mi = &msp->ht; |
---|
687 | 892 | struct ieee80211_tx_rate *ar = info->status.rates; |
---|
688 | | - struct minstrel_rate_stats *rate, *rate2; |
---|
| 893 | + struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; |
---|
689 | 894 | struct minstrel_priv *mp = priv; |
---|
| 895 | + u32 update_interval = mp->update_interval / 2; |
---|
690 | 896 | bool last, update = false; |
---|
| 897 | + bool sample_status = false; |
---|
691 | 898 | int i; |
---|
692 | 899 | |
---|
693 | 900 | if (!msp->is_ht) |
---|
694 | 901 | return mac80211_minstrel.tx_status_ext(priv, sband, |
---|
695 | 902 | &msp->legacy, st); |
---|
| 903 | + |
---|
696 | 904 | |
---|
697 | 905 | /* This packet was aggregated but doesn't carry status info */ |
---|
698 | 906 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
---|
.. | .. |
---|
709 | 917 | mi->ampdu_len += info->status.ampdu_len; |
---|
710 | 918 | |
---|
711 | 919 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { |
---|
712 | | - mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); |
---|
| 920 | + int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi); |
---|
| 921 | + |
---|
| 922 | + mi->sample_wait = 16 + 2 * avg_ampdu_len; |
---|
713 | 923 | mi->sample_tries = 1; |
---|
714 | 924 | mi->sample_count--; |
---|
715 | 925 | } |
---|
.. | .. |
---|
717 | 927 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
---|
718 | 928 | mi->sample_packets += info->status.ampdu_len; |
---|
719 | 929 | |
---|
| 930 | + if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) |
---|
| 931 | + rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); |
---|
| 932 | + |
---|
720 | 933 | last = !minstrel_ht_txstat_valid(mp, &ar[0]); |
---|
721 | 934 | for (i = 0; !last; i++) { |
---|
722 | 935 | last = (i == IEEE80211_TX_MAX_RATES - 1) || |
---|
723 | 936 | !minstrel_ht_txstat_valid(mp, &ar[i + 1]); |
---|
724 | 937 | |
---|
725 | 938 | rate = minstrel_ht_get_stats(mp, mi, &ar[i]); |
---|
| 939 | + if (rate == rate_sample) |
---|
| 940 | + sample_status = true; |
---|
726 | 941 | |
---|
727 | 942 | if (last) |
---|
728 | 943 | rate->success += info->status.ampdu_ack_len; |
---|
.. | .. |
---|
730 | 945 | rate->attempts += ar[i].count * info->status.ampdu_len; |
---|
731 | 946 | } |
---|
732 | 947 | |
---|
733 | | - /* |
---|
734 | | - * check for sudden death of spatial multiplexing, |
---|
735 | | - * downgrade to a lower number of streams if necessary. |
---|
736 | | - */ |
---|
737 | | - rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); |
---|
738 | | - if (rate->attempts > 30 && |
---|
739 | | - MINSTREL_FRAC(rate->success, rate->attempts) < |
---|
740 | | - MINSTREL_FRAC(20, 100)) { |
---|
741 | | - minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); |
---|
| 948 | + switch (mi->sample_mode) { |
---|
| 949 | + case MINSTREL_SAMPLE_IDLE: |
---|
| 950 | + if (mp->new_avg && |
---|
| 951 | + (mp->hw->max_rates > 1 || |
---|
| 952 | + mi->total_packets_cur < SAMPLE_SWITCH_THR)) |
---|
| 953 | + update_interval /= 2; |
---|
| 954 | + break; |
---|
| 955 | + |
---|
| 956 | + case MINSTREL_SAMPLE_ACTIVE: |
---|
| 957 | + if (!sample_status) |
---|
| 958 | + break; |
---|
| 959 | + |
---|
| 960 | + mi->sample_mode = MINSTREL_SAMPLE_PENDING; |
---|
742 | 961 | update = true; |
---|
| 962 | + break; |
---|
| 963 | + |
---|
| 964 | + case MINSTREL_SAMPLE_PENDING: |
---|
| 965 | + if (sample_status) |
---|
| 966 | + break; |
---|
| 967 | + |
---|
| 968 | + update = true; |
---|
| 969 | + minstrel_ht_update_stats(mp, mi, false); |
---|
| 970 | + break; |
---|
743 | 971 | } |
---|
744 | 972 | |
---|
745 | | - rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); |
---|
746 | | - if (rate2->attempts > 30 && |
---|
747 | | - MINSTREL_FRAC(rate2->success, rate2->attempts) < |
---|
748 | | - MINSTREL_FRAC(20, 100)) { |
---|
749 | | - minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); |
---|
750 | | - update = true; |
---|
| 973 | + |
---|
| 974 | + if (mp->hw->max_rates > 1) { |
---|
| 975 | + /* |
---|
| 976 | + * check for sudden death of spatial multiplexing, |
---|
| 977 | + * downgrade to a lower number of streams if necessary. |
---|
| 978 | + */ |
---|
| 979 | + rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); |
---|
| 980 | + if (rate->attempts > 30 && |
---|
| 981 | + rate->success < rate->attempts / 4) { |
---|
| 982 | + minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); |
---|
| 983 | + update = true; |
---|
| 984 | + } |
---|
| 985 | + |
---|
| 986 | + rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); |
---|
| 987 | + if (rate2->attempts > 30 && |
---|
| 988 | + rate2->success < rate2->attempts / 4) { |
---|
| 989 | + minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); |
---|
| 990 | + update = true; |
---|
| 991 | + } |
---|
751 | 992 | } |
---|
752 | 993 | |
---|
753 | | - if (time_after(jiffies, mi->last_stats_update + |
---|
754 | | - (mp->update_interval / 2 * HZ) / 1000)) { |
---|
| 994 | + if (time_after(jiffies, mi->last_stats_update + update_interval)) { |
---|
755 | 995 | update = true; |
---|
756 | | - minstrel_ht_update_stats(mp, mi); |
---|
| 996 | + minstrel_ht_update_stats(mp, mi, true); |
---|
757 | 997 | } |
---|
758 | 998 | |
---|
759 | 999 | if (update) |
---|
.. | .. |
---|
765 | 1005 | int index) |
---|
766 | 1006 | { |
---|
767 | 1007 | struct minstrel_rate_stats *mrs; |
---|
768 | | - const struct mcs_group *group; |
---|
769 | 1008 | unsigned int tx_time, tx_time_rtscts, tx_time_data; |
---|
770 | 1009 | unsigned int cw = mp->cw_min; |
---|
771 | 1010 | unsigned int ctime = 0; |
---|
772 | 1011 | unsigned int t_slot = 9; /* FIXME */ |
---|
773 | | - unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); |
---|
| 1012 | + unsigned int ampdu_len = minstrel_ht_avg_ampdu_len(mi); |
---|
774 | 1013 | unsigned int overhead = 0, overhead_rtscts = 0; |
---|
775 | 1014 | |
---|
776 | 1015 | mrs = minstrel_get_ratestats(mi, index); |
---|
777 | | - if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) { |
---|
| 1016 | + if (mrs->prob_avg < MINSTREL_FRAC(1, 10)) { |
---|
778 | 1017 | mrs->retry_count = 1; |
---|
779 | 1018 | mrs->retry_count_rtscts = 1; |
---|
780 | 1019 | return; |
---|
.. | .. |
---|
784 | 1023 | mrs->retry_count_rtscts = 2; |
---|
785 | 1024 | mrs->retry_updated = true; |
---|
786 | 1025 | |
---|
787 | | - group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
---|
788 | | - tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000; |
---|
| 1026 | + tx_time_data = minstrel_get_duration(index) * ampdu_len / 1000; |
---|
789 | 1027 | |
---|
790 | 1028 | /* Contention time for first 2 tries */ |
---|
791 | 1029 | ctime = (t_slot * cw) >> 1; |
---|
.. | .. |
---|
832 | 1070 | if (!mrs->retry_updated) |
---|
833 | 1071 | minstrel_calc_retransmit(mp, mi, index); |
---|
834 | 1072 | |
---|
835 | | - if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { |
---|
| 1073 | + if (mrs->prob_avg < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { |
---|
836 | 1074 | ratetbl->rate[offset].count = 2; |
---|
837 | 1075 | ratetbl->rate[offset].count_rts = 2; |
---|
838 | 1076 | ratetbl->rate[offset].count_cts = 2; |
---|
.. | .. |
---|
866 | 1104 | } |
---|
867 | 1105 | |
---|
868 | 1106 | static inline int |
---|
869 | | -minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate) |
---|
| 1107 | +minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) |
---|
870 | 1108 | { |
---|
871 | 1109 | int group = rate / MCS_GROUP_RATES; |
---|
872 | 1110 | rate %= MCS_GROUP_RATES; |
---|
873 | | - return mi->groups[group].rates[rate].prob_ewma; |
---|
| 1111 | + return mi->groups[group].rates[rate].prob_avg; |
---|
874 | 1112 | } |
---|
875 | 1113 | |
---|
876 | 1114 | static int |
---|
.. | .. |
---|
879 | 1117 | int group = mi->max_prob_rate / MCS_GROUP_RATES; |
---|
880 | 1118 | const struct mcs_group *g = &minstrel_mcs_groups[group]; |
---|
881 | 1119 | int rate = mi->max_prob_rate % MCS_GROUP_RATES; |
---|
| 1120 | + unsigned int duration; |
---|
882 | 1121 | |
---|
883 | 1122 | /* Disable A-MSDU if max_prob_rate is bad */ |
---|
884 | | - if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) |
---|
| 1123 | + if (mi->groups[group].rates[rate].prob_avg < MINSTREL_FRAC(50, 100)) |
---|
885 | 1124 | return 1; |
---|
886 | 1125 | |
---|
| 1126 | + duration = g->duration[rate]; |
---|
| 1127 | + duration <<= g->shift; |
---|
| 1128 | + |
---|
887 | 1129 | /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ |
---|
888 | | - if (g->duration[rate] > MCS_DURATION(1, 0, 52)) |
---|
| 1130 | + if (duration > MCS_DURATION(1, 0, 52)) |
---|
889 | 1131 | return 500; |
---|
890 | 1132 | |
---|
891 | 1133 | /* |
---|
892 | 1134 | * If the rate is slower than single-stream MCS4, limit A-MSDU to usual |
---|
893 | 1135 | * data packet size |
---|
894 | 1136 | */ |
---|
895 | | - if (g->duration[rate] > MCS_DURATION(1, 0, 104)) |
---|
| 1137 | + if (duration > MCS_DURATION(1, 0, 104)) |
---|
896 | 1138 | return 1600; |
---|
897 | 1139 | |
---|
898 | 1140 | /* |
---|
.. | .. |
---|
900 | 1142 | * rate success probability is less than 75%, limit A-MSDU to twice the usual |
---|
901 | 1143 | * data packet size |
---|
902 | 1144 | */ |
---|
903 | | - if (g->duration[rate] > MCS_DURATION(1, 0, 260) || |
---|
904 | | - (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) < |
---|
| 1145 | + if (duration > MCS_DURATION(1, 0, 260) || |
---|
| 1146 | + (minstrel_ht_get_prob_avg(mi, mi->max_tp_rate[0]) < |
---|
905 | 1147 | MINSTREL_FRAC(75, 100))) |
---|
906 | 1148 | return 3200; |
---|
907 | 1149 | |
---|
.. | .. |
---|
922 | 1164 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) |
---|
923 | 1165 | { |
---|
924 | 1166 | struct ieee80211_sta_rates *rates; |
---|
| 1167 | + u16 first_rate = mi->max_tp_rate[0]; |
---|
925 | 1168 | int i = 0; |
---|
| 1169 | + |
---|
| 1170 | + if (mi->sample_mode == MINSTREL_SAMPLE_ACTIVE) |
---|
| 1171 | + first_rate = mi->sample_rate; |
---|
926 | 1172 | |
---|
927 | 1173 | rates = kzalloc(sizeof(*rates), GFP_ATOMIC); |
---|
928 | 1174 | if (!rates) |
---|
929 | 1175 | return; |
---|
930 | 1176 | |
---|
931 | 1177 | /* Start with max_tp_rate[0] */ |
---|
932 | | - minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]); |
---|
| 1178 | + minstrel_ht_set_rate(mp, mi, rates, i++, first_rate); |
---|
933 | 1179 | |
---|
934 | 1180 | if (mp->hw->max_rates >= 3) { |
---|
935 | 1181 | /* At least 3 tx rates supported, use max_tp_rate[1] next */ |
---|
.. | .. |
---|
937 | 1183 | } |
---|
938 | 1184 | |
---|
939 | 1185 | if (mp->hw->max_rates >= 2) { |
---|
940 | | - /* |
---|
941 | | - * At least 2 tx rates supported, use max_prob_rate next */ |
---|
942 | 1186 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); |
---|
943 | 1187 | } |
---|
944 | 1188 | |
---|
945 | 1189 | mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); |
---|
946 | 1190 | rates->rate[i].idx = -1; |
---|
947 | 1191 | rate_control_set_rates(mp->hw, mi->sta, rates); |
---|
948 | | -} |
---|
949 | | - |
---|
950 | | -static inline int |
---|
951 | | -minstrel_get_duration(int index) |
---|
952 | | -{ |
---|
953 | | - const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
---|
954 | | - return group->duration[index % MCS_GROUP_RATES]; |
---|
955 | 1192 | } |
---|
956 | 1193 | |
---|
957 | 1194 | static int |
---|
.. | .. |
---|
962 | 1199 | unsigned int sample_dur, sample_group, cur_max_tp_streams; |
---|
963 | 1200 | int tp_rate1, tp_rate2; |
---|
964 | 1201 | int sample_idx = 0; |
---|
| 1202 | + |
---|
| 1203 | + if (mp->hw->max_rates == 1 && mp->sample_switch && |
---|
| 1204 | + (mi->total_packets_cur >= SAMPLE_SWITCH_THR || |
---|
| 1205 | + mp->sample_switch == 1)) |
---|
| 1206 | + return -1; |
---|
965 | 1207 | |
---|
966 | 1208 | if (mi->sample_wait > 0) { |
---|
967 | 1209 | mi->sample_wait--; |
---|
.. | .. |
---|
1001 | 1243 | return -1; |
---|
1002 | 1244 | |
---|
1003 | 1245 | /* |
---|
1004 | | - * Do not sample if the probability is already higher than 95% |
---|
1005 | | - * to avoid wasting airtime. |
---|
| 1246 | + * Do not sample if the probability is already higher than 95%, |
---|
| 1247 | + * or if the rate is 3 times slower than the current max probability |
---|
| 1248 | + * rate, to avoid wasting airtime. |
---|
1006 | 1249 | */ |
---|
1007 | | - if (mrs->prob_ewma > MINSTREL_FRAC(95, 100)) |
---|
| 1250 | + sample_dur = minstrel_get_duration(sample_idx); |
---|
| 1251 | + if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || |
---|
| 1252 | + minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) |
---|
| 1253 | + return -1; |
---|
| 1254 | + |
---|
| 1255 | + |
---|
| 1256 | + /* |
---|
| 1257 | + * For devices with no configurable multi-rate retry, skip sampling |
---|
| 1258 | + * below the per-group max throughput rate, and only use one sampling |
---|
| 1259 | + * attempt per rate |
---|
| 1260 | + */ |
---|
| 1261 | + if (mp->hw->max_rates == 1 && |
---|
| 1262 | + (minstrel_get_duration(mg->max_group_tp_rate[0]) < sample_dur || |
---|
| 1263 | + mrs->attempts)) |
---|
| 1264 | + return -1; |
---|
| 1265 | + |
---|
| 1266 | + /* Skip already sampled slow rates */ |
---|
| 1267 | + if (sample_dur >= minstrel_get_duration(tp_rate1) && mrs->attempts) |
---|
1008 | 1268 | return -1; |
---|
1009 | 1269 | |
---|
1010 | 1270 | /* |
---|
.. | .. |
---|
1014 | 1274 | |
---|
1015 | 1275 | cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / |
---|
1016 | 1276 | MCS_GROUP_RATES].streams; |
---|
1017 | | - sample_dur = minstrel_get_duration(sample_idx); |
---|
1018 | 1277 | if (sample_dur >= minstrel_get_duration(tp_rate2) && |
---|
1019 | 1278 | (cur_max_tp_streams - 1 < |
---|
1020 | 1279 | minstrel_mcs_groups[sample_group].streams || |
---|
.. | .. |
---|
1041 | 1300 | struct minstrel_ht_sta *mi = &msp->ht; |
---|
1042 | 1301 | struct minstrel_priv *mp = priv; |
---|
1043 | 1302 | int sample_idx; |
---|
1044 | | - |
---|
1045 | | - if (rate_control_send_low(sta, priv_sta, txrc)) |
---|
1046 | | - return; |
---|
1047 | 1303 | |
---|
1048 | 1304 | if (!msp->is_ht) |
---|
1049 | 1305 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); |
---|
.. | .. |
---|
1136 | 1392 | struct minstrel_ht_sta_priv *msp = priv_sta; |
---|
1137 | 1393 | struct minstrel_ht_sta *mi = &msp->ht; |
---|
1138 | 1394 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; |
---|
1139 | | - u16 sta_cap = sta->ht_cap.cap; |
---|
| 1395 | + u16 ht_cap = sta->ht_cap.cap; |
---|
1140 | 1396 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; |
---|
1141 | 1397 | int use_vht; |
---|
1142 | 1398 | int n_supported = 0; |
---|
1143 | 1399 | int ack_dur; |
---|
1144 | 1400 | int stbc; |
---|
1145 | 1401 | int i; |
---|
| 1402 | + bool ldpc; |
---|
1146 | 1403 | |
---|
1147 | 1404 | /* fall back to the old minstrel for legacy stations */ |
---|
1148 | 1405 | if (!sta->ht_cap.ht_supported) |
---|
.. | .. |
---|
1150 | 1407 | |
---|
1151 | 1408 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); |
---|
1152 | 1409 | |
---|
1153 | | -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
---|
1154 | 1410 | if (vht_cap->vht_supported) |
---|
1155 | 1411 | use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); |
---|
1156 | 1412 | else |
---|
1157 | | -#endif |
---|
1158 | | - use_vht = 0; |
---|
| 1413 | + use_vht = 0; |
---|
1159 | 1414 | |
---|
1160 | 1415 | msp->is_ht = true; |
---|
1161 | 1416 | memset(mi, 0, sizeof(*mi)); |
---|
.. | .. |
---|
1180 | 1435 | } |
---|
1181 | 1436 | mi->sample_tries = 4; |
---|
1182 | 1437 | |
---|
1183 | | - /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */ |
---|
1184 | 1438 | if (!use_vht) { |
---|
1185 | | - stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> |
---|
| 1439 | + stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> |
---|
1186 | 1440 | IEEE80211_HT_CAP_RX_STBC_SHIFT; |
---|
1187 | | - mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; |
---|
1188 | 1441 | |
---|
1189 | | - if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
---|
1190 | | - mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
---|
| 1442 | + ldpc = ht_cap & IEEE80211_HT_CAP_LDPC_CODING; |
---|
| 1443 | + } else { |
---|
| 1444 | + stbc = (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) >> |
---|
| 1445 | + IEEE80211_VHT_CAP_RXSTBC_SHIFT; |
---|
| 1446 | + |
---|
| 1447 | + ldpc = vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC; |
---|
1191 | 1448 | } |
---|
| 1449 | + |
---|
| 1450 | + mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; |
---|
| 1451 | + if (ldpc) |
---|
| 1452 | + mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
---|
1192 | 1453 | |
---|
1193 | 1454 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
---|
1194 | 1455 | u32 gflags = minstrel_mcs_groups[i].flags; |
---|
.. | .. |
---|
1202 | 1463 | |
---|
1203 | 1464 | if (gflags & IEEE80211_TX_RC_SHORT_GI) { |
---|
1204 | 1465 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
---|
1205 | | - if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) |
---|
| 1466 | + if (!(ht_cap & IEEE80211_HT_CAP_SGI_40)) |
---|
1206 | 1467 | continue; |
---|
1207 | 1468 | } else { |
---|
1208 | | - if (!(sta_cap & IEEE80211_HT_CAP_SGI_20)) |
---|
| 1469 | + if (!(ht_cap & IEEE80211_HT_CAP_SGI_20)) |
---|
1209 | 1470 | continue; |
---|
1210 | 1471 | } |
---|
1211 | 1472 | } |
---|
.. | .. |
---|
1222 | 1483 | |
---|
1223 | 1484 | /* HT rate */ |
---|
1224 | 1485 | if (gflags & IEEE80211_TX_RC_MCS) { |
---|
1225 | | -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
---|
1226 | 1486 | if (use_vht && minstrel_vht_only) |
---|
1227 | 1487 | continue; |
---|
1228 | | -#endif |
---|
| 1488 | + |
---|
1229 | 1489 | mi->supported[i] = mcs->rx_mask[nss - 1]; |
---|
1230 | 1490 | if (mi->supported[i]) |
---|
1231 | 1491 | n_supported++; |
---|
.. | .. |
---|
1266 | 1526 | mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4; |
---|
1267 | 1527 | |
---|
1268 | 1528 | /* create an initial rate table with the lowest supported rates */ |
---|
1269 | | - minstrel_ht_update_stats(mp, mi); |
---|
| 1529 | + minstrel_ht_update_stats(mp, mi, true); |
---|
1270 | 1530 | minstrel_ht_update_rates(mp, mi); |
---|
1271 | 1531 | |
---|
1272 | 1532 | return; |
---|
.. | .. |
---|
1344 | 1604 | kfree(msp); |
---|
1345 | 1605 | } |
---|
1346 | 1606 | |
---|
1347 | | -static void * |
---|
1348 | | -minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
---|
| 1607 | +static void |
---|
| 1608 | +minstrel_ht_init_cck_rates(struct minstrel_priv *mp) |
---|
1349 | 1609 | { |
---|
1350 | | - return mac80211_minstrel.alloc(hw, debugfsdir); |
---|
| 1610 | + static const int bitrates[4] = { 10, 20, 55, 110 }; |
---|
| 1611 | + struct ieee80211_supported_band *sband; |
---|
| 1612 | + u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); |
---|
| 1613 | + int i, j; |
---|
| 1614 | + |
---|
| 1615 | + sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; |
---|
| 1616 | + if (!sband) |
---|
| 1617 | + return; |
---|
| 1618 | + |
---|
| 1619 | + for (i = 0; i < sband->n_bitrates; i++) { |
---|
| 1620 | + struct ieee80211_rate *rate = &sband->bitrates[i]; |
---|
| 1621 | + |
---|
| 1622 | + if (rate->flags & IEEE80211_RATE_ERP_G) |
---|
| 1623 | + continue; |
---|
| 1624 | + |
---|
| 1625 | + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) |
---|
| 1626 | + continue; |
---|
| 1627 | + |
---|
| 1628 | + for (j = 0; j < ARRAY_SIZE(bitrates); j++) { |
---|
| 1629 | + if (rate->bitrate != bitrates[j]) |
---|
| 1630 | + continue; |
---|
| 1631 | + |
---|
| 1632 | + mp->cck_rates[j] = i; |
---|
| 1633 | + break; |
---|
| 1634 | + } |
---|
| 1635 | + } |
---|
1351 | 1636 | } |
---|
| 1637 | + |
---|
| 1638 | +static void * |
---|
| 1639 | +minstrel_ht_alloc(struct ieee80211_hw *hw) |
---|
| 1640 | +{ |
---|
| 1641 | + struct minstrel_priv *mp; |
---|
| 1642 | + |
---|
| 1643 | + mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); |
---|
| 1644 | + if (!mp) |
---|
| 1645 | + return NULL; |
---|
| 1646 | + |
---|
| 1647 | + mp->sample_switch = -1; |
---|
| 1648 | + |
---|
| 1649 | + /* contention window settings |
---|
| 1650 | + * Just an approximation. Using the per-queue values would complicate |
---|
| 1651 | + * the calculations and is probably unnecessary */ |
---|
| 1652 | + mp->cw_min = 15; |
---|
| 1653 | + mp->cw_max = 1023; |
---|
| 1654 | + |
---|
| 1655 | + /* number of packets (in %) to use for sampling other rates |
---|
| 1656 | + * sample less often for non-mrr packets, because the overhead |
---|
| 1657 | + * is much higher than with mrr */ |
---|
| 1658 | + mp->lookaround_rate = 5; |
---|
| 1659 | + mp->lookaround_rate_mrr = 10; |
---|
| 1660 | + |
---|
| 1661 | + /* maximum time that the hw is allowed to stay in one MRR segment */ |
---|
| 1662 | + mp->segment_size = 6000; |
---|
| 1663 | + |
---|
| 1664 | + if (hw->max_rate_tries > 0) |
---|
| 1665 | + mp->max_retry = hw->max_rate_tries; |
---|
| 1666 | + else |
---|
| 1667 | + /* safe default, does not necessarily have to match hw properties */ |
---|
| 1668 | + mp->max_retry = 7; |
---|
| 1669 | + |
---|
| 1670 | + if (hw->max_rates >= 4) |
---|
| 1671 | + mp->has_mrr = true; |
---|
| 1672 | + |
---|
| 1673 | + mp->hw = hw; |
---|
| 1674 | + mp->update_interval = HZ / 10; |
---|
| 1675 | + mp->new_avg = true; |
---|
| 1676 | + |
---|
| 1677 | + minstrel_ht_init_cck_rates(mp); |
---|
| 1678 | + |
---|
| 1679 | + return mp; |
---|
| 1680 | +} |
---|
| 1681 | + |
---|
| 1682 | +#ifdef CONFIG_MAC80211_DEBUGFS |
---|
| 1683 | +static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, |
---|
| 1684 | + struct dentry *debugfsdir) |
---|
| 1685 | +{ |
---|
| 1686 | + struct minstrel_priv *mp = priv; |
---|
| 1687 | + |
---|
| 1688 | + mp->fixed_rate_idx = (u32) -1; |
---|
| 1689 | + debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, |
---|
| 1690 | + &mp->fixed_rate_idx); |
---|
| 1691 | + debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, |
---|
| 1692 | + &mp->sample_switch); |
---|
| 1693 | + debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir, |
---|
| 1694 | + &mp->new_avg); |
---|
| 1695 | +} |
---|
| 1696 | +#endif |
---|
1352 | 1697 | |
---|
1353 | 1698 | static void |
---|
1354 | 1699 | minstrel_ht_free(void *priv) |
---|
1355 | 1700 | { |
---|
1356 | | - mac80211_minstrel.free(priv); |
---|
| 1701 | + kfree(priv); |
---|
1357 | 1702 | } |
---|
1358 | 1703 | |
---|
1359 | 1704 | static u32 minstrel_ht_get_expected_throughput(void *priv_sta) |
---|
.. | .. |
---|
1367 | 1712 | |
---|
1368 | 1713 | i = mi->max_tp_rate[0] / MCS_GROUP_RATES; |
---|
1369 | 1714 | j = mi->max_tp_rate[0] % MCS_GROUP_RATES; |
---|
1370 | | - prob = mi->groups[i].rates[j].prob_ewma; |
---|
| 1715 | + prob = mi->groups[i].rates[j].prob_avg; |
---|
1371 | 1716 | |
---|
1372 | 1717 | /* convert tp_avg from pkt per second in kbps */ |
---|
1373 | 1718 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; |
---|
.. | .. |
---|
1387 | 1732 | .alloc = minstrel_ht_alloc, |
---|
1388 | 1733 | .free = minstrel_ht_free, |
---|
1389 | 1734 | #ifdef CONFIG_MAC80211_DEBUGFS |
---|
| 1735 | + .add_debugfs = minstrel_ht_add_debugfs, |
---|
1390 | 1736 | .add_sta_debugfs = minstrel_ht_add_sta_debugfs, |
---|
1391 | | - .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, |
---|
1392 | 1737 | #endif |
---|
1393 | 1738 | .get_expected_throughput = minstrel_ht_get_expected_throughput, |
---|
1394 | 1739 | }; |
---|
.. | .. |
---|
1413 | 1758 | } |
---|
1414 | 1759 | |
---|
1415 | 1760 | int __init |
---|
1416 | | -rc80211_minstrel_ht_init(void) |
---|
| 1761 | +rc80211_minstrel_init(void) |
---|
1417 | 1762 | { |
---|
1418 | 1763 | init_sample_table(); |
---|
1419 | 1764 | return ieee80211_rate_control_register(&mac80211_minstrel_ht); |
---|
1420 | 1765 | } |
---|
1421 | 1766 | |
---|
1422 | 1767 | void |
---|
1423 | | -rc80211_minstrel_ht_exit(void) |
---|
| 1768 | +rc80211_minstrel_exit(void) |
---|
1424 | 1769 | { |
---|
1425 | 1770 | ieee80211_rate_control_unregister(&mac80211_minstrel_ht); |
---|
1426 | 1771 | } |
---|