Blame view

net/mac80211/rc80211_minstrel_ht.c 38.7 KB
ec8aa669b   Felix Fietkau   mac80211: add the...
1
  /*
a0497f9f5   Felix Fietkau   mac80211/minstrel...
2
   * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
ec8aa669b   Felix Fietkau   mac80211: add the...
3
4
5
6
7
8
9
10
11
12
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  #include <linux/netdevice.h>
  #include <linux/types.h>
  #include <linux/skbuff.h>
  #include <linux/debugfs.h>
  #include <linux/random.h>
9208247d7   Karl Beldan   mac80211: minstre...
13
  #include <linux/moduleparam.h>
ec8aa669b   Felix Fietkau   mac80211: add the...
14
15
16
  #include <linux/ieee80211.h>
  #include <net/mac80211.h>
  #include "rate.h"
782dda00a   Felix Fietkau   mac80211: minstre...
17
  #include "sta_info.h"
ec8aa669b   Felix Fietkau   mac80211: add the...
18
19
  #include "rc80211_minstrel.h"
  #include "rc80211_minstrel_ht.h"
d66c25827   Felix Fietkau   mac80211: minstre...
20
  #define AVG_AMPDU_SIZE	16
ec8aa669b   Felix Fietkau   mac80211: add the...
21
  #define AVG_PKT_SIZE	1200
ec8aa669b   Felix Fietkau   mac80211: add the...
22
23
  
  /* Number of bits for an average sized packet */
d66c25827   Felix Fietkau   mac80211: minstre...
24
  #define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)
ec8aa669b   Felix Fietkau   mac80211: add the...
25
26
  
  /* Number of symbols for a packet with (bps) bits per symbol */
00591cea3   Johannes Berg   mac80211: minstre...
27
  #define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
ec8aa669b   Felix Fietkau   mac80211: add the...
28

ed97a13c5   Felix Fietkau   mac80211/minstrel...
29
  /* Transmission time (nanoseconds) for a packet containing (syms) symbols */
ec8aa669b   Felix Fietkau   mac80211: add the...
30
31
  #define MCS_SYMBOL_TIME(sgi, syms)					\
  	(sgi ?								\
ed97a13c5   Felix Fietkau   mac80211/minstrel...
32
33
  	  ((syms) * 18000 + 4000) / 5 :	/* syms * 3.6 us */		\
  	  ((syms) * 1000) << 2		/* syms * 4 us */		\
ec8aa669b   Felix Fietkau   mac80211: add the...
34
35
36
  	)
  
  /* Transmit duration for the raw data part of an average sized packet */
d66c25827   Felix Fietkau   mac80211: minstre...
37
38
  #define MCS_DURATION(streams, sgi, bps) \
  	(MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE)
ec8aa669b   Felix Fietkau   mac80211: add the...
39

8a0ee4fe1   Karl Beldan   mac80211: minstre...
40
41
  #define BW_20			0
  #define BW_40			1
9208247d7   Karl Beldan   mac80211: minstre...
42
  #define BW_80			2
8a0ee4fe1   Karl Beldan   mac80211: minstre...
43

a5f69d94d   Helmut Schaa   mac80211: Get rid...
44
45
46
47
  /*
   * Define group sort order: HT40 -> SGI -> #streams
   */
  #define GROUP_IDX(_streams, _sgi, _ht40)	\
8a0ee4fe1   Karl Beldan   mac80211: minstre...
48
  	MINSTREL_HT_GROUP_0 +			\
a5f69d94d   Helmut Schaa   mac80211: Get rid...
49
  	MINSTREL_MAX_STREAMS * 2 * _ht40 +	\
8a0ee4fe1   Karl Beldan   mac80211: minstre...
50
  	MINSTREL_MAX_STREAMS * _sgi +	\
a5f69d94d   Helmut Schaa   mac80211: Get rid...
51
  	_streams - 1
ec8aa669b   Felix Fietkau   mac80211: add the...
52
  /* MCS rate information for an MCS group */
a5f69d94d   Helmut Schaa   mac80211: Get rid...
53
54
  #define MCS_GROUP(_streams, _sgi, _ht40)				\
  	[GROUP_IDX(_streams, _sgi, _ht40)] = {				\
ec8aa669b   Felix Fietkau   mac80211: add the...
55
56
  	.streams = _streams,						\
  	.flags =							\
3ec373c42   Karl Beldan   mac80211: minstre...
57
  		IEEE80211_TX_RC_MCS |					\
ec8aa669b   Felix Fietkau   mac80211: add the...
58
59
60
61
62
63
64
65
66
67
68
69
70
  		(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |			\
  		(_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),		\
  	.duration = {							\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26),		\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52),		\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78),		\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104),	\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156),	\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208),	\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234),	\
  		MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260)		\
  	}								\
  }
9208247d7   Karl Beldan   mac80211: minstre...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  #define VHT_GROUP_IDX(_streams, _sgi, _bw)				\
  	(MINSTREL_VHT_GROUP_0 +						\
  	 MINSTREL_MAX_STREAMS * 2 * (_bw) +				\
  	 MINSTREL_MAX_STREAMS * (_sgi) +				\
  	 (_streams) - 1)
  
  #define BW2VBPS(_bw, r3, r2, r1)					\
  	(_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
  
  #define VHT_GROUP(_streams, _sgi, _bw)					\
  	[VHT_GROUP_IDX(_streams, _sgi, _bw)] = {			\
  	.streams = _streams,						\
  	.flags =							\
  		IEEE80211_TX_RC_VHT_MCS |				\
  		(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |			\
  		(_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH :		\
  		 _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),	\
  	.duration = {							\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  117,  54,  26)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  234, 108,  52)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  351, 162,  78)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  468, 216, 104)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  702, 324, 156)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw,  936, 432, 208)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw, 1053, 486, 234)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw, 1170, 540, 260)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw, 1404, 648, 312)),		\
  		MCS_DURATION(_streams, _sgi,				\
  			     BW2VBPS(_bw, 1560, 720, 346))		\
  	}								\
  }
a0497f9f5   Felix Fietkau   mac80211/minstrel...
111
  #define CCK_DURATION(_bitrate, _short, _len)		\
ed97a13c5   Felix Fietkau   mac80211/minstrel...
112
  	(1000 * (10 /* SIFS */ +			\
f359d3fe8   Weilong Chen   mac80211: fix che...
113
  	 (_short ? 72 + 24 : 144 + 48) +		\
ed97a13c5   Felix Fietkau   mac80211/minstrel...
114
  	 (8 * (_len + 4) * 10) / (_bitrate)))
a0497f9f5   Felix Fietkau   mac80211/minstrel...
115
116
117
118
119
120
121
122
123
124
  
  #define CCK_ACK_DURATION(_bitrate, _short)			\
  	(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) +	\
  	 CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
  
  #define CCK_DURATION_LIST(_short)			\
  	CCK_ACK_DURATION(10, _short),			\
  	CCK_ACK_DURATION(20, _short),			\
  	CCK_ACK_DURATION(55, _short),			\
  	CCK_ACK_DURATION(110, _short)
8a0ee4fe1   Karl Beldan   mac80211: minstre...
125
126
127
  #define CCK_GROUP					\
  	[MINSTREL_CCK_GROUP] = {			\
  		.streams = 0,				\
3ec373c42   Karl Beldan   mac80211: minstre...
128
  		.flags = 0,				\
8a0ee4fe1   Karl Beldan   mac80211: minstre...
129
130
131
132
  		.duration = {				\
  			CCK_DURATION_LIST(false),	\
  			CCK_DURATION_LIST(true)		\
  		}					\
a0497f9f5   Felix Fietkau   mac80211/minstrel...
133
  	}
9208247d7   Karl Beldan   mac80211: minstre...
134
135
136
137
138
139
  #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
  static bool minstrel_vht_only = true;
  module_param(minstrel_vht_only, bool, 0644);
  MODULE_PARM_DESC(minstrel_vht_only,
  		 "Use only VHT rates when VHT is supported by sta.");
  #endif
