Blame view

net/mac80211/rc80211_minstrel.c 20.9 KB
cccf129f8   Felix Fietkau   mac80211: add the...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  /*
   * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
   *
   * 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.
   *
   * Based on minstrel.c:
   *   Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz>
   *   Sponsored by Indranet Technologies Ltd
   *
   * Based on sample.c:
   *   Copyright (c) 2005 John Bicket
   *   All rights reserved.
   *
   *   Redistribution and use in source and binary forms, with or without
   *   modification, are permitted provided that the following conditions
   *   are met:
   *   1. Redistributions of source code must retain the above copyright
   *      notice, this list of conditions and the following disclaimer,
   *      without modification.
   *   2. Redistributions in binary form must reproduce at minimum a disclaimer
   *      similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   *      redistribution must be conditioned upon including a substantially
   *      similar Disclaimer requirement for further binary redistribution.
   *   3. Neither the names of the above-listed copyright holders nor the names
   *      of any contributors may be used to endorse or promote products derived
   *      from this software without specific prior written permission.
   *
   *   Alternatively, this software may be distributed under the terms of the
   *   GNU General Public License ("GPL") version 2 as published by the Free
   *   Software Foundation.
   *
   *   NO WARRANTY
   *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   *   LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   *   THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   *   OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   *   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   *   THE POSSIBILITY OF SUCH DAMAGES.
   */
  #include <linux/netdevice.h>
  #include <linux/types.h>
  #include <linux/skbuff.h>
  #include <linux/debugfs.h>
  #include <linux/random.h>
  #include <linux/ieee80211.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
53
  #include <linux/slab.h>
cccf129f8   Felix Fietkau   mac80211: add the...
54
55
56
  #include <net/mac80211.h>
  #include "rate.h"
  #include "rc80211_minstrel.h"
cccf129f8   Felix Fietkau   mac80211: add the...
57
58
59
60
61
62
63
64
65
66
67
  #define SAMPLE_TBL(_mi, _idx, _col) \
  		_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
  
  /* convert mac80211 rate index to local array index */
  static inline int
  rix_to_ndx(struct minstrel_sta_info *mi, int rix)
  {
  	int i = rix;
  	for (i = rix; i >= 0; i--)
  		if (mi->r[i].rix == rix)
  			break;
cccf129f8   Felix Fietkau   mac80211: add the...
68
69
  	return i;
  }
6a27b2c40   Thomas Huehn   mac80211: restruc...
70
  /* return current EMWA throughput */
50e55a8ea   Thomas Huehn   mac80211: add max...
71
  int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
6a27b2c40   Thomas Huehn   mac80211: restruc...
72
73
74
75
76
77
78
79
80
81
  {
  	int usecs;
  
  	usecs = mr->perfect_tx_time;
  	if (!usecs)
  		usecs = 1000000;
  
  	/* reset thr. below 10% success */
  	if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
  		return 0;
50e55a8ea   Thomas Huehn   mac80211: add max...
82
83
84
  
  	if (prob_ewma > MINSTREL_FRAC(90, 100))
  		return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
6a27b2c40   Thomas Huehn   mac80211: restruc...
85
  	else
50e55a8ea   Thomas Huehn   mac80211: add max...
86
  		return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
6a27b2c40   Thomas Huehn   mac80211: restruc...
87
  }
2ff2b690c   Thomas Huehn   mac80211: improve...
88
89
90
91
  /* find & sort topmost throughput rates */
  static inline void
  minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
  {
f5eeb5fa1   Adrien Schildknecht   mac80211: fix inv...
92
93
  	int j;
  	struct minstrel_rate_stats *tmp_mrs;
50e55a8ea   Thomas Huehn   mac80211: add max...
94
  	struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
2ff2b690c   Thomas Huehn   mac80211: improve...
95

f5eeb5fa1   Adrien Schildknecht   mac80211: fix inv...
96
  	for (j = MAX_THR_RATES; j > 0; --j) {
50e55a8ea   Thomas Huehn   mac80211: add max...
97
  		tmp_mrs = &mi->r[tp_list[j - 1]].stats;
f5eeb5fa1   Adrien Schildknecht   mac80211: fix inv...
98
99
100
  		if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
  		    minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
  			break;
50e55a8ea   Thomas Huehn   mac80211: add max...
101
  	}
6a27b2c40   Thomas Huehn   mac80211: restruc...
102

2ff2b690c   Thomas Huehn   mac80211: improve...
103
104
105
106
107
  	if (j < MAX_THR_RATES - 1)
  		memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
  	if (j < MAX_THR_RATES)
  		tp_list[j] = i;
  }
cccf129f8   Felix Fietkau   mac80211: add the...
108
  static void
