| .. | .. |
|---|
| 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 | } |
|---|