ec8aa669b   Felix Fietkau   mac80211: add the...
140
141
142
143
  /*
   * To enable sufficiently targeted rate sampling, MCS rates are divided into
   * groups, based on the number of streams and flags (HT40, SGI) that they
   * use.
a5f69d94d   Helmut Schaa   mac80211: Get rid...
144
145
   *
   * Sortorder has to be fixed for GROUP_IDX macro to be applicable:
8a0ee4fe1   Karl Beldan   mac80211: minstre...
146
   * BW -> SGI -> #streams
ec8aa669b   Felix Fietkau   mac80211: add the...
147
148
   */
  const struct mcs_group minstrel_mcs_groups[] = {
8a0ee4fe1   Karl Beldan   mac80211: minstre...
149
150
  	MCS_GROUP(1, 0, BW_20),
  	MCS_GROUP(2, 0, BW_20),
8a0ee4fe1   Karl Beldan   mac80211: minstre...
151
  	MCS_GROUP(3, 0, BW_20),
ec8aa669b   Felix Fietkau   mac80211: add the...
152

8a0ee4fe1   Karl Beldan   mac80211: minstre...
153
154
  	MCS_GROUP(1, 1, BW_20),
  	MCS_GROUP(2, 1, BW_20),
8a0ee4fe1   Karl Beldan   mac80211: minstre...
155
  	MCS_GROUP(3, 1, BW_20),
ec8aa669b   Felix Fietkau   mac80211: add the...
156

8a0ee4fe1   Karl Beldan   mac80211: minstre...
157
158
  	MCS_GROUP(1, 0, BW_40),
  	MCS_GROUP(2, 0, BW_40),
8a0ee4fe1   Karl Beldan   mac80211: minstre...
159
  	MCS_GROUP(3, 0, BW_40),
ec8aa669b   Felix Fietkau   mac80211: add the...
160

8a0ee4fe1   Karl Beldan   mac80211: minstre...
161
162
  	MCS_GROUP(1, 1, BW_40),
  	MCS_GROUP(2, 1, BW_40),
8a0ee4fe1   Karl Beldan   mac80211: minstre...
163
  	MCS_GROUP(3, 1, BW_40),
a0497f9f5   Felix Fietkau   mac80211/minstrel...
164

9208247d7   Karl Beldan   mac80211: minstre...
165
166
167
168
169
  	CCK_GROUP,
  
  #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
  	VHT_GROUP(1, 0, BW_20),
  	VHT_GROUP(2, 0, BW_20),
9208247d7   Karl Beldan   mac80211: minstre...
170
  	VHT_GROUP(3, 0, BW_20),
9208247d7   Karl Beldan   mac80211: minstre...
171
172
173
  
  	VHT_GROUP(1, 1, BW_20),
  	VHT_GROUP(2, 1, BW_20),
9208247d7   Karl Beldan   mac80211: minstre...
174
  	VHT_GROUP(3, 1, BW_20),
ec8aa669b   Felix Fietkau   mac80211: add the...
175

9208247d7   Karl Beldan   mac80211: minstre...
176
177
  	VHT_GROUP(1, 0, BW_40),
  	VHT_GROUP(2, 0, BW_40),
9208247d7   Karl Beldan   mac80211: minstre...
178
  	VHT_GROUP(3, 0, BW_40),
9208247d7   Karl Beldan   mac80211: minstre...
179
180
181
  
  	VHT_GROUP(1, 1, BW_40),
  	VHT_GROUP(2, 1, BW_40),
9208247d7   Karl Beldan   mac80211: minstre...
182
  	VHT_GROUP(3, 1, BW_40),
9208247d7   Karl Beldan   mac80211: minstre...
183
184
185
  
  	VHT_GROUP(1, 0, BW_80),
  	VHT_GROUP(2, 0, BW_80),
9208247d7   Karl Beldan   mac80211: minstre...
186
  	VHT_GROUP(3, 0, BW_80),
9208247d7   Karl Beldan   mac80211: minstre...
187
188
189
  
  	VHT_GROUP(1, 1, BW_80),
  	VHT_GROUP(2, 1, BW_80),
9208247d7   Karl Beldan   mac80211: minstre...
190
191
  	VHT_GROUP(3, 1, BW_80),
  #endif
9208247d7   Karl Beldan   mac80211: minstre...
192
  };
a0497f9f5   Felix Fietkau   mac80211/minstrel...
193

f6e1a73b6   Johannes Berg   mac80211: minstre...
194
  static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
ec8aa669b   Felix Fietkau   mac80211: add the...
195

a85666627   Felix Fietkau   mac80211/minstrel...
196
197
  static void
  minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
ec8aa669b   Felix Fietkau   mac80211: add the...
198
  /*
9208247d7   Karl Beldan   mac80211: minstre...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
   * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer)
   * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1
   *
   * Returns the valid mcs map for struct minstrel_mcs_group_data.supported
   */
  static u16
  minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map)
  {
  	u16 mask = 0;
  
  	if (bw == BW_20) {
  		if (nss != 3 && nss != 6)
  			mask = BIT(9);
  	} else if (bw == BW_80) {
  		if (nss == 3 || nss == 7)
  			mask = BIT(6);
  		else if (nss == 6)
  			mask = BIT(9);
  	} else {
  		WARN_ON(bw != BW_40);
  	}
  
  	switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) {
  	case IEEE80211_VHT_MCS_SUPPORT_0_7:
  		mask |= 0x300;
  		break;
  	case IEEE80211_VHT_MCS_SUPPORT_0_8:
  		mask |= 0x200;
  		break;
  	case IEEE80211_VHT_MCS_SUPPORT_0_9:
  		break;
  	default:
  		mask = 0x3ff;
  	}
  
  	return 0x3ff & ~mask;
  }
  
  /*
ec8aa669b   Felix Fietkau   mac80211: add the...
238
239
240
241
242
   * Look up an MCS group index based on mac80211 rate information
   */
  static int
  minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
  {
cc61d8df0   Karl Beldan   mac80211: minstre...
243
  	return GROUP_IDX((rate->idx / 8) + 1,
a5f69d94d   Helmut Schaa   mac80211: Get rid...
244
245
  			 !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
  			 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
ec8aa669b   Felix Fietkau   mac80211: add the...
246
  }
9208247d7   Karl Beldan   mac80211: minstre...
247
248
249
250
251
252
253
254
  static int
  minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate)
  {
  	return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate),
  			     !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
  			     !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +
  			     2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH));
  }
a0497f9f5   Felix Fietkau   mac80211/minstrel...
255
256
257
258
259
260
261
262
  static struct minstrel_rate_stats *
  minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
  		      struct ieee80211_tx_rate *rate)
  {
  	int group, idx;
  
  	if (rate->flags & IEEE80211_TX_RC_MCS) {
  		group = minstrel_ht_get_group_idx(rate);
7a5e3fa2c   Karl Beldan   mac80211: minstre...
263
  		idx = rate->idx % 8;
9208247d7   Karl Beldan   mac80211: minstre...
264
265
266
  	} else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
  		group = minstrel_vht_get_group_idx(rate);
  		idx = ieee80211_rate_get_vht_mcs(rate);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
267
268
269
270
271
272
273
274
  	} else {
  		group = MINSTREL_CCK_GROUP;
  
  		for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++)
  			if (rate->idx == mp->cck_rates[idx])
  				break;
  
  		/* short preamble */
41d085835   Felix Fietkau   mac80211: minstre...
275
  		if (!(mi->supported[group] & BIT(idx)))
a0497f9f5   Felix Fietkau   mac80211/minstrel...
276
277
278
279
  			idx += 4;
  	}
  	return &mi->groups[group].rates[idx];
  }
ec8aa669b   Felix Fietkau   mac80211: add the...
280
281
282
283
284
  static inline struct minstrel_rate_stats *
  minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
  {
  	return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
  }
ec8aa669b   Felix Fietkau   mac80211: add the...
285
  /*
6a27b2c40   Thomas Huehn   mac80211: restruc...
286
287
   * Return current throughput based on the average A-MPDU length, taking into
   * account the expected number of retransmissions and their expected length
ec8aa669b   Felix Fietkau   mac80211: add the...
288
   */
6a27b2c40   Thomas Huehn   mac80211: restruc...
289
  int
50e55a8ea   Thomas Huehn   mac80211: add max...
290
291
  minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
  		       int prob_ewma)
ec8aa669b   Felix Fietkau   mac80211: add the...
292
  {
ed97a13c5   Felix Fietkau   mac80211/minstrel...
293
  	unsigned int nsecs = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
294

9134073bc   Thomas Huehn   mac80211: improve...
295
  	/* do not account throughput if sucess prob is below 10% */
50e55a8ea   Thomas Huehn   mac80211: add max...
296
  	if (prob_ewma < MINSTREL_FRAC(10, 100))
6a27b2c40   Thomas Huehn   mac80211: restruc...
297
  		return 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
298

a0497f9f5   Felix Fietkau   mac80211/minstrel...
299
  	if (group != MINSTREL_CCK_GROUP)
ed97a13c5   Felix Fietkau   mac80211/minstrel...
300
  		nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
301

ed97a13c5   Felix Fietkau   mac80211/minstrel...
302
  	nsecs += minstrel_mcs_groups[group].duration[rate];
ed97a13c5   Felix Fietkau   mac80211/minstrel...
303

50e55a8ea   Thomas Huehn   mac80211: add max...
304
305
306
307
308
309
310
311
312
313
  	/*
  	 * For the throughput calculation, limit the probability value to 90% to
  	 * account for collision related packet error rate fluctuation
  	 * (prob is scaled - see MINSTREL_FRAC above)
  	 */
  	if (prob_ewma > MINSTREL_FRAC(90, 100))
  		return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
  								      / nsecs));
  	else
  		return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
ec8aa669b   Felix Fietkau   mac80211: add the...
314
315
316
  }
  
  /*
5935839ad   Thomas Huehn   mac80211: improve...
317
318
319
320
321
322
323
   * Find & sort topmost throughput rates
   *
   * If multiple rates provide equal throughput the sorting is based on their
   * current success probability. Higher success probability is preferred among
   * MCS groups, CCK rates do not provide aggregation and are therefore at last.
   */
  static void
d4d141cae   Karl Beldan   mac80211: minstre...
324
325
  minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
  			       u16 *tp_list)
5935839ad   Thomas Huehn   mac80211: improve...
326
  {
6a27b2c40   Thomas Huehn   mac80211: restruc...
327
328
  	int cur_group, cur_idx, cur_tp_avg, cur_prob;
  	int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
5935839ad   Thomas Huehn   mac80211: improve...
329
330
331
332
  	int j = MAX_THR_RATES;
  
  	cur_group = index / MCS_GROUP_RATES;
  	cur_idx = index  % MCS_GROUP_RATES;
9134073bc   Thomas Huehn   mac80211: improve...
333
  	cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
50e55a8ea   Thomas Huehn   mac80211: add max...
334
  	cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
5935839ad   Thomas Huehn   mac80211: improve...
335

280ba51d6   Felix Fietkau   mac80211: minstre...
336
  	do {
5935839ad   Thomas Huehn   mac80211: improve...
337
338
  		tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
  		tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
9134073bc   Thomas Huehn   mac80211: improve...
339
  		tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
50e55a8ea   Thomas Huehn   mac80211: add max...
340
341
  		tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
  						    tmp_prob);
6a27b2c40   Thomas Huehn   mac80211: restruc...
342
343
  		if (cur_tp_avg < tmp_tp_avg ||
  		    (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
280ba51d6   Felix Fietkau   mac80211: minstre...
344
345
346
  			break;
  		j--;
  	} while (j > 0);
5935839ad   Thomas Huehn   mac80211: improve...
347
348
349
350
351
352
353
354
355
356
357
358
359
  
  	if (j < MAX_THR_RATES - 1) {
  		memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) *
  		       (MAX_THR_RATES - (j + 1))));
  	}
  	if (j < MAX_THR_RATES)
  		tp_list[j] = index;
  }
  
  /*
   * Find and set the topmost probability rate per sta and per group
   */
  static void