06d961a8e   Felix Fietkau   mac80211/minstrel...
109
110
111
112
113
114
115
116
  minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *ratetbl,
  		  int offset, int idx)
  {
  	struct minstrel_rate *r = &mi->r[idx];
  
  	ratetbl->rate[offset].idx = r->rix;
  	ratetbl->rate[offset].count = r->adjusted_retry_count;
  	ratetbl->rate[offset].count_cts = r->retry_count_cts;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
117
  	ratetbl->rate[offset].count_rts = r->stats.retry_count_rtscts;
06d961a8e   Felix Fietkau   mac80211/minstrel...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  }
  
  static void
  minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
  {
  	struct ieee80211_sta_rates *ratetbl;
  	int i = 0;
  
  	ratetbl = kzalloc(sizeof(*ratetbl), GFP_ATOMIC);
  	if (!ratetbl)
  		return;
  
  	/* Start with max_tp_rate */
  	minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[0]);
  
  	if (mp->hw->max_rates >= 3) {
  		/* At least 3 tx rates supported, use max_tp_rate2 next */
  		minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[1]);
  	}
  
  	if (mp->hw->max_rates >= 2) {
  		/* At least 2 tx rates supported, use max_prob_rate next */
  		minstrel_set_rate(mi, ratetbl, i++, mi->max_prob_rate);
  	}
  
  	/* Use lowest rate last */
  	ratetbl->rate[i].idx = mi->lowest_rix;
  	ratetbl->rate[i].count = mp->max_retry;
  	ratetbl->rate[i].count_cts = mp->max_retry;
  	ratetbl->rate[i].count_rts = mp->max_retry;
  
  	rate_control_set_rates(mp->hw, mi->sta, ratetbl);
  }
f62838bcc   Thomas Huehn   mac80211: unify M...
151
  /*
5f919abc7   Thomas Huehn   mac80211: add sta...
152
  * Recalculate statistics and counters of a given rate
f62838bcc   Thomas Huehn   mac80211: unify M...
153
154
155
156
  */
  void
  minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
  {
1109dc392   Felix Fietkau   mac80211: minstre...
157
  	unsigned int cur_prob;
f62838bcc   Thomas Huehn   mac80211: unify M...
158
159
  	if (unlikely(mrs->attempts > 0)) {
  		mrs->sample_skipped = 0;
1109dc392   Felix Fietkau   mac80211: minstre...
160
  		cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
5f919abc7   Thomas Huehn   mac80211: add sta...
161
  		if (unlikely(!mrs->att_hist)) {
1109dc392   Felix Fietkau   mac80211: minstre...
162
  			mrs->prob_ewma = cur_prob;
5f919abc7   Thomas Huehn   mac80211: add sta...
163
164
  		} else {
  			/* update exponential weighted moving variance */
4f0bc9c61   Felix Fietkau   mac80211: minstre...
165
166
167
168
  			mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv,
  							cur_prob,
  							mrs->prob_ewma,
  							EWMA_LEVEL);
5f919abc7   Thomas Huehn   mac80211: add sta...
169
170
  
  			/*update exponential weighted moving avarage */
9134073bc   Thomas Huehn   mac80211: improve...
171
  			mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
1109dc392   Felix Fietkau   mac80211: minstre...
172
  						       cur_prob,
5f919abc7   Thomas Huehn   mac80211: add sta...
173
174
  						       EWMA_LEVEL);
  		}
f62838bcc   Thomas Huehn   mac80211: unify M...
175
176
177
178
179
180
181
182
183
184
185
  		mrs->att_hist += mrs->attempts;
  		mrs->succ_hist += mrs->success;
  	} else {
  		mrs->sample_skipped++;
  	}
  
  	mrs->last_success = mrs->success;
  	mrs->last_attempts = mrs->attempts;
  	mrs->success = 0;
  	mrs->attempts = 0;
  }
06d961a8e   Felix Fietkau   mac80211/minstrel...
186
  static void
cccf129f8   Felix Fietkau   mac80211: add the...
187
188
  minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
  {
2ff2b690c   Thomas Huehn   mac80211: improve...
189
190
  	u8 tmp_tp_rate[MAX_THR_RATES];
  	u8 tmp_prob_rate = 0;
6a27b2c40   Thomas Huehn   mac80211: restruc...
191
  	int i, tmp_cur_tp, tmp_prob_tp;
cccf129f8   Felix Fietkau   mac80211: add the...
192

f359d3fe8   Weilong Chen   mac80211: fix che...
193
  	for (i = 0; i < MAX_THR_RATES; i++)
2ff2b690c   Thomas Huehn   mac80211: improve...
194
  	    tmp_tp_rate[i] = 0;
cccf129f8   Felix Fietkau   mac80211: add the...
195
196
  	for (i = 0; i < mi->n_rates; i++) {
  		struct minstrel_rate *mr = &mi->r[i];
ca12c0c83   Thomas Huehn   mac80211: Unify r...
197
  		struct minstrel_rate_stats *mrs = &mi->r[i].stats;
50e55a8ea   Thomas Huehn   mac80211: add max...
198
  		struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
cccf129f8   Felix Fietkau   mac80211: add the...
199

5f919abc7   Thomas Huehn   mac80211: add sta...
200
  		/* Update statistics of success probability per rate */
f62838bcc   Thomas Huehn   mac80211: unify M...
201
  		minstrel_calc_rate_stats(mrs);
cccf129f8   Felix Fietkau   mac80211: add the...
202
203
204
  
  		/* Sample less often below the 10% chance of success.
  		 * Sample less often above the 95% chance of success. */
9134073bc   Thomas Huehn   mac80211: improve...
205
206
  		if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
  		    mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
ca12c0c83   Thomas Huehn   mac80211: Unify r...
207
  			mr->adjusted_retry_count = mrs->retry_count >> 1;
cccf129f8   Felix Fietkau   mac80211: add the...
208
209
  			if (mr->adjusted_retry_count > 2)
  				mr->adjusted_retry_count = 2;
f4a8cd94f   Felix Fietkau   minstrel: improve...
210
  			mr->sample_limit = 4;
cccf129f8   Felix Fietkau   mac80211: add the...
211
  		} else {
f4a8cd94f   Felix Fietkau   minstrel: improve...
212
  			mr->sample_limit = -1;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
213
  			mr->adjusted_retry_count = mrs->retry_count;
cccf129f8   Felix Fietkau   mac80211: add the...
214
215
216
  		}
  		if (!mr->adjusted_retry_count)
  			mr->adjusted_retry_count = 2;
cccf129f8   Felix Fietkau   mac80211: add the...
217

2ff2b690c   Thomas Huehn   mac80211: improve...
218
219
220
221
222
223
224
  		minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate);
  
  		/* To determine the most robust rate (max_prob_rate) used at
  		 * 3rd mmr stage we distinct between two cases:
  		 * (1) if any success probabilitiy >= 95%, out of those rates
  		 * choose the maximum throughput rate as max_prob_rate
  		 * (2) if all success probabilities < 95%, the rate with
d070f9137   Stephen Hemminger   mac80211: fix spe...
225
  		 * highest success probability is chosen as max_prob_rate */
