diff options
author | Felix Fietkau <nbd@openwrt.org> | 2016-03-03 16:59:01 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2016-04-06 07:18:20 -0400 |
commit | 918fe04b288b3784f4ca90d3dff12fc23dc2751f (patch) | |
tree | b99a0d6af4edf88ed9825a2ce2bfc90bbe35f69e | |
parent | 6e0456b5454561c4e9fa9e8a4acea405e6d56c80 (diff) |
mac80211: minstrel_ht: set A-MSDU tx limits based on selected max_prob_rate
Prevents excessive A-MSDU aggregation at low data rates or bad
conditions.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 46ce08ed70b5..d77a9a842338 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -883,6 +883,59 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
883 | ratetbl->rate[offset].flags = flags; | 883 | ratetbl->rate[offset].flags = flags; |
884 | } | 884 | } |
885 | 885 | ||
886 | static inline int | ||
887 | minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate) | ||
888 | { | ||
889 | int group = rate / MCS_GROUP_RATES; | ||
890 | rate %= MCS_GROUP_RATES; | ||
891 | return mi->groups[group].rates[rate].prob_ewma; | ||
892 | } | ||
893 | |||
894 | static int | ||
895 | minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) | ||
896 | { | ||
897 | int group = mi->max_prob_rate / MCS_GROUP_RATES; | ||
898 | const struct mcs_group *g = &minstrel_mcs_groups[group]; | ||
899 | int rate = mi->max_prob_rate % MCS_GROUP_RATES; | ||
900 | |||
901 | /* Disable A-MSDU if max_prob_rate is bad */ | ||
902 | if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) | ||
903 | return 1; | ||
904 | |||
905 | /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ | ||
906 | if (g->duration[rate] > MCS_DURATION(1, 0, 52)) | ||
907 | return 500; | ||
908 | |||
909 | /* | ||
910 | * If the rate is slower than single-stream MCS4, limit A-MSDU to usual | ||
911 | * data packet size | ||
912 | */ | ||
913 | if (g->duration[rate] > MCS_DURATION(1, 0, 104)) | ||
914 | return 1600; | ||
915 | |||
916 | /* | ||
917 | * If the rate is slower than single-stream MCS7, or if the max throughput | ||
918 | * rate success probability is less than 75%, limit A-MSDU to twice the usual | ||
919 | * data packet size | ||
920 | */ | ||
921 | if (g->duration[rate] > MCS_DURATION(1, 0, 260) || | ||
922 | (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) < | ||
923 | MINSTREL_FRAC(75, 100))) | ||
924 | return 3200; | ||
925 | |||
926 | /* | ||
927 | * HT A-MPDU limits maximum MPDU size under BA agreement to 4095 bytes. | ||
928 | * Since aggregation sessions are started/stopped without txq flush, use | ||
929 | * the limit here to avoid the complexity of having to de-aggregate | ||
930 | * packets in the queue. | ||
931 | */ | ||
932 | if (!mi->sta->vht_cap.vht_supported) | ||
933 | return IEEE80211_MAX_MPDU_LEN_HT_BA; | ||
934 | |||
935 | /* unlimited */ | ||
936 | return 0; | ||
937 | } | ||
938 | |||
886 | static void | 939 | static void |
887 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | 940 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) |
888 | { | 941 | { |
@@ -907,6 +960,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
907 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); | 960 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); |
908 | } | 961 | } |
909 | 962 | ||
963 | mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); | ||
910 | rates->rate[i].idx = -1; | 964 | rates->rate[i].idx = -1; |
911 | rate_control_set_rates(mp->hw, mi->sta, rates); | 965 | rate_control_set_rates(mp->hw, mi->sta, rates); |
912 | } | 966 | } |