d4d141cae   Karl Beldan   mac80211: minstre...
360
  minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
5935839ad   Thomas Huehn   mac80211: improve...
361
362
  {
  	struct minstrel_mcs_group_data *mg;
9134073bc   Thomas Huehn   mac80211: improve...
363
  	struct minstrel_rate_stats *mrs;
6a27b2c40   Thomas Huehn   mac80211: restruc...
364
365
  	int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
  	int max_tp_group, cur_tp_avg, cur_group, cur_idx;
50e55a8ea   Thomas Huehn   mac80211: add max...
366
367
  	int max_gpr_group, max_gpr_idx;
  	int max_gpr_tp_avg, max_gpr_prob;
5935839ad   Thomas Huehn   mac80211: improve...
368

6a27b2c40   Thomas Huehn   mac80211: restruc...
369
370
  	cur_group = index / MCS_GROUP_RATES;
  	cur_idx = index % MCS_GROUP_RATES;
5935839ad   Thomas Huehn   mac80211: improve...
371
  	mg = &mi->groups[index / MCS_GROUP_RATES];
9134073bc   Thomas Huehn   mac80211: improve...
372
  	mrs = &mg->rates[index % MCS_GROUP_RATES];
5935839ad   Thomas Huehn   mac80211: improve...
373
374
375
  
  	tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
  	tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
9134073bc   Thomas Huehn   mac80211: improve...
376
  	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
50e55a8ea   Thomas Huehn   mac80211: add max...
377
  	tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
5935839ad   Thomas Huehn   mac80211: improve...
378
379
380
381
382
383
384
  
  	/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
  	 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */
  	max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES;
  	if((index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) &&
  	    (max_tp_group != MINSTREL_CCK_GROUP))
  		return;
f84a93726   Konstantin Khlebnikov   mac80211: minstre...
385
386
387
  	max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
  	max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
  	max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
9134073bc   Thomas Huehn   mac80211: improve...
388
  	if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
50e55a8ea   Thomas Huehn   mac80211: add max...
389
390
  		cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
  						    mrs->prob_ewma);
6a27b2c40   Thomas Huehn   mac80211: restruc...
391
  		if (cur_tp_avg > tmp_tp_avg)
5935839ad   Thomas Huehn   mac80211: improve...
392
  			mi->max_prob_rate = index;
6a27b2c40   Thomas Huehn   mac80211: restruc...
393

50e55a8ea   Thomas Huehn   mac80211: add max...
394
395
396
397
  		max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
  							max_gpr_idx,
  							max_gpr_prob);
  		if (cur_tp_avg > max_gpr_tp_avg)
5935839ad   Thomas Huehn   mac80211: improve...
398
399
  			mg->max_group_prob_rate = index;
  	} else {
9134073bc   Thomas Huehn   mac80211: improve...
400
  		if (mrs->prob_ewma > tmp_prob)
5935839ad   Thomas Huehn   mac80211: improve...
401
  			mi->max_prob_rate = index;
f84a93726   Konstantin Khlebnikov   mac80211: minstre...
402
  		if (mrs->prob_ewma > max_gpr_prob)
5935839ad   Thomas Huehn   mac80211: improve...
403
404
405
406
407
408
409
410
411
412
413
414
415
  			mg->max_group_prob_rate = index;
  	}
  }
  
  
  /*
   * Assign new rate set per sta and use CCK rates only if the fastest
   * rate (max_tp_rate[0]) is from CCK group. This prohibits such sorted
   * rate sets where MCS and CCK rates are mixed, because CCK rates can
   * not use aggregation.
   */
  static void
  minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
d4d141cae   Karl Beldan   mac80211: minstre...
416
417
  				 u16 tmp_mcs_tp_rate[MAX_THR_RATES],
  				 u16 tmp_cck_tp_rate[MAX_THR_RATES])
5935839ad   Thomas Huehn   mac80211: improve...
418
  {
50e55a8ea   Thomas Huehn   mac80211: add max...
419
  	unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob;
5935839ad   Thomas Huehn   mac80211: improve...
420
421
422
423
  	int i;
  
  	tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
  	tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
50e55a8ea   Thomas Huehn   mac80211: add max...
424
425
  	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
  	tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
5935839ad   Thomas Huehn   mac80211: improve...
426
427
428
  
  	tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
  	tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
50e55a8ea   Thomas Huehn   mac80211: add max...
429
430
  	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
  	tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
5935839ad   Thomas Huehn   mac80211: improve...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  
  	if (tmp_cck_tp > tmp_mcs_tp) {
  		for(i = 0; i < MAX_THR_RATES; i++) {
  			minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
  						       tmp_mcs_tp_rate);
  		}
  	}
  
  }
  
  /*
   * Try to increase robustness of max_prob rate by decrease number of
   * streams if possible.
   */
  static inline void
  minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
  {
  	struct minstrel_mcs_group_data *mg;
50e55a8ea   Thomas Huehn   mac80211: add max...
449
  	int tmp_max_streams, group, tmp_idx, tmp_prob;
5935839ad   Thomas Huehn   mac80211: improve...
450
451
452
453
454
455
  	int tmp_tp = 0;
  
  	tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
  			  MCS_GROUP_RATES].streams;
  	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
  		mg = &mi->groups[group];
41d085835   Felix Fietkau   mac80211: minstre...
456
  		if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
5935839ad   Thomas Huehn   mac80211: improve...
457
  			continue;
6a27b2c40   Thomas Huehn   mac80211: restruc...
458
459
  
  		tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
50e55a8ea   Thomas Huehn   mac80211: add max...
460
  		tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
6a27b2c40   Thomas Huehn   mac80211: restruc...
461

50e55a8ea   Thomas Huehn   mac80211: add max...
462
  		if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
5935839ad   Thomas Huehn   mac80211: improve...
463
464
  		   (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
  				mi->max_prob_rate = mg->max_group_prob_rate;
6a27b2c40   Thomas Huehn   mac80211: restruc...
465
  				tmp_tp = minstrel_ht_get_tp_avg(mi, group,
50e55a8ea   Thomas Huehn   mac80211: add max...
466
467
  								tmp_idx,
  								tmp_prob);
5935839ad   Thomas Huehn   mac80211: improve...
468
469
470
471
472
  		}
  	}
  }
  
  /*
ec8aa669b   Felix Fietkau   mac80211: add the...
473
474
475
476
477
   * Update rate statistics and select new primary rates
   *
   * Rules for rate selection:
   *  - max_prob_rate must use only one stream, as a tradeoff between delivery
   *    probability and throughput during strong fluctuations
5935839ad   Thomas Huehn   mac80211: improve...
478
   *  - as long as the max prob rate has a probability of more than 75%, pick
ec8aa669b   Felix Fietkau   mac80211: add the...
479
480
481
482
483
484
   *    higher throughput rates, even if the probablity is a bit lower
   */
  static void
  minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
  {
  	struct minstrel_mcs_group_data *mg;
9134073bc   Thomas Huehn   mac80211: improve...
485
  	struct minstrel_rate_stats *mrs;
50e55a8ea   Thomas Huehn   mac80211: add max...
486
  	int group, i, j, cur_prob;
d4d141cae   Karl Beldan   mac80211: minstre...
487
488
  	u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
  	u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
ec8aa669b   Felix Fietkau   mac80211: add the...
489
490
491
492
493
494
495
496
497
498
  
  	if (mi->ampdu_packets > 0) {
  		mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
  			MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
  		mi->ampdu_len = 0;
  		mi->ampdu_packets = 0;
  	}
  
  	mi->sample_slow = 0;
  	mi->sample_count = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
499

5935839ad   Thomas Huehn   mac80211: improve...
500
501
502
503
504
  	/* Initialize global rate indexes */
  	for(j = 0; j < MAX_THR_RATES; j++){
  		tmp_mcs_tp_rate[j] = 0;
  		tmp_cck_tp_rate[j] = 0;
  	}
c2eb5b0f3   Karl Beldan   mac80211: minstre...
505

5935839ad   Thomas Huehn   mac80211: improve...
506
507
  	/* Find best rate sets within all MCS groups*/
  	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
ec8aa669b   Felix Fietkau   mac80211: add the...
508
509
  
  		mg = &mi->groups[group];
41d085835   Felix Fietkau   mac80211: minstre...
510
  		if (!mi->supported[group])
ec8aa669b   Felix Fietkau   mac80211: add the...
511
  			continue;
ec8aa669b   Felix Fietkau   mac80211: add the...
512
  		mi->sample_count++;
5935839ad   Thomas Huehn   mac80211: improve...
513
514
515
  		/* (re)Initialize group rate indexes */
  		for(j = 0; j < MAX_THR_RATES; j++)
  			tmp_group_tp_rate[j] = group;
ec8aa669b   Felix Fietkau   mac80211: add the...
516
  		for (i = 0; i < MCS_GROUP_RATES; i++) {
41d085835   Felix Fietkau   mac80211: minstre...
517
  			if (!(mi->supported[group] & BIT(i)))
ec8aa669b   Felix Fietkau   mac80211: add the...
518
  				continue;
351df0997   Karl Beldan   mac80211: minstre...
519
  			index = MCS_GROUP_RATES * group + i;
9134073bc   Thomas Huehn   mac80211: improve...
520
521
522
  			mrs = &mg->rates[i];
  			mrs->retry_updated = false;
  			minstrel_calc_rate_stats(mrs);
50e55a8ea   Thomas Huehn   mac80211: add max...
523
  			cur_prob = mrs->prob_ewma;
ec8aa669b   Felix Fietkau   mac80211: add the...
524

50e55a8ea   Thomas Huehn   mac80211: add max...
525
  			if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
ec8aa669b   Felix Fietkau   mac80211: add the...
526
  				continue;
5935839ad   Thomas Huehn   mac80211: improve...
527
528
529
530
531
532
533
  			/* Find max throughput rate set */
  			if (group != MINSTREL_CCK_GROUP) {
  				minstrel_ht_sort_best_tp_rates(mi, index,
  							       tmp_mcs_tp_rate);
  			} else if (group == MINSTREL_CCK_GROUP) {
  				minstrel_ht_sort_best_tp_rates(mi, index,
  							       tmp_cck_tp_rate);
ec8aa669b   Felix Fietkau   mac80211: add the...
534
  			}
ec8aa669b   Felix Fietkau   mac80211: add the...
535

5935839ad   Thomas Huehn   mac80211: improve...
536
537
538
  			/* Find max throughput rate set within a group */
  			minstrel_ht_sort_best_tp_rates(mi, index,
  						       tmp_group_tp_rate);
ec8aa669b   Felix Fietkau   mac80211: add the...
539

5935839ad   Thomas Huehn   mac80211: improve...
540
541
  			/* Find max probability rate per group and global */
  			minstrel_ht_set_best_prob_rate(mi, index);
ec8aa669b   Felix Fietkau   mac80211: add the...
542
  		}
5935839ad   Thomas Huehn   mac80211: improve...
543
544
  		memcpy(mg->max_group_tp_rate, tmp_group_tp_rate,
  		       sizeof(mg->max_group_tp_rate));
ec8aa669b   Felix Fietkau   mac80211: add the...
545
  	}