9134073bc   Thomas Huehn   mac80211: improve...
226
  		if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
50e55a8ea   Thomas Huehn   mac80211: add max...
227
228
229
  			tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
  			tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
  							  tmp_mrs->prob_ewma);
6a27b2c40   Thomas Huehn   mac80211: restruc...
230
  			if (tmp_cur_tp >= tmp_prob_tp)
2ff2b690c   Thomas Huehn   mac80211: improve...
231
232
  				tmp_prob_rate = i;
  		} else {
50e55a8ea   Thomas Huehn   mac80211: add max...
233
  			if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
2ff2b690c   Thomas Huehn   mac80211: improve...
234
  				tmp_prob_rate = i;
cccf129f8   Felix Fietkau   mac80211: add the...
235
236
  		}
  	}
2ff2b690c   Thomas Huehn   mac80211: improve...
237
238
239
  	/* Assign the new rate set */
  	memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
  	mi->max_prob_rate = tmp_prob_rate;
8f1576119   Thomas Huehn   mac80211: add doc...
240

45966aeba   Lorenzo Bianconi   mac80211: add fix...
241
242
243
244
245
246
247
248
  #ifdef CONFIG_MAC80211_DEBUGFS
  	/* use fixed index if set */
  	if (mp->fixed_rate_idx != -1) {
  		mi->max_tp_rate[0] = mp->fixed_rate_idx;
  		mi->max_tp_rate[1] = mp->fixed_rate_idx;
  		mi->max_prob_rate = mp->fixed_rate_idx;
  	}
  #endif
8f1576119   Thomas Huehn   mac80211: add doc...
249
  	/* Reset update timer */
9134073bc   Thomas Huehn   mac80211: improve...
250
  	mi->last_stats_update = jiffies;
06d961a8e   Felix Fietkau   mac80211/minstrel...
251
252
  
  	minstrel_update_rates(mp, mi);
cccf129f8   Felix Fietkau   mac80211: add the...
253
254
255
256
  }
  
  static void
  minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
18fb84d98   Felix Fietkau   mac80211: make ra...
257
  		   void *priv_sta, struct ieee80211_tx_status *st)
cccf129f8   Felix Fietkau   mac80211: add the...
258
  {
18fb84d98   Felix Fietkau   mac80211: make ra...
259
  	struct ieee80211_tx_info *info = st->info;
8acbcddb5   Johannes Berg   minstrel: update ...
260
  	struct minstrel_priv *mp = priv;
cccf129f8   Felix Fietkau   mac80211: add the...
261
  	struct minstrel_sta_info *mi = priv_sta;
e6a9854b0   Johannes Berg   mac80211/drivers:...
262
263
264
  	struct ieee80211_tx_rate *ar = info->status.rates;
  	int i, ndx;
  	int success;
cccf129f8   Felix Fietkau   mac80211: add the...
265

e6a9854b0   Johannes Berg   mac80211/drivers:...
266
  	success = !!(info->flags & IEEE80211_TX_STAT_ACK);
cccf129f8   Felix Fietkau   mac80211: add the...
267

e6a9854b0   Johannes Berg   mac80211/drivers:...
268
269
  	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
  		if (ar[i].idx < 0)
cccf129f8   Felix Fietkau   mac80211: add the...
270
  			break;
e6a9854b0   Johannes Berg   mac80211/drivers:...
271
  		ndx = rix_to_ndx(mi, ar[i].idx);
3938b45c1   Luciano Coelho   mac80211: minstre...
272
273
  		if (ndx < 0)
  			continue;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
274
  		mi->r[ndx].stats.attempts += ar[i].count;
cccf129f8   Felix Fietkau   mac80211: add the...
275

bfc32e6a9   Javier Cardona   mac80211: Decoupl...
276
  		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
ca12c0c83   Thomas Huehn   mac80211: Unify r...
277
  			mi->r[ndx].stats.success += success;
cccf129f8   Felix Fietkau   mac80211: add the...
278
279
280
  	}
  
  	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
ca12c0c83   Thomas Huehn   mac80211: Unify r...
281
  		mi->sample_packets++;
cccf129f8   Felix Fietkau   mac80211: add the...
282
283
284
  
  	if (mi->sample_deferred > 0)
  		mi->sample_deferred--;
8acbcddb5   Johannes Berg   minstrel: update ...
285

