diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-02-13 04:51:08 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-13 04:56:33 -0500 |
commit | a0497f9f57478c5a37c5628eb32833dd9729a821 (patch) | |
tree | ba36d9fd8aa48161af7d997ecefe360032c4171e /net | |
parent | 6719429dd61cde1fe30d9644d0aa2369eefc9005 (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')
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 29 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.h | 2 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 152 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.h | 5 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht_debugfs.c | 109 |
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 | ||
497 | static void | ||
498 | minstrel_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 | |||
497 | static void * | 524 | static void * |
498 | minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 525 | minstrel_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 | |||
100 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 129 | static 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 | ||
151 | static struct minstrel_rate_stats * | ||
152 | minstrel_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 | |||
122 | static inline struct minstrel_rate_stats * | 174 | static inline struct minstrel_rate_stats * |
123 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | 175 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) |
124 | { | 176 | { |
@@ -159,7 +211,7 @@ static void | |||
159 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 211 | minstrel_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 | ||
295 | static bool | 349 | static bool |
296 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | 350 | minstrel_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 | ||
307 | static void | 367 | static 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 | ||
594 | static void | 666 | static void |
667 | minstrel_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 | |||
682 | static void | ||
595 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 683 | minstrel_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 | ||
685 | static void | 774 | static void |
775 | minstrel_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 | |||
798 | static void | ||
686 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 799 | minstrel_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 | ||
114 | struct minstrel_ht_sta_priv { | 117 | struct 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 | ||
18 | static char * | ||
19 | minstrel_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 | |||
18 | static int | 80 | static int |
19 | minstrel_ht_stats_open(struct inode *inode, struct file *file) | 81 | minstrel_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), |