5935839ad   Thomas Huehn   mac80211: improve...
546
547
548
  	/* Assign new rate set per sta */
  	minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate);
  	memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate));
a299c6d59   Felix Fietkau   mac80211/minstrel...
549

5935839ad   Thomas Huehn   mac80211: improve...
550
551
552
553
554
  	/* Try to increase robustness of max_prob_rate*/
  	minstrel_ht_prob_rate_reduce_streams(mi);
  
  	/* try to sample all available rates during each interval */
  	mi->sample_count *= 8;
a299c6d59   Felix Fietkau   mac80211/minstrel...
555

37feb7e2f   Lorenzo Bianconi   mac80211: do not ...
556
557
558
  #ifdef CONFIG_MAC80211_DEBUGFS
  	/* use fixed index if set */
  	if (mp->fixed_rate_idx != -1) {
5935839ad   Thomas Huehn   mac80211: improve...
559
560
  		for (i = 0; i < 4; i++)
  			mi->max_tp_rate[i] = mp->fixed_rate_idx;
37feb7e2f   Lorenzo Bianconi   mac80211: do not ...
561
562
563
  		mi->max_prob_rate = mp->fixed_rate_idx;
  	}
  #endif
a299c6d59   Felix Fietkau   mac80211/minstrel...
564

5935839ad   Thomas Huehn   mac80211: improve...
565
  	/* Reset update timer */
9134073bc   Thomas Huehn   mac80211: improve...
566
  	mi->last_stats_update = jiffies;
ec8aa669b   Felix Fietkau   mac80211: add the...
567
568
569
  }
  
  static bool
a0497f9f5   Felix Fietkau   mac80211/minstrel...
570
  minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate)
ec8aa669b   Felix Fietkau   mac80211: add the...
571
  {
b79296bee   Helmut Schaa   mac80211: Check r...
572
  	if (rate->idx < 0)
ec8aa669b   Felix Fietkau   mac80211: add the...
573
  		return false;
b79296bee   Helmut Schaa   mac80211: Check r...
574
  	if (!rate->count)
ec8aa669b   Felix Fietkau   mac80211: add the...
575
  		return false;
9208247d7   Karl Beldan   mac80211: minstre...
576
577
  	if (rate->flags & IEEE80211_TX_RC_MCS ||
  	    rate->flags & IEEE80211_TX_RC_VHT_MCS)
a0497f9f5   Felix Fietkau   mac80211/minstrel...
578
579
580
581
582
583
  		return true;
  
  	return rate->idx == mp->cck_rates[0] ||
  	       rate->idx == mp->cck_rates[1] ||
  	       rate->idx == mp->cck_rates[2] ||
  	       rate->idx == mp->cck_rates[3];
ec8aa669b   Felix Fietkau   mac80211: add the...
584
585
586
  }
  
  static void
9134073bc   Thomas Huehn   mac80211: improve...
587
  minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi)
ec8aa669b   Felix Fietkau   mac80211: add the...
588
589
590
591
592
593
594
  {
  	struct minstrel_mcs_group_data *mg;
  
  	for (;;) {
  		mi->sample_group++;
  		mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
  		mg = &mi->groups[mi->sample_group];
41d085835   Felix Fietkau   mac80211: minstre...
595
  		if (!mi->supported[mi->sample_group])
ec8aa669b   Felix Fietkau   mac80211: add the...
596
597
598
599
600
601
602
603
604
605
606
607
  			continue;
  
  		if (++mg->index >= MCS_GROUP_RATES) {
  			mg->index = 0;
  			if (++mg->column >= ARRAY_SIZE(sample_table))
  				mg->column = 0;
  		}
  		break;
  	}
  }
  
  static void
d4d141cae   Karl Beldan   mac80211: minstre...
608
  minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
ec8aa669b   Felix Fietkau   mac80211: add the...
609
610
611
612
613
614
  {
  	int group, orig_group;
  
  	orig_group = group = *idx / MCS_GROUP_RATES;
  	while (group > 0) {
  		group--;
41d085835   Felix Fietkau   mac80211: minstre...
615
  		if (!mi->supported[group])
ec8aa669b   Felix Fietkau   mac80211: add the...
616
617
618
619
620
621
622
  			continue;
  
  		if (minstrel_mcs_groups[group].streams >
  		    minstrel_mcs_groups[orig_group].streams)
  			continue;
  
  		if (primary)
5935839ad   Thomas Huehn   mac80211: improve...
623
  			*idx = mi->groups[group].max_group_tp_rate[0];
ec8aa669b   Felix Fietkau   mac80211: add the...
624
  		else
5935839ad   Thomas Huehn   mac80211: improve...
625
  			*idx = mi->groups[group].max_group_tp_rate[1];
ec8aa669b   Felix Fietkau   mac80211: add the...
626
627
628
629
630
  		break;
  	}
  }
  
  static void
6048d7638   Patrick Kelle   minstrel_ht: Remo...
631
  minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
ec8aa669b   Felix Fietkau   mac80211: add the...
632
633
634
635
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
  	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
  	u16 tid;
75769c80e   Felix Fietkau   mac80211: minstre...
636
637
  	if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
  		return;
ec8aa669b   Felix Fietkau   mac80211: add the...
638
639
  	if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
  		return;
e133fae26   Johannes Berg   mac80211: minstre...
640
  	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
ec8aa669b   Felix Fietkau   mac80211: add the...
641
642
643
  		return;
  
  	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
a622ab72b   Johannes Berg   mac80211: use RCU...
644
  	if (likely(sta->ampdu_mlme.tid_tx[tid]))
ec8aa669b   Felix Fietkau   mac80211: add the...
645
  		return;
7a36b930e   Felix Fietkau   mac80211: minstre...
646
  	ieee80211_start_tx_ba_session(pubsta, tid, 0);
ec8aa669b   Felix Fietkau   mac80211: add the...
647
648
649
650
  }
  
  static void
  minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
18fb84d98   Felix Fietkau   mac80211: make ra...
651
                        void *priv_sta, struct ieee80211_tx_status *st)
ec8aa669b   Felix Fietkau   mac80211: add the...
652
  {
18fb84d98   Felix Fietkau   mac80211: make ra...
653
  	struct ieee80211_tx_info *info = st->info;
ec8aa669b   Felix Fietkau   mac80211: add the...
654
655
  	struct minstrel_ht_sta_priv *msp = priv_sta;
  	struct minstrel_ht_sta *mi = &msp->ht;
ec8aa669b   Felix Fietkau   mac80211: add the...
656
657
658
  	struct ieee80211_tx_rate *ar = info->status.rates;
  	struct minstrel_rate_stats *rate, *rate2;
  	struct minstrel_priv *mp = priv;
a85666627   Felix Fietkau   mac80211/minstrel...
659
  	bool last, update = false;
a544ab7f9   Johannes Berg   mac80211: simplif...
660
  	int i;
ec8aa669b   Felix Fietkau   mac80211: add the...
661
662
  
  	if (!msp->is_ht)
18fb84d98   Felix Fietkau   mac80211: make ra...
663
664
  		return mac80211_minstrel.tx_status_ext(priv, sband,
  						       &msp->legacy, st);
ec8aa669b   Felix Fietkau   mac80211: add the...
665
666
667
668
669
  
  	/* This packet was aggregated but doesn't carry status info */
  	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
  	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
  		return;
15d46f38d   Björn Smedman   mac80211: minstre...
670
671
672
  	if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) {
  		info->status.ampdu_ack_len =
  			(info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
ec8aa669b   Felix Fietkau   mac80211: add the...
673
674
675
676
677
678
679
  		info->status.ampdu_len = 1;
  	}
  
  	mi->ampdu_packets++;
  	mi->ampdu_len += info->status.ampdu_len;
  
  	if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
c7317e41d   Felix Fietkau   mac80211: minstre...
680
  		mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
52c00a37a   Felix Fietkau   mac80211/minstrel...
681
  		mi->sample_tries = 1;
ec8aa669b   Felix Fietkau   mac80211: add the...
682
683
  		mi->sample_count--;
  	}