9134073bc   Thomas Huehn   mac80211: improve...
286
  	if (time_after(jiffies, mi->last_stats_update +
8acbcddb5   Johannes Berg   minstrel: update ...
287
288
  				(mp->update_interval * HZ) / 1000))
  		minstrel_update_stats(mp, mi);
cccf129f8   Felix Fietkau   mac80211: add the...
289
290
291
292
293
  }
  
  
  static inline unsigned int
  minstrel_get_retry_count(struct minstrel_rate *mr,
f359d3fe8   Weilong Chen   mac80211: fix che...
294
  			 struct ieee80211_tx_info *info)
cccf129f8   Felix Fietkau   mac80211: add the...
295
  {
8d819a92c   Felix Fietkau   mac80211: minstre...
296
  	u8 retry = mr->adjusted_retry_count;
cccf129f8   Felix Fietkau   mac80211: add the...
297

991fec091   Felix Fietkau   mac80211: fix CTS...
298
  	if (info->control.use_rts)
8d819a92c   Felix Fietkau   mac80211: minstre...
299
  		retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry));
991fec091   Felix Fietkau   mac80211: fix CTS...
300
  	else if (info->control.use_cts_prot)
8d819a92c   Felix Fietkau   mac80211: minstre...
301
  		retry = max_t(u8, 2, min(mr->retry_count_cts, retry));
cccf129f8   Felix Fietkau   mac80211: add the...
302
303
304
305
306
307
308
309
  	return retry;
  }
  
  
  static int
  minstrel_get_next_sample(struct minstrel_sta_info *mi)
  {
  	unsigned int sample_ndx;
8f1576119   Thomas Huehn   mac80211: add doc...
310
311
  	sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column);
  	mi->sample_row++;
f744bf81f   Thomas Huehn   mac80211: add low...
312
  	if ((int) mi->sample_row >= mi->n_rates) {
8f1576119   Thomas Huehn   mac80211: add doc...
313
  		mi->sample_row = 0;
cccf129f8   Felix Fietkau   mac80211: add the...
314
315
316
317
318
319
  		mi->sample_column++;
  		if (mi->sample_column >= SAMPLE_COLUMNS)
  			mi->sample_column = 0;
  	}
  	return sample_ndx;
  }
2df78167a   Johannes Berg   wireless: fix a f...
320
  static void
e6a9854b0   Johannes Berg   mac80211/drivers:...
321
322
  minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
  		  void *priv_sta, struct ieee80211_tx_rate_control *txrc)
