aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-02-13 04:51:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-13 04:56:33 -0500
commita0497f9f57478c5a37c5628eb32833dd9729a821 (patch)
treeba36d9fd8aa48161af7d997ecefe360032c4171e /net/mac80211
parent6719429dd61cde1fe30d9644d0aa2369eefc9005 (diff)
mac80211/minstrel_ht: add support for using CCK rates
When MCS rates start to get bad in 2.4 GHz because of long range or strong interference, CCK rates can be a lot more robust. This patch adds a pseudo MCS group containing CCK rates (long preamble in the lower 4 slots, short preamble in the upper slots). Signed-off-by: Felix Fietkau <nbd@openwrt.org> [make minstrel_ht_get_stats static] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/rc80211_minstrel.c29
-rw-r--r--net/mac80211/rc80211_minstrel.h2
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c152
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h5
-rw-r--r--net/mac80211/rc80211_minstrel_ht_debugfs.c109
5 files changed, 237 insertions, 60 deletions
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 8c5acdc06226..eea45a2c7c35 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
494 kfree(mi); 494 kfree(mi);
495} 495}
496 496
497static void
498minstrel_init_cck_rates(struct minstrel_priv *mp)
499{
500 static const int bitrates[4] = { 10, 20, 55, 110 };
501 struct ieee80211_supported_band *sband;
502 int i, j;
503
504 sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
505 if (!sband)
506 return;
507
508 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
509 struct ieee80211_rate *rate = &sband->bitrates[i];
510
511 if (rate->flags & IEEE80211_RATE_ERP_G)
512 continue;
513
514 for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
515 if (rate->bitrate != bitrates[j])
516 continue;
517
518 mp->cck_rates[j] = i;
519 break;
520 }
521 }
522}
523
497static void * 524static void *
498minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) 525minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
499{ 526{
@@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
539 S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); 566 S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx);
540#endif 567#endif
541 568
569 minstrel_init_cck_rates(mp);
570
542 return mp; 571 return mp;
543} 572}
544 573
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 5d278eccaef0..5ecf757817f2 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -79,6 +79,8 @@ struct minstrel_priv {
79 unsigned int lookaround_rate; 79 unsigned int lookaround_rate;
80 unsigned int lookaround_rate_mrr; 80 unsigned int lookaround_rate_mrr;
81 81
82 u8 cck_rates[4];
83
82#ifdef CONFIG_MAC80211_DEBUGFS 84#ifdef CONFIG_MAC80211_DEBUGFS
83 /* 85 /*
84 * enable fixed rate processing per RC 86 * enable fixed rate processing per RC
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 5bb316aff21a..6e35dcd2aa2f 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 2 * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 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 5 * it under the terms of the GNU General Public License version 2 as
@@ -63,6 +63,30 @@
63 } \ 63 } \
64} 64}
65 65
66#define CCK_DURATION(_bitrate, _short, _len) \
67 (10 /* SIFS */ + \
68 (_short ? 72 + 24 : 144 + 48 ) + \
69 (8 * (_len + 4) * 10) / (_bitrate))
70
71#define CCK_ACK_DURATION(_bitrate, _short) \
72 (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
73 CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
74
75#define CCK_DURATION_LIST(_short) \
76 CCK_ACK_DURATION(10, _short), \
77 CCK_ACK_DURATION(20, _short), \
78 CCK_ACK_DURATION(55, _short), \
79 CCK_ACK_DURATION(110, _short)
80
81#define CCK_GROUP \
82 [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \
83 .streams = 0, \
84 .duration = { \
85 CCK_DURATION_LIST(false), \
86 CCK_DURATION_LIST(true) \
87 } \
88 }
89
66/* 90/*
67 * To enable sufficiently targeted rate sampling, MCS rates are divided into 91 * To enable sufficiently targeted rate sampling, MCS rates are divided into
68 * groups, based on the number of streams and flags (HT40, SGI) that they 92 * groups, based on the number of streams and flags (HT40, SGI) that they
@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = {
95#if MINSTREL_MAX_STREAMS >= 3 119#if MINSTREL_MAX_STREAMS >= 3
96 MCS_GROUP(3, 1, 1), 120 MCS_GROUP(3, 1, 1),
97#endif 121#endif
122
123 /* must be last */
124 CCK_GROUP
98}; 125};
99 126
127#define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1)
128
100static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; 129static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
101 130
102/* 131/*
@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
119 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); 148 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
120} 149}
121 150
151static struct minstrel_rate_stats *
152minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
153 struct ieee80211_tx_rate *rate)
154{
155 int group, idx;
156
157 if (rate->flags & IEEE80211_TX_RC_MCS) {
158 group = minstrel_ht_get_group_idx(rate);
159 idx = rate->idx % MCS_GROUP_RATES;
160 } else {
161 group = MINSTREL_CCK_GROUP;
162
163 for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++)
164 if (rate->idx == mp->cck_rates[idx])
165 break;
166
167 /* short preamble */
168 if (!(mi->groups[group].supported & BIT(idx)))
169 idx += 4;
170 }
171 return &mi->groups[group].rates[idx];
172}
173
122static inline struct minstrel_rate_stats * 174static inline struct minstrel_rate_stats *
123minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) 175minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
124{ 176{
@@ -159,7 +211,7 @@ static void
159minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) 211minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
160{ 212{
161 struct minstrel_rate_stats *mr; 213 struct minstrel_rate_stats *mr;
162 unsigned int usecs; 214 unsigned int usecs = 0;
163 215
164 mr = &mi->groups[group].rates[rate]; 216 mr = &mi->groups[group].rates[rate];
165 217
@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
168 return; 220 return;
169 } 221 }
170 222
171 usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); 223 if (group != MINSTREL_CCK_GROUP)
224 usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
225
172 usecs += minstrel_mcs_groups[group].duration[rate]; 226 usecs += minstrel_mcs_groups[group].duration[rate];
173 mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); 227 mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
174} 228}
@@ -293,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
293} 347}
294 348
295static bool 349static bool
296minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) 350minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate)
297{ 351{
298 if (rate->idx < 0) 352 if (rate->idx < 0)
299 return false; 353 return false;
@@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
301 if (!rate->count) 355 if (!rate->count)
302 return false; 356 return false;
303 357
304 return !!(rate->flags & IEEE80211_TX_RC_MCS); 358 if (rate->flags & IEEE80211_TX_RC_MCS)
359 return true;
360
361 return rate->idx == mp->cck_rates[0] ||
362 rate->idx == mp->cck_rates[1] ||
363 rate->idx == mp->cck_rates[2] ||
364 rate->idx == mp->cck_rates[3];
305} 365}
306 366
307static void 367static void
@@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
386 struct minstrel_rate_stats *rate, *rate2; 446 struct minstrel_rate_stats *rate, *rate2;
387 struct minstrel_priv *mp = priv; 447 struct minstrel_priv *mp = priv;
388 bool last; 448 bool last;
389 int group;
390 int i; 449 int i;
391 450
392 if (!msp->is_ht) 451 if (!msp->is_ht)
@@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
415 if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) 474 if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
416 mi->sample_packets += info->status.ampdu_len; 475 mi->sample_packets += info->status.ampdu_len;
417 476
418 last = !minstrel_ht_txstat_valid(&ar[0]); 477 last = !minstrel_ht_txstat_valid(mp, &ar[0]);
419 for (i = 0; !last; i++) { 478 for (i = 0; !last; i++) {
420 last = (i == IEEE80211_TX_MAX_RATES - 1) || 479 last = (i == IEEE80211_TX_MAX_RATES - 1) ||
421 !minstrel_ht_txstat_valid(&ar[i + 1]); 480 !minstrel_ht_txstat_valid(mp, &ar[i + 1]);
422 481
423 group = minstrel_ht_get_group_idx(&ar[i]); 482 rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
424 rate = &mi->groups[group].rates[ar[i].idx % 8];
425 483
426 if (last) 484 if (last)
427 rate->success += info->status.ampdu_ack_len; 485 rate->success += info->status.ampdu_ack_len;
@@ -447,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
447 505
448 if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { 506 if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
449 minstrel_ht_update_stats(mp, mi); 507 minstrel_ht_update_stats(mp, mi);
450 if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) 508 if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
509 mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
451 minstrel_aggr_check(sta, skb); 510 minstrel_aggr_check(sta, skb);
452 } 511 }
453} 512}
@@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
463 unsigned int ctime = 0; 522 unsigned int ctime = 0;
464 unsigned int t_slot = 9; /* FIXME */ 523 unsigned int t_slot = 9; /* FIXME */
465 unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); 524 unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
525 unsigned int overhead = 0, overhead_rtscts = 0;
466 526
467 mr = minstrel_get_ratestats(mi, index); 527 mr = minstrel_get_ratestats(mi, index);
468 if (mr->probability < MINSTREL_FRAC(1, 10)) { 528 if (mr->probability < MINSTREL_FRAC(1, 10)) {
@@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
484 ctime += (t_slot * cw) >> 1; 544 ctime += (t_slot * cw) >> 1;
485 cw = min((cw << 1) | 1, mp->cw_max); 545 cw = min((cw << 1) | 1, mp->cw_max);
486 546
547 if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) {
548 overhead = mi->overhead;
549 overhead_rtscts = mi->overhead_rtscts;
550 }
551
487 /* Total TX time for data and Contention after first 2 tries */ 552 /* Total TX time for data and Contention after first 2 tries */
488 tx_time = ctime + 2 * (mi->overhead + tx_time_data); 553 tx_time = ctime + 2 * (overhead + tx_time_data);
489 tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); 554 tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data);
490 555
491 /* See how many more tries we can fit inside segment size */ 556 /* See how many more tries we can fit inside segment size */
492 do { 557 do {
@@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
495 cw = min((cw << 1) | 1, mp->cw_max); 560 cw = min((cw << 1) | 1, mp->cw_max);
496 561
497 /* Total TX time after this try */ 562 /* Total TX time after this try */
498 tx_time += ctime + mi->overhead + tx_time_data; 563 tx_time += ctime + overhead + tx_time_data;
499 tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; 564 tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;
500 565
501 if (tx_time_rtscts < mp->segment_size) 566 if (tx_time_rtscts < mp->segment_size)
502 mr->retry_count_rtscts++; 567 mr->retry_count_rtscts++;
@@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
526 else 591 else
527 rate->count = mr->retry_count; 592 rate->count = mr->retry_count;
528 593
529 rate->flags = IEEE80211_TX_RC_MCS | group->flags; 594 rate->flags = 0;
530 if (rtscts) 595 if (rtscts)
531 rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; 596 rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
597
598 if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
599 rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
600 return;
601 }
602
603 rate->flags |= IEEE80211_TX_RC_MCS | group->flags;
532 rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; 604 rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
533} 605}
534 606
@@ -592,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
592} 664}
593 665
594static void 666static void
667minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp,
668 struct minstrel_ht_sta *mi, bool val)
669{
670 u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported;
671
672 if (!supported || !mi->cck_supported_short)
673 return;
674
675 if (supported & (mi->cck_supported_short << (val * 4)))
676 return;
677
678 supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4);
679 mi->groups[MINSTREL_CCK_GROUP].supported = supported;
680}
681
682static void
595minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, 683minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
596 struct ieee80211_tx_rate_control *txrc) 684 struct ieee80211_tx_rate_control *txrc)
597{ 685{
@@ -610,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
610 return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); 698 return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
611 699
612 info->flags |= mi->tx_flags; 700 info->flags |= mi->tx_flags;
701 minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
613 702
614 /* Don't use EAPOL frames for sampling on non-mrr hw */ 703 /* Don't use EAPOL frames for sampling on non-mrr hw */
615 if (mp->hw->max_rates == 1 && 704 if (mp->hw->max_rates == 1 &&
@@ -683,6 +772,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
683} 772}
684 773
685static void 774static void
775minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
776 struct ieee80211_supported_band *sband,
777 struct ieee80211_sta *sta)
778{
779 int i;
780
781 if (sband->band != IEEE80211_BAND_2GHZ)
782 return;
783
784 mi->cck_supported = 0;
785 mi->cck_supported_short = 0;
786 for (i = 0; i < 4; i++) {
787 if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
788 continue;
789
790 mi->cck_supported |= BIT(i);
791 if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
792 mi->cck_supported_short |= BIT(i);
793 }
794
795 mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported;
796}
797
798static void
686minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, 799minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
687 struct ieee80211_sta *sta, void *priv_sta) 800 struct ieee80211_sta *sta, void *priv_sta)
688{ 801{
@@ -702,7 +815,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
702 goto use_legacy; 815 goto use_legacy;
703 816
704 BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != 817 BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
705 MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); 818 MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
706 819
707 msp->is_ht = true; 820 msp->is_ht = true;
708 memset(mi, 0, sizeof(*mi)); 821 memset(mi, 0, sizeof(*mi));
@@ -738,6 +851,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
738 u16 req = 0; 851 u16 req = 0;
739 852
740 mi->groups[i].supported = 0; 853 mi->groups[i].supported = 0;
854 if (i == MINSTREL_CCK_GROUP) {
855 minstrel_ht_update_cck(mp, mi, sband, sta);
856 continue;
857 }
858
741 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { 859 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
742 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 860 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
743 req |= IEEE80211_HT_CAP_SGI_40; 861 req |= IEEE80211_HT_CAP_SGI_40;
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 462d2b227ed5..302dbd52180d 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -107,8 +107,11 @@ struct minstrel_ht_sta {
107 /* current MCS group to be sampled */ 107 /* current MCS group to be sampled */
108 u8 sample_group; 108 u8 sample_group;
109 109
110 u8 cck_supported;
111 u8 cck_supported_short;
112
110 /* MCS rate group info and statistics */ 113 /* MCS rate group info and statistics */
111 struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; 114 struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1];
112}; 115};
113 116
114struct minstrel_ht_sta_priv { 117struct minstrel_ht_sta_priv {
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index f2b7d26370f0..df44a5ad8270 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -15,13 +15,76 @@
15#include "rc80211_minstrel.h" 15#include "rc80211_minstrel.h"
16#include "rc80211_minstrel_ht.h" 16#include "rc80211_minstrel_ht.h"
17 17
18static char *
19minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
20{
21 unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
22 const struct mcs_group *mg;
23 unsigned int j, tp, prob, eprob;
24 char htmode = '2';
25 char gimode = 'L';
26
27 if (!mi->groups[i].supported)
28 return p;
29
30 mg = &minstrel_mcs_groups[i];
31 if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
32 htmode = '4';
33 if (mg->flags & IEEE80211_TX_RC_SHORT_GI)
34 gimode = 'S';
35
36 for (j = 0; j < MCS_GROUP_RATES; j++) {
37 struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
38 static const int bitrates[4] = { 10, 20, 55, 110 };
39 int idx = i * MCS_GROUP_RATES + j;
40
41 if (!(mi->groups[i].supported & BIT(j)))
42 continue;
43
44 if (i == max_mcs)
45 p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S');
46 else
47 p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
48
49 *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
50 *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
51 *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
52
53 if (i == max_mcs) {
54 int r = bitrates[j % 4];
55 p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
56 } else {
57 p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
58 MCS_GROUP_RATES + j);
59 }
60
61 tp = mr->cur_tp / 10;
62 prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
63 eprob = MINSTREL_TRUNC(mr->probability * 1000);
64
65 p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
66 "%3u %3u(%3u) %8llu %8llu\n",
67 tp / 10, tp % 10,
68 eprob / 10, eprob % 10,
69 prob / 10, prob % 10,
70 mr->retry_count,
71 mr->last_success,
72 mr->last_attempts,
73 (unsigned long long)mr->succ_hist,
74 (unsigned long long)mr->att_hist);
75 }
76
77 return p;
78}
79
18static int 80static int
19minstrel_ht_stats_open(struct inode *inode, struct file *file) 81minstrel_ht_stats_open(struct inode *inode, struct file *file)
20{ 82{
21 struct minstrel_ht_sta_priv *msp = inode->i_private; 83 struct minstrel_ht_sta_priv *msp = inode->i_private;
22 struct minstrel_ht_sta *mi = &msp->ht; 84 struct minstrel_ht_sta *mi = &msp->ht;
23 struct minstrel_debugfs_info *ms; 85 struct minstrel_debugfs_info *ms;
24 unsigned int i, j, tp, prob, eprob; 86 unsigned int i;
87 unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
25 char *p; 88 char *p;
26 int ret; 89 int ret;
27 90
@@ -40,49 +103,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
40 p = ms->buf; 103 p = ms->buf;
41 p += sprintf(p, "type rate throughput ewma prob this prob " 104 p += sprintf(p, "type rate throughput ewma prob this prob "
42 "retry this succ/attempt success attempts\n"); 105 "retry this succ/attempt success attempts\n");
43 for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
44 char htmode = '2';
45 char gimode = 'L';
46
47 if (!mi->groups[i].supported)
48 continue;
49
50 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
51 htmode = '4';
52 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
53 gimode = 'S';
54 106
55 for (j = 0; j < MCS_GROUP_RATES; j++) { 107 p = minstrel_ht_stats_dump(mi, max_mcs, p);
56 struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; 108 for (i = 0; i < max_mcs; i++)
57 int idx = i * MCS_GROUP_RATES + j; 109 p = minstrel_ht_stats_dump(mi, i, p);
58 110
59 if (!(mi->groups[i].supported & BIT(j)))
60 continue;
61
62 p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
63
64 *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
65 *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
66 *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
67 p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
68 MCS_GROUP_RATES + j);
69
70 tp = mr->cur_tp / 10;
71 prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
72 eprob = MINSTREL_TRUNC(mr->probability * 1000);
73
74 p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
75 "%3u %3u(%3u) %8llu %8llu\n",
76 tp / 10, tp % 10,
77 eprob / 10, eprob % 10,
78 prob / 10, prob % 10,
79 mr->retry_count,
80 mr->last_success,
81 mr->last_attempts,
82 (unsigned long long)mr->succ_hist,
83 (unsigned long long)mr->att_hist);
84 }
85 }
86 p += sprintf(p, "\nTotal packet count:: ideal %d " 111 p += sprintf(p, "\nTotal packet count:: ideal %d "
87 "lookaround %d\n", 112 "lookaround %d\n",
88 max(0, (int) mi->total_packets - (int) mi->sample_packets), 113 max(0, (int) mi->total_packets - (int) mi->sample_packets),