8d5eab5aa   Daniel Halperin   mac80211: update ...
684
  	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
ec8aa669b   Felix Fietkau   mac80211: add the...
685
  		mi->sample_packets += info->status.ampdu_len;
ec8aa669b   Felix Fietkau   mac80211: add the...
686

a0497f9f5   Felix Fietkau   mac80211/minstrel...
687
  	last = !minstrel_ht_txstat_valid(mp, &ar[0]);
ec8aa669b   Felix Fietkau   mac80211: add the...
688
689
  	for (i = 0; !last; i++) {
  		last = (i == IEEE80211_TX_MAX_RATES - 1) ||
a0497f9f5   Felix Fietkau   mac80211/minstrel...
690
  		       !minstrel_ht_txstat_valid(mp, &ar[i + 1]);
ec8aa669b   Felix Fietkau   mac80211: add the...
691

a0497f9f5   Felix Fietkau   mac80211/minstrel...
692
  		rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
ec8aa669b   Felix Fietkau   mac80211: add the...
693

15d46f38d   Björn Smedman   mac80211: minstre...
694
  		if (last)
ec8aa669b   Felix Fietkau   mac80211: add the...
695
696
697
698
699
700
701
702
703
  			rate->success += info->status.ampdu_ack_len;
  
  		rate->attempts += ar[i].count * info->status.ampdu_len;
  	}
  
  	/*
  	 * check for sudden death of spatial multiplexing,
  	 * downgrade to a lower number of streams if necessary.
  	 */
5935839ad   Thomas Huehn   mac80211: improve...
704
  	rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
ec8aa669b   Felix Fietkau   mac80211: add the...
705
706
  	if (rate->attempts > 30 &&
  	    MINSTREL_FRAC(rate->success, rate->attempts) <
a85666627   Felix Fietkau   mac80211/minstrel...
707
  	    MINSTREL_FRAC(20, 100)) {
5935839ad   Thomas Huehn   mac80211: improve...
708
  		minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
a85666627   Felix Fietkau   mac80211/minstrel...
709
710
  		update = true;
  	}
ec8aa669b   Felix Fietkau   mac80211: add the...
711

5935839ad   Thomas Huehn   mac80211: improve...
712
  	rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
ecc3d5ae1   Ming Lei   minstrel_ht: fix ...
713
714
  	if (rate2->attempts > 30 &&
  	    MINSTREL_FRAC(rate2->success, rate2->attempts) <
a85666627   Felix Fietkau   mac80211/minstrel...
715
  	    MINSTREL_FRAC(20, 100)) {
5935839ad   Thomas Huehn   mac80211: improve...
716
  		minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
a85666627   Felix Fietkau   mac80211/minstrel...
717
718
  		update = true;
  	}
ec8aa669b   Felix Fietkau   mac80211: add the...
719

9134073bc   Thomas Huehn   mac80211: improve...
720
721
  	if (time_after(jiffies, mi->last_stats_update +
  				(mp->update_interval / 2 * HZ) / 1000)) {
a85666627   Felix Fietkau   mac80211/minstrel...
722
  		update = true;
ec8aa669b   Felix Fietkau   mac80211: add the...
723
  		minstrel_ht_update_stats(mp, mi);
ec8aa669b   Felix Fietkau   mac80211: add the...
724
  	}
a85666627   Felix Fietkau   mac80211/minstrel...
725
726
727
  
  	if (update)
  		minstrel_ht_update_rates(mp, mi);
ec8aa669b   Felix Fietkau   mac80211: add the...
728
729
730
731
732
733
  }
  
  static void
  minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
                           int index)
  {
9134073bc   Thomas Huehn   mac80211: improve...
734
  	struct minstrel_rate_stats *mrs;
ec8aa669b   Felix Fietkau   mac80211: add the...
735
736
737
  	const struct mcs_group *group;
  	unsigned int tx_time, tx_time_rtscts, tx_time_data;
  	unsigned int cw = mp->cw_min;
8fddddff0   Daniel Halperin   mac80211: fix con...
738
  	unsigned int ctime = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
739
740
  	unsigned int t_slot = 9; /* FIXME */
  	unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
741
  	unsigned int overhead = 0, overhead_rtscts = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
742

9134073bc   Thomas Huehn   mac80211: improve...
743
744
745
746
  	mrs = minstrel_get_ratestats(mi, index);
  	if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) {
  		mrs->retry_count = 1;
  		mrs->retry_count_rtscts = 1;
ec8aa669b   Felix Fietkau   mac80211: add the...
747
748
  		return;
  	}
9134073bc   Thomas Huehn   mac80211: improve...
749
750
751
  	mrs->retry_count = 2;
  	mrs->retry_count_rtscts = 2;
  	mrs->retry_updated = true;
ec8aa669b   Felix Fietkau   mac80211: add the...
752
753
  
  	group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
ed97a13c5   Felix Fietkau   mac80211/minstrel...
754
  	tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
8fddddff0   Daniel Halperin   mac80211: fix con...
755
756
757
758
759
760
  
  	/* Contention time for first 2 tries */
  	ctime = (t_slot * cw) >> 1;
  	cw = min((cw << 1) | 1, mp->cw_max);
  	ctime += (t_slot * cw) >> 1;
  	cw = min((cw << 1) | 1, mp->cw_max);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
761
762
763
764
  	if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) {
  		overhead = mi->overhead;
  		overhead_rtscts = mi->overhead_rtscts;
  	}
8fddddff0   Daniel Halperin   mac80211: fix con...
765
  	/* Total TX time for data and Contention after first 2 tries */
a0497f9f5   Felix Fietkau   mac80211/minstrel...
766
767
  	tx_time = ctime + 2 * (overhead + tx_time_data);
  	tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data);
8fddddff0   Daniel Halperin   mac80211: fix con...
768
769
  
  	/* See how many more tries we can fit inside segment size */
ec8aa669b   Felix Fietkau   mac80211: add the...
770
  	do {
8fddddff0   Daniel Halperin   mac80211: fix con...
771
772
773
774
775
  		/* Contention time for this try */
  		ctime = (t_slot * cw) >> 1;
  		cw = min((cw << 1) | 1, mp->cw_max);
  
  		/* Total TX time after this try */
a0497f9f5   Felix Fietkau   mac80211/minstrel...
776
777
  		tx_time += ctime + overhead + tx_time_data;
  		tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;
8fddddff0   Daniel Halperin   mac80211: fix con...
778

ec8aa669b   Felix Fietkau   mac80211: add the...
779
  		if (tx_time_rtscts < mp->segment_size)
9134073bc   Thomas Huehn   mac80211: improve...
780
  			mrs->retry_count_rtscts++;
ec8aa669b   Felix Fietkau   mac80211: add the...
781
  	} while ((tx_time < mp->segment_size) &&
9134073bc   Thomas Huehn   mac80211: improve...
782
  	         (++mrs->retry_count < mp->max_retry));
ec8aa669b   Felix Fietkau   mac80211: add the...
783
784
785
786
787
  }
  
  
  static void
  minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
a85666627   Felix Fietkau   mac80211/minstrel...
788
                       struct ieee80211_sta_rates *ratetbl, int offset, int index)
ec8aa669b   Felix Fietkau   mac80211: add the...
789
790
  {
  	const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
9134073bc   Thomas Huehn   mac80211: improve...
791
  	struct minstrel_rate_stats *mrs;
a85666627   Felix Fietkau   mac80211/minstrel...
792
  	u8 idx;
3ec373c42   Karl Beldan   mac80211: minstre...
793
  	u16 flags = group->flags;
ec8aa669b   Felix Fietkau   mac80211: add the...
794

9134073bc   Thomas Huehn   mac80211: improve...
795
796
  	mrs = minstrel_get_ratestats(mi, index);
  	if (!mrs->retry_updated)
ec8aa669b   Felix Fietkau   mac80211: add the...
797
  		minstrel_calc_retransmit(mp, mi, index);
9134073bc   Thomas Huehn   mac80211: improve...
798
  	if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
a85666627   Felix Fietkau   mac80211/minstrel...
799
800
801
802
  		ratetbl->rate[offset].count = 2;
  		ratetbl->rate[offset].count_rts = 2;
  		ratetbl->rate[offset].count_cts = 2;
  	} else {
9134073bc   Thomas Huehn   mac80211: improve...
803
804
805
  		ratetbl->rate[offset].count = mrs->retry_count;
  		ratetbl->rate[offset].count_cts = mrs->retry_count;
  		ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts;
a85666627   Felix Fietkau   mac80211/minstrel...
806
  	}
a0497f9f5   Felix Fietkau   mac80211/minstrel...
807

3ec373c42   Karl Beldan   mac80211: minstre...
808
  	if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP)
a85666627   Felix Fietkau   mac80211/minstrel...
809
  		idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
9208247d7   Karl Beldan   mac80211: minstre...
810
811
812
  	else if (flags & IEEE80211_TX_RC_VHT_MCS)
  		idx = ((group->streams - 1) << 4) |
  		      ((index % MCS_GROUP_RATES) & 0xF);
3ec373c42   Karl Beldan   mac80211: minstre...
813
  	else
7a5e3fa2c   Karl Beldan   mac80211: minstre...
814
  		idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
a85666627   Felix Fietkau   mac80211/minstrel...
815

a3ebb4e1b   Krishna Chaitanya   mac80211: minstre...
816
817
818
819
  	/* enable RTS/CTS if needed:
  	 *  - if station is in dynamic SMPS (and streams > 1)
  	 *  - for fallback rates, to increase chances of getting through
  	 */