cccf129f8   Felix Fietkau   mac80211: add the...
323
  {
e6a9854b0   Johannes Berg   mac80211/drivers:...
324
  	struct sk_buff *skb = txrc->skb;
cccf129f8   Felix Fietkau   mac80211: add the...
325
326
327
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  	struct minstrel_sta_info *mi = priv_sta;
  	struct minstrel_priv *mp = priv;
06d961a8e   Felix Fietkau   mac80211/minstrel...
328
329
330
  	struct ieee80211_tx_rate *rate = &info->control.rates[0];
  	struct minstrel_rate *msr, *mr;
  	unsigned int ndx;
8f1576119   Thomas Huehn   mac80211: add doc...
331
  	bool mrr_capable;
5c9fc93bc   Felix Fietkau   mac80211/minstrel...
332
  	bool prev_sample;
06d961a8e   Felix Fietkau   mac80211/minstrel...
333
  	int delta;
8f1576119   Thomas Huehn   mac80211: add doc...
334
  	int sampling_ratio;
cccf129f8   Felix Fietkau   mac80211: add the...
335

8f1576119   Thomas Huehn   mac80211: add doc...
336
  	/* management/no-ack frames do not use rate control */
4c6d4f5c3   Luis R. Rodriguez   mac80211: add hel...
337
  	if (rate_control_send_low(sta, priv_sta, txrc))
cccf129f8   Felix Fietkau   mac80211: add the...
338
  		return;
cccf129f8   Felix Fietkau   mac80211: add the...
339

8f1576119   Thomas Huehn   mac80211: add doc...
340
341
342
343
344
345
346
347
  	/* check multi-rate-retry capabilities & adjust lookaround_rate */
  	mrr_capable = mp->has_mrr &&
  		      !txrc->rts &&
  		      !txrc->bss_conf->use_cts_prot;
  	if (mrr_capable)
  		sampling_ratio = mp->lookaround_rate_mrr;
  	else
  		sampling_ratio = mp->lookaround_rate;
cccf129f8   Felix Fietkau   mac80211: add the...
348

8f1576119   Thomas Huehn   mac80211: add doc...
349
  	/* increase sum packet counter */
ca12c0c83   Thomas Huehn   mac80211: Unify r...
350
  	mi->total_packets++;
8f1576119   Thomas Huehn   mac80211: add doc...
351

45966aeba   Lorenzo Bianconi   mac80211: add fix...
352
353
354
355
  #ifdef CONFIG_MAC80211_DEBUGFS
  	if (mp->fixed_rate_idx != -1)
  		return;
  #endif
38252e9ef   Thomas Huehn   mac80211: minstre...
356
357
358
359
  	/* Don't use EAPOL frames for sampling on non-mrr hw */
  	if (mp->hw->max_rates == 1 &&
  	    (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
  		return;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
360
361
  	delta = (mi->total_packets * sampling_ratio / 100) -
  			(mi->sample_packets + mi->sample_deferred / 2);
cccf129f8   Felix Fietkau   mac80211: add the...
362

06d961a8e   Felix Fietkau   mac80211/minstrel...
363
  	/* delta < 0: no sampling required */
5c9fc93bc   Felix Fietkau   mac80211/minstrel...
364
  	prev_sample = mi->prev_sample;
06d961a8e   Felix Fietkau   mac80211/minstrel...
365
366
367
  	mi->prev_sample = false;
  	if (delta < 0 || (!mrr_capable && prev_sample))
  		return;
cccf129f8   Felix Fietkau   mac80211: add the...
368

ca12c0c83   Thomas Huehn   mac80211: Unify r...
369
  	if (mi->total_packets >= 10000) {
06d961a8e   Felix Fietkau   mac80211/minstrel...
370
  		mi->sample_deferred = 0;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
371
372
  		mi->sample_packets = 0;
  		mi->total_packets = 0;
06d961a8e   Felix Fietkau   mac80211/minstrel...
373
374
375
376
377
378
379
380
381
382
  	} else if (delta > mi->n_rates * 2) {
  		/* With multi-rate retry, not every planned sample
  		 * attempt actually gets used, due to the way the retry
  		 * chain is set up - [max_tp,sample,prob,lowest] for
  		 * sample_rate < max_tp.
  		 *
  		 * If there's too much sampling backlog and the link
  		 * starts getting worse, minstrel would start bursting
  		 * out lots of sampling frames, which would result
  		 * in a large throughput loss. */
ca12c0c83   Thomas Huehn   mac80211: Unify r...
383
  		mi->sample_packets += (delta - mi->n_rates * 2);
06d961a8e   Felix Fietkau   mac80211/minstrel...
384
385
386
387
388
389
390
391
392
393
394
395
396
  	}
  
  	/* get next random rate sample */
  	ndx = minstrel_get_next_sample(mi);
  	msr = &mi->r[ndx];
  	mr = &mi->r[mi->max_tp_rate[0]];
  
  	/* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
  	 * rate sampling method should be used.
  	 * Respect such rates that are not sampled for 20 interations.
  	 */
  	if (mrr_capable &&
  	    msr->perfect_tx_time > mr->perfect_tx_time &&
ca12c0c83   Thomas Huehn   mac80211: Unify r...
397
  	    msr->stats.sample_skipped < 20) {
06d961a8e   Felix Fietkau   mac80211/minstrel...
398
399
400
401
402
403
404
405
406
407
  		/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
  		 * packets that have the sampling rate deferred to the
  		 * second MRR stage. Increase the sample counter only
  		 * if the deferred sample rate was actually used.
  		 * Use the sample_deferred counter to make sure that
  		 * the sampling is not done in large bursts */
  		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
  		rate++;
  		mi->sample_deferred++;
  	} else {
17dce1580   Jiri Slaby   mac80211/minstrel...
408
  		if (!msr->sample_limit)
06d961a8e   Felix Fietkau   mac80211/minstrel...
409
  			return;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
410
  		mi->sample_packets++;
06d961a8e   Felix Fietkau   mac80211/minstrel...
411
412
  		if (msr->sample_limit > 0)
  			msr->sample_limit--;
cccf129f8   Felix Fietkau   mac80211: add the...
413
  	}
f4a8cd94f   Felix Fietkau   minstrel: improve...
414
415
416
417
  
  	/* If we're not using MRR and the sampling rate already
  	 * has a probability of >95%, we shouldn't be attempting
  	 * to use it, as this only wastes precious airtime */
06d961a8e   Felix Fietkau   mac80211/minstrel...
418
  	if (!mrr_capable &&
9134073bc   Thomas Huehn   mac80211: improve...
419
  	   (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100)))
cccf129f8   Felix Fietkau   mac80211: add the...
420
  		return;
cccf129f8   Felix Fietkau   mac80211: add the...
421

06d961a8e   Felix Fietkau   mac80211/minstrel...
422
  	mi->prev_sample = true;
8f1576119   Thomas Huehn   mac80211: add doc...
423

06d961a8e   Felix Fietkau   mac80211/minstrel...
424
425
  	rate->idx = mi->r[ndx].rix;
  	rate->count = minstrel_get_retry_count(&mi->r[ndx], info);
cccf129f8   Felix Fietkau   mac80211: add the...
426
427
428
429
  }
  
  
  static void
57fbcce37   Johannes Berg   cfg80211: remove ...
430
  calc_rate_durations(enum nl80211_band band,
4ee73f338   Michal Kazior   mac80211: remove ...
431
  		    struct minstrel_rate *d,
438b61b77   Simon Wunderlich   mac80211: fix tim...
432
433
  		    struct ieee80211_rate *rate,
  		    struct cfg80211_chan_def *chandef)
cccf129f8   Felix Fietkau   mac80211: add the...
434
435
  {
  	int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
438b61b77   Simon Wunderlich   mac80211: fix tim...
436
  	int shift = ieee80211_chandef_get_shift(chandef);
cccf129f8   Felix Fietkau   mac80211: add the...
437

4ee73f338   Michal Kazior   mac80211: remove ...
438
  	d->perfect_tx_time = ieee80211_frame_duration(band, 1200,
438b61b77   Simon Wunderlich   mac80211: fix tim...
439
440
  			DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1,
  			shift);
4ee73f338   Michal Kazior   mac80211: remove ...
441
  	d->ack_time = ieee80211_frame_duration(band, 10,
438b61b77   Simon Wunderlich   mac80211: fix tim...
442
443
  			DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1,
  			shift);
cccf129f8   Felix Fietkau   mac80211: add the...
444
445
446
447
448
449
  }
  
  static void
  init_sample_table(struct minstrel_sta_info *mi)
  {
  	unsigned int i, col, new_idx;
cccf129f8   Felix Fietkau   mac80211: add the...
450
451
452
  	u8 rnd[8];
  
  	mi->sample_column = 0;
8f1576119   Thomas Huehn   mac80211: add doc...
453
  	mi->sample_row = 0;
f744bf81f   Thomas Huehn   mac80211: add low...
454
  	memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
cccf129f8   Felix Fietkau   mac80211: add the...
455
456
  
  	for (col = 0; col < SAMPLE_COLUMNS; col++) {
f7d8ad81c   Karl Beldan   mac80211: minstre...
457
  		prandom_bytes(rnd, sizeof(rnd));
f744bf81f   Thomas Huehn   mac80211: add low...
458
  		for (i = 0; i < mi->n_rates; i++) {
f744bf81f   Thomas Huehn   mac80211: add low...
459
  			new_idx = (i + rnd[i & 7]) % mi->n_rates;
f744bf81f   Thomas Huehn   mac80211: add low...
460
461
  			while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
  				new_idx = (new_idx + 1) % mi->n_rates;
cccf129f8   Felix Fietkau   mac80211: add the...
462

f744bf81f   Thomas Huehn   mac80211: add low...
463
  			SAMPLE_TBL(mi, new_idx, col) = i;
cccf129f8   Felix Fietkau   mac80211: add the...
464
465
466
467
468
469
  		}
  	}
  }
  
  static void
  minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
3de805cf9   Simon Wunderlich   mac80211/rc80211:...
470
471
  		   struct cfg80211_chan_def *chandef,
  		   struct ieee80211_sta *sta, void *priv_sta)
