| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org> | 
|---|
| 4 | * Copyright (C) 2019-2022 Intel Corporation | 
|---|
| 5 | */ | 
|---|
| 6 | #include <linux/netdevice.h> | 
|---|
| 7 | #include <linux/types.h> | 
|---|
| 8 | #include <linux/skbuff.h> | 
|---|
| 9 | #include <linux/debugfs.h> | 
|---|
| 10 | #include <linux/random.h> | 
|---|
| 11 | #include <linux/moduleparam.h> | 
|---|
| 12 | #include <linux/ieee80211.h> | 
|---|
| 13 | #include <linux/minmax.h> | 
|---|
| 14 | #include <net/mac80211.h> | 
|---|
| 15 | #include "rate.h" | 
|---|
| 16 | #include "sta_info.h" | 
|---|
| 17 | #include "rc80211_minstrel_ht.h" | 
|---|
| 18 |  | 
|---|
| 19 | #define AVG_AMPDU_SIZE	16 | 
|---|
| 20 | #define AVG_PKT_SIZE	1200 | 
|---|
| 21 |  | 
|---|
| 22 | /* Number of bits for an average sized packet */ | 
|---|
| 23 | #define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3) | 
|---|
| 24 |  | 
|---|
| 25 | /* Number of symbols for a packet with (bps) bits per symbol */ | 
|---|
| 26 | #define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) | 
|---|
| 27 |  | 
|---|
| 28 | /* Transmission time (nanoseconds) for a packet containing (syms) symbols */ | 
|---|
| 29 | #define MCS_SYMBOL_TIME(sgi, syms)					\ | 
|---|
| 30 | (sgi ?								\ | 
|---|
| 31 | ((syms) * 18000 + 4000) / 5 :	/* syms * 3.6 us */		\ | 
|---|
| 32 | ((syms) * 1000) << 2		/* syms * 4 us */		\ | 
|---|
| 33 | ) | 
|---|
| 34 |  | 
|---|
| 35 | /* Transmit duration for the raw data part of an average sized packet */ | 
|---|
| 36 | #define MCS_DURATION(streams, sgi, bps) \ | 
|---|
| 37 | (MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE) | 
|---|
| 38 |  | 
|---|
| 39 | #define BW_20			0 | 
|---|
| 40 | #define BW_40			1 | 
|---|
| 41 | #define BW_80			2 | 
|---|
| 42 |  | 
|---|
| 43 | /* | 
|---|
| 44 | * Define group sort order: HT40 -> SGI -> #streams | 
|---|
| 45 | */ | 
|---|
| 46 | #define GROUP_IDX(_streams, _sgi, _ht40)	\ | 
|---|
| 47 | MINSTREL_HT_GROUP_0 +			\ | 
|---|
| 48 | MINSTREL_MAX_STREAMS * 2 * _ht40 +	\ | 
|---|
| 49 | MINSTREL_MAX_STREAMS * _sgi +	\ | 
|---|
| 50 | _streams - 1 | 
|---|
| 51 |  | 
|---|
| 52 | #define _MAX(a, b) (((a)>(b))?(a):(b)) | 
|---|
| 53 |  | 
|---|
| 54 | #define GROUP_SHIFT(duration)						\ | 
|---|
| 55 | _MAX(0, 16 - __builtin_clz(duration)) | 
|---|
| 56 |  | 
|---|
| 57 | /* MCS rate information for an MCS group */ | 
|---|
| 58 | #define __MCS_GROUP(_streams, _sgi, _ht40, _s)				\ | 
|---|
| 59 | [GROUP_IDX(_streams, _sgi, _ht40)] = {				\ | 
|---|
| 60 | .streams = _streams,						\ | 
|---|
| 61 | .shift = _s,							\ | 
|---|
| 62 | .bw = _ht40,							\ | 
|---|
| 63 | .flags =							\ | 
|---|
| 64 | IEEE80211_TX_RC_MCS |					\ | 
|---|
| 65 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |			\ | 
|---|
| 66 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),		\ | 
|---|
| 67 | .duration = {							\ | 
|---|
| 68 | MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s,	\ | 
|---|
| 69 | MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s,	\ | 
|---|
| 70 | MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s,	\ | 
|---|
| 71 | MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s,	\ | 
|---|
| 72 | MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s,	\ | 
|---|
| 73 | MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s,	\ | 
|---|
| 74 | MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s,	\ | 
|---|
| 75 | MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s	\ | 
|---|
| 76 | }								\ | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | #define MCS_GROUP_SHIFT(_streams, _sgi, _ht40)				\ | 
|---|
| 80 | GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) | 
|---|
| 81 |  | 
|---|
| 82 | #define MCS_GROUP(_streams, _sgi, _ht40)				\ | 
|---|
| 83 | __MCS_GROUP(_streams, _sgi, _ht40,				\ | 
|---|
| 84 | MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) | 
|---|
| 85 |  | 
|---|
| 86 | #define VHT_GROUP_IDX(_streams, _sgi, _bw)				\ | 
|---|
| 87 | (MINSTREL_VHT_GROUP_0 +						\ | 
|---|
| 88 | MINSTREL_MAX_STREAMS * 2 * (_bw) +				\ | 
|---|
| 89 | MINSTREL_MAX_STREAMS * (_sgi) +				\ | 
|---|
| 90 | (_streams) - 1) | 
|---|
| 91 |  | 
|---|
| 92 | #define BW2VBPS(_bw, r3, r2, r1)					\ | 
|---|
| 93 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) | 
|---|
| 94 |  | 
|---|
| 95 | #define __VHT_GROUP(_streams, _sgi, _bw, _s)				\ | 
|---|
| 96 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = {			\ | 
|---|
| 97 | .streams = _streams,						\ | 
|---|
| 98 | .shift = _s,							\ | 
|---|
| 99 | .bw = _bw,							\ | 
|---|
| 100 | .flags =							\ | 
|---|
| 101 | IEEE80211_TX_RC_VHT_MCS |				\ | 
|---|
| 102 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |			\ | 
|---|
| 103 | (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH :		\ | 
|---|
| 104 | _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),	\ | 
|---|
| 105 | .duration = {							\ | 
|---|
| 106 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 107 | BW2VBPS(_bw,  117,  54,  26)) >> _s,	\ | 
|---|
| 108 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 109 | BW2VBPS(_bw,  234, 108,  52)) >> _s,	\ | 
|---|
| 110 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 111 | BW2VBPS(_bw,  351, 162,  78)) >> _s,	\ | 
|---|
| 112 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 113 | BW2VBPS(_bw,  468, 216, 104)) >> _s,	\ | 
|---|
| 114 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 115 | BW2VBPS(_bw,  702, 324, 156)) >> _s,	\ | 
|---|
| 116 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 117 | BW2VBPS(_bw,  936, 432, 208)) >> _s,	\ | 
|---|
| 118 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 119 | BW2VBPS(_bw, 1053, 486, 234)) >> _s,	\ | 
|---|
| 120 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 121 | BW2VBPS(_bw, 1170, 540, 260)) >> _s,	\ | 
|---|
| 122 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 123 | BW2VBPS(_bw, 1404, 648, 312)) >> _s,	\ | 
|---|
| 124 | MCS_DURATION(_streams, _sgi,				\ | 
|---|
| 125 | BW2VBPS(_bw, 1560, 720, 346)) >> _s	\ | 
|---|
| 126 | }								\ | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | #define VHT_GROUP_SHIFT(_streams, _sgi, _bw)				\ | 
|---|
| 130 | GROUP_SHIFT(MCS_DURATION(_streams, _sgi,			\ | 
|---|
| 131 | BW2VBPS(_bw,  117,  54,  26))) | 
|---|
| 132 |  | 
|---|
| 133 | #define VHT_GROUP(_streams, _sgi, _bw)					\ | 
|---|
| 134 | __VHT_GROUP(_streams, _sgi, _bw,				\ | 
|---|
| 135 | VHT_GROUP_SHIFT(_streams, _sgi, _bw)) | 
|---|
| 136 |  | 
|---|
| 137 | #define CCK_DURATION(_bitrate, _short)			\ | 
|---|
| 138 | (1000 * (10 /* SIFS */ +			\ | 
|---|
| 139 | (_short ? 72 + 24 : 144 + 48) +		\ | 
|---|
| 140 | (8 * (AVG_PKT_SIZE + 4) * 10) / (_bitrate))) | 
|---|
| 141 |  | 
|---|
| 142 | #define CCK_DURATION_LIST(_short, _s)			\ | 
|---|
| 143 | CCK_DURATION(10, _short) >> _s,			\ | 
|---|
| 144 | CCK_DURATION(20, _short) >> _s,			\ | 
|---|
| 145 | CCK_DURATION(55, _short) >> _s,			\ | 
|---|
| 146 | CCK_DURATION(110, _short) >> _s | 
|---|
| 147 |  | 
|---|
| 148 | #define __CCK_GROUP(_s)					\ | 
|---|
| 149 | [MINSTREL_CCK_GROUP] = {			\ | 
|---|
| 150 | .streams = 1,				\ | 
|---|
| 151 | .flags = 0,				\ | 
|---|
| 152 | .shift = _s,				\ | 
|---|
| 153 | .duration = {				\ | 
|---|
| 154 | CCK_DURATION_LIST(false, _s),	\ | 
|---|
| 155 | CCK_DURATION_LIST(true, _s)	\ | 
|---|
| 156 | }					\ | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | #define CCK_GROUP_SHIFT					\ | 
|---|
| 160 | GROUP_SHIFT(CCK_DURATION(10, false)) | 
|---|
| 161 |  | 
|---|
| 162 | #define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) | 
|---|
| 163 |  | 
|---|
| 164 | #define OFDM_DURATION(_bitrate)				\ | 
|---|
| 165 | (1000 * (16 /* SIFS + signal ext */ +		\ | 
|---|
| 166 | 16 /* T_PREAMBLE */ +				\ | 
|---|
| 167 | 4 /* T_SIGNAL */ +				\ | 
|---|
| 168 | 4 * (((16 + 80 * (AVG_PKT_SIZE + 4) + 6) /	\ | 
|---|
| 169 | ((_bitrate) * 4))))) | 
|---|
| 170 |  | 
|---|
| 171 | #define OFDM_DURATION_LIST(_s)				\ | 
|---|
| 172 | OFDM_DURATION(60) >> _s,			\ | 
|---|
| 173 | OFDM_DURATION(90) >> _s,			\ | 
|---|
| 174 | OFDM_DURATION(120) >> _s,			\ | 
|---|
| 175 | OFDM_DURATION(180) >> _s,			\ | 
|---|
| 176 | OFDM_DURATION(240) >> _s,			\ | 
|---|
| 177 | OFDM_DURATION(360) >> _s,			\ | 
|---|
| 178 | OFDM_DURATION(480) >> _s,			\ | 
|---|
| 179 | OFDM_DURATION(540) >> _s | 
|---|
| 180 |  | 
|---|
| 181 | #define __OFDM_GROUP(_s)				\ | 
|---|
| 182 | [MINSTREL_OFDM_GROUP] = {			\ | 
|---|
| 183 | .streams = 1,				\ | 
|---|
| 184 | .flags = 0,				\ | 
|---|
| 185 | .shift = _s,				\ | 
|---|
| 186 | .duration = {				\ | 
|---|
| 187 | OFDM_DURATION_LIST(_s),		\ | 
|---|
| 188 | }					\ | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 | #define OFDM_GROUP_SHIFT				\ | 
|---|
| 192 | GROUP_SHIFT(OFDM_DURATION(60)) | 
|---|
| 193 |  | 
|---|
| 194 | #define OFDM_GROUP __OFDM_GROUP(OFDM_GROUP_SHIFT) | 
|---|
| 195 |  | 
|---|
| 196 |  | 
|---|
| 197 | static bool minstrel_vht_only = true; | 
|---|
| 198 | module_param(minstrel_vht_only, bool, 0644); | 
|---|
| 199 | MODULE_PARM_DESC(minstrel_vht_only, | 
|---|
| 200 | "Use only VHT rates when VHT is supported by sta."); | 
|---|
| 201 |  | 
|---|
| 202 | /* | 
|---|
| 203 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 
|---|
| 204 | * groups, based on the number of streams and flags (HT40, SGI) that they | 
|---|
| 205 | * use. | 
|---|
| 206 | * | 
|---|
| 207 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: | 
|---|
| 208 | * BW -> SGI -> #streams | 
|---|
| 209 | */ | 
|---|
| 210 | const struct mcs_group minstrel_mcs_groups[] = { | 
|---|
| 211 | MCS_GROUP(1, 0, BW_20), | 
|---|
| 212 | MCS_GROUP(2, 0, BW_20), | 
|---|
| 213 | MCS_GROUP(3, 0, BW_20), | 
|---|
| 214 | MCS_GROUP(4, 0, BW_20), | 
|---|
| 215 |  | 
|---|
| 216 | MCS_GROUP(1, 1, BW_20), | 
|---|
| 217 | MCS_GROUP(2, 1, BW_20), | 
|---|
| 218 | MCS_GROUP(3, 1, BW_20), | 
|---|
| 219 | MCS_GROUP(4, 1, BW_20), | 
|---|
| 220 |  | 
|---|
| 221 | MCS_GROUP(1, 0, BW_40), | 
|---|
| 222 | MCS_GROUP(2, 0, BW_40), | 
|---|
| 223 | MCS_GROUP(3, 0, BW_40), | 
|---|
| 224 | MCS_GROUP(4, 0, BW_40), | 
|---|
| 225 |  | 
|---|
| 226 | MCS_GROUP(1, 1, BW_40), | 
|---|
| 227 | MCS_GROUP(2, 1, BW_40), | 
|---|
| 228 | MCS_GROUP(3, 1, BW_40), | 
|---|
| 229 | MCS_GROUP(4, 1, BW_40), | 
|---|
| 230 |  | 
|---|
| 231 | CCK_GROUP, | 
|---|
| 232 | OFDM_GROUP, | 
|---|
| 233 |  | 
|---|
| 234 | VHT_GROUP(1, 0, BW_20), | 
|---|
| 235 | VHT_GROUP(2, 0, BW_20), | 
|---|
| 236 | VHT_GROUP(3, 0, BW_20), | 
|---|
| 237 | VHT_GROUP(4, 0, BW_20), | 
|---|
| 238 |  | 
|---|
| 239 | VHT_GROUP(1, 1, BW_20), | 
|---|
| 240 | VHT_GROUP(2, 1, BW_20), | 
|---|
| 241 | VHT_GROUP(3, 1, BW_20), | 
|---|
| 242 | VHT_GROUP(4, 1, BW_20), | 
|---|
| 243 |  | 
|---|
| 244 | VHT_GROUP(1, 0, BW_40), | 
|---|
| 245 | VHT_GROUP(2, 0, BW_40), | 
|---|
| 246 | VHT_GROUP(3, 0, BW_40), | 
|---|
| 247 | VHT_GROUP(4, 0, BW_40), | 
|---|
| 248 |  | 
|---|
| 249 | VHT_GROUP(1, 1, BW_40), | 
|---|
| 250 | VHT_GROUP(2, 1, BW_40), | 
|---|
| 251 | VHT_GROUP(3, 1, BW_40), | 
|---|
| 252 | VHT_GROUP(4, 1, BW_40), | 
|---|
| 253 |  | 
|---|
| 254 | VHT_GROUP(1, 0, BW_80), | 
|---|
| 255 | VHT_GROUP(2, 0, BW_80), | 
|---|
| 256 | VHT_GROUP(3, 0, BW_80), | 
|---|
| 257 | VHT_GROUP(4, 0, BW_80), | 
|---|
| 258 |  | 
|---|
| 259 | VHT_GROUP(1, 1, BW_80), | 
|---|
| 260 | VHT_GROUP(2, 1, BW_80), | 
|---|
| 261 | VHT_GROUP(3, 1, BW_80), | 
|---|
| 262 | VHT_GROUP(4, 1, BW_80), | 
|---|
| 263 | }; | 
|---|
| 264 |  | 
|---|
| 265 | const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 }; | 
|---|
| 266 | const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; | 
|---|
| 267 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; | 
|---|
| 268 | static const u8 minstrel_sample_seq[] = { | 
|---|
| 269 | MINSTREL_SAMPLE_TYPE_INC, | 
|---|
| 270 | MINSTREL_SAMPLE_TYPE_JUMP, | 
|---|
| 271 | MINSTREL_SAMPLE_TYPE_INC, | 
|---|
| 272 | MINSTREL_SAMPLE_TYPE_JUMP, | 
|---|
| 273 | MINSTREL_SAMPLE_TYPE_INC, | 
|---|
| 274 | MINSTREL_SAMPLE_TYPE_SLOW, | 
|---|
| 275 | }; | 
|---|
| 276 |  | 
|---|
| 277 | static void | 
|---|
| 278 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | 
|---|
| 279 |  | 
|---|
| 280 | /* | 
|---|
| 281 | * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer) | 
|---|
| 282 | * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1 | 
|---|
| 283 | * | 
|---|
| 284 | * Returns the valid mcs map for struct minstrel_mcs_group_data.supported | 
|---|
| 285 | */ | 
|---|
| 286 | static u16 | 
|---|
| 287 | minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map) | 
|---|
| 288 | { | 
|---|
| 289 | u16 mask = 0; | 
|---|
| 290 |  | 
|---|
| 291 | if (bw == BW_20) { | 
|---|
| 292 | if (nss != 3 && nss != 6) | 
|---|
| 293 | mask = BIT(9); | 
|---|
| 294 | } else if (bw == BW_80) { | 
|---|
| 295 | if (nss == 3 || nss == 7) | 
|---|
| 296 | mask = BIT(6); | 
|---|
| 297 | else if (nss == 6) | 
|---|
| 298 | mask = BIT(9); | 
|---|
| 299 | } else { | 
|---|
| 300 | WARN_ON(bw != BW_40); | 
|---|
| 301 | } | 
|---|
| 302 |  | 
|---|
| 303 | switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) { | 
|---|
| 304 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | 
|---|
| 305 | mask |= 0x300; | 
|---|
| 306 | break; | 
|---|
| 307 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | 
|---|
| 308 | mask |= 0x200; | 
|---|
| 309 | break; | 
|---|
| 310 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | 
|---|
| 311 | break; | 
|---|
| 312 | default: | 
|---|
| 313 | mask = 0x3ff; | 
|---|
| 314 | } | 
|---|
| 315 |  | 
|---|
| 316 | return 0x3ff & ~mask; | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | static bool | 
|---|
| 320 | minstrel_ht_is_legacy_group(int group) | 
|---|
| 321 | { | 
|---|
| 322 | return group == MINSTREL_CCK_GROUP || | 
|---|
| 323 | group == MINSTREL_OFDM_GROUP; | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 | /* | 
|---|
| 327 | * Look up an MCS group index based on mac80211 rate information | 
|---|
| 328 | */ | 
|---|
| 329 | static int | 
|---|
| 330 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 
|---|
| 331 | { | 
|---|
| 332 | return GROUP_IDX((rate->idx / 8) + 1, | 
|---|
| 333 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 
|---|
| 334 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | /* | 
|---|
| 338 | * Look up an MCS group index based on new cfg80211 rate_info. | 
|---|
| 339 | */ | 
|---|
| 340 | static int | 
|---|
| 341 | minstrel_ht_ri_get_group_idx(struct rate_info *rate) | 
|---|
| 342 | { | 
|---|
| 343 | return GROUP_IDX((rate->mcs / 8) + 1, | 
|---|
| 344 | !!(rate->flags & RATE_INFO_FLAGS_SHORT_GI), | 
|---|
| 345 | !!(rate->bw & RATE_INFO_BW_40)); | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | static int | 
|---|
| 349 | minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate) | 
|---|
| 350 | { | 
|---|
| 351 | return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate), | 
|---|
| 352 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 
|---|
| 353 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + | 
|---|
| 354 | 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)); | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | /* | 
|---|
| 358 | * Look up an MCS group index based on new cfg80211 rate_info. | 
|---|
| 359 | */ | 
|---|
| 360 | static int | 
|---|
| 361 | minstrel_vht_ri_get_group_idx(struct rate_info *rate) | 
|---|
| 362 | { | 
|---|
| 363 | return VHT_GROUP_IDX(rate->nss, | 
|---|
| 364 | !!(rate->flags & RATE_INFO_FLAGS_SHORT_GI), | 
|---|
| 365 | !!(rate->bw & RATE_INFO_BW_40) + | 
|---|
| 366 | 2*!!(rate->bw & RATE_INFO_BW_80)); | 
|---|
| 367 | } | 
|---|
| 368 |  | 
|---|
| 369 | static struct minstrel_rate_stats * | 
|---|
| 370 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 371 | struct ieee80211_tx_rate *rate) | 
|---|
| 372 | { | 
|---|
| 373 | int group, idx; | 
|---|
| 374 |  | 
|---|
| 375 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 
|---|
| 376 | group = minstrel_ht_get_group_idx(rate); | 
|---|
| 377 | idx = rate->idx % 8; | 
|---|
| 378 | goto out; | 
|---|
| 379 | } | 
|---|
| 380 |  | 
|---|
| 381 | if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | 
|---|
| 382 | group = minstrel_vht_get_group_idx(rate); | 
|---|
| 383 | idx = ieee80211_rate_get_vht_mcs(rate); | 
|---|
| 384 | goto out; | 
|---|
| 385 | } | 
|---|
| 386 |  | 
|---|
| 387 | group = MINSTREL_CCK_GROUP; | 
|---|
| 388 | for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) { | 
|---|
| 389 | if (!(mi->supported[group] & BIT(idx))) | 
|---|
| 390 | continue; | 
|---|
| 391 |  | 
|---|
| 392 | if (rate->idx != mp->cck_rates[idx]) | 
|---|
| 393 | continue; | 
|---|
| 394 |  | 
|---|
| 395 | /* short preamble */ | 
|---|
| 396 | if ((mi->supported[group] & BIT(idx + 4)) && | 
|---|
| 397 | (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) | 
|---|
| 398 | idx += 4; | 
|---|
| 399 | goto out; | 
|---|
| 400 | } | 
|---|
| 401 |  | 
|---|
| 402 | group = MINSTREL_OFDM_GROUP; | 
|---|
| 403 | for (idx = 0; idx < ARRAY_SIZE(mp->ofdm_rates[0]); idx++) | 
|---|
| 404 | if (rate->idx == mp->ofdm_rates[mi->band][idx]) | 
|---|
| 405 | goto out; | 
|---|
| 406 |  | 
|---|
| 407 | idx = 0; | 
|---|
| 408 | out: | 
|---|
| 409 | return &mi->groups[group].rates[idx]; | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | /* | 
|---|
| 413 | * Get the minstrel rate statistics for specified STA and rate info. | 
|---|
| 414 | */ | 
|---|
| 415 | static struct minstrel_rate_stats * | 
|---|
| 416 | minstrel_ht_ri_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 417 | struct ieee80211_rate_status *rate_status) | 
|---|
| 418 | { | 
|---|
| 419 | int group, idx; | 
|---|
| 420 | struct rate_info *rate = &rate_status->rate_idx; | 
|---|
| 421 |  | 
|---|
| 422 | if (rate->flags & RATE_INFO_FLAGS_MCS) { | 
|---|
| 423 | group = minstrel_ht_ri_get_group_idx(rate); | 
|---|
| 424 | idx = rate->mcs % 8; | 
|---|
| 425 | goto out; | 
|---|
| 426 | } | 
|---|
| 427 |  | 
|---|
| 428 | if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) { | 
|---|
| 429 | group = minstrel_vht_ri_get_group_idx(rate); | 
|---|
| 430 | idx = rate->mcs; | 
|---|
| 431 | goto out; | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | group = MINSTREL_CCK_GROUP; | 
|---|
| 435 | for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) { | 
|---|
| 436 | if (rate->legacy != minstrel_cck_bitrates[ mp->cck_rates[idx] ]) | 
|---|
| 437 | continue; | 
|---|
| 438 |  | 
|---|
| 439 | /* short preamble */ | 
|---|
| 440 | if ((mi->supported[group] & BIT(idx + 4)) && | 
|---|
| 441 | mi->use_short_preamble) | 
|---|
| 442 | idx += 4; | 
|---|
| 443 | goto out; | 
|---|
| 444 | } | 
|---|
| 445 |  | 
|---|
| 446 | group = MINSTREL_OFDM_GROUP; | 
|---|
| 447 | for (idx = 0; idx < ARRAY_SIZE(mp->ofdm_rates[0]); idx++) | 
|---|
| 448 | if (rate->legacy == minstrel_ofdm_bitrates[ mp->ofdm_rates[mi->band][idx] ]) | 
|---|
| 449 | goto out; | 
|---|
| 450 |  | 
|---|
| 451 | idx = 0; | 
|---|
| 452 | out: | 
|---|
| 453 | return &mi->groups[group].rates[idx]; | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | static inline struct minstrel_rate_stats * | 
|---|
| 457 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | 
|---|
| 458 | { | 
|---|
| 459 | return &mi->groups[MI_RATE_GROUP(index)].rates[MI_RATE_IDX(index)]; | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 | static inline int minstrel_get_duration(int index) | 
|---|
| 463 | { | 
|---|
| 464 | const struct mcs_group *group = &minstrel_mcs_groups[MI_RATE_GROUP(index)]; | 
|---|
| 465 | unsigned int duration = group->duration[MI_RATE_IDX(index)]; | 
|---|
| 466 |  | 
|---|
| 467 | return duration << group->shift; | 
|---|
| 468 | } | 
|---|
| 469 |  | 
|---|
| 470 | static unsigned int | 
|---|
| 471 | minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) | 
|---|
| 472 | { | 
|---|
| 473 | int duration; | 
|---|
| 474 |  | 
|---|
| 475 | if (mi->avg_ampdu_len) | 
|---|
| 476 | return MINSTREL_TRUNC(mi->avg_ampdu_len); | 
|---|
| 477 |  | 
|---|
| 478 | if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_tp_rate[0]))) | 
|---|
| 479 | return 1; | 
|---|
| 480 |  | 
|---|
| 481 | duration = minstrel_get_duration(index: mi->max_tp_rate[0]); | 
|---|
| 482 |  | 
|---|
| 483 | if (duration > 400 * 1000) | 
|---|
| 484 | return 2; | 
|---|
| 485 |  | 
|---|
| 486 | if (duration > 250 * 1000) | 
|---|
| 487 | return 4; | 
|---|
| 488 |  | 
|---|
| 489 | if (duration > 150 * 1000) | 
|---|
| 490 | return 8; | 
|---|
| 491 |  | 
|---|
| 492 | return 16; | 
|---|
| 493 | } | 
|---|
| 494 |  | 
|---|
| 495 | /* | 
|---|
| 496 | * Return current throughput based on the average A-MPDU length, taking into | 
|---|
| 497 | * account the expected number of retransmissions and their expected length | 
|---|
| 498 | */ | 
|---|
| 499 | int | 
|---|
| 500 | minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, | 
|---|
| 501 | int prob_avg) | 
|---|
| 502 | { | 
|---|
| 503 | unsigned int nsecs = 0, overhead = mi->overhead; | 
|---|
| 504 | unsigned int ampdu_len = 1; | 
|---|
| 505 |  | 
|---|
| 506 | /* do not account throughput if success prob is below 10% */ | 
|---|
| 507 | if (prob_avg < MINSTREL_FRAC(10, 100)) | 
|---|
| 508 | return 0; | 
|---|
| 509 |  | 
|---|
| 510 | if (minstrel_ht_is_legacy_group(group)) | 
|---|
| 511 | overhead = mi->overhead_legacy; | 
|---|
| 512 | else | 
|---|
| 513 | ampdu_len = minstrel_ht_avg_ampdu_len(mi); | 
|---|
| 514 |  | 
|---|
| 515 | nsecs = 1000 * overhead / ampdu_len; | 
|---|
| 516 | nsecs += minstrel_mcs_groups[group].duration[rate] << | 
|---|
| 517 | minstrel_mcs_groups[group].shift; | 
|---|
| 518 |  | 
|---|
| 519 | /* | 
|---|
| 520 | * For the throughput calculation, limit the probability value to 90% to | 
|---|
| 521 | * account for collision related packet error rate fluctuation | 
|---|
| 522 | * (prob is scaled - see MINSTREL_FRAC above) | 
|---|
| 523 | */ | 
|---|
| 524 | if (prob_avg > MINSTREL_FRAC(90, 100)) | 
|---|
| 525 | prob_avg = MINSTREL_FRAC(90, 100); | 
|---|
| 526 |  | 
|---|
| 527 | return MINSTREL_TRUNC(100 * ((prob_avg * 1000000) / nsecs)); | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | /* | 
|---|
| 531 | * Find & sort topmost throughput rates | 
|---|
| 532 | * | 
|---|
| 533 | * If multiple rates provide equal throughput the sorting is based on their | 
|---|
| 534 | * current success probability. Higher success probability is preferred among | 
|---|
| 535 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. | 
|---|
| 536 | */ | 
|---|
| 537 | static void | 
|---|
| 538 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, | 
|---|
| 539 | u16 *tp_list) | 
|---|
| 540 | { | 
|---|
| 541 | int cur_group, cur_idx, cur_tp_avg, cur_prob; | 
|---|
| 542 | int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; | 
|---|
| 543 | int j = MAX_THR_RATES; | 
|---|
| 544 |  | 
|---|
| 545 | cur_group = MI_RATE_GROUP(index); | 
|---|
| 546 | cur_idx = MI_RATE_IDX(index); | 
|---|
| 547 | cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; | 
|---|
| 548 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, group: cur_group, rate: cur_idx, prob_avg: cur_prob); | 
|---|
| 549 |  | 
|---|
| 550 | do { | 
|---|
| 551 | tmp_group = MI_RATE_GROUP(tp_list[j - 1]); | 
|---|
| 552 | tmp_idx = MI_RATE_IDX(tp_list[j - 1]); | 
|---|
| 553 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; | 
|---|
| 554 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, group: tmp_group, rate: tmp_idx, | 
|---|
| 555 | prob_avg: tmp_prob); | 
|---|
| 556 | if (cur_tp_avg < tmp_tp_avg || | 
|---|
| 557 | (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) | 
|---|
| 558 | break; | 
|---|
| 559 | j--; | 
|---|
| 560 | } while (j > 0); | 
|---|
| 561 |  | 
|---|
| 562 | if (j < MAX_THR_RATES - 1) { | 
|---|
| 563 | memmove(dest: &tp_list[j + 1], src: &tp_list[j], count: (sizeof(*tp_list) * | 
|---|
| 564 | (MAX_THR_RATES - (j + 1)))); | 
|---|
| 565 | } | 
|---|
| 566 | if (j < MAX_THR_RATES) | 
|---|
| 567 | tp_list[j] = index; | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | /* | 
|---|
| 571 | * Find and set the topmost probability rate per sta and per group | 
|---|
| 572 | */ | 
|---|
| 573 | static void | 
|---|
| 574 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 *dest, u16 index) | 
|---|
| 575 | { | 
|---|
| 576 | struct minstrel_mcs_group_data *mg; | 
|---|
| 577 | struct minstrel_rate_stats *mrs; | 
|---|
| 578 | int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; | 
|---|
| 579 | int max_tp_group, max_tp_idx, max_tp_prob; | 
|---|
| 580 | int cur_tp_avg, cur_group, cur_idx; | 
|---|
| 581 | int max_gpr_group, max_gpr_idx; | 
|---|
| 582 | int max_gpr_tp_avg, max_gpr_prob; | 
|---|
| 583 |  | 
|---|
| 584 | cur_group = MI_RATE_GROUP(index); | 
|---|
| 585 | cur_idx = MI_RATE_IDX(index); | 
|---|
| 586 | mg = &mi->groups[cur_group]; | 
|---|
| 587 | mrs = &mg->rates[cur_idx]; | 
|---|
| 588 |  | 
|---|
| 589 | tmp_group = MI_RATE_GROUP(*dest); | 
|---|
| 590 | tmp_idx = MI_RATE_IDX(*dest); | 
|---|
| 591 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; | 
|---|
| 592 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, group: tmp_group, rate: tmp_idx, prob_avg: tmp_prob); | 
|---|
| 593 |  | 
|---|
| 594 | /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from | 
|---|
| 595 | * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ | 
|---|
| 596 | max_tp_group = MI_RATE_GROUP(mi->max_tp_rate[0]); | 
|---|
| 597 | max_tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); | 
|---|
| 598 | max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg; | 
|---|
| 599 |  | 
|---|
| 600 | if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index)) && | 
|---|
| 601 | !minstrel_ht_is_legacy_group(group: max_tp_group)) | 
|---|
| 602 | return; | 
|---|
| 603 |  | 
|---|
| 604 | /* skip rates faster than max tp rate with lower prob */ | 
|---|
| 605 | if (minstrel_get_duration(index: mi->max_tp_rate[0]) > minstrel_get_duration(index) && | 
|---|
| 606 | mrs->prob_avg < max_tp_prob) | 
|---|
| 607 | return; | 
|---|
| 608 |  | 
|---|
| 609 | max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); | 
|---|
| 610 | max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); | 
|---|
| 611 | max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; | 
|---|
| 612 |  | 
|---|
| 613 | if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { | 
|---|
| 614 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, group: cur_group, rate: cur_idx, | 
|---|
| 615 | prob_avg: mrs->prob_avg); | 
|---|
| 616 | if (cur_tp_avg > tmp_tp_avg) | 
|---|
| 617 | *dest = index; | 
|---|
| 618 |  | 
|---|
| 619 | max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, group: max_gpr_group, | 
|---|
| 620 | rate: max_gpr_idx, | 
|---|
| 621 | prob_avg: max_gpr_prob); | 
|---|
| 622 | if (cur_tp_avg > max_gpr_tp_avg) | 
|---|
| 623 | mg->max_group_prob_rate = index; | 
|---|
| 624 | } else { | 
|---|
| 625 | if (mrs->prob_avg > tmp_prob) | 
|---|
| 626 | *dest = index; | 
|---|
| 627 | if (mrs->prob_avg > max_gpr_prob) | 
|---|
| 628 | mg->max_group_prob_rate = index; | 
|---|
| 629 | } | 
|---|
| 630 | } | 
|---|
| 631 |  | 
|---|
| 632 |  | 
|---|
| 633 | /* | 
|---|
| 634 | * Assign new rate set per sta and use CCK rates only if the fastest | 
|---|
| 635 | * rate (max_tp_rate[0]) is from CCK group. This prohibits such sorted | 
|---|
| 636 | * rate sets where MCS and CCK rates are mixed, because CCK rates can | 
|---|
| 637 | * not use aggregation. | 
|---|
| 638 | */ | 
|---|
| 639 | static void | 
|---|
| 640 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, | 
|---|
| 641 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], | 
|---|
| 642 | u16 tmp_legacy_tp_rate[MAX_THR_RATES]) | 
|---|
| 643 | { | 
|---|
| 644 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; | 
|---|
| 645 | int i; | 
|---|
| 646 |  | 
|---|
| 647 | tmp_group = MI_RATE_GROUP(tmp_legacy_tp_rate[0]); | 
|---|
| 648 | tmp_idx = MI_RATE_IDX(tmp_legacy_tp_rate[0]); | 
|---|
| 649 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; | 
|---|
| 650 | tmp_cck_tp = minstrel_ht_get_tp_avg(mi, group: tmp_group, rate: tmp_idx, prob_avg: tmp_prob); | 
|---|
| 651 |  | 
|---|
| 652 | tmp_group = MI_RATE_GROUP(tmp_mcs_tp_rate[0]); | 
|---|
| 653 | tmp_idx = MI_RATE_IDX(tmp_mcs_tp_rate[0]); | 
|---|
| 654 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; | 
|---|
| 655 | tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, group: tmp_group, rate: tmp_idx, prob_avg: tmp_prob); | 
|---|
| 656 |  | 
|---|
| 657 | if (tmp_cck_tp > tmp_mcs_tp) { | 
|---|
| 658 | for(i = 0; i < MAX_THR_RATES; i++) { | 
|---|
| 659 | minstrel_ht_sort_best_tp_rates(mi, index: tmp_legacy_tp_rate[i], | 
|---|
| 660 | tp_list: tmp_mcs_tp_rate); | 
|---|
| 661 | } | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | } | 
|---|
| 665 |  | 
|---|
| 666 | /* | 
|---|
| 667 | * Try to increase robustness of max_prob rate by decrease number of | 
|---|
| 668 | * streams if possible. | 
|---|
| 669 | */ | 
|---|
| 670 | static inline void | 
|---|
| 671 | minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) | 
|---|
| 672 | { | 
|---|
| 673 | struct minstrel_mcs_group_data *mg; | 
|---|
| 674 | int tmp_max_streams, group, tmp_idx, tmp_prob; | 
|---|
| 675 | int tmp_tp = 0; | 
|---|
| 676 |  | 
|---|
| 677 | if (!mi->sta->deflink.ht_cap.ht_supported) | 
|---|
| 678 | return; | 
|---|
| 679 |  | 
|---|
| 680 | group = MI_RATE_GROUP(mi->max_tp_rate[0]); | 
|---|
| 681 | tmp_max_streams = minstrel_mcs_groups[group].streams; | 
|---|
| 682 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | 
|---|
| 683 | mg = &mi->groups[group]; | 
|---|
| 684 | if (!mi->supported[group] || group == MINSTREL_CCK_GROUP) | 
|---|
| 685 | continue; | 
|---|
| 686 |  | 
|---|
| 687 | tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate); | 
|---|
| 688 | tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; | 
|---|
| 689 |  | 
|---|
| 690 | if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, rate: tmp_idx, prob_avg: tmp_prob) && | 
|---|
| 691 | (minstrel_mcs_groups[group].streams < tmp_max_streams)) { | 
|---|
| 692 | mi->max_prob_rate = mg->max_group_prob_rate; | 
|---|
| 693 | tmp_tp = minstrel_ht_get_tp_avg(mi, group, | 
|---|
| 694 | rate: tmp_idx, | 
|---|
| 695 | prob_avg: tmp_prob); | 
|---|
| 696 | } | 
|---|
| 697 | } | 
|---|
| 698 | } | 
|---|
| 699 |  | 
|---|
| 700 | static u16 | 
|---|
| 701 | __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, | 
|---|
| 702 | enum minstrel_sample_type type) | 
|---|
| 703 | { | 
|---|
| 704 | u16 *rates = mi->sample[type].sample_rates; | 
|---|
| 705 | u16 cur; | 
|---|
| 706 | int i; | 
|---|
| 707 |  | 
|---|
| 708 | for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { | 
|---|
| 709 | if (!rates[i]) | 
|---|
| 710 | continue; | 
|---|
| 711 |  | 
|---|
| 712 | cur = rates[i]; | 
|---|
| 713 | rates[i] = 0; | 
|---|
| 714 | return cur; | 
|---|
| 715 | } | 
|---|
| 716 |  | 
|---|
| 717 | return 0; | 
|---|
| 718 | } | 
|---|
| 719 |  | 
|---|
| 720 | static inline int | 
|---|
| 721 | minstrel_ewma(int old, int new, int weight) | 
|---|
| 722 | { | 
|---|
| 723 | int diff, incr; | 
|---|
| 724 |  | 
|---|
| 725 | diff = new - old; | 
|---|
| 726 | incr = (EWMA_DIV - weight) * diff / EWMA_DIV; | 
|---|
| 727 |  | 
|---|
| 728 | return old + incr; | 
|---|
| 729 | } | 
|---|
| 730 |  | 
|---|
| 731 | static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) | 
|---|
| 732 | { | 
|---|
| 733 | s32 out_1 = *prev_1; | 
|---|
| 734 | s32 out_2 = *prev_2; | 
|---|
| 735 | s32 val; | 
|---|
| 736 |  | 
|---|
| 737 | if (!in) | 
|---|
| 738 | in += 1; | 
|---|
| 739 |  | 
|---|
| 740 | if (!out_1) { | 
|---|
| 741 | val = out_1 = in; | 
|---|
| 742 | goto out; | 
|---|
| 743 | } | 
|---|
| 744 |  | 
|---|
| 745 | val = MINSTREL_AVG_COEFF1 * in; | 
|---|
| 746 | val += MINSTREL_AVG_COEFF2 * out_1; | 
|---|
| 747 | val += MINSTREL_AVG_COEFF3 * out_2; | 
|---|
| 748 | val >>= MINSTREL_SCALE; | 
|---|
| 749 |  | 
|---|
| 750 | if (val > 1 << MINSTREL_SCALE) | 
|---|
| 751 | val = 1 << MINSTREL_SCALE; | 
|---|
| 752 | if (val < 0) | 
|---|
| 753 | val = 1; | 
|---|
| 754 |  | 
|---|
| 755 | out: | 
|---|
| 756 | *prev_2 = out_1; | 
|---|
| 757 | *prev_1 = val; | 
|---|
| 758 |  | 
|---|
| 759 | return val; | 
|---|
| 760 | } | 
|---|
| 761 |  | 
|---|
| 762 | /* | 
|---|
| 763 | * Recalculate statistics and counters of a given rate | 
|---|
| 764 | */ | 
|---|
| 765 | static void | 
|---|
| 766 | minstrel_ht_calc_rate_stats(struct minstrel_priv *mp, | 
|---|
| 767 | struct minstrel_rate_stats *mrs) | 
|---|
| 768 | { | 
|---|
| 769 | unsigned int cur_prob; | 
|---|
| 770 |  | 
|---|
| 771 | if (unlikely(mrs->attempts > 0)) { | 
|---|
| 772 | cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); | 
|---|
| 773 | minstrel_filter_avg_add(prev_1: &mrs->prob_avg, | 
|---|
| 774 | prev_2: &mrs->prob_avg_1, in: cur_prob); | 
|---|
| 775 | mrs->att_hist += mrs->attempts; | 
|---|
| 776 | mrs->succ_hist += mrs->success; | 
|---|
| 777 | } | 
|---|
| 778 |  | 
|---|
| 779 | mrs->last_success = mrs->success; | 
|---|
| 780 | mrs->last_attempts = mrs->attempts; | 
|---|
| 781 | mrs->success = 0; | 
|---|
| 782 | mrs->attempts = 0; | 
|---|
| 783 | } | 
|---|
| 784 |  | 
|---|
| 785 | static bool | 
|---|
| 786 | minstrel_ht_find_sample_rate(struct minstrel_ht_sta *mi, int type, int idx) | 
|---|
| 787 | { | 
|---|
| 788 | int i; | 
|---|
| 789 |  | 
|---|
| 790 | for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { | 
|---|
| 791 | u16 cur = mi->sample[type].sample_rates[i]; | 
|---|
| 792 |  | 
|---|
| 793 | if (cur == idx) | 
|---|
| 794 | return true; | 
|---|
| 795 |  | 
|---|
| 796 | if (!cur) | 
|---|
| 797 | break; | 
|---|
| 798 | } | 
|---|
| 799 |  | 
|---|
| 800 | return false; | 
|---|
| 801 | } | 
|---|
| 802 |  | 
|---|
| 803 | static int | 
|---|
| 804 | minstrel_ht_move_sample_rates(struct minstrel_ht_sta *mi, int type, | 
|---|
| 805 | u32 fast_rate_dur, u32 slow_rate_dur) | 
|---|
| 806 | { | 
|---|
| 807 | u16 *rates = mi->sample[type].sample_rates; | 
|---|
| 808 | int i, j; | 
|---|
| 809 |  | 
|---|
| 810 | for (i = 0, j = 0; i < MINSTREL_SAMPLE_RATES; i++) { | 
|---|
| 811 | u32 duration; | 
|---|
| 812 | bool valid = false; | 
|---|
| 813 | u16 cur; | 
|---|
| 814 |  | 
|---|
| 815 | cur = rates[i]; | 
|---|
| 816 | if (!cur) | 
|---|
| 817 | continue; | 
|---|
| 818 |  | 
|---|
| 819 | duration = minstrel_get_duration(index: cur); | 
|---|
| 820 | switch (type) { | 
|---|
| 821 | case MINSTREL_SAMPLE_TYPE_SLOW: | 
|---|
| 822 | valid = duration > fast_rate_dur && | 
|---|
| 823 | duration < slow_rate_dur; | 
|---|
| 824 | break; | 
|---|
| 825 | case MINSTREL_SAMPLE_TYPE_INC: | 
|---|
| 826 | case MINSTREL_SAMPLE_TYPE_JUMP: | 
|---|
| 827 | valid = duration < fast_rate_dur; | 
|---|
| 828 | break; | 
|---|
| 829 | default: | 
|---|
| 830 | valid = false; | 
|---|
| 831 | break; | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | if (!valid) { | 
|---|
| 835 | rates[i] = 0; | 
|---|
| 836 | continue; | 
|---|
| 837 | } | 
|---|
| 838 |  | 
|---|
| 839 | if (i == j) | 
|---|
| 840 | continue; | 
|---|
| 841 |  | 
|---|
| 842 | rates[j++] = cur; | 
|---|
| 843 | rates[i] = 0; | 
|---|
| 844 | } | 
|---|
| 845 |  | 
|---|
| 846 | return j; | 
|---|
| 847 | } | 
|---|
| 848 |  | 
|---|
| 849 | static int | 
|---|
| 850 | minstrel_ht_group_min_rate_offset(struct minstrel_ht_sta *mi, int group, | 
|---|
| 851 | u32 max_duration) | 
|---|
| 852 | { | 
|---|
| 853 | u16 supported = mi->supported[group]; | 
|---|
| 854 | int i; | 
|---|
| 855 |  | 
|---|
| 856 | for (i = 0; i < MCS_GROUP_RATES && supported; i++, supported >>= 1) { | 
|---|
| 857 | if (!(supported & BIT(0))) | 
|---|
| 858 | continue; | 
|---|
| 859 |  | 
|---|
| 860 | if (minstrel_get_duration(MI_RATE(group, i)) >= max_duration) | 
|---|
| 861 | continue; | 
|---|
| 862 |  | 
|---|
| 863 | return i; | 
|---|
| 864 | } | 
|---|
| 865 |  | 
|---|
| 866 | return -1; | 
|---|
| 867 | } | 
|---|
| 868 |  | 
|---|
| 869 | /* | 
|---|
| 870 | * Incremental update rates: | 
|---|
| 871 | * Flip through groups and pick the first group rate that is faster than the | 
|---|
| 872 | * highest currently selected rate | 
|---|
| 873 | */ | 
|---|
| 874 | static u16 | 
|---|
| 875 | minstrel_ht_next_inc_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur) | 
|---|
| 876 | { | 
|---|
| 877 | u8 type = MINSTREL_SAMPLE_TYPE_INC; | 
|---|
| 878 | int i, index = 0; | 
|---|
| 879 | u8 group; | 
|---|
| 880 |  | 
|---|
| 881 | group = mi->sample[type].sample_group; | 
|---|
| 882 | for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { | 
|---|
| 883 | group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); | 
|---|
| 884 |  | 
|---|
| 885 | index = minstrel_ht_group_min_rate_offset(mi, group, | 
|---|
| 886 | max_duration: fast_rate_dur); | 
|---|
| 887 | if (index < 0) | 
|---|
| 888 | continue; | 
|---|
| 889 |  | 
|---|
| 890 | index = MI_RATE(group, index & 0xf); | 
|---|
| 891 | if (!minstrel_ht_find_sample_rate(mi, type, idx: index)) | 
|---|
| 892 | goto out; | 
|---|
| 893 | } | 
|---|
| 894 | index = 0; | 
|---|
| 895 |  | 
|---|
| 896 | out: | 
|---|
| 897 | mi->sample[type].sample_group = group; | 
|---|
| 898 |  | 
|---|
| 899 | return index; | 
|---|
| 900 | } | 
|---|
| 901 |  | 
|---|
| 902 | static int | 
|---|
| 903 | minstrel_ht_next_group_sample_rate(struct minstrel_ht_sta *mi, int group, | 
|---|
| 904 | u16 supported, int offset) | 
|---|
| 905 | { | 
|---|
| 906 | struct minstrel_mcs_group_data *mg = &mi->groups[group]; | 
|---|
| 907 | u16 idx; | 
|---|
| 908 | int i; | 
|---|
| 909 |  | 
|---|
| 910 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 
|---|
| 911 | idx = sample_table[mg->column][mg->index]; | 
|---|
| 912 | if (++mg->index >= MCS_GROUP_RATES) { | 
|---|
| 913 | mg->index = 0; | 
|---|
| 914 | if (++mg->column >= ARRAY_SIZE(sample_table)) | 
|---|
| 915 | mg->column = 0; | 
|---|
| 916 | } | 
|---|
| 917 |  | 
|---|
| 918 | if (idx < offset) | 
|---|
| 919 | continue; | 
|---|
| 920 |  | 
|---|
| 921 | if (!(supported & BIT(idx))) | 
|---|
| 922 | continue; | 
|---|
| 923 |  | 
|---|
| 924 | return MI_RATE(group, idx); | 
|---|
| 925 | } | 
|---|
| 926 |  | 
|---|
| 927 | return -1; | 
|---|
| 928 | } | 
|---|
| 929 |  | 
|---|
| 930 | /* | 
|---|
| 931 | * Jump rates: | 
|---|
| 932 | * Sample random rates, use those that are faster than the highest | 
|---|
| 933 | * currently selected rate. Rates between the fastest and the slowest | 
|---|
| 934 | * get sorted into the slow sample bucket, but only if it has room | 
|---|
| 935 | */ | 
|---|
| 936 | static u16 | 
|---|
| 937 | minstrel_ht_next_jump_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur, | 
|---|
| 938 | u32 slow_rate_dur, int *slow_rate_ofs) | 
|---|
| 939 | { | 
|---|
| 940 | struct minstrel_rate_stats *mrs; | 
|---|
| 941 | u32 max_duration = slow_rate_dur; | 
|---|
| 942 | int i, index, offset; | 
|---|
| 943 | u16 *slow_rates; | 
|---|
| 944 | u16 supported; | 
|---|
| 945 | u32 duration; | 
|---|
| 946 | u8 group; | 
|---|
| 947 |  | 
|---|
| 948 | if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) | 
|---|
| 949 | max_duration = fast_rate_dur; | 
|---|
| 950 |  | 
|---|
| 951 | slow_rates = mi->sample[MINSTREL_SAMPLE_TYPE_SLOW].sample_rates; | 
|---|
| 952 | group = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group; | 
|---|
| 953 | for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { | 
|---|
| 954 | u8 type; | 
|---|
| 955 |  | 
|---|
| 956 | group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); | 
|---|
| 957 |  | 
|---|
| 958 | supported = mi->supported[group]; | 
|---|
| 959 | if (!supported) | 
|---|
| 960 | continue; | 
|---|
| 961 |  | 
|---|
| 962 | offset = minstrel_ht_group_min_rate_offset(mi, group, | 
|---|
| 963 | max_duration); | 
|---|
| 964 | if (offset < 0) | 
|---|
| 965 | continue; | 
|---|
| 966 |  | 
|---|
| 967 | index = minstrel_ht_next_group_sample_rate(mi, group, supported, | 
|---|
| 968 | offset); | 
|---|
| 969 | if (index < 0) | 
|---|
| 970 | continue; | 
|---|
| 971 |  | 
|---|
| 972 | duration = minstrel_get_duration(index); | 
|---|
| 973 | if (duration < fast_rate_dur) | 
|---|
| 974 | type = MINSTREL_SAMPLE_TYPE_JUMP; | 
|---|
| 975 | else | 
|---|
| 976 | type = MINSTREL_SAMPLE_TYPE_SLOW; | 
|---|
| 977 |  | 
|---|
| 978 | if (minstrel_ht_find_sample_rate(mi, type, idx: index)) | 
|---|
| 979 | continue; | 
|---|
| 980 |  | 
|---|
| 981 | if (type == MINSTREL_SAMPLE_TYPE_JUMP) | 
|---|
| 982 | goto found; | 
|---|
| 983 |  | 
|---|
| 984 | if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) | 
|---|
| 985 | continue; | 
|---|
| 986 |  | 
|---|
| 987 | if (duration >= slow_rate_dur) | 
|---|
| 988 | continue; | 
|---|
| 989 |  | 
|---|
| 990 | /* skip slow rates with high success probability */ | 
|---|
| 991 | mrs = minstrel_get_ratestats(mi, index); | 
|---|
| 992 | if (mrs->prob_avg > MINSTREL_FRAC(95, 100)) | 
|---|
| 993 | continue; | 
|---|
| 994 |  | 
|---|
| 995 | slow_rates[(*slow_rate_ofs)++] = index; | 
|---|
| 996 | if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) | 
|---|
| 997 | max_duration = fast_rate_dur; | 
|---|
| 998 | } | 
|---|
| 999 | index = 0; | 
|---|
| 1000 |  | 
|---|
| 1001 | found: | 
|---|
| 1002 | mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group = group; | 
|---|
| 1003 |  | 
|---|
| 1004 | return index; | 
|---|
| 1005 | } | 
|---|
| 1006 |  | 
|---|
| 1007 | static void | 
|---|
| 1008 | minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi) | 
|---|
| 1009 | { | 
|---|
| 1010 | u32 prob_dur = minstrel_get_duration(index: mi->max_prob_rate); | 
|---|
| 1011 | u32 tp_dur = minstrel_get_duration(index: mi->max_tp_rate[0]); | 
|---|
| 1012 | u32 tp2_dur = minstrel_get_duration(index: mi->max_tp_rate[1]); | 
|---|
| 1013 | u32 fast_rate_dur = min(min(tp_dur, tp2_dur), prob_dur); | 
|---|
| 1014 | u32 slow_rate_dur = max(max(tp_dur, tp2_dur), prob_dur); | 
|---|
| 1015 | u16 *rates; | 
|---|
| 1016 | int i, j; | 
|---|
| 1017 |  | 
|---|
| 1018 | rates = mi->sample[MINSTREL_SAMPLE_TYPE_INC].sample_rates; | 
|---|
| 1019 | i = minstrel_ht_move_sample_rates(mi, type: MINSTREL_SAMPLE_TYPE_INC, | 
|---|
| 1020 | fast_rate_dur, slow_rate_dur); | 
|---|
| 1021 | while (i < MINSTREL_SAMPLE_RATES) { | 
|---|
| 1022 | rates[i] = minstrel_ht_next_inc_rate(mi, fast_rate_dur: tp_dur); | 
|---|
| 1023 | if (!rates[i]) | 
|---|
| 1024 | break; | 
|---|
| 1025 |  | 
|---|
| 1026 | i++; | 
|---|
| 1027 | } | 
|---|
| 1028 |  | 
|---|
| 1029 | rates = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_rates; | 
|---|
| 1030 | i = minstrel_ht_move_sample_rates(mi, type: MINSTREL_SAMPLE_TYPE_JUMP, | 
|---|
| 1031 | fast_rate_dur, slow_rate_dur); | 
|---|
| 1032 | j = minstrel_ht_move_sample_rates(mi, type: MINSTREL_SAMPLE_TYPE_SLOW, | 
|---|
| 1033 | fast_rate_dur, slow_rate_dur); | 
|---|
| 1034 | while (i < MINSTREL_SAMPLE_RATES) { | 
|---|
| 1035 | rates[i] = minstrel_ht_next_jump_rate(mi, fast_rate_dur, | 
|---|
| 1036 | slow_rate_dur, slow_rate_ofs: &j); | 
|---|
| 1037 | if (!rates[i]) | 
|---|
| 1038 | break; | 
|---|
| 1039 |  | 
|---|
| 1040 | i++; | 
|---|
| 1041 | } | 
|---|
| 1042 |  | 
|---|
| 1043 | for (i = 0; i < ARRAY_SIZE(mi->sample); i++) | 
|---|
| 1044 | memcpy(to: mi->sample[i].cur_sample_rates, from: mi->sample[i].sample_rates, | 
|---|
| 1045 | len: sizeof(mi->sample[i].cur_sample_rates)); | 
|---|
| 1046 | } | 
|---|
| 1047 |  | 
|---|
| 1048 |  | 
|---|
| 1049 | /* | 
|---|
| 1050 | * Update rate statistics and select new primary rates | 
|---|
| 1051 | * | 
|---|
| 1052 | * Rules for rate selection: | 
|---|
| 1053 | *  - max_prob_rate must use only one stream, as a tradeoff between delivery | 
|---|
| 1054 | *    probability and throughput during strong fluctuations | 
|---|
| 1055 | *  - as long as the max prob rate has a probability of more than 75%, pick | 
|---|
| 1056 | *    higher throughput rates, even if the probability is a bit lower | 
|---|
| 1057 | */ | 
|---|
| 1058 | static void | 
|---|
| 1059 | minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | 
|---|
| 1060 | { | 
|---|
| 1061 | struct minstrel_mcs_group_data *mg; | 
|---|
| 1062 | struct minstrel_rate_stats *mrs; | 
|---|
| 1063 | int group, i, j, cur_prob; | 
|---|
| 1064 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; | 
|---|
| 1065 | u16 tmp_legacy_tp_rate[MAX_THR_RATES], tmp_max_prob_rate; | 
|---|
| 1066 | u16 index; | 
|---|
| 1067 | bool ht_supported = mi->sta->deflink.ht_cap.ht_supported; | 
|---|
| 1068 |  | 
|---|
| 1069 | if (mi->ampdu_packets > 0) { | 
|---|
| 1070 | if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) | 
|---|
| 1071 | mi->avg_ampdu_len = minstrel_ewma(old: mi->avg_ampdu_len, | 
|---|
| 1072 | MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), | 
|---|
| 1073 | EWMA_LEVEL); | 
|---|
| 1074 | else | 
|---|
| 1075 | mi->avg_ampdu_len = 0; | 
|---|
| 1076 | mi->ampdu_len = 0; | 
|---|
| 1077 | mi->ampdu_packets = 0; | 
|---|
| 1078 | } | 
|---|
| 1079 |  | 
|---|
| 1080 | if (mi->supported[MINSTREL_CCK_GROUP]) | 
|---|
| 1081 | group = MINSTREL_CCK_GROUP; | 
|---|
| 1082 | else if (mi->supported[MINSTREL_OFDM_GROUP]) | 
|---|
| 1083 | group = MINSTREL_OFDM_GROUP; | 
|---|
| 1084 | else | 
|---|
| 1085 | group = 0; | 
|---|
| 1086 |  | 
|---|
| 1087 | index = MI_RATE(group, 0); | 
|---|
| 1088 | for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) | 
|---|
| 1089 | tmp_legacy_tp_rate[j] = index; | 
|---|
| 1090 |  | 
|---|
| 1091 | if (mi->supported[MINSTREL_VHT_GROUP_0]) | 
|---|
| 1092 | group = MINSTREL_VHT_GROUP_0; | 
|---|
| 1093 | else if (ht_supported) | 
|---|
| 1094 | group = MINSTREL_HT_GROUP_0; | 
|---|
| 1095 | else if (mi->supported[MINSTREL_CCK_GROUP]) | 
|---|
| 1096 | group = MINSTREL_CCK_GROUP; | 
|---|
| 1097 | else | 
|---|
| 1098 | group = MINSTREL_OFDM_GROUP; | 
|---|
| 1099 |  | 
|---|
| 1100 | index = MI_RATE(group, 0); | 
|---|
| 1101 | tmp_max_prob_rate = index; | 
|---|
| 1102 | for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) | 
|---|
| 1103 | tmp_mcs_tp_rate[j] = index; | 
|---|
| 1104 |  | 
|---|
| 1105 | /* Find best rate sets within all MCS groups*/ | 
|---|
| 1106 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | 
|---|
| 1107 | u16 *tp_rate = tmp_mcs_tp_rate; | 
|---|
| 1108 | u16 last_prob = 0; | 
|---|
| 1109 |  | 
|---|
| 1110 | mg = &mi->groups[group]; | 
|---|
| 1111 | if (!mi->supported[group]) | 
|---|
| 1112 | continue; | 
|---|
| 1113 |  | 
|---|
| 1114 | /* (re)Initialize group rate indexes */ | 
|---|
| 1115 | for(j = 0; j < MAX_THR_RATES; j++) | 
|---|
| 1116 | tmp_group_tp_rate[j] = MI_RATE(group, 0); | 
|---|
| 1117 |  | 
|---|
| 1118 | if (group == MINSTREL_CCK_GROUP && ht_supported) | 
|---|
| 1119 | tp_rate = tmp_legacy_tp_rate; | 
|---|
| 1120 |  | 
|---|
| 1121 | for (i = MCS_GROUP_RATES - 1; i >= 0; i--) { | 
|---|
| 1122 | if (!(mi->supported[group] & BIT(i))) | 
|---|
| 1123 | continue; | 
|---|
| 1124 |  | 
|---|
| 1125 | index = MI_RATE(group, i); | 
|---|
| 1126 |  | 
|---|
| 1127 | mrs = &mg->rates[i]; | 
|---|
| 1128 | mrs->retry_updated = false; | 
|---|
| 1129 | minstrel_ht_calc_rate_stats(mp, mrs); | 
|---|
| 1130 |  | 
|---|
| 1131 | if (mrs->att_hist) | 
|---|
| 1132 | last_prob = max(last_prob, mrs->prob_avg); | 
|---|
| 1133 | else | 
|---|
| 1134 | mrs->prob_avg = max(last_prob, mrs->prob_avg); | 
|---|
| 1135 | cur_prob = mrs->prob_avg; | 
|---|
| 1136 |  | 
|---|
| 1137 | if (minstrel_ht_get_tp_avg(mi, group, rate: i, prob_avg: cur_prob) == 0) | 
|---|
| 1138 | continue; | 
|---|
| 1139 |  | 
|---|
| 1140 | /* Find max throughput rate set */ | 
|---|
| 1141 | minstrel_ht_sort_best_tp_rates(mi, index, tp_list: tp_rate); | 
|---|
| 1142 |  | 
|---|
| 1143 | /* Find max throughput rate set within a group */ | 
|---|
| 1144 | minstrel_ht_sort_best_tp_rates(mi, index, | 
|---|
| 1145 | tp_list: tmp_group_tp_rate); | 
|---|
| 1146 | } | 
|---|
| 1147 |  | 
|---|
| 1148 | memcpy(to: mg->max_group_tp_rate, from: tmp_group_tp_rate, | 
|---|
| 1149 | len: sizeof(mg->max_group_tp_rate)); | 
|---|
| 1150 | } | 
|---|
| 1151 |  | 
|---|
| 1152 | /* Assign new rate set per sta */ | 
|---|
| 1153 | minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, | 
|---|
| 1154 | tmp_legacy_tp_rate); | 
|---|
| 1155 | memcpy(to: mi->max_tp_rate, from: tmp_mcs_tp_rate, len: sizeof(mi->max_tp_rate)); | 
|---|
| 1156 |  | 
|---|
| 1157 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | 
|---|
| 1158 | if (!mi->supported[group]) | 
|---|
| 1159 | continue; | 
|---|
| 1160 |  | 
|---|
| 1161 | mg = &mi->groups[group]; | 
|---|
| 1162 | mg->max_group_prob_rate = MI_RATE(group, 0); | 
|---|
| 1163 |  | 
|---|
| 1164 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 
|---|
| 1165 | if (!(mi->supported[group] & BIT(i))) | 
|---|
| 1166 | continue; | 
|---|
| 1167 |  | 
|---|
| 1168 | index = MI_RATE(group, i); | 
|---|
| 1169 |  | 
|---|
| 1170 | /* Find max probability rate per group and global */ | 
|---|
| 1171 | minstrel_ht_set_best_prob_rate(mi, dest: &tmp_max_prob_rate, | 
|---|
| 1172 | index); | 
|---|
| 1173 | } | 
|---|
| 1174 | } | 
|---|
| 1175 |  | 
|---|
| 1176 | mi->max_prob_rate = tmp_max_prob_rate; | 
|---|
| 1177 |  | 
|---|
| 1178 | /* Try to increase robustness of max_prob_rate*/ | 
|---|
| 1179 | minstrel_ht_prob_rate_reduce_streams(mi); | 
|---|
| 1180 | minstrel_ht_refill_sample_rates(mi); | 
|---|
| 1181 |  | 
|---|
| 1182 | #ifdef CONFIG_MAC80211_DEBUGFS | 
|---|
| 1183 | /* use fixed index if set */ | 
|---|
| 1184 | if (mp->fixed_rate_idx != -1) { | 
|---|
| 1185 | for (i = 0; i < 4; i++) | 
|---|
| 1186 | mi->max_tp_rate[i] = mp->fixed_rate_idx; | 
|---|
| 1187 | mi->max_prob_rate = mp->fixed_rate_idx; | 
|---|
| 1188 | } | 
|---|
| 1189 | #endif | 
|---|
| 1190 |  | 
|---|
| 1191 | /* Reset update timer */ | 
|---|
| 1192 | mi->last_stats_update = jiffies; | 
|---|
| 1193 | mi->sample_time = jiffies; | 
|---|
| 1194 | } | 
|---|
| 1195 |  | 
|---|
| 1196 | static bool | 
|---|
| 1197 | minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 1198 | struct ieee80211_tx_rate *rate) | 
|---|
| 1199 | { | 
|---|
| 1200 | int i; | 
|---|
| 1201 |  | 
|---|
| 1202 | if (rate->idx < 0) | 
|---|
| 1203 | return false; | 
|---|
| 1204 |  | 
|---|
| 1205 | if (!rate->count) | 
|---|
| 1206 | return false; | 
|---|
| 1207 |  | 
|---|
| 1208 | if (rate->flags & IEEE80211_TX_RC_MCS || | 
|---|
| 1209 | rate->flags & IEEE80211_TX_RC_VHT_MCS) | 
|---|
| 1210 | return true; | 
|---|
| 1211 |  | 
|---|
| 1212 | for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) | 
|---|
| 1213 | if (rate->idx == mp->cck_rates[i]) | 
|---|
| 1214 | return true; | 
|---|
| 1215 |  | 
|---|
| 1216 | for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) | 
|---|
| 1217 | if (rate->idx == mp->ofdm_rates[mi->band][i]) | 
|---|
| 1218 | return true; | 
|---|
| 1219 |  | 
|---|
| 1220 | return false; | 
|---|
| 1221 | } | 
|---|
| 1222 |  | 
|---|
| 1223 | /* | 
|---|
| 1224 | * Check whether rate_status contains valid information. | 
|---|
| 1225 | */ | 
|---|
| 1226 | static bool | 
|---|
| 1227 | minstrel_ht_ri_txstat_valid(struct minstrel_priv *mp, | 
|---|
| 1228 | struct minstrel_ht_sta *mi, | 
|---|
| 1229 | struct ieee80211_rate_status *rate_status) | 
|---|
| 1230 | { | 
|---|
| 1231 | int i; | 
|---|
| 1232 |  | 
|---|
| 1233 | if (!rate_status) | 
|---|
| 1234 | return false; | 
|---|
| 1235 | if (!rate_status->try_count) | 
|---|
| 1236 | return false; | 
|---|
| 1237 |  | 
|---|
| 1238 | if (rate_status->rate_idx.flags & RATE_INFO_FLAGS_MCS || | 
|---|
| 1239 | rate_status->rate_idx.flags & RATE_INFO_FLAGS_VHT_MCS) | 
|---|
| 1240 | return true; | 
|---|
| 1241 |  | 
|---|
| 1242 | for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) { | 
|---|
| 1243 | if (rate_status->rate_idx.legacy == | 
|---|
| 1244 | minstrel_cck_bitrates[ mp->cck_rates[i] ]) | 
|---|
| 1245 | return true; | 
|---|
| 1246 | } | 
|---|
| 1247 |  | 
|---|
| 1248 | for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates); i++) { | 
|---|
| 1249 | if (rate_status->rate_idx.legacy == | 
|---|
| 1250 | minstrel_ofdm_bitrates[ mp->ofdm_rates[mi->band][i] ]) | 
|---|
| 1251 | return true; | 
|---|
| 1252 | } | 
|---|
| 1253 |  | 
|---|
| 1254 | return false; | 
|---|
| 1255 | } | 
|---|
| 1256 |  | 
|---|
| 1257 | static void | 
|---|
| 1258 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) | 
|---|
| 1259 | { | 
|---|
| 1260 | int group, orig_group; | 
|---|
| 1261 |  | 
|---|
| 1262 | orig_group = group = MI_RATE_GROUP(*idx); | 
|---|
| 1263 | while (group > 0) { | 
|---|
| 1264 | group--; | 
|---|
| 1265 |  | 
|---|
| 1266 | if (!mi->supported[group]) | 
|---|
| 1267 | continue; | 
|---|
| 1268 |  | 
|---|
| 1269 | if (minstrel_mcs_groups[group].streams > | 
|---|
| 1270 | minstrel_mcs_groups[orig_group].streams) | 
|---|
| 1271 | continue; | 
|---|
| 1272 |  | 
|---|
| 1273 | if (primary) | 
|---|
| 1274 | *idx = mi->groups[group].max_group_tp_rate[0]; | 
|---|
| 1275 | else | 
|---|
| 1276 | *idx = mi->groups[group].max_group_tp_rate[1]; | 
|---|
| 1277 | break; | 
|---|
| 1278 | } | 
|---|
| 1279 | } | 
|---|
| 1280 |  | 
|---|
| 1281 | static void | 
|---|
| 1282 | minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | 
|---|
| 1283 | void *priv_sta, struct ieee80211_tx_status *st) | 
|---|
| 1284 | { | 
|---|
| 1285 | struct ieee80211_tx_info *info = st->info; | 
|---|
| 1286 | struct minstrel_ht_sta *mi = priv_sta; | 
|---|
| 1287 | struct ieee80211_tx_rate *ar = info->status.rates; | 
|---|
| 1288 | struct minstrel_rate_stats *rate, *rate2; | 
|---|
| 1289 | struct minstrel_priv *mp = priv; | 
|---|
| 1290 | u32 update_interval = mp->update_interval; | 
|---|
| 1291 | bool last, update = false; | 
|---|
| 1292 | int i; | 
|---|
| 1293 |  | 
|---|
| 1294 | /* Ignore packet that was sent with noAck flag */ | 
|---|
| 1295 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | 
|---|
| 1296 | return; | 
|---|
| 1297 |  | 
|---|
| 1298 | /* This packet was aggregated but doesn't carry status info */ | 
|---|
| 1299 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 
|---|
| 1300 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | 
|---|
| 1301 | return; | 
|---|
| 1302 |  | 
|---|
| 1303 | if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) { | 
|---|
| 1304 | info->status.ampdu_ack_len = | 
|---|
| 1305 | (info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); | 
|---|
| 1306 | info->status.ampdu_len = 1; | 
|---|
| 1307 | } | 
|---|
| 1308 |  | 
|---|
| 1309 | /* wraparound */ | 
|---|
| 1310 | if (mi->total_packets >= ~0 - info->status.ampdu_len) { | 
|---|
| 1311 | mi->total_packets = 0; | 
|---|
| 1312 | mi->sample_packets = 0; | 
|---|
| 1313 | } | 
|---|
| 1314 |  | 
|---|
| 1315 | mi->total_packets += info->status.ampdu_len; | 
|---|
| 1316 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | 
|---|
| 1317 | mi->sample_packets += info->status.ampdu_len; | 
|---|
| 1318 |  | 
|---|
| 1319 | mi->ampdu_packets++; | 
|---|
| 1320 | mi->ampdu_len += info->status.ampdu_len; | 
|---|
| 1321 |  | 
|---|
| 1322 | if (st->rates && st->n_rates) { | 
|---|
| 1323 | last = !minstrel_ht_ri_txstat_valid(mp, mi, rate_status: &(st->rates[0])); | 
|---|
| 1324 | for (i = 0; !last; i++) { | 
|---|
| 1325 | last = (i == st->n_rates - 1) || | 
|---|
| 1326 | !minstrel_ht_ri_txstat_valid(mp, mi, | 
|---|
| 1327 | rate_status: &(st->rates[i + 1])); | 
|---|
| 1328 |  | 
|---|
| 1329 | rate = minstrel_ht_ri_get_stats(mp, mi, | 
|---|
| 1330 | rate_status: &(st->rates[i])); | 
|---|
| 1331 |  | 
|---|
| 1332 | if (last) | 
|---|
| 1333 | rate->success += info->status.ampdu_ack_len; | 
|---|
| 1334 |  | 
|---|
| 1335 | rate->attempts += st->rates[i].try_count * | 
|---|
| 1336 | info->status.ampdu_len; | 
|---|
| 1337 | } | 
|---|
| 1338 | } else { | 
|---|
| 1339 | last = !minstrel_ht_txstat_valid(mp, mi, rate: &ar[0]); | 
|---|
| 1340 | for (i = 0; !last; i++) { | 
|---|
| 1341 | last = (i == IEEE80211_TX_MAX_RATES - 1) || | 
|---|
| 1342 | !minstrel_ht_txstat_valid(mp, mi, rate: &ar[i + 1]); | 
|---|
| 1343 |  | 
|---|
| 1344 | rate = minstrel_ht_get_stats(mp, mi, rate: &ar[i]); | 
|---|
| 1345 | if (last) | 
|---|
| 1346 | rate->success += info->status.ampdu_ack_len; | 
|---|
| 1347 |  | 
|---|
| 1348 | rate->attempts += ar[i].count * info->status.ampdu_len; | 
|---|
| 1349 | } | 
|---|
| 1350 | } | 
|---|
| 1351 |  | 
|---|
| 1352 | if (mp->hw->max_rates > 1) { | 
|---|
| 1353 | /* | 
|---|
| 1354 | * check for sudden death of spatial multiplexing, | 
|---|
| 1355 | * downgrade to a lower number of streams if necessary. | 
|---|
| 1356 | */ | 
|---|
| 1357 | rate = minstrel_get_ratestats(mi, index: mi->max_tp_rate[0]); | 
|---|
| 1358 | if (rate->attempts > 30 && | 
|---|
| 1359 | rate->success < rate->attempts / 4) { | 
|---|
| 1360 | minstrel_downgrade_rate(mi, idx: &mi->max_tp_rate[0], primary: true); | 
|---|
| 1361 | update = true; | 
|---|
| 1362 | } | 
|---|
| 1363 |  | 
|---|
| 1364 | rate2 = minstrel_get_ratestats(mi, index: mi->max_tp_rate[1]); | 
|---|
| 1365 | if (rate2->attempts > 30 && | 
|---|
| 1366 | rate2->success < rate2->attempts / 4) { | 
|---|
| 1367 | minstrel_downgrade_rate(mi, idx: &mi->max_tp_rate[1], primary: false); | 
|---|
| 1368 | update = true; | 
|---|
| 1369 | } | 
|---|
| 1370 | } | 
|---|
| 1371 |  | 
|---|
| 1372 | if (time_after(jiffies, mi->last_stats_update + update_interval)) { | 
|---|
| 1373 | update = true; | 
|---|
| 1374 | minstrel_ht_update_stats(mp, mi); | 
|---|
| 1375 | } | 
|---|
| 1376 |  | 
|---|
| 1377 | if (update) | 
|---|
| 1378 | minstrel_ht_update_rates(mp, mi); | 
|---|
| 1379 | } | 
|---|
| 1380 |  | 
|---|
| 1381 | static void | 
|---|
| 1382 | minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 1383 | int index) | 
|---|
| 1384 | { | 
|---|
| 1385 | struct minstrel_rate_stats *mrs; | 
|---|
| 1386 | unsigned int tx_time, tx_time_rtscts, tx_time_data; | 
|---|
| 1387 | unsigned int cw = mp->cw_min; | 
|---|
| 1388 | unsigned int ctime = 0; | 
|---|
| 1389 | unsigned int t_slot = 9; /* FIXME */ | 
|---|
| 1390 | unsigned int ampdu_len = minstrel_ht_avg_ampdu_len(mi); | 
|---|
| 1391 | unsigned int overhead = 0, overhead_rtscts = 0; | 
|---|
| 1392 |  | 
|---|
| 1393 | mrs = minstrel_get_ratestats(mi, index); | 
|---|
| 1394 | if (mrs->prob_avg < MINSTREL_FRAC(1, 10)) { | 
|---|
| 1395 | mrs->retry_count = 1; | 
|---|
| 1396 | mrs->retry_count_rtscts = 1; | 
|---|
| 1397 | return; | 
|---|
| 1398 | } | 
|---|
| 1399 |  | 
|---|
| 1400 | mrs->retry_count = 2; | 
|---|
| 1401 | mrs->retry_count_rtscts = 2; | 
|---|
| 1402 | mrs->retry_updated = true; | 
|---|
| 1403 |  | 
|---|
| 1404 | tx_time_data = minstrel_get_duration(index) * ampdu_len / 1000; | 
|---|
| 1405 |  | 
|---|
| 1406 | /* Contention time for first 2 tries */ | 
|---|
| 1407 | ctime = (t_slot * cw) >> 1; | 
|---|
| 1408 | cw = min((cw << 1) | 1, mp->cw_max); | 
|---|
| 1409 | ctime += (t_slot * cw) >> 1; | 
|---|
| 1410 | cw = min((cw << 1) | 1, mp->cw_max); | 
|---|
| 1411 |  | 
|---|
| 1412 | if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index))) { | 
|---|
| 1413 | overhead = mi->overhead_legacy; | 
|---|
| 1414 | overhead_rtscts = mi->overhead_legacy_rtscts; | 
|---|
| 1415 | } else { | 
|---|
| 1416 | overhead = mi->overhead; | 
|---|
| 1417 | overhead_rtscts = mi->overhead_rtscts; | 
|---|
| 1418 | } | 
|---|
| 1419 |  | 
|---|
| 1420 | /* Total TX time for data and Contention after first 2 tries */ | 
|---|
| 1421 | tx_time = ctime + 2 * (overhead + tx_time_data); | 
|---|
| 1422 | tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data); | 
|---|
| 1423 |  | 
|---|
| 1424 | /* See how many more tries we can fit inside segment size */ | 
|---|
| 1425 | do { | 
|---|
| 1426 | /* Contention time for this try */ | 
|---|
| 1427 | ctime = (t_slot * cw) >> 1; | 
|---|
| 1428 | cw = min((cw << 1) | 1, mp->cw_max); | 
|---|
| 1429 |  | 
|---|
| 1430 | /* Total TX time after this try */ | 
|---|
| 1431 | tx_time += ctime + overhead + tx_time_data; | 
|---|
| 1432 | tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; | 
|---|
| 1433 |  | 
|---|
| 1434 | if (tx_time_rtscts < mp->segment_size) | 
|---|
| 1435 | mrs->retry_count_rtscts++; | 
|---|
| 1436 | } while ((tx_time < mp->segment_size) && | 
|---|
| 1437 | (++mrs->retry_count < mp->max_retry)); | 
|---|
| 1438 | } | 
|---|
| 1439 |  | 
|---|
| 1440 |  | 
|---|
| 1441 | static void | 
|---|
| 1442 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 1443 | struct ieee80211_sta_rates *ratetbl, int offset, int index) | 
|---|
| 1444 | { | 
|---|
| 1445 | int group_idx = MI_RATE_GROUP(index); | 
|---|
| 1446 | const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; | 
|---|
| 1447 | struct minstrel_rate_stats *mrs; | 
|---|
| 1448 | u8 idx; | 
|---|
| 1449 | u16 flags = group->flags; | 
|---|
| 1450 |  | 
|---|
| 1451 | mrs = minstrel_get_ratestats(mi, index); | 
|---|
| 1452 | if (!mrs->retry_updated) | 
|---|
| 1453 | minstrel_calc_retransmit(mp, mi, index); | 
|---|
| 1454 |  | 
|---|
| 1455 | if (mrs->prob_avg < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { | 
|---|
| 1456 | ratetbl->rate[offset].count = 2; | 
|---|
| 1457 | ratetbl->rate[offset].count_rts = 2; | 
|---|
| 1458 | ratetbl->rate[offset].count_cts = 2; | 
|---|
| 1459 | } else { | 
|---|
| 1460 | ratetbl->rate[offset].count = mrs->retry_count; | 
|---|
| 1461 | ratetbl->rate[offset].count_cts = mrs->retry_count; | 
|---|
| 1462 | ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; | 
|---|
| 1463 | } | 
|---|
| 1464 |  | 
|---|
| 1465 | index = MI_RATE_IDX(index); | 
|---|
| 1466 | if (group_idx == MINSTREL_CCK_GROUP) | 
|---|
| 1467 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 
|---|
| 1468 | else if (group_idx == MINSTREL_OFDM_GROUP) | 
|---|
| 1469 | idx = mp->ofdm_rates[mi->band][index % | 
|---|
| 1470 | ARRAY_SIZE(mp->ofdm_rates[0])]; | 
|---|
| 1471 | else if (flags & IEEE80211_TX_RC_VHT_MCS) | 
|---|
| 1472 | idx = ((group->streams - 1) << 4) | | 
|---|
| 1473 | (index & 0xF); | 
|---|
| 1474 | else | 
|---|
| 1475 | idx = index + (group->streams - 1) * 8; | 
|---|
| 1476 |  | 
|---|
| 1477 | /* enable RTS/CTS if needed: | 
|---|
| 1478 | *  - if station is in dynamic SMPS (and streams > 1) | 
|---|
| 1479 | *  - for fallback rates, to increase chances of getting through | 
|---|
| 1480 | */ | 
|---|
| 1481 | if (offset > 0 || | 
|---|
| 1482 | (mi->sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC && | 
|---|
| 1483 | group->streams > 1)) { | 
|---|
| 1484 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | 
|---|
| 1485 | flags |= IEEE80211_TX_RC_USE_RTS_CTS; | 
|---|
| 1486 | } | 
|---|
| 1487 |  | 
|---|
| 1488 | ratetbl->rate[offset].idx = idx; | 
|---|
| 1489 | ratetbl->rate[offset].flags = flags; | 
|---|
| 1490 | } | 
|---|
| 1491 |  | 
|---|
| 1492 | static inline int | 
|---|
| 1493 | minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) | 
|---|
| 1494 | { | 
|---|
| 1495 | int group = MI_RATE_GROUP(rate); | 
|---|
| 1496 | rate = MI_RATE_IDX(rate); | 
|---|
| 1497 | return mi->groups[group].rates[rate].prob_avg; | 
|---|
| 1498 | } | 
|---|
| 1499 |  | 
|---|
| 1500 | static int | 
|---|
| 1501 | minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) | 
|---|
| 1502 | { | 
|---|
| 1503 | int group = MI_RATE_GROUP(mi->max_prob_rate); | 
|---|
| 1504 | const struct mcs_group *g = &minstrel_mcs_groups[group]; | 
|---|
| 1505 | int rate = MI_RATE_IDX(mi->max_prob_rate); | 
|---|
| 1506 | unsigned int duration; | 
|---|
| 1507 |  | 
|---|
| 1508 | /* Disable A-MSDU if max_prob_rate is bad */ | 
|---|
| 1509 | if (mi->groups[group].rates[rate].prob_avg < MINSTREL_FRAC(50, 100)) | 
|---|
| 1510 | return 1; | 
|---|
| 1511 |  | 
|---|
| 1512 | duration = g->duration[rate]; | 
|---|
| 1513 | duration <<= g->shift; | 
|---|
| 1514 |  | 
|---|
| 1515 | /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ | 
|---|
| 1516 | if (duration > MCS_DURATION(1, 0, 52)) | 
|---|
| 1517 | return 500; | 
|---|
| 1518 |  | 
|---|
| 1519 | /* | 
|---|
| 1520 | * If the rate is slower than single-stream MCS4, limit A-MSDU to usual | 
|---|
| 1521 | * data packet size | 
|---|
| 1522 | */ | 
|---|
| 1523 | if (duration > MCS_DURATION(1, 0, 104)) | 
|---|
| 1524 | return 1600; | 
|---|
| 1525 |  | 
|---|
| 1526 | /* | 
|---|
| 1527 | * If the rate is slower than single-stream MCS7, or if the max throughput | 
|---|
| 1528 | * rate success probability is less than 75%, limit A-MSDU to twice the usual | 
|---|
| 1529 | * data packet size | 
|---|
| 1530 | */ | 
|---|
| 1531 | if (duration > MCS_DURATION(1, 0, 260) || | 
|---|
| 1532 | (minstrel_ht_get_prob_avg(mi, rate: mi->max_tp_rate[0]) < | 
|---|
| 1533 | MINSTREL_FRAC(75, 100))) | 
|---|
| 1534 | return 3200; | 
|---|
| 1535 |  | 
|---|
| 1536 | /* | 
|---|
| 1537 | * HT A-MPDU limits maximum MPDU size under BA agreement to 4095 bytes. | 
|---|
| 1538 | * Since aggregation sessions are started/stopped without txq flush, use | 
|---|
| 1539 | * the limit here to avoid the complexity of having to de-aggregate | 
|---|
| 1540 | * packets in the queue. | 
|---|
| 1541 | */ | 
|---|
| 1542 | if (!mi->sta->deflink.vht_cap.vht_supported) | 
|---|
| 1543 | return IEEE80211_MAX_MPDU_LEN_HT_BA; | 
|---|
| 1544 |  | 
|---|
| 1545 | /* unlimited */ | 
|---|
| 1546 | return 0; | 
|---|
| 1547 | } | 
|---|
| 1548 |  | 
|---|
| 1549 | static void | 
|---|
| 1550 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | 
|---|
| 1551 | { | 
|---|
| 1552 | struct ieee80211_sta_rates *rates; | 
|---|
| 1553 | int i = 0; | 
|---|
| 1554 | int max_rates = min_t(int, mp->hw->max_rates, IEEE80211_TX_RATE_TABLE_SIZE); | 
|---|
| 1555 |  | 
|---|
| 1556 | rates = kzalloc(sizeof(*rates), GFP_ATOMIC); | 
|---|
| 1557 | if (!rates) | 
|---|
| 1558 | return; | 
|---|
| 1559 |  | 
|---|
| 1560 | /* Start with max_tp_rate[0] */ | 
|---|
| 1561 | minstrel_ht_set_rate(mp, mi, ratetbl: rates, offset: i++, index: mi->max_tp_rate[0]); | 
|---|
| 1562 |  | 
|---|
| 1563 | /* Fill up remaining, keep one entry for max_probe_rate */ | 
|---|
| 1564 | for (; i < (max_rates - 1); i++) | 
|---|
| 1565 | minstrel_ht_set_rate(mp, mi, ratetbl: rates, offset: i, index: mi->max_tp_rate[i]); | 
|---|
| 1566 |  | 
|---|
| 1567 | if (i < max_rates) | 
|---|
| 1568 | minstrel_ht_set_rate(mp, mi, ratetbl: rates, offset: i++, index: mi->max_prob_rate); | 
|---|
| 1569 |  | 
|---|
| 1570 | if (i < IEEE80211_TX_RATE_TABLE_SIZE) | 
|---|
| 1571 | rates->rate[i].idx = -1; | 
|---|
| 1572 |  | 
|---|
| 1573 | mi->sta->deflink.agg.max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); | 
|---|
| 1574 | ieee80211_sta_recalc_aggregates(pubsta: mi->sta); | 
|---|
| 1575 | rate_control_set_rates(hw: mp->hw, pubsta: mi->sta, rates); | 
|---|
| 1576 | } | 
|---|
| 1577 |  | 
|---|
| 1578 | static u16 | 
|---|
| 1579 | minstrel_ht_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | 
|---|
| 1580 | { | 
|---|
| 1581 | u8 seq; | 
|---|
| 1582 |  | 
|---|
| 1583 | if (mp->hw->max_rates > 1) { | 
|---|
| 1584 | seq = mi->sample_seq; | 
|---|
| 1585 | mi->sample_seq = (seq + 1) % ARRAY_SIZE(minstrel_sample_seq); | 
|---|
| 1586 | seq = minstrel_sample_seq[seq]; | 
|---|
| 1587 | } else { | 
|---|
| 1588 | seq = MINSTREL_SAMPLE_TYPE_INC; | 
|---|
| 1589 | } | 
|---|
| 1590 |  | 
|---|
| 1591 | return __minstrel_ht_get_sample_rate(mi, type: seq); | 
|---|
| 1592 | } | 
|---|
| 1593 |  | 
|---|
| 1594 | static void | 
|---|
| 1595 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 
|---|
| 1596 | struct ieee80211_tx_rate_control *txrc) | 
|---|
| 1597 | { | 
|---|
| 1598 | const struct mcs_group *sample_group; | 
|---|
| 1599 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb: txrc->skb); | 
|---|
| 1600 | struct ieee80211_tx_rate *rate = &info->status.rates[0]; | 
|---|
| 1601 | struct minstrel_ht_sta *mi = priv_sta; | 
|---|
| 1602 | struct minstrel_priv *mp = priv; | 
|---|
| 1603 | u16 sample_idx; | 
|---|
| 1604 |  | 
|---|
| 1605 | info->flags |= mi->tx_flags; | 
|---|
| 1606 |  | 
|---|
| 1607 | #ifdef CONFIG_MAC80211_DEBUGFS | 
|---|
| 1608 | if (mp->fixed_rate_idx != -1) | 
|---|
| 1609 | return; | 
|---|
| 1610 | #endif | 
|---|
| 1611 |  | 
|---|
| 1612 | /* Don't use EAPOL frames for sampling on non-mrr hw */ | 
|---|
| 1613 | if (mp->hw->max_rates == 1 && | 
|---|
| 1614 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) | 
|---|
| 1615 | return; | 
|---|
| 1616 |  | 
|---|
| 1617 | if (time_is_after_jiffies(mi->sample_time)) | 
|---|
| 1618 | return; | 
|---|
| 1619 |  | 
|---|
| 1620 | mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL; | 
|---|
| 1621 | sample_idx = minstrel_ht_get_sample_rate(mp, mi); | 
|---|
| 1622 | if (!sample_idx) | 
|---|
| 1623 | return; | 
|---|
| 1624 |  | 
|---|
| 1625 | sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; | 
|---|
| 1626 | sample_idx = MI_RATE_IDX(sample_idx); | 
|---|
| 1627 |  | 
|---|
| 1628 | if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && | 
|---|
| 1629 | (sample_idx >= 4) != txrc->short_preamble) | 
|---|
| 1630 | return; | 
|---|
| 1631 |  | 
|---|
| 1632 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 
|---|
| 1633 | rate->count = 1; | 
|---|
| 1634 |  | 
|---|
| 1635 | if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP]) { | 
|---|
| 1636 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); | 
|---|
| 1637 | rate->idx = mp->cck_rates[idx]; | 
|---|
| 1638 | } else if (sample_group == &minstrel_mcs_groups[MINSTREL_OFDM_GROUP]) { | 
|---|
| 1639 | int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); | 
|---|
| 1640 | rate->idx = mp->ofdm_rates[mi->band][idx]; | 
|---|
| 1641 | } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { | 
|---|
| 1642 | ieee80211_rate_set_vht(rate, MI_RATE_IDX(sample_idx), | 
|---|
| 1643 | nss: sample_group->streams); | 
|---|
| 1644 | } else { | 
|---|
| 1645 | rate->idx = sample_idx + (sample_group->streams - 1) * 8; | 
|---|
| 1646 | } | 
|---|
| 1647 |  | 
|---|
| 1648 | rate->flags = sample_group->flags; | 
|---|
| 1649 | } | 
|---|
| 1650 |  | 
|---|
| 1651 | static void | 
|---|
| 1652 | minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 1653 | struct ieee80211_supported_band *sband, | 
|---|
| 1654 | struct ieee80211_sta *sta) | 
|---|
| 1655 | { | 
|---|
| 1656 | int i; | 
|---|
| 1657 |  | 
|---|
| 1658 | if (sband->band != NL80211_BAND_2GHZ) | 
|---|
| 1659 | return; | 
|---|
| 1660 |  | 
|---|
| 1661 | if (sta->deflink.ht_cap.ht_supported && | 
|---|
| 1662 | !ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) | 
|---|
| 1663 | return; | 
|---|
| 1664 |  | 
|---|
| 1665 | for (i = 0; i < 4; i++) { | 
|---|
| 1666 | if (mp->cck_rates[i] == 0xff || | 
|---|
| 1667 | !rate_supported(sta, band: sband->band, index: mp->cck_rates[i])) | 
|---|
| 1668 | continue; | 
|---|
| 1669 |  | 
|---|
| 1670 | mi->supported[MINSTREL_CCK_GROUP] |= BIT(i); | 
|---|
| 1671 | if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE) | 
|---|
| 1672 | mi->supported[MINSTREL_CCK_GROUP] |= BIT(i + 4); | 
|---|
| 1673 | } | 
|---|
| 1674 | } | 
|---|
| 1675 |  | 
|---|
| 1676 | static void | 
|---|
| 1677 | minstrel_ht_update_ofdm(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 
|---|
| 1678 | struct ieee80211_supported_band *sband, | 
|---|
| 1679 | struct ieee80211_sta *sta) | 
|---|
| 1680 | { | 
|---|
| 1681 | const u8 *rates; | 
|---|
| 1682 | int i; | 
|---|
| 1683 |  | 
|---|
| 1684 | if (sta->deflink.ht_cap.ht_supported) | 
|---|
| 1685 | return; | 
|---|
| 1686 |  | 
|---|
| 1687 | rates = mp->ofdm_rates[sband->band]; | 
|---|
| 1688 | for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) { | 
|---|
| 1689 | if (rates[i] == 0xff || | 
|---|
| 1690 | !rate_supported(sta, band: sband->band, index: rates[i])) | 
|---|
| 1691 | continue; | 
|---|
| 1692 |  | 
|---|
| 1693 | mi->supported[MINSTREL_OFDM_GROUP] |= BIT(i); | 
|---|
| 1694 | } | 
|---|
| 1695 | } | 
|---|
| 1696 |  | 
|---|
| 1697 | static void | 
|---|
| 1698 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 
|---|
| 1699 | struct cfg80211_chan_def *chandef, | 
|---|
| 1700 | struct ieee80211_sta *sta, void *priv_sta) | 
|---|
| 1701 | { | 
|---|
| 1702 | struct minstrel_priv *mp = priv; | 
|---|
| 1703 | struct minstrel_ht_sta *mi = priv_sta; | 
|---|
| 1704 | struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs; | 
|---|
| 1705 | u16 ht_cap = sta->deflink.ht_cap.cap; | 
|---|
| 1706 | struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; | 
|---|
| 1707 | const struct ieee80211_rate *ctl_rate; | 
|---|
| 1708 | struct sta_info *sta_info; | 
|---|
| 1709 | bool ldpc, erp; | 
|---|
| 1710 | int use_vht; | 
|---|
| 1711 | int ack_dur; | 
|---|
| 1712 | int stbc; | 
|---|
| 1713 | int i; | 
|---|
| 1714 |  | 
|---|
| 1715 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); | 
|---|
| 1716 |  | 
|---|
| 1717 | if (vht_cap->vht_supported) | 
|---|
| 1718 | use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); | 
|---|
| 1719 | else | 
|---|
| 1720 | use_vht = 0; | 
|---|
| 1721 |  | 
|---|
| 1722 | memset(s: mi, c: 0, n: sizeof(*mi)); | 
|---|
| 1723 |  | 
|---|
| 1724 | mi->sta = sta; | 
|---|
| 1725 | mi->band = sband->band; | 
|---|
| 1726 | mi->last_stats_update = jiffies; | 
|---|
| 1727 |  | 
|---|
| 1728 | ack_dur = ieee80211_frame_duration(band: sband->band, len: 10, rate: 60, erp: 1, short_preamble: 1); | 
|---|
| 1729 | mi->overhead = ieee80211_frame_duration(band: sband->band, len: 0, rate: 60, erp: 1, short_preamble: 1); | 
|---|
| 1730 | mi->overhead += ack_dur; | 
|---|
| 1731 | mi->overhead_rtscts = mi->overhead + 2 * ack_dur; | 
|---|
| 1732 |  | 
|---|
| 1733 | ctl_rate = &sband->bitrates[rate_lowest_index(sband, sta)]; | 
|---|
| 1734 | erp = ctl_rate->flags & IEEE80211_RATE_ERP_G; | 
|---|
| 1735 | ack_dur = ieee80211_frame_duration(band: sband->band, len: 10, | 
|---|
| 1736 | rate: ctl_rate->bitrate, erp, short_preamble: 1); | 
|---|
| 1737 | mi->overhead_legacy = ack_dur; | 
|---|
| 1738 | mi->overhead_legacy_rtscts = mi->overhead_legacy + 2 * ack_dur; | 
|---|
| 1739 |  | 
|---|
| 1740 | mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); | 
|---|
| 1741 |  | 
|---|
| 1742 | if (!use_vht) { | 
|---|
| 1743 | stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> | 
|---|
| 1744 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | 
|---|
| 1745 |  | 
|---|
| 1746 | ldpc = ht_cap & IEEE80211_HT_CAP_LDPC_CODING; | 
|---|
| 1747 | } else { | 
|---|
| 1748 | stbc = (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) >> | 
|---|
| 1749 | IEEE80211_VHT_CAP_RXSTBC_SHIFT; | 
|---|
| 1750 |  | 
|---|
| 1751 | ldpc = vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC; | 
|---|
| 1752 | } | 
|---|
| 1753 |  | 
|---|
| 1754 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | 
|---|
| 1755 | if (ldpc) | 
|---|
| 1756 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 
|---|
| 1757 |  | 
|---|
| 1758 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 
|---|
| 1759 | u32 gflags = minstrel_mcs_groups[i].flags; | 
|---|
| 1760 | int bw, nss; | 
|---|
| 1761 |  | 
|---|
| 1762 | mi->supported[i] = 0; | 
|---|
| 1763 | if (minstrel_ht_is_legacy_group(group: i)) | 
|---|
| 1764 | continue; | 
|---|
| 1765 |  | 
|---|
| 1766 | if (gflags & IEEE80211_TX_RC_SHORT_GI) { | 
|---|
| 1767 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | 
|---|
| 1768 | if (!(ht_cap & IEEE80211_HT_CAP_SGI_40)) | 
|---|
| 1769 | continue; | 
|---|
| 1770 | } else { | 
|---|
| 1771 | if (!(ht_cap & IEEE80211_HT_CAP_SGI_20)) | 
|---|
| 1772 | continue; | 
|---|
| 1773 | } | 
|---|
| 1774 | } | 
|---|
| 1775 |  | 
|---|
| 1776 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH && | 
|---|
| 1777 | sta->deflink.bandwidth < IEEE80211_STA_RX_BW_40) | 
|---|
| 1778 | continue; | 
|---|
| 1779 |  | 
|---|
| 1780 | nss = minstrel_mcs_groups[i].streams; | 
|---|
| 1781 |  | 
|---|
| 1782 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 
|---|
| 1783 | if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC && nss > 1) | 
|---|
| 1784 | continue; | 
|---|
| 1785 |  | 
|---|
| 1786 | /* HT rate */ | 
|---|
| 1787 | if (gflags & IEEE80211_TX_RC_MCS) { | 
|---|
| 1788 | if (use_vht && minstrel_vht_only) | 
|---|
| 1789 | continue; | 
|---|
| 1790 |  | 
|---|
| 1791 | mi->supported[i] = mcs->rx_mask[nss - 1]; | 
|---|
| 1792 | continue; | 
|---|
| 1793 | } | 
|---|
| 1794 |  | 
|---|
| 1795 | /* VHT rate */ | 
|---|
| 1796 | if (!vht_cap->vht_supported || | 
|---|
| 1797 | WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) || | 
|---|
| 1798 | WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH)) | 
|---|
| 1799 | continue; | 
|---|
| 1800 |  | 
|---|
| 1801 | if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) { | 
|---|
| 1802 | if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_80 || | 
|---|
| 1803 | ((gflags & IEEE80211_TX_RC_SHORT_GI) && | 
|---|
| 1804 | !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) { | 
|---|
| 1805 | continue; | 
|---|
| 1806 | } | 
|---|
| 1807 | } | 
|---|
| 1808 |  | 
|---|
| 1809 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 
|---|
| 1810 | bw = BW_40; | 
|---|
| 1811 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) | 
|---|
| 1812 | bw = BW_80; | 
|---|
| 1813 | else | 
|---|
| 1814 | bw = BW_20; | 
|---|
| 1815 |  | 
|---|
| 1816 | mi->supported[i] = minstrel_get_valid_vht_rates(bw, nss, | 
|---|
| 1817 | mcs_map: vht_cap->vht_mcs.tx_mcs_map); | 
|---|
| 1818 | } | 
|---|
| 1819 |  | 
|---|
| 1820 | sta_info = container_of(sta, struct sta_info, sta); | 
|---|
| 1821 | mi->use_short_preamble = test_sta_flag(sta: sta_info, flag: WLAN_STA_SHORT_PREAMBLE) && | 
|---|
| 1822 | sta_info->sdata->vif.bss_conf.use_short_preamble; | 
|---|
| 1823 |  | 
|---|
| 1824 | minstrel_ht_update_cck(mp, mi, sband, sta); | 
|---|
| 1825 | minstrel_ht_update_ofdm(mp, mi, sband, sta); | 
|---|
| 1826 |  | 
|---|
| 1827 | /* create an initial rate table with the lowest supported rates */ | 
|---|
| 1828 | minstrel_ht_update_stats(mp, mi); | 
|---|
| 1829 | minstrel_ht_update_rates(mp, mi); | 
|---|
| 1830 | } | 
|---|
| 1831 |  | 
|---|
| 1832 | static void | 
|---|
| 1833 | minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, | 
|---|
| 1834 | struct cfg80211_chan_def *chandef, | 
|---|
| 1835 | struct ieee80211_sta *sta, void *priv_sta) | 
|---|
| 1836 | { | 
|---|
| 1837 | minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); | 
|---|
| 1838 | } | 
|---|
| 1839 |  | 
|---|
| 1840 | static void | 
|---|
| 1841 | minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, | 
|---|
| 1842 | struct cfg80211_chan_def *chandef, | 
|---|
| 1843 | struct ieee80211_sta *sta, void *priv_sta, | 
|---|
| 1844 | u32 changed) | 
|---|
| 1845 | { | 
|---|
| 1846 | minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); | 
|---|
| 1847 | } | 
|---|
| 1848 |  | 
|---|
| 1849 | static void * | 
|---|
| 1850 | minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) | 
|---|
| 1851 | { | 
|---|
| 1852 | struct ieee80211_supported_band *sband; | 
|---|
| 1853 | struct minstrel_ht_sta *mi; | 
|---|
| 1854 | struct minstrel_priv *mp = priv; | 
|---|
| 1855 | struct ieee80211_hw *hw = mp->hw; | 
|---|
| 1856 | int max_rates = 0; | 
|---|
| 1857 | int i; | 
|---|
| 1858 |  | 
|---|
| 1859 | for (i = 0; i < NUM_NL80211_BANDS; i++) { | 
|---|
| 1860 | sband = hw->wiphy->bands[i]; | 
|---|
| 1861 | if (sband && sband->n_bitrates > max_rates) | 
|---|
| 1862 | max_rates = sband->n_bitrates; | 
|---|
| 1863 | } | 
|---|
| 1864 |  | 
|---|
| 1865 | return kzalloc(sizeof(*mi), gfp); | 
|---|
| 1866 | } | 
|---|
| 1867 |  | 
|---|
| 1868 | static void | 
|---|
| 1869 | minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) | 
|---|
| 1870 | { | 
|---|
| 1871 | kfree(objp: priv_sta); | 
|---|
| 1872 | } | 
|---|
| 1873 |  | 
|---|
| 1874 | static void | 
|---|
| 1875 | minstrel_ht_fill_rate_array(u8 *dest, struct ieee80211_supported_band *sband, | 
|---|
| 1876 | const s16 *bitrates, int n_rates) | 
|---|
| 1877 | { | 
|---|
| 1878 | int i, j; | 
|---|
| 1879 |  | 
|---|
| 1880 | for (i = 0; i < sband->n_bitrates; i++) { | 
|---|
| 1881 | struct ieee80211_rate *rate = &sband->bitrates[i]; | 
|---|
| 1882 |  | 
|---|
| 1883 | for (j = 0; j < n_rates; j++) { | 
|---|
| 1884 | if (rate->bitrate != bitrates[j]) | 
|---|
| 1885 | continue; | 
|---|
| 1886 |  | 
|---|
| 1887 | dest[j] = i; | 
|---|
| 1888 | break; | 
|---|
| 1889 | } | 
|---|
| 1890 | } | 
|---|
| 1891 | } | 
|---|
| 1892 |  | 
|---|
| 1893 | static void | 
|---|
| 1894 | minstrel_ht_init_cck_rates(struct minstrel_priv *mp) | 
|---|
| 1895 | { | 
|---|
| 1896 | static const s16 bitrates[4] = { 10, 20, 55, 110 }; | 
|---|
| 1897 | struct ieee80211_supported_band *sband; | 
|---|
| 1898 |  | 
|---|
| 1899 | memset(s: mp->cck_rates, c: 0xff, n: sizeof(mp->cck_rates)); | 
|---|
| 1900 | sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; | 
|---|
| 1901 | if (!sband) | 
|---|
| 1902 | return; | 
|---|
| 1903 |  | 
|---|
| 1904 | BUILD_BUG_ON(ARRAY_SIZE(mp->cck_rates) != ARRAY_SIZE(bitrates)); | 
|---|
| 1905 | minstrel_ht_fill_rate_array(dest: mp->cck_rates, sband, | 
|---|
| 1906 | bitrates: minstrel_cck_bitrates, | 
|---|
| 1907 | ARRAY_SIZE(minstrel_cck_bitrates)); | 
|---|
| 1908 | } | 
|---|
| 1909 |  | 
|---|
| 1910 | static void | 
|---|
| 1911 | minstrel_ht_init_ofdm_rates(struct minstrel_priv *mp, enum nl80211_band band) | 
|---|
| 1912 | { | 
|---|
| 1913 | static const s16 bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; | 
|---|
| 1914 | struct ieee80211_supported_band *sband; | 
|---|
| 1915 |  | 
|---|
| 1916 | memset(s: mp->ofdm_rates[band], c: 0xff, n: sizeof(mp->ofdm_rates[band])); | 
|---|
| 1917 | sband = mp->hw->wiphy->bands[band]; | 
|---|
| 1918 | if (!sband) | 
|---|
| 1919 | return; | 
|---|
| 1920 |  | 
|---|
| 1921 | BUILD_BUG_ON(ARRAY_SIZE(mp->ofdm_rates[band]) != ARRAY_SIZE(bitrates)); | 
|---|
| 1922 | minstrel_ht_fill_rate_array(dest: mp->ofdm_rates[band], sband, | 
|---|
| 1923 | bitrates: minstrel_ofdm_bitrates, | 
|---|
| 1924 | ARRAY_SIZE(minstrel_ofdm_bitrates)); | 
|---|
| 1925 | } | 
|---|
| 1926 |  | 
|---|
| 1927 | static void * | 
|---|
| 1928 | minstrel_ht_alloc(struct ieee80211_hw *hw) | 
|---|
| 1929 | { | 
|---|
| 1930 | struct minstrel_priv *mp; | 
|---|
| 1931 | int i; | 
|---|
| 1932 |  | 
|---|
| 1933 | mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); | 
|---|
| 1934 | if (!mp) | 
|---|
| 1935 | return NULL; | 
|---|
| 1936 |  | 
|---|
| 1937 | /* contention window settings | 
|---|
| 1938 | * Just an approximation. Using the per-queue values would complicate | 
|---|
| 1939 | * the calculations and is probably unnecessary */ | 
|---|
| 1940 | mp->cw_min = 15; | 
|---|
| 1941 | mp->cw_max = 1023; | 
|---|
| 1942 |  | 
|---|
| 1943 | /* maximum time that the hw is allowed to stay in one MRR segment */ | 
|---|
| 1944 | mp->segment_size = 6000; | 
|---|
| 1945 |  | 
|---|
| 1946 | if (hw->max_rate_tries > 0) | 
|---|
| 1947 | mp->max_retry = hw->max_rate_tries; | 
|---|
| 1948 | else | 
|---|
| 1949 | /* safe default, does not necessarily have to match hw properties */ | 
|---|
| 1950 | mp->max_retry = 7; | 
|---|
| 1951 |  | 
|---|
| 1952 | mp->hw = hw; | 
|---|
| 1953 | mp->update_interval = HZ / 20; | 
|---|
| 1954 |  | 
|---|
| 1955 | minstrel_ht_init_cck_rates(mp); | 
|---|
| 1956 | for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) | 
|---|
| 1957 | minstrel_ht_init_ofdm_rates(mp, band: i); | 
|---|
| 1958 |  | 
|---|
| 1959 | return mp; | 
|---|
| 1960 | } | 
|---|
| 1961 |  | 
|---|
| 1962 | #ifdef CONFIG_MAC80211_DEBUGFS | 
|---|
| 1963 | static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, | 
|---|
| 1964 | struct dentry *debugfsdir) | 
|---|
| 1965 | { | 
|---|
| 1966 | struct minstrel_priv *mp = priv; | 
|---|
| 1967 |  | 
|---|
| 1968 | mp->fixed_rate_idx = (u32) -1; | 
|---|
| 1969 | debugfs_create_u32( "fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, | 
|---|
| 1970 | &mp->fixed_rate_idx); | 
|---|
| 1971 | } | 
|---|
| 1972 | #endif | 
|---|
| 1973 |  | 
|---|
| 1974 | static void | 
|---|
| 1975 | minstrel_ht_free(void *priv) | 
|---|
| 1976 | { | 
|---|
| 1977 | kfree(objp: priv); | 
|---|
| 1978 | } | 
|---|
| 1979 |  | 
|---|
| 1980 | static u32 minstrel_ht_get_expected_throughput(void *priv_sta) | 
|---|
| 1981 | { | 
|---|
| 1982 | struct minstrel_ht_sta *mi = priv_sta; | 
|---|
| 1983 | int i, j, prob, tp_avg; | 
|---|
| 1984 |  | 
|---|
| 1985 | i = MI_RATE_GROUP(mi->max_tp_rate[0]); | 
|---|
| 1986 | j = MI_RATE_IDX(mi->max_tp_rate[0]); | 
|---|
| 1987 | prob = mi->groups[i].rates[j].prob_avg; | 
|---|
| 1988 |  | 
|---|
| 1989 | /* convert tp_avg from pkt per second in kbps */ | 
|---|
| 1990 | tp_avg = minstrel_ht_get_tp_avg(mi, group: i, rate: j, prob_avg: prob) * 10; | 
|---|
| 1991 | tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024; | 
|---|
| 1992 |  | 
|---|
| 1993 | return tp_avg; | 
|---|
| 1994 | } | 
|---|
| 1995 |  | 
|---|
| 1996 | static const struct rate_control_ops mac80211_minstrel_ht = { | 
|---|
| 1997 | .name = "minstrel_ht", | 
|---|
| 1998 | .capa = RATE_CTRL_CAPA_AMPDU_TRIGGER, | 
|---|
| 1999 | .tx_status_ext = minstrel_ht_tx_status, | 
|---|
| 2000 | .get_rate = minstrel_ht_get_rate, | 
|---|
| 2001 | .rate_init = minstrel_ht_rate_init, | 
|---|
| 2002 | .rate_update = minstrel_ht_rate_update, | 
|---|
| 2003 | .alloc_sta = minstrel_ht_alloc_sta, | 
|---|
| 2004 | .free_sta = minstrel_ht_free_sta, | 
|---|
| 2005 | .alloc = minstrel_ht_alloc, | 
|---|
| 2006 | .free = minstrel_ht_free, | 
|---|
| 2007 | #ifdef CONFIG_MAC80211_DEBUGFS | 
|---|
| 2008 | .add_debugfs = minstrel_ht_add_debugfs, | 
|---|
| 2009 | .add_sta_debugfs = minstrel_ht_add_sta_debugfs, | 
|---|
| 2010 | #endif | 
|---|
| 2011 | .get_expected_throughput = minstrel_ht_get_expected_throughput, | 
|---|
| 2012 | }; | 
|---|
| 2013 |  | 
|---|
| 2014 |  | 
|---|
| 2015 | static void __init init_sample_table(void) | 
|---|
| 2016 | { | 
|---|
| 2017 | int col, i, new_idx; | 
|---|
| 2018 | u8 rnd[MCS_GROUP_RATES]; | 
|---|
| 2019 |  | 
|---|
| 2020 | memset(s: sample_table, c: 0xff, n: sizeof(sample_table)); | 
|---|
| 2021 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 
|---|
| 2022 | get_random_bytes(buf: rnd, len: sizeof(rnd)); | 
|---|
| 2023 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 
|---|
| 2024 | new_idx = (i + rnd[i]) % MCS_GROUP_RATES; | 
|---|
| 2025 | while (sample_table[col][new_idx] != 0xff) | 
|---|
| 2026 | new_idx = (new_idx + 1) % MCS_GROUP_RATES; | 
|---|
| 2027 |  | 
|---|
| 2028 | sample_table[col][new_idx] = i; | 
|---|
| 2029 | } | 
|---|
| 2030 | } | 
|---|
| 2031 | } | 
|---|
| 2032 |  | 
|---|
| 2033 | int __init | 
|---|
| 2034 | rc80211_minstrel_init(void) | 
|---|
| 2035 | { | 
|---|
| 2036 | init_sample_table(); | 
|---|
| 2037 | return ieee80211_rate_control_register(ops: &mac80211_minstrel_ht); | 
|---|
| 2038 | } | 
|---|
| 2039 |  | 
|---|
| 2040 | void | 
|---|
| 2041 | rc80211_minstrel_exit(void) | 
|---|
| 2042 | { | 
|---|
| 2043 | ieee80211_rate_control_unregister(ops: &mac80211_minstrel_ht); | 
|---|
| 2044 | } | 
|---|
| 2045 |  | 
|---|