c36dd3eaf   Felix Fietkau   mac80211: minstre...
820
  	if (offset > 0 ||
a3ebb4e1b   Krishna Chaitanya   mac80211: minstre...
821
822
  	    (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC &&
  	     group->streams > 1)) {
a85666627   Felix Fietkau   mac80211/minstrel...
823
824
825
826
827
828
829
  		ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
  		flags |= IEEE80211_TX_RC_USE_RTS_CTS;
  	}
  
  	ratetbl->rate[offset].idx = idx;
  	ratetbl->rate[offset].flags = flags;
  }
918fe04b2   Felix Fietkau   mac80211: minstre...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  static inline int
  minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate)
  {
  	int group = rate / MCS_GROUP_RATES;
  	rate %= MCS_GROUP_RATES;
  	return mi->groups[group].rates[rate].prob_ewma;
  }
  
  static int
  minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi)
  {
  	int group = mi->max_prob_rate / MCS_GROUP_RATES;
  	const struct mcs_group *g = &minstrel_mcs_groups[group];
  	int rate = mi->max_prob_rate % MCS_GROUP_RATES;
  
  	/* Disable A-MSDU if max_prob_rate is bad */
  	if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
  		return 1;
  
  	/* If the rate is slower than single-stream MCS1, make A-MSDU limit small */
  	if (g->duration[rate] > MCS_DURATION(1, 0, 52))
  		return 500;
  
  	/*
  	 * If the rate is slower than single-stream MCS4, limit A-MSDU to usual
  	 * data packet size
  	 */
  	if (g->duration[rate] > MCS_DURATION(1, 0, 104))
  		return 1600;
  
  	/*
  	 * If the rate is slower than single-stream MCS7, or if the max throughput
  	 * rate success probability is less than 75%, limit A-MSDU to twice the usual
  	 * data packet size
  	 */
  	if (g->duration[rate] > MCS_DURATION(1, 0, 260) ||
  	    (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) <
  	     MINSTREL_FRAC(75, 100)))
  		return 3200;
  
  	/*
  	 * HT A-MPDU limits maximum MPDU size under BA agreement to 4095 bytes.
  	 * Since aggregation sessions are started/stopped without txq flush, use
  	 * the limit here to avoid the complexity of having to de-aggregate
  	 * packets in the queue.
  	 */
  	if (!mi->sta->vht_cap.vht_supported)
  		return IEEE80211_MAX_MPDU_LEN_HT_BA;
  
  	/* unlimited */
  	return 0;
  }
a85666627   Felix Fietkau   mac80211/minstrel...
882
883
884
885
886
887
888
889
  static void
  minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
  {
  	struct ieee80211_sta_rates *rates;
  	int i = 0;
  
  	rates = kzalloc(sizeof(*rates), GFP_ATOMIC);
  	if (!rates)
a0497f9f5   Felix Fietkau   mac80211/minstrel...
890
  		return;
a85666627   Felix Fietkau   mac80211/minstrel...
891

5935839ad   Thomas Huehn   mac80211: improve...
892
893
  	/* Start with max_tp_rate[0] */
  	minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]);
a85666627   Felix Fietkau   mac80211/minstrel...
894
895
  
  	if (mp->hw->max_rates >= 3) {
5935839ad   Thomas Huehn   mac80211: improve...
896
897
  		/* At least 3 tx rates supported, use max_tp_rate[1] next */
  		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[1]);
a85666627   Felix Fietkau   mac80211/minstrel...
898
899
900
901
902
903
  	}
  
  	if (mp->hw->max_rates >= 2) {
  		/*
  		 * At least 2 tx rates supported, use max_prob_rate next */
  		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
904
  	}
918fe04b2   Felix Fietkau   mac80211: minstre...
905
  	mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi);
a85666627   Felix Fietkau   mac80211/minstrel...
906
907
  	rates->rate[i].idx = -1;
  	rate_control_set_rates(mp->hw, mi->sta, rates);
ec8aa669b   Felix Fietkau   mac80211: add the...
908
909
910
911
912
913
914
915
916
917
918
919
  }
  
  static inline int
  minstrel_get_duration(int index)
  {
  	const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
  	return group->duration[index % MCS_GROUP_RATES];
  }
  
  static int
  minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
  {
9134073bc   Thomas Huehn   mac80211: improve...
920
  	struct minstrel_rate_stats *mrs;
ec8aa669b   Felix Fietkau   mac80211: add the...
921
  	struct minstrel_mcs_group_data *mg;
5935839ad   Thomas Huehn   mac80211: improve...
922
  	unsigned int sample_dur, sample_group, cur_max_tp_streams;
06171e9c0   Felix Fietkau   mac80211: minstre...
923
  	int tp_rate1, tp_rate2;
ec8aa669b   Felix Fietkau   mac80211: add the...
924
925
926
927
928
929
930
931
932
  	int sample_idx = 0;
  
  	if (mi->sample_wait > 0) {
  		mi->sample_wait--;
  		return -1;
  	}
  
  	if (!mi->sample_tries)
  		return -1;
f12140c04   Karl Beldan   mac80211: minstre...
933
934
  	sample_group = mi->sample_group;
  	mg = &mi->groups[sample_group];
ec8aa669b   Felix Fietkau   mac80211: add the...
935
  	sample_idx = sample_table[mg->column][mg->index];
9134073bc   Thomas Huehn   mac80211: improve...
936
  	minstrel_set_next_sample_idx(mi);
f12140c04   Karl Beldan   mac80211: minstre...
937

41d085835   Felix Fietkau   mac80211: minstre...
938
  	if (!(mi->supported[sample_group] & BIT(sample_idx)))
f12140c04   Karl Beldan   mac80211: minstre...
939
  		return -1;
9134073bc   Thomas Huehn   mac80211: improve...
940
  	mrs = &mg->rates[sample_idx];
965237ab9   Felix Fietkau   mac80211/minstrel...
941
  	sample_idx += sample_group * MCS_GROUP_RATES;
ec8aa669b   Felix Fietkau   mac80211: add the...
942

06171e9c0   Felix Fietkau   mac80211: minstre...
943
944
945
946
947
948
949
950
951
  	/* Set tp_rate1, tp_rate2 to the highest / second highest max_tp_rate */
  	if (minstrel_get_duration(mi->max_tp_rate[0]) >
  	    minstrel_get_duration(mi->max_tp_rate[1])) {
  		tp_rate1 = mi->max_tp_rate[1];
  		tp_rate2 = mi->max_tp_rate[0];
  	} else {
  		tp_rate1 = mi->max_tp_rate[0];
  		tp_rate2 = mi->max_tp_rate[1];
  	}
ec8aa669b   Felix Fietkau   mac80211: add the...
952
  	/*
ba6fa29c6   Helmut Schaa   mac80211: Don't s...
953
  	 * Sampling might add some overhead (RTS, no aggregation)
06171e9c0   Felix Fietkau   mac80211: minstre...
954
955
  	 * to the frame. Hence, don't use sampling for the highest currently
  	 * used highest throughput or probability rate.
ba6fa29c6   Helmut Schaa   mac80211: Don't s...
956
  	 */
06171e9c0   Felix Fietkau   mac80211: minstre...
957
  	if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate)
ba6fa29c6   Helmut Schaa   mac80211: Don't s...
958
  		return -1;
a0ca796c4   Felix Fietkau   mac80211/minstrel...
959

ba6fa29c6   Helmut Schaa   mac80211: Don't s...
960
  	/*
bc96f2426   Felix Fietkau   mac80211/minstrel...
961
962
  	 * Do not sample if the probability is already higher than 95%
  	 * to avoid wasting airtime.
ec8aa669b   Felix Fietkau   mac80211: add the...
963
  	 */
9134073bc   Thomas Huehn   mac80211: improve...
964
  	if (mrs->prob_ewma > MINSTREL_FRAC(95, 100))
8d5eab5aa   Daniel Halperin   mac80211: update ...
965
  		return -1;
ec8aa669b   Felix Fietkau   mac80211: add the...
966
967
968
969
970
  
  	/*
  	 * Make sure that lower rates get sampled only occasionally,
  	 * if the link is working perfectly.
  	 */
5935839ad   Thomas Huehn   mac80211: improve...
971

06171e9c0   Felix Fietkau   mac80211: minstre...
972
  	cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 /
5935839ad   Thomas Huehn   mac80211: improve...
973
  		MCS_GROUP_RATES].streams;
965237ab9   Felix Fietkau   mac80211/minstrel...
974
  	sample_dur = minstrel_get_duration(sample_idx);