cccf129f8   Felix Fietkau   mac80211: add the...
472
473
474
  {
  	struct minstrel_sta_info *mi = priv_sta;
  	struct minstrel_priv *mp = priv;
d57854bb1   Christian Lamparter   minstrel: fix war...
475
  	struct ieee80211_rate *ctl_rate;
cccf129f8   Felix Fietkau   mac80211: add the...
476
477
  	unsigned int i, n = 0;
  	unsigned int t_slot = 9; /* FIXME: get real slot time */
438b61b77   Simon Wunderlich   mac80211: fix tim...
478
  	u32 rate_flags;
cccf129f8   Felix Fietkau   mac80211: add the...
479

06d961a8e   Felix Fietkau   mac80211/minstrel...
480
  	mi->sta = sta;
cccf129f8   Felix Fietkau   mac80211: add the...
481
  	mi->lowest_rix = rate_lowest_index(sband, sta);
d57854bb1   Christian Lamparter   minstrel: fix war...
482
  	ctl_rate = &sband->bitrates[mi->lowest_rix];
4ee73f338   Michal Kazior   mac80211: remove ...
483
484
  	mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10,
  				ctl_rate->bitrate,
438b61b77   Simon Wunderlich   mac80211: fix tim...
485
486
  				!!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1,
  				ieee80211_chandef_get_shift(chandef));
cccf129f8   Felix Fietkau   mac80211: add the...
487

438b61b77   Simon Wunderlich   mac80211: fix tim...
488
  	rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
06d961a8e   Felix Fietkau   mac80211/minstrel...
489
490
  	memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate));
  	mi->max_prob_rate = 0;
cccf129f8   Felix Fietkau   mac80211: add the...
491
492
  	for (i = 0; i < sband->n_bitrates; i++) {
  		struct minstrel_rate *mr = &mi->r[n];
ca12c0c83   Thomas Huehn   mac80211: Unify r...
493
  		struct minstrel_rate_stats *mrs = &mi->r[n].stats;
cccf129f8   Felix Fietkau   mac80211: add the...
494
495
496
  		unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
  		unsigned int tx_time_single;
  		unsigned int cw = mp->cw_min;
438b61b77   Simon Wunderlich   mac80211: fix tim...
497
  		int shift;
cccf129f8   Felix Fietkau   mac80211: add the...
498
499
500
  
  		if (!rate_supported(sta, sband->band, i))
  			continue;
438b61b77   Simon Wunderlich   mac80211: fix tim...
501
502
  		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
  			continue;
cccf129f8   Felix Fietkau   mac80211: add the...
503
504
  		n++;
  		memset(mr, 0, sizeof(*mr));
ca12c0c83   Thomas Huehn   mac80211: Unify r...
505
  		memset(mrs, 0, sizeof(*mrs));
cccf129f8   Felix Fietkau   mac80211: add the...
506
507
  
  		mr->rix = i;
438b61b77   Simon Wunderlich   mac80211: fix tim...
508
509
510
511
512
  		shift = ieee80211_chandef_get_shift(chandef);
  		mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
  					   (1 << shift) * 5);
  		calc_rate_durations(sband->band, mr, &sband->bitrates[i],
  				    chandef);
cccf129f8   Felix Fietkau   mac80211: add the...
513
514
515
  
  		/* calculate maximum number of retransmissions before
  		 * fallback (based on maximum segment size) */
f4a8cd94f   Felix Fietkau   minstrel: improve...
516
  		mr->sample_limit = -1;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
517
  		mrs->retry_count = 1;
cccf129f8   Felix Fietkau   mac80211: add the...
518
  		mr->retry_count_cts = 1;
ca12c0c83   Thomas Huehn   mac80211: Unify r...
519
  		mrs->retry_count_rtscts = 1;
cccf129f8   Felix Fietkau   mac80211: add the...
520
521
522
523
524
525
  		tx_time = mr->perfect_tx_time + mi->sp_ack_dur;
  		do {
  			/* add one retransmission */
  			tx_time_single = mr->ack_time + mr->perfect_tx_time;
  
  			/* contention window */
8fddddff0   Daniel Halperin   mac80211: fix con...
526
527
  			tx_time_single += (t_slot * cw) >> 1;
  			cw = min((cw << 1) | 1, mp->cw_max);
cccf129f8   Felix Fietkau   mac80211: add the...
528
529
530
531
532
533
534
535
  
  			tx_time += tx_time_single;
  			tx_time_cts += tx_time_single + mi->sp_ack_dur;
  			tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur;
  			if ((tx_time_cts < mp->segment_size) &&
  				(mr->retry_count_cts < mp->max_retry))
  				mr->retry_count_cts++;
  			if ((tx_time_rtscts < mp->segment_size) &&
ca12c0c83   Thomas Huehn   mac80211: Unify r...
536
537
  				(mrs->retry_count_rtscts < mp->max_retry))
  				mrs->retry_count_rtscts++;
cccf129f8   Felix Fietkau   mac80211: add the...
538
  		} while ((tx_time < mp->segment_size) &&
ca12c0c83   Thomas Huehn   mac80211: Unify r...
539
540
  				(++mr->stats.retry_count < mp->max_retry));
  		mr->adjusted_retry_count = mrs->retry_count;
991fec091   Felix Fietkau   mac80211: fix CTS...
541
  		if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G))
ca12c0c83   Thomas Huehn   mac80211: Unify r...
542
  			mr->retry_count_cts = mrs->retry_count;
cccf129f8   Felix Fietkau   mac80211: add the...
543
544
545
546
547
548
549
550
  	}
  
  	for (i = n; i < sband->n_bitrates; i++) {
  		struct minstrel_rate *mr = &mi->r[i];
  		mr->rix = -1;
  	}
  
  	mi->n_rates = n;
9134073bc   Thomas Huehn   mac80211: improve...
551
  	mi->last_stats_update = jiffies;
cccf129f8   Felix Fietkau   mac80211: add the...
552
553
  
  	init_sample_table(mi);
06d961a8e   Felix Fietkau   mac80211/minstrel...
554
  	minstrel_update_rates(mp, mi);
cccf129f8   Felix Fietkau   mac80211: add the...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  }
  
  static void *
  minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
  {
  	struct ieee80211_supported_band *sband;
  	struct minstrel_sta_info *mi;
  	struct minstrel_priv *mp = priv;
  	struct ieee80211_hw *hw = mp->hw;
  	int max_rates = 0;
  	int i;
  
  	mi = kzalloc(sizeof(struct minstrel_sta_info), gfp);
  	if (!mi)
  		return NULL;
57fbcce37   Johannes Berg   cfg80211: remove ...
570
  	for (i = 0; i < NUM_NL80211_BANDS; i++) {
8e5321752   Jiri Slaby   mac80211: minstre...
571
  		sband = hw->wiphy->bands[i];
621ad7c96   John W. Linville   mac80211: avoid N...
572
  		if (sband && sband->n_bitrates > max_rates)
cccf129f8   Felix Fietkau   mac80211: add the...
573
574
575
576
577
578
579
580
581
582
  			max_rates = sband->n_bitrates;
  	}
  
  	mi->r = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
  	if (!mi->r)
  		goto error;
  
  	mi->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
  	if (!mi->sample_table)
  		goto error1;
9134073bc   Thomas Huehn   mac80211: improve...
583
  	mi->last_stats_update = jiffies;
cccf129f8   Felix Fietkau   mac80211: add the...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  	return mi;
  
  error1:
  	kfree(mi->r);
  error:
  	kfree(mi);
  	return NULL;
  }
  
  static void
  minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
  {
  	struct minstrel_sta_info *mi = priv_sta;
  
  	kfree(mi->sample_table);
  	kfree(mi->r);
  	kfree(mi);
  }
a0497f9f5   Felix Fietkau   mac80211/minstrel...
602
603
604
605
606
  static void
  minstrel_init_cck_rates(struct minstrel_priv *mp)
  {
  	static const int bitrates[4] = { 10, 20, 55, 110 };
  	struct ieee80211_supported_band *sband;
438b61b77   Simon Wunderlich   mac80211: fix tim...
607
  	u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
a0497f9f5   Felix Fietkau   mac80211/minstrel...
608
  	int i, j;
57fbcce37   Johannes Berg   cfg80211: remove ...
609
  	sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ];
a0497f9f5   Felix Fietkau   mac80211/minstrel...
610
611
612
613
614
615
616
617
  	if (!sband)
  		return;
  
  	for (i = 0, j = 0; i < sband->n_bitrates; i++) {
  		struct ieee80211_rate *rate = &sband->bitrates[i];
  
  		if (rate->flags & IEEE80211_RATE_ERP_G)
  			continue;
438b61b77   Simon Wunderlich   mac80211: fix tim...
618
619
  		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
  			continue;
a0497f9f5   Felix Fietkau   mac80211/minstrel...
620
621
622
623
624
625
626
627
628
  		for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
  			if (rate->bitrate != bitrates[j])
  				continue;
  
  			mp->cck_rates[j] = i;
  			break;
  		}
  	}
  }
cccf129f8   Felix Fietkau   mac80211: add the...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  static void *
  minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
  {
  	struct minstrel_priv *mp;
  
  	mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC);
  	if (!mp)
  		return NULL;
  
  	/* contention window settings
  	 * Just an approximation. Using the per-queue values would complicate
  	 * the calculations and is probably unnecessary */
  	mp->cw_min = 15;
  	mp->cw_max = 1023;
  
  	/* number of packets (in %) to use for sampling other rates
  	 * sample less often for non-mrr packets, because the overhead
  	 * is much higher than with mrr */
  	mp->lookaround_rate = 5;
  	mp->lookaround_rate_mrr = 10;
cccf129f8   Felix Fietkau   mac80211: add the...
649
650
  	/* maximum time that the hw is allowed to stay in one MRR segment */
  	mp->segment_size = 6000;
e6a9854b0   Johannes Berg   mac80211/drivers:...
651
652
  	if (hw->max_rate_tries > 0)
  		mp->max_retry = hw->max_rate_tries;
cccf129f8   Felix Fietkau   mac80211: add the...
653
654
655
  	else
  		/* safe default, does not necessarily have to match hw properties */
  		mp->max_retry = 7;
e6a9854b0   Johannes Berg   mac80211/drivers:...
656
  	if (hw->max_rates >= 4)
cccf129f8   Felix Fietkau   mac80211: add the...
657
658
659
660
  		mp->has_mrr = true;
  
  	mp->hw = hw;
  	mp->update_interval = 100;
24f7580e8   Zefir Kurtisi   minstrel_ht: fixe...
661
662
663
664
665
  #ifdef CONFIG_MAC80211_DEBUGFS
  	mp->fixed_rate_idx = (u32) -1;
  	mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx",
  			S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx);
  #endif
a0497f9f5   Felix Fietkau   mac80211/minstrel...
666
  	minstrel_init_cck_rates(mp);
cccf129f8   Felix Fietkau   mac80211: add the...
667
668
669
670
671
672
  	return mp;
  }
  
  static void
  minstrel_free(void *priv)
  {
24f7580e8   Zefir Kurtisi   minstrel_ht: fixe...
673
674
675
  #ifdef CONFIG_MAC80211_DEBUGFS
  	debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate);
  #endif
cccf129f8   Felix Fietkau   mac80211: add the...
676
677
  	kfree(priv);
  }
cca674d47   Antonio Quartulli   mac80211: export ...
678
679
680
  static u32 minstrel_get_expected_throughput(void *priv_sta)
  {
  	struct minstrel_sta_info *mi = priv_sta;
50e55a8ea   Thomas Huehn   mac80211: add max...
681
  	struct minstrel_rate_stats *tmp_mrs;
cca674d47   Antonio Quartulli   mac80211: export ...
682
  	int idx = mi->max_tp_rate[0];
6a27b2c40   Thomas Huehn   mac80211: restruc...
683
  	int tmp_cur_tp;
cca674d47   Antonio Quartulli   mac80211: export ...
684
685
686
687
  
  	/* convert pkt per sec in kbps (1200 is the average pkt size used for
  	 * computing cur_tp
  	 */
50e55a8ea   Thomas Huehn   mac80211: add max...
688
  	tmp_mrs = &mi->r[idx].stats;
212c5a5e6   Sven Eckelmann   mac80211: minstre...
689
  	tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
6a27b2c40   Thomas Huehn   mac80211: restruc...
690
691
692
  	tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
  
  	return tmp_cur_tp;
cca674d47   Antonio Quartulli   mac80211: export ...
693
  }
631ad703b   Johannes Berg   mac80211: make ra...
694
  const struct rate_control_ops mac80211_minstrel = {
cccf129f8   Felix Fietkau   mac80211: add the...
695
  	.name = "minstrel",
18fb84d98   Felix Fietkau   mac80211: make ra...
696
  	.tx_status_ext = minstrel_tx_status,
cccf129f8   Felix Fietkau   mac80211: add the...
697
698
  	.get_rate = minstrel_get_rate,
  	.rate_init = minstrel_rate_init,
cccf129f8   Felix Fietkau   mac80211: add the...
699
700
701
702
703
704
705
706
  	.alloc = minstrel_alloc,
  	.free = minstrel_free,
  	.alloc_sta = minstrel_alloc_sta,
  	.free_sta = minstrel_free_sta,
  #ifdef CONFIG_MAC80211_DEBUGFS
  	.add_sta_debugfs = minstrel_add_sta_debugfs,
  	.remove_sta_debugfs = minstrel_remove_sta_debugfs,
  #endif
cca674d47   Antonio Quartulli   mac80211: export ...
707
  	.get_expected_throughput = minstrel_get_expected_throughput,
cccf129f8   Felix Fietkau   mac80211: add the...
708
709
710
711
712
713
714
715
716
717
718
719
720
  };
  
  int __init
  rc80211_minstrel_init(void)
  {
  	return ieee80211_rate_control_register(&mac80211_minstrel);
  }
  
  void
  rc80211_minstrel_exit(void)
  {
  	ieee80211_rate_control_unregister(&mac80211_minstrel);
  }