aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2008-10-05 12:07:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-06 18:14:57 -0400
commitcccf129f820e431d84690729254a32f1709328fb (patch)
tree0539c013be61ba6c8eeb0790ccb7df50bf2cb3bd /net/mac80211
parent2f7fe87034298d94301315ba4bb65c7284c709d0 (diff)
mac80211: add the 'minstrel' rate control algorithm
Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig13
-rw-r--r--net/mac80211/Makefile4
-rw-r--r--net/mac80211/main.c5
-rw-r--r--net/mac80211/rate.h14
-rw-r--r--net/mac80211/rc80211_minstrel.c583
-rw-r--r--net/mac80211/rc80211_minstrel.h85
-rw-r--r--net/mac80211/rc80211_minstrel_debugfs.c164
7 files changed, 868 insertions, 0 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 8427518e4f20..7f710a27e91c 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -22,6 +22,11 @@ config MAC80211_RC_PID
22 mac80211 that uses a PID controller to select the TX 22 mac80211 that uses a PID controller to select the TX
23 rate. 23 rate.
24 24
25config MAC80211_RC_MINSTREL
26 bool "Minstrel"
27 ---help---
28 This option enables the 'minstrel' TX rate control algorithm
29
25choice 30choice
26 prompt "Default rate control algorithm" 31 prompt "Default rate control algorithm"
27 default MAC80211_RC_DEFAULT_PID 32 default MAC80211_RC_DEFAULT_PID
@@ -39,11 +44,19 @@ config MAC80211_RC_DEFAULT_PID
39 default rate control algorithm. You should choose 44 default rate control algorithm. You should choose
40 this unless you know what you are doing. 45 this unless you know what you are doing.
41 46
47config MAC80211_RC_DEFAULT_MINSTREL
48 bool "Minstrel"
49 depends on MAC80211_RC_MINSTREL
50 ---help---
51 Select Minstrel as the default rate control algorithm.
52
53
42endchoice 54endchoice
43 55
44config MAC80211_RC_DEFAULT 56config MAC80211_RC_DEFAULT
45 string 57 string
46 default "pid" if MAC80211_RC_DEFAULT_PID 58 default "pid" if MAC80211_RC_DEFAULT_PID
59 default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
47 default "" 60 default ""
48 61
49endmenu 62endmenu
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 2dc8f2bff27b..31cfd1f89a72 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -41,4 +41,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
41rc80211_pid-y := rc80211_pid_algo.o 41rc80211_pid-y := rc80211_pid_algo.o
42rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o 42rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
43 43
44rc80211_minstrel-y := rc80211_minstrel.o
45rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
46
44mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) 47mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
48mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d608c44047c0..ae62ad40ad63 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1015,6 +1015,10 @@ static int __init ieee80211_init(void)
1015 BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + 1015 BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
1016 IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); 1016 IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
1017 1017
1018 ret = rc80211_minstrel_init();
1019 if (ret)
1020 return ret;
1021
1018 ret = rc80211_pid_init(); 1022 ret = rc80211_pid_init();
1019 if (ret) 1023 if (ret)
1020 return ret; 1024 return ret;
@@ -1027,6 +1031,7 @@ static int __init ieee80211_init(void)
1027static void __exit ieee80211_exit(void) 1031static void __exit ieee80211_exit(void)
1028{ 1032{
1029 rc80211_pid_exit(); 1033 rc80211_pid_exit();
1034 rc80211_minstrel_exit();
1030 1035
1031 /* 1036 /*
1032 * For key todo, it'll be empty by now but the work 1037 * For key todo, it'll be empty by now but the work
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index eb94e584d24e..d0092f847f82 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -125,4 +125,18 @@ static inline void rc80211_pid_exit(void)
125} 125}
126#endif 126#endif
127 127
128#ifdef CONFIG_MAC80211_RC_MINSTREL
129extern int rc80211_minstrel_init(void);
130extern void rc80211_minstrel_exit(void);
131#else
132static inline int rc80211_minstrel_init(void)
133{
134 return 0;
135}
136static inline void rc80211_minstrel_exit(void)
137{
138}
139#endif
140
141
128#endif /* IEEE80211_RATE_H */ 142#endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
new file mode 100644
index 000000000000..f6d69dab07a3
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel.c
@@ -0,0 +1,583 @@
1/*
2 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Based on minstrel.c:
9 * Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz>
10 * Sponsored by Indranet Technologies Ltd
11 *
12 * Based on sample.c:
13 * Copyright (c) 2005 John Bicket
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer,
21 * without modification.
22 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
23 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
24 * redistribution must be conditioned upon including a substantially
25 * similar Disclaimer requirement for further binary redistribution.
26 * 3. Neither the names of the above-listed copyright holders nor the names
27 * of any contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * Alternatively, this software may be distributed under the terms of the
31 * GNU General Public License ("GPL") version 2 as published by the Free
32 * Software Foundation.
33 *
34 * NO WARRANTY
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
38 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
39 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
40 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
43 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGES.
46 */
47#include <linux/netdevice.h>
48#include <linux/types.h>
49#include <linux/skbuff.h>
50#include <linux/debugfs.h>
51#include <linux/random.h>
52#include <linux/ieee80211.h>
53#include <net/mac80211.h>
54#include "rate.h"
55#include "rc80211_minstrel.h"
56
57#define SAMPLE_COLUMNS 10
58#define SAMPLE_TBL(_mi, _idx, _col) \
59 _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
60
61/* convert mac80211 rate index to local array index */
62static inline int
63rix_to_ndx(struct minstrel_sta_info *mi, int rix)
64{
65 int i = rix;
66 for (i = rix; i >= 0; i--)
67 if (mi->r[i].rix == rix)
68 break;
69 WARN_ON(mi->r[i].rix != rix);
70 return i;
71}
72
73static inline bool
74use_low_rate(struct sk_buff *skb)
75{
76 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
77 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
78 u16 fc;
79
80 fc = le16_to_cpu(hdr->frame_control);
81
82 return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
83 (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
84 is_multicast_ether_addr(hdr->addr1));
85}
86
87
88static void
89minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
90{
91 u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
92 u32 max_prob = 0, index_max_prob = 0;
93 u32 usecs;
94 u32 p;
95 int i;
96
97 mi->stats_update = jiffies;
98 for (i = 0; i < mi->n_rates; i++) {
99 struct minstrel_rate *mr = &mi->r[i];
100
101 usecs = mr->perfect_tx_time;
102 if (!usecs)
103 usecs = 1000000;
104
105 /* To avoid rounding issues, probabilities scale from 0 (0%)
106 * to 18000 (100%) */
107 if (mr->attempts) {
108 p = (mr->success * 18000) / mr->attempts;
109 mr->succ_hist += mr->success;
110 mr->att_hist += mr->attempts;
111 mr->cur_prob = p;
112 p = ((p * (100 - mp->ewma_level)) + (mr->probability *
113 mp->ewma_level)) / 100;
114 mr->probability = p;
115 mr->cur_tp = p * (1000000 / usecs);
116 }
117
118 mr->last_success = mr->success;
119 mr->last_attempts = mr->attempts;
120 mr->success = 0;
121 mr->attempts = 0;
122
123 /* Sample less often below the 10% chance of success.
124 * Sample less often above the 95% chance of success. */
125 if ((mr->probability > 17100) || (mr->probability < 1800)) {
126 mr->adjusted_retry_count = mr->retry_count >> 1;
127 if (mr->adjusted_retry_count > 2)
128 mr->adjusted_retry_count = 2;
129 } else {
130 mr->adjusted_retry_count = mr->retry_count;
131 }
132 if (!mr->adjusted_retry_count)
133 mr->adjusted_retry_count = 2;
134 }
135
136 for (i = 0; i < mi->n_rates; i++) {
137 struct minstrel_rate *mr = &mi->r[i];
138 if (max_tp < mr->cur_tp) {
139 index_max_tp = i;
140 max_tp = mr->cur_tp;
141 }
142 if (max_prob < mr->probability) {
143 index_max_prob = i;
144 max_prob = mr->probability;
145 }
146 }
147
148 max_tp = 0;
149 for (i = 0; i < mi->n_rates; i++) {
150 struct minstrel_rate *mr = &mi->r[i];
151
152 if (i == index_max_tp)
153 continue;
154
155 if (max_tp < mr->cur_tp) {
156 index_max_tp2 = i;
157 max_tp = mr->cur_tp;
158 }
159 }
160 mi->max_tp_rate = index_max_tp;
161 mi->max_tp_rate2 = index_max_tp2;
162 mi->max_prob_rate = index_max_prob;
163}
164
165static void
166minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
167 struct ieee80211_sta *sta, void *priv_sta,
168 struct sk_buff *skb)
169{
170 struct minstrel_sta_info *mi = priv_sta;
171 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
172 struct ieee80211_tx_altrate *ar = info->status.retries;
173 struct minstrel_priv *mp = priv;
174 int i, ndx, tries;
175 int success = 0;
176
177 if (!info->status.excessive_retries)
178 success = 1;
179
180 if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
181 ndx = rix_to_ndx(mi, info->tx_rate_idx);
182 tries = info->status.retry_count + 1;
183 mi->r[ndx].success += success;
184 mi->r[ndx].attempts += tries;
185 return;
186 }
187
188 for (i = 0; i < 4; i++) {
189 if (ar[i].rate_idx < 0)
190 break;
191
192 ndx = rix_to_ndx(mi, ar[i].rate_idx);
193 mi->r[ndx].attempts += ar[i].limit + 1;
194
195 if ((i != 3) && (ar[i + 1].rate_idx < 0))
196 mi->r[ndx].success += success;
197 }
198
199 if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
200 mi->sample_count++;
201
202 if (mi->sample_deferred > 0)
203 mi->sample_deferred--;
204}
205
206
207static inline unsigned int
208minstrel_get_retry_count(struct minstrel_rate *mr,
209 struct ieee80211_tx_info *info)
210{
211 unsigned int retry = mr->adjusted_retry_count;
212
213 if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
214 retry = max(2U, min(mr->retry_count_rtscts, retry));
215 else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
216 retry = max(2U, min(mr->retry_count_cts, retry));
217 return retry;
218}
219
220
221static int
222minstrel_get_next_sample(struct minstrel_sta_info *mi)
223{
224 unsigned int sample_ndx;
225 sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
226 mi->sample_idx++;
227 if (mi->sample_idx > (mi->n_rates - 2)) {
228 mi->sample_idx = 0;
229 mi->sample_column++;
230 if (mi->sample_column >= SAMPLE_COLUMNS)
231 mi->sample_column = 0;
232 }
233 return sample_ndx;
234}
235
236void
237minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
238 struct ieee80211_sta *sta, void *priv_sta,
239 struct sk_buff *skb, struct rate_selection *sel)
240{
241 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
242 struct minstrel_sta_info *mi = priv_sta;
243 struct minstrel_priv *mp = priv;
244 struct ieee80211_tx_altrate *ar = info->control.retries;
245 unsigned int ndx, sample_ndx = 0;
246 bool mrr;
247 bool sample_slower = false;
248 bool sample = false;
249 int i, delta;
250 int mrr_ndx[3];
251 int sample_rate;
252
253 if (!sta || !mi || use_low_rate(skb)) {
254 sel->rate_idx = rate_lowest_index(sband, sta);
255 return;
256 }
257
258 mrr = mp->has_mrr;
259
260 /* mac80211 does not allow mrr for RTS/CTS */
261 if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
262 (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
263 mrr = false;
264
265 if (time_after(jiffies, mi->stats_update + (mp->update_interval *
266 HZ) / 1000))
267 minstrel_update_stats(mp, mi);
268
269 ndx = mi->max_tp_rate;
270
271 if (mrr)
272 sample_rate = mp->lookaround_rate_mrr;
273 else
274 sample_rate = mp->lookaround_rate;
275
276 mi->packet_count++;
277 delta = (mi->packet_count * sample_rate / 100) -
278 (mi->sample_count + mi->sample_deferred / 2);
279
280 /* delta > 0: sampling required */
281 if (delta > 0) {
282 if (mi->packet_count >= 10000) {
283 mi->sample_deferred = 0;
284 mi->sample_count = 0;
285 mi->packet_count = 0;
286 } else if (delta > mi->n_rates * 2) {
287 /* With multi-rate retry, not every planned sample
288 * attempt actually gets used, due to the way the retry
289 * chain is set up - [max_tp,sample,prob,lowest] for
290 * sample_rate < max_tp.
291 *
292 * If there's too much sampling backlog and the link
293 * starts getting worse, minstrel would start bursting
294 * out lots of sampling frames, which would result
295 * in a large throughput loss. */
296 mi->sample_count += (delta - mi->n_rates * 2);
297 }
298
299 sample_ndx = minstrel_get_next_sample(mi);
300 sample = true;
301 sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time >
302 mi->r[ndx].perfect_tx_time);
303
304 if (!sample_slower) {
305 ndx = sample_ndx;
306 mi->sample_count++;
307 } else {
308 /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
309 * packets that have the sampling rate deferred to the
310 * second MRR stage. Increase the sample counter only
311 * if the deferred sample rate was actually used.
312 * Use the sample_deferred counter to make sure that
313 * the sampling is not done in large bursts */
314 info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
315 mi->sample_deferred++;
316 }
317 }
318 sel->rate_idx = mi->r[ndx].rix;
319 info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
320
321 if (!mrr) {
322 ar[0].rate_idx = mi->lowest_rix;
323 ar[0].limit = mp->max_retry;
324 ar[1].rate_idx = -1;
325 return;
326 }
327
328 /* MRR setup */
329 if (sample) {
330 if (sample_slower)
331 mrr_ndx[0] = sample_ndx;
332 else
333 mrr_ndx[0] = mi->max_tp_rate;
334 } else {
335 mrr_ndx[0] = mi->max_tp_rate2;
336 }
337 mrr_ndx[1] = mi->max_prob_rate;
338 mrr_ndx[2] = 0;
339 for (i = 0; i < 3; i++) {
340 ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
341 ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
342 }
343}
344
345
346static void
347calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local,
348 struct minstrel_rate *d, struct ieee80211_rate *rate)
349{
350 int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
351
352 d->perfect_tx_time = ieee80211_frame_duration(local, 1200,
353 rate->bitrate, erp, 1);
354 d->ack_time = ieee80211_frame_duration(local, 10,
355 rate->bitrate, erp, 1);
356}
357
358static void
359init_sample_table(struct minstrel_sta_info *mi)
360{
361 unsigned int i, col, new_idx;
362 unsigned int n_srates = mi->n_rates - 1;
363 u8 rnd[8];
364
365 mi->sample_column = 0;
366 mi->sample_idx = 0;
367 memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
368
369 for (col = 0; col < SAMPLE_COLUMNS; col++) {
370 for (i = 0; i < n_srates; i++) {
371 get_random_bytes(rnd, sizeof(rnd));
372 new_idx = (i + rnd[i & 7]) % n_srates;
373
374 while (SAMPLE_TBL(mi, new_idx, col) != 0)
375 new_idx = (new_idx + 1) % n_srates;
376
377 /* Don't sample the slowest rate (i.e. slowest base
378 * rate). We must presume that the slowest rate works
379 * fine, or else other management frames will also be
380 * failing and the link will break */
381 SAMPLE_TBL(mi, new_idx, col) = i + 1;
382 }
383 }
384}
385
386static void
387minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
388 struct ieee80211_sta *sta, void *priv_sta)
389{
390 struct minstrel_sta_info *mi = priv_sta;
391 struct minstrel_priv *mp = priv;
392 struct minstrel_rate *mr_ctl;
393 unsigned int i, n = 0;
394 unsigned int t_slot = 9; /* FIXME: get real slot time */
395
396 mi->lowest_rix = rate_lowest_index(sband, sta);
397 mr_ctl = &mi->r[rix_to_ndx(mi, mi->lowest_rix)];
398 mi->sp_ack_dur = mr_ctl->ack_time;
399
400 for (i = 0; i < sband->n_bitrates; i++) {
401 struct minstrel_rate *mr = &mi->r[n];
402 unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
403 unsigned int tx_time_single;
404 unsigned int cw = mp->cw_min;
405
406 if (!rate_supported(sta, sband->band, i))
407 continue;
408 n++;
409 memset(mr, 0, sizeof(*mr));
410
411 mr->rix = i;
412 mr->bitrate = sband->bitrates[i].bitrate / 5;
413 calc_rate_durations(mi, hw_to_local(mp->hw), mr,
414 &sband->bitrates[i]);
415
416 /* calculate maximum number of retransmissions before
417 * fallback (based on maximum segment size) */
418 mr->retry_count = 1;
419 mr->retry_count_cts = 1;
420 mr->retry_count_rtscts = 1;
421 tx_time = mr->perfect_tx_time + mi->sp_ack_dur;
422 do {
423 /* add one retransmission */
424 tx_time_single = mr->ack_time + mr->perfect_tx_time;
425
426 /* contention window */
427 tx_time_single += t_slot + min(cw, mp->cw_max);
428 cw = (cw + 1) << 1;
429
430 tx_time += tx_time_single;
431 tx_time_cts += tx_time_single + mi->sp_ack_dur;
432 tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur;
433 if ((tx_time_cts < mp->segment_size) &&
434 (mr->retry_count_cts < mp->max_retry))
435 mr->retry_count_cts++;
436 if ((tx_time_rtscts < mp->segment_size) &&
437 (mr->retry_count_rtscts < mp->max_retry))
438 mr->retry_count_rtscts++;
439 } while ((tx_time < mp->segment_size) &&
440 (++mr->retry_count < mp->max_retry));
441 mr->adjusted_retry_count = mr->retry_count;
442 }
443
444 for (i = n; i < sband->n_bitrates; i++) {
445 struct minstrel_rate *mr = &mi->r[i];
446 mr->rix = -1;
447 }
448
449 mi->n_rates = n;
450 mi->stats_update = jiffies;
451
452 init_sample_table(mi);
453}
454
455static void *
456minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
457{
458 struct ieee80211_supported_band *sband;
459 struct minstrel_sta_info *mi;
460 struct minstrel_priv *mp = priv;
461 struct ieee80211_hw *hw = mp->hw;
462 int max_rates = 0;
463 int i;
464
465 mi = kzalloc(sizeof(struct minstrel_sta_info), gfp);
466 if (!mi)
467 return NULL;
468
469 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
470 sband = hw->wiphy->bands[hw->conf.channel->band];
471 if (sband->n_bitrates > max_rates)
472 max_rates = sband->n_bitrates;
473 }
474
475 mi->r = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
476 if (!mi->r)
477 goto error;
478
479 mi->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
480 if (!mi->sample_table)
481 goto error1;
482
483 mi->stats_update = jiffies;
484 return mi;
485
486error1:
487 kfree(mi->r);
488error:
489 kfree(mi);
490 return NULL;
491}
492
493static void
494minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
495{
496 struct minstrel_sta_info *mi = priv_sta;
497
498 kfree(mi->sample_table);
499 kfree(mi->r);
500 kfree(mi);
501}
502
503static void
504minstrel_clear(void *priv)
505{
506}
507
508static void *
509minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
510{
511 struct minstrel_priv *mp;
512
513 mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC);
514 if (!mp)
515 return NULL;
516
517 /* contention window settings
518 * Just an approximation. Using the per-queue values would complicate
519 * the calculations and is probably unnecessary */
520 mp->cw_min = 15;
521 mp->cw_max = 1023;
522
523 /* number of packets (in %) to use for sampling other rates
524 * sample less often for non-mrr packets, because the overhead
525 * is much higher than with mrr */
526 mp->lookaround_rate = 5;
527 mp->lookaround_rate_mrr = 10;
528
529 /* moving average weight for EWMA */
530 mp->ewma_level = 75;
531
532 /* maximum time that the hw is allowed to stay in one MRR segment */
533 mp->segment_size = 6000;
534
535 if (hw->max_altrate_tries > 0)
536 mp->max_retry = hw->max_altrate_tries;
537 else
538 /* safe default, does not necessarily have to match hw properties */
539 mp->max_retry = 7;
540
541 if (hw->max_altrates >= 3)
542 mp->has_mrr = true;
543
544 mp->hw = hw;
545 mp->update_interval = 100;
546
547 return mp;
548}
549
550static void
551minstrel_free(void *priv)
552{
553 kfree(priv);
554}
555
556static struct rate_control_ops mac80211_minstrel = {
557 .name = "minstrel",
558 .tx_status = minstrel_tx_status,
559 .get_rate = minstrel_get_rate,
560 .rate_init = minstrel_rate_init,
561 .clear = minstrel_clear,
562 .alloc = minstrel_alloc,
563 .free = minstrel_free,
564 .alloc_sta = minstrel_alloc_sta,
565 .free_sta = minstrel_free_sta,
566#ifdef CONFIG_MAC80211_DEBUGFS
567 .add_sta_debugfs = minstrel_add_sta_debugfs,
568 .remove_sta_debugfs = minstrel_remove_sta_debugfs,
569#endif
570};
571
572int __init
573rc80211_minstrel_init(void)
574{
575 return ieee80211_rate_control_register(&mac80211_minstrel);
576}
577
578void
579rc80211_minstrel_exit(void)
580{
581 ieee80211_rate_control_unregister(&mac80211_minstrel);
582}
583
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
new file mode 100644
index 000000000000..9a90a6aee043
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel.h
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __RC_MINSTREL_H
10#define __RC_MINSTREL_H
11
12struct minstrel_rate {
13 int bitrate;
14 int rix;
15
16 unsigned int perfect_tx_time;
17 unsigned int ack_time;
18
19 unsigned int retry_count;
20 unsigned int retry_count_cts;
21 unsigned int retry_count_rtscts;
22 unsigned int adjusted_retry_count;
23
24 u32 success;
25 u32 attempts;
26 u32 last_attempts;
27 u32 last_success;
28
29 /* parts per thousand */
30 u32 cur_prob;
31 u32 probability;
32
33 /* per-rate throughput */
34 u32 cur_tp;
35 u32 throughput;
36
37 u64 succ_hist;
38 u64 att_hist;
39};
40
41struct minstrel_sta_info {
42 unsigned long stats_update;
43 unsigned int sp_ack_dur;
44 unsigned int rate_avg;
45
46 unsigned int lowest_rix;
47
48 unsigned int max_tp_rate;
49 unsigned int max_tp_rate2;
50 unsigned int max_prob_rate;
51 unsigned int packet_count;
52 unsigned int sample_count;
53 int sample_deferred;
54
55 unsigned int sample_idx;
56 unsigned int sample_column;
57
58 int n_rates;
59 struct minstrel_rate *r;
60
61 /* sampling table */
62 u8 *sample_table;
63
64#ifdef CONFIG_MAC80211_DEBUGFS
65 struct dentry *dbg_stats;
66#endif
67};
68
69struct minstrel_priv {
70 struct ieee80211_hw *hw;
71 bool has_mrr;
72 unsigned int cw_min;
73 unsigned int cw_max;
74 unsigned int max_retry;
75 unsigned int ewma_level;
76 unsigned int segment_size;
77 unsigned int update_interval;
78 unsigned int lookaround_rate;
79 unsigned int lookaround_rate_mrr;
80};
81
82void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
83void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
84
85#endif
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
new file mode 100644
index 000000000000..0b024cd6b809
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -0,0 +1,164 @@
1/*
2 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Based on minstrel.c:
9 * Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz>
10 * Sponsored by Indranet Technologies Ltd
11 *
12 * Based on sample.c:
13 * Copyright (c) 2005 John Bicket
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer,
21 * without modification.
22 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
23 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
24 * redistribution must be conditioned upon including a substantially
25 * similar Disclaimer requirement for further binary redistribution.
26 * 3. Neither the names of the above-listed copyright holders nor the names
27 * of any contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * Alternatively, this software may be distributed under the terms of the
31 * GNU General Public License ("GPL") version 2 as published by the Free
32 * Software Foundation.
33 *
34 * NO WARRANTY
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
38 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
39 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
40 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
43 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGES.
46 */
47#include <linux/netdevice.h>
48#include <linux/types.h>
49#include <linux/skbuff.h>
50#include <linux/debugfs.h>
51#include <linux/ieee80211.h>
52#include <net/mac80211.h>
53#include "rc80211_minstrel.h"
54
55struct minstrel_stats_info {
56 struct minstrel_sta_info *mi;
57 char buf[4096];
58 size_t len;
59};
60
61static int
62minstrel_stats_open(struct inode *inode, struct file *file)
63{
64 struct minstrel_sta_info *mi = inode->i_private;
65 struct minstrel_stats_info *ms;
66 unsigned int i, tp, prob, eprob;
67 char *p;
68
69 ms = kmalloc(sizeof(*ms), GFP_KERNEL);
70 if (!ms)
71 return -ENOMEM;
72
73 file->private_data = ms;
74 p = ms->buf;
75 p += sprintf(p, "rate throughput ewma prob this prob "
76 "this succ/attempt success attempts\n");
77 for (i = 0; i < mi->n_rates; i++) {
78 struct minstrel_rate *mr = &mi->r[i];
79
80 *(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
81 *(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
82 *(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
83 p += sprintf(p, "%3u%s", mr->bitrate / 2,
84 (mr->bitrate & 1 ? ".5" : " "));
85
86 tp = ((mr->cur_tp * 96) / 18000) >> 10;
87 prob = mr->cur_prob / 18;
88 eprob = mr->probability / 18;
89
90 p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
91 "%3u(%3u) %8llu %8llu\n",
92 tp / 10, tp % 10,
93 eprob / 10, eprob % 10,
94 prob / 10, prob % 10,
95 mr->last_success,
96 mr->last_attempts,
97 mr->succ_hist,
98 mr->att_hist);
99 }
100 p += sprintf(p, "\nTotal packet count:: ideal %d "
101 "lookaround %d\n\n",
102 mi->packet_count - mi->sample_count,
103 mi->sample_count);
104 ms->len = p - ms->buf;
105
106 return 0;
107}
108
109static int
110minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *o)
111{
112 struct minstrel_stats_info *ms;
113 char *src;
114
115 ms = file->private_data;
116 src = ms->buf;
117
118 len = min(len, ms->len);
119 if (len <= *o)
120 return 0;
121
122 src += *o;
123 len -= *o;
124 *o += len;
125
126 if (copy_to_user(buf, src, len))
127 return -EFAULT;
128
129 return len;
130}
131
132static int
133minstrel_stats_release(struct inode *inode, struct file *file)
134{
135 struct minstrel_stats_info *ms = file->private_data;
136
137 kfree(ms);
138
139 return 0;
140}
141
142static struct file_operations minstrel_stat_fops = {
143 .owner = THIS_MODULE,
144 .open = minstrel_stats_open,
145 .read = minstrel_stats_read,
146 .release = minstrel_stats_release,
147};
148
149void
150minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
151{
152 struct minstrel_sta_info *mi = priv_sta;
153
154 mi->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, mi,
155 &minstrel_stat_fops);
156}
157
158void
159minstrel_remove_sta_debugfs(void *priv, void *priv_sta)
160{
161 struct minstrel_sta_info *mi = priv_sta;
162
163 debugfs_remove(mi->dbg_stats);
164}