06171e9c0   Felix Fietkau   mac80211: minstre...
975
  	if (sample_dur >= minstrel_get_duration(tp_rate2) &&
5935839ad   Thomas Huehn   mac80211: improve...
976
  	    (cur_max_tp_streams - 1 <
965237ab9   Felix Fietkau   mac80211/minstrel...
977
978
  	     minstrel_mcs_groups[sample_group].streams ||
  	     sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
9134073bc   Thomas Huehn   mac80211: improve...
979
  		if (mrs->sample_skipped < 20)
8d5eab5aa   Daniel Halperin   mac80211: update ...
980
  			return -1;
ec8aa669b   Felix Fietkau   mac80211: add the...
981
982
  
  		if (mi->sample_slow++ > 2)
8d5eab5aa   Daniel Halperin   mac80211: update ...
983
  			return -1;
ec8aa669b   Felix Fietkau   mac80211: add the...
984
  	}
098b8afbf   Felix Fietkau   mac80211/minstrel...
985
  	mi->sample_tries--;
ec8aa669b   Felix Fietkau   mac80211: add the...
986
987
  
  	return sample_idx;
ec8aa669b   Felix Fietkau   mac80211: add the...
988
989
990
991
992
993
  }
  
  static void
  minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
                       struct ieee80211_tx_rate_control *txrc)
  {
a85666627   Felix Fietkau   mac80211/minstrel...
994
  	const struct mcs_group *sample_group;
ec8aa669b   Felix Fietkau   mac80211: add the...
995
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
a85666627   Felix Fietkau   mac80211/minstrel...
996
  	struct ieee80211_tx_rate *rate = &info->status.rates[0];
ec8aa669b   Felix Fietkau   mac80211: add the...
997
998
999
1000
1001
1002
1003
1004
1005
1006
  	struct minstrel_ht_sta_priv *msp = priv_sta;
  	struct minstrel_ht_sta *mi = &msp->ht;
  	struct minstrel_priv *mp = priv;
  	int sample_idx;
  
  	if (rate_control_send_low(sta, priv_sta, txrc))
  		return;
  
  	if (!msp->is_ht)
  		return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
95943425c   Felix Fietkau   mac80211: minstre...
1007
1008
1009
  	if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
  	    mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
  		minstrel_aggr_check(sta, txrc->skb);
ec8aa669b   Felix Fietkau   mac80211: add the...
1010
  	info->flags |= mi->tx_flags;
6de062ced   Helmut Schaa   mac80211: Don't u...
1011

37feb7e2f   Lorenzo Bianconi   mac80211: do not ...
1012
1013
1014
1015
  #ifdef CONFIG_MAC80211_DEBUGFS
  	if (mp->fixed_rate_idx != -1)
  		return;
  #endif
6de062ced   Helmut Schaa   mac80211: Don't u...
1016
1017
  	/* Don't use EAPOL frames for sampling on non-mrr hw */
  	if (mp->hw->max_rates == 1 &&
af61a1651   Johannes Berg   mac80211: add con...
1018
  	    (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
6de062ced   Helmut Schaa   mac80211: Don't u...
1019
1020
1021
  		sample_idx = -1;
  	else
  		sample_idx = minstrel_get_sample_rate(mp, mi);
24f7580e8   Zefir Kurtisi   minstrel_ht: fixe...
1022

ec8aa669b   Felix Fietkau   mac80211: add the...
1023
1024
1025
1026
1027
1028
1029
  	mi->total_packets++;
  
  	/* wraparound */
  	if (mi->total_packets == ~0) {
  		mi->total_packets = 0;
  		mi->sample_packets = 0;
  	}
a85666627   Felix Fietkau   mac80211/minstrel...
1030
1031
1032
1033
1034
1035
  
  	if (sample_idx < 0)
  		return;
  
  	sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
  	info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
1cd158573   Felix Fietkau   mac80211/minstrel...
1036
1037
1038
1039
1040
  	rate->count = 1;
  
  	if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
  		int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
  		rate->idx = mp->cck_rates[idx];
9208247d7   Karl Beldan   mac80211: minstre...
1041
1042
1043
  	} else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) {
  		ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES,
  				       sample_group->streams);
3ec373c42   Karl Beldan   mac80211: minstre...
1044
1045
1046
  	} else {
  		rate->idx = sample_idx % MCS_GROUP_RATES +
  			    (sample_group->streams - 1) * 8;
1cd158573   Felix Fietkau   mac80211/minstrel...
1047
  	}
3ec373c42   Karl Beldan   mac80211: minstre...
1048
  	rate->flags = sample_group->flags;
ec8aa669b   Felix Fietkau   mac80211: add the...
1049
1050
1051
  }
  
  static void
a0497f9f5   Felix Fietkau   mac80211/minstrel...
1052
1053
1054
1055
1056
  minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
  		       struct ieee80211_supported_band *sband,
  		       struct ieee80211_sta *sta)
  {
  	int i;
57fbcce37   Johannes Berg   cfg80211: remove ...
1057
  	if (sband->band != NL80211_BAND_2GHZ)
a0497f9f5   Felix Fietkau   mac80211/minstrel...
1058
  		return;
30686bf7f   Johannes Berg   mac80211: convert...
1059
  	if (!ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES))
2dfca312a   Felix Fietkau   mac80211: add a f...
1060
  		return;
a0497f9f5   Felix Fietkau   mac80211/minstrel...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  	mi->cck_supported = 0;
  	mi->cck_supported_short = 0;
  	for (i = 0; i < 4; i++) {
  		if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
  			continue;
  
  		mi->cck_supported |= BIT(i);
  		if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
  			mi->cck_supported_short |= BIT(i);
  	}
41d085835   Felix Fietkau   mac80211: minstre...
1071
  	mi->supported[MINSTREL_CCK_GROUP] = mi->cck_supported;
a0497f9f5   Felix Fietkau   mac80211/minstrel...
1072
1073
1074
  }
  
  static void
ec8aa669b   Felix Fietkau   mac80211: add the...
1075
  minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1076
  			struct cfg80211_chan_def *chandef,
64f68e5d1   Johannes Berg   mac80211: remove ...
1077
                          struct ieee80211_sta *sta, void *priv_sta)
ec8aa669b   Felix Fietkau   mac80211: add the...
1078
1079
1080
1081
1082
  {
  	struct minstrel_priv *mp = priv;
  	struct minstrel_ht_sta_priv *msp = priv_sta;
  	struct minstrel_ht_sta *mi = &msp->ht;
  	struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
ec8aa669b   Felix Fietkau   mac80211: add the...
1083
  	u16 sta_cap = sta->ht_cap.cap;
9208247d7   Karl Beldan   mac80211: minstre...
1084
  	struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
782dda00a   Felix Fietkau   mac80211: minstre...
1085
  	struct sta_info *sinfo = container_of(sta, struct sta_info, sta);
9208247d7   Karl Beldan   mac80211: minstre...
1086
  	int use_vht;
4dc217df6   Felix Fietkau   mac80211: fix a c...
1087
  	int n_supported = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
1088
1089
1090
1091
1092
  	int ack_dur;
  	int stbc;
  	int i;
  
  	/* fall back to the old minstrel for legacy stations */
4dc217df6   Felix Fietkau   mac80211: fix a c...
1093
1094
  	if (!sta->ht_cap.ht_supported)
  		goto use_legacy;
ec8aa669b   Felix Fietkau   mac80211: add the...
1095

8a0ee4fe1   Karl Beldan   mac80211: minstre...
1096
  	BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB);
ec8aa669b   Felix Fietkau   mac80211: add the...
1097

9208247d7   Karl Beldan   mac80211: minstre...
1098
1099
1100
1101
1102
1103
  #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
  	if (vht_cap->vht_supported)
  		use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0);
  	else
  #endif
  	use_vht = 0;
ec8aa669b   Felix Fietkau   mac80211: add the...
1104
1105
  	msp->is_ht = true;
  	memset(mi, 0, sizeof(*mi));
a85666627   Felix Fietkau   mac80211/minstrel...
1106
1107
  
  	mi->sta = sta;
9134073bc   Thomas Huehn   mac80211: improve...
1108
  	mi->last_stats_update = jiffies;
ec8aa669b   Felix Fietkau   mac80211: add the...
1109

438b61b77   Simon Wunderlich   mac80211: fix tim...
1110
1111
1112
  	ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0);
  	mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0);
  	mi->overhead += ack_dur;
ec8aa669b   Felix Fietkau   mac80211: add the...
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  	mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
  
  	mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
  
  	/* When using MRR, sample more on the first attempt, without delay */
  	if (mp->has_mrr) {
  		mi->sample_count = 16;
  		mi->sample_wait = 0;
  	} else {
  		mi->sample_count = 8;
  		mi->sample_wait = 8;
  	}
  	mi->sample_tries = 4;
9208247d7   Karl Beldan   mac80211: minstre...
1126
1127
1128
1129
1130
  	/* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */
  	if (!use_vht) {
  		stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
  			IEEE80211_HT_CAP_RX_STBC_SHIFT;
  		mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
ec8aa669b   Felix Fietkau   mac80211: add the...
1131

9208247d7   Karl Beldan   mac80211: minstre...
1132
1133
1134
  		if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
  			mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
  	}
ec8aa669b   Felix Fietkau   mac80211: add the...
1135

ec8aa669b   Felix Fietkau   mac80211: add the...
1136
  	for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
3ec373c42   Karl Beldan   mac80211: minstre...
1137
  		u32 gflags = minstrel_mcs_groups[i].flags;
9208247d7   Karl Beldan   mac80211: minstre...
1138
  		int bw, nss;
3ec373c42   Karl Beldan   mac80211: minstre...
1139

41d085835   Felix Fietkau   mac80211: minstre...
1140
  		mi->supported[i] = 0;
a0497f9f5   Felix Fietkau   mac80211/minstrel...
1141
1142
1143
1144
  		if (i == MINSTREL_CCK_GROUP) {
  			minstrel_ht_update_cck(mp, mi, sband, sta);
  			continue;
  		}
3ec373c42   Karl Beldan   mac80211: minstre...
1145
1146
  		if (gflags & IEEE80211_TX_RC_SHORT_GI) {
  			if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
e1a0c6b3a   Johannes Berg   mac80211: stop to...
1147
1148
1149
1150
1151
1152
  				if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
  					continue;
  			} else {
  				if (!(sta_cap & IEEE80211_HT_CAP_SGI_20))
  					continue;
  			}
ec8aa669b   Felix Fietkau   mac80211: add the...
1153
  		}
3ec373c42   Karl Beldan   mac80211: minstre...
1154
  		if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
e1a0c6b3a   Johannes Berg   mac80211: stop to...
1155
  		    sta->bandwidth < IEEE80211_STA_RX_BW_40)
ec8aa669b   Felix Fietkau   mac80211: add the...
1156
  			continue;
9208247d7   Karl Beldan   mac80211: minstre...
1157
  		nss = minstrel_mcs_groups[i].streams;
e9219779f   Helmut Schaa   mac80211: Disable...
1158
  		/* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
9208247d7   Karl Beldan   mac80211: minstre...
1159
1160
1161
1162
1163
1164
  		if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1)
  			continue;
  
  		/* HT rate */
  		if (gflags & IEEE80211_TX_RC_MCS) {
  #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
9ffe90440   Karl Beldan   mac80211: minstre...
1165
  			if (use_vht && minstrel_vht_only)
9208247d7   Karl Beldan   mac80211: minstre...
1166
1167
  				continue;
  #endif
41d085835   Felix Fietkau   mac80211: minstre...
1168
1169
  			mi->supported[i] = mcs->rx_mask[nss - 1];
  			if (mi->supported[i])
9208247d7   Karl Beldan   mac80211: minstre...
1170
1171
1172
1173
1174
1175
1176
1177
  				n_supported++;
  			continue;
  		}
  
  		/* VHT rate */
  		if (!vht_cap->vht_supported ||
  		    WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) ||
  		    WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH))
e9219779f   Helmut Schaa   mac80211: Disable...
1178
  			continue;
9208247d7   Karl Beldan   mac80211: minstre...
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  		if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) {
  			if (sta->bandwidth < IEEE80211_STA_RX_BW_80 ||
  			    ((gflags & IEEE80211_TX_RC_SHORT_GI) &&
  			     !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) {
  				continue;
  			}
  		}
  
  		if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  			bw = BW_40;
  		else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
  			bw = BW_80;
  		else
  			bw = BW_20;
41d085835   Felix Fietkau   mac80211: minstre...
1193
  		mi->supported[i] = minstrel_get_valid_vht_rates(bw, nss,
9208247d7   Karl Beldan   mac80211: minstre...
1194
  				vht_cap->vht_mcs.tx_mcs_map);
4dc217df6   Felix Fietkau   mac80211: fix a c...
1195

41d085835   Felix Fietkau   mac80211: minstre...
1196
  		if (mi->supported[i])
4dc217df6   Felix Fietkau   mac80211: fix a c...
1197
  			n_supported++;
ec8aa669b   Felix Fietkau   mac80211: add the...
1198
  	}
4dc217df6   Felix Fietkau   mac80211: fix a c...
1199
1200
1201
  
  	if (!n_supported)
  		goto use_legacy;
782dda00a   Felix Fietkau   mac80211: minstre...
1202
1203
  	if (test_sta_flag(sinfo, WLAN_STA_SHORT_PREAMBLE))
  		mi->cck_supported_short |= mi->cck_supported_short << 4;
a85666627   Felix Fietkau   mac80211/minstrel...
1204
  	/* create an initial rate table with the lowest supported rates */
a36473621   Karl Beldan   mac80211: minstre...
1205
  	minstrel_ht_update_stats(mp, mi);
a85666627   Felix Fietkau   mac80211/minstrel...
1206
  	minstrel_ht_update_rates(mp, mi);
a36473621   Karl Beldan   mac80211: minstre...
1207

4dc217df6   Felix Fietkau   mac80211: fix a c...
1208
1209
1210
1211
1212
1213
1214
  	return;
  
  use_legacy:
  	msp->is_ht = false;
  	memset(&msp->legacy, 0, sizeof(msp->legacy));
  	msp->legacy.r = msp->ratelist;
  	msp->legacy.sample_table = msp->sample_table;
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1215
1216
  	return mac80211_minstrel.rate_init(priv, sband, chandef, sta,
  					   &msp->legacy);
ec8aa669b   Felix Fietkau   mac80211: add the...
1217
1218
1219
1220
  }
  
  static void
  minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1221
  		      struct cfg80211_chan_def *chandef,
ec8aa669b   Felix Fietkau   mac80211: add the...
1222
1223
                        struct ieee80211_sta *sta, void *priv_sta)
  {
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1224
  	minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta);
ec8aa669b   Felix Fietkau   mac80211: add the...
1225
1226
1227
1228
  }
  
  static void
  minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1229
  			struct cfg80211_chan_def *chandef,
ec8aa669b   Felix Fietkau   mac80211: add the...
1230
                          struct ieee80211_sta *sta, void *priv_sta,
64f68e5d1   Johannes Berg   mac80211: remove ...
1231
                          u32 changed)
ec8aa669b   Felix Fietkau   mac80211: add the...
1232
  {
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
1233
  	minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta);
ec8aa669b   Felix Fietkau   mac80211: add the...
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
  }
  
  static void *
  minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
  {
  	struct ieee80211_supported_band *sband;
  	struct minstrel_ht_sta_priv *msp;
  	struct minstrel_priv *mp = priv;
  	struct ieee80211_hw *hw = mp->hw;
  	int max_rates = 0;
  	int i;
57fbcce37   Johannes Berg   cfg80211: remove ...
1245
  	for (i = 0; i < NUM_NL80211_BANDS; i++) {
ec8aa669b   Felix Fietkau   mac80211: add the...
1246
1247
1248
1249
  		sband = hw->wiphy->bands[i];
  		if (sband && sband->n_bitrates > max_rates)
  			max_rates = sband->n_bitrates;
  	}
472dd35cc   Thomas Huehn   mac80211: correct...
1250
  	msp = kzalloc(sizeof(*msp), gfp);
ec8aa669b   Felix Fietkau   mac80211: add the...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
  	if (!msp)
  		return NULL;
  
  	msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
  	if (!msp->ratelist)
  		goto error;
  
  	msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
  	if (!msp->sample_table)
  		goto error1;
  
  	return msp;
  
  error1:
7e988014c   Dan Carpenter   mac80211: freeing...
1265
  	kfree(msp->ratelist);
ec8aa669b   Felix Fietkau   mac80211: add the...
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  error:
  	kfree(msp);
  	return NULL;
  }
  
  static void
  minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
  {
  	struct minstrel_ht_sta_priv *msp = priv_sta;
  
  	kfree(msp->sample_table);
  	kfree(msp->ratelist);
  	kfree(msp);
  }
  
  static void *
  minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
  {
  	return mac80211_minstrel.alloc(hw, debugfsdir);
  }
  
  static void
  minstrel_ht_free(void *priv)
  {
  	mac80211_minstrel.free(priv);
  }
cca674d47   Antonio Quartulli   mac80211: export ...
1292
1293
1294
1295
  static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
  {
  	struct minstrel_ht_sta_priv *msp = priv_sta;
  	struct minstrel_ht_sta *mi = &msp->ht;
50e55a8ea   Thomas Huehn   mac80211: add max...
1296
  	int i, j, prob, tp_avg;
cca674d47   Antonio Quartulli   mac80211: export ...
1297
1298
1299
  
  	if (!msp->is_ht)
  		return mac80211_minstrel.get_expected_throughput(priv_sta);
5935839ad   Thomas Huehn   mac80211: improve...
1300
1301
  	i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
  	j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
50e55a8ea   Thomas Huehn   mac80211: add max...
1302
  	prob = mi->groups[i].rates[j].prob_ewma;
cca674d47   Antonio Quartulli   mac80211: export ...
1303

6a27b2c40   Thomas Huehn   mac80211: restruc...
1304
  	/* convert tp_avg from pkt per second in kbps */
212c5a5e6   Sven Eckelmann   mac80211: minstre...
1305
1306
  	tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
  	tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024;
6a27b2c40   Thomas Huehn   mac80211: restruc...
1307
1308
  
  	return tp_avg;
cca674d47   Antonio Quartulli   mac80211: export ...
1309
  }
631ad703b   Johannes Berg   mac80211: make ra...
1310
  static const struct rate_control_ops mac80211_minstrel_ht = {
ec8aa669b   Felix Fietkau   mac80211: add the...
1311
  	.name = "minstrel_ht",
18fb84d98   Felix Fietkau   mac80211: make ra...
1312
  	.tx_status_ext = minstrel_ht_tx_status,
ec8aa669b   Felix Fietkau   mac80211: add the...
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  	.get_rate = minstrel_ht_get_rate,
  	.rate_init = minstrel_ht_rate_init,
  	.rate_update = minstrel_ht_rate_update,
  	.alloc_sta = minstrel_ht_alloc_sta,
  	.free_sta = minstrel_ht_free_sta,
  	.alloc = minstrel_ht_alloc,
  	.free = minstrel_ht_free,
  #ifdef CONFIG_MAC80211_DEBUGFS
  	.add_sta_debugfs = minstrel_ht_add_sta_debugfs,
  	.remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
  #endif
cca674d47   Antonio Quartulli   mac80211: export ...
1324
  	.get_expected_throughput = minstrel_ht_get_expected_throughput,
ec8aa669b   Felix Fietkau   mac80211: add the...
1325
  };
f6e1a73b6   Johannes Berg   mac80211: minstre...
1326
  static void __init init_sample_table(void)
ec8aa669b   Felix Fietkau   mac80211: add the...
1327
1328
1329
1330
1331
1332
  {
  	int col, i, new_idx;
  	u8 rnd[MCS_GROUP_RATES];
  
  	memset(sample_table, 0xff, sizeof(sample_table));
  	for (col = 0; col < SAMPLE_COLUMNS; col++) {
f7d8ad81c   Karl Beldan   mac80211: minstre...
1333
  		prandom_bytes(rnd, sizeof(rnd));
ec8aa669b   Felix Fietkau   mac80211: add the...
1334
  		for (i = 0; i < MCS_GROUP_RATES; i++) {
ec8aa669b   Felix Fietkau   mac80211: add the...
1335
  			new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
ec8aa669b   Felix Fietkau   mac80211: add the...
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  			while (sample_table[col][new_idx] != 0xff)
  				new_idx = (new_idx + 1) % MCS_GROUP_RATES;
  
  			sample_table[col][new_idx] = i;
  		}
  	}
  }
  
  int __init
  rc80211_minstrel_ht_init(void)
  {
  	init_sample_table();
  	return ieee80211_rate_control_register(&mac80211_minstrel_ht);
  }
  
  void
  rc80211_minstrel_ht_exit(void)
  {
  	ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
  }