diff options
Diffstat (limited to 'net/mac80211/rc80211_minstrel_ht.c')
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 172 |
1 files changed, 99 insertions, 73 deletions
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index d2b264d1311d..5b2d3012b983 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -126,6 +126,9 @@ const struct mcs_group minstrel_mcs_groups[] = { static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; +static void +minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); + /* * Look up an MCS group index based on mac80211 rate information */ @@ -244,6 +247,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) struct minstrel_rate_stats *mr; int cur_prob, cur_prob_tp, cur_tp, cur_tp2; int group, i, index; + bool mi_rates_valid = false; if (mi->ampdu_packets > 0) { mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, @@ -254,11 +258,10 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) mi->sample_slow = 0; mi->sample_count = 0; - mi->max_tp_rate = 0; - mi->max_tp_rate2 = 0; - mi->max_prob_rate = 0; for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { + bool mg_rates_valid = false; + cur_prob = 0; cur_prob_tp = 0; cur_tp = 0; @@ -268,15 +271,24 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) if (!mg->supported) continue; - mg->max_tp_rate = 0; - mg->max_tp_rate2 = 0; - mg->max_prob_rate = 0; mi->sample_count++; for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mg->supported & BIT(i))) continue; + /* initialize rates selections starting indexes */ + if (!mg_rates_valid) { + mg->max_tp_rate = mg->max_tp_rate2 = + mg->max_prob_rate = i; + if (!mi_rates_valid) { + mi->max_tp_rate = mi->max_tp_rate2 = + mi->max_prob_rate = i; + mi_rates_valid = true; + } + mg_rates_valid = true; + } + mr = &mg->rates[i]; mr->retry_updated = false; index = MCS_GROUP_RATES * group + i; @@ -456,7 +468,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_tx_rate *ar = info->status.rates; struct minstrel_rate_stats *rate, *rate2; struct minstrel_priv *mp = priv; - bool last; + bool last, update = false; int i; if (!msp->is_ht) @@ -505,21 +517,29 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, rate = minstrel_get_ratestats(mi, mi->max_tp_rate); if (rate->attempts > 30 && MINSTREL_FRAC(rate->success, rate->attempts) < - MINSTREL_FRAC(20, 100)) + MINSTREL_FRAC(20, 100)) { minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); + update = true; + } rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); if (rate2->attempts > 30 && MINSTREL_FRAC(rate2->success, rate2->attempts) < - MINSTREL_FRAC(20, 100)) + MINSTREL_FRAC(20, 100)) { minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); + update = true; + } if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { + update = true; minstrel_ht_update_stats(mp, mi); if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) minstrel_aggr_check(sta, skb); } + + if (update) + minstrel_ht_update_rates(mp, mi); } static void @@ -583,36 +603,71 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, static void minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - struct ieee80211_tx_rate *rate, int index, - bool sample, bool rtscts) + struct ieee80211_sta_rates *ratetbl, int offset, int index) { const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; struct minstrel_rate_stats *mr; + u8 idx; + u16 flags; mr = minstrel_get_ratestats(mi, index); if (!mr->retry_updated) minstrel_calc_retransmit(mp, mi, index); - if (sample) - rate->count = 1; - else if (mr->probability < MINSTREL_FRAC(20, 100)) - rate->count = 2; - else if (rtscts) - rate->count = mr->retry_count_rtscts; - else - rate->count = mr->retry_count; - - rate->flags = 0; - if (rtscts) - rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) { + ratetbl->rate[offset].count = 2; + ratetbl->rate[offset].count_rts = 2; + ratetbl->rate[offset].count_cts = 2; + } else { + ratetbl->rate[offset].count = mr->retry_count; + ratetbl->rate[offset].count_cts = mr->retry_count; + ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; + } if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { - rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; + idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; + flags = 0; + } else { + idx = index % MCS_GROUP_RATES + + (group->streams - 1) * MCS_GROUP_RATES; + flags = IEEE80211_TX_RC_MCS | group->flags; + } + + if (offset > 0) { + ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; + flags |= IEEE80211_TX_RC_USE_RTS_CTS; + } + + ratetbl->rate[offset].idx = idx; + ratetbl->rate[offset].flags = flags; +} + +static void +minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) +{ + struct ieee80211_sta_rates *rates; + int i = 0; + + rates = kzalloc(sizeof(*rates), GFP_ATOMIC); + if (!rates) return; + + /* Start with max_tp_rate */ + minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate); + + if (mp->hw->max_rates >= 3) { + /* At least 3 tx rates supported, use max_tp_rate2 next */ + minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate2); + } + + if (mp->hw->max_rates >= 2) { + /* + * At least 2 tx rates supported, use max_prob_rate next */ + minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); } - rate->flags |= IEEE80211_TX_RC_MCS | group->flags; - rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; + rates->rate[i].idx = -1; + rate_control_set_rates(mp->hw, mi->sta, rates); } static inline int @@ -702,13 +757,13 @@ static void minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + const struct mcs_group *sample_group; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); - struct ieee80211_tx_rate *ar = info->status.rates; + struct ieee80211_tx_rate *rate = &info->status.rates[0]; struct minstrel_ht_sta_priv *msp = priv_sta; struct minstrel_ht_sta *mi = &msp->ht; struct minstrel_priv *mp = priv; int sample_idx; - bool sample = false; if (rate_control_send_low(sta, priv_sta, txrc)) return; @@ -736,51 +791,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, } #endif - if (sample_idx >= 0) { - sample = true; - minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, - true, false); - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, - false, false); - } - - if (mp->hw->max_rates >= 3) { - /* - * At least 3 tx rates supported, use - * sample_rate -> max_tp_rate -> max_prob_rate for sampling and - * max_tp_rate -> max_tp_rate2 -> max_prob_rate by default. - */ - if (sample_idx >= 0) - minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, - false, false); - else - minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, - false, true); - - minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, - false, !sample); - - ar[3].count = 0; - ar[3].idx = -1; - } else if (mp->hw->max_rates == 2) { - /* - * Only 2 tx rates supported, use - * sample_rate -> max_prob_rate for sampling and - * max_tp_rate -> max_prob_rate by default. - */ - minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate, - false, !sample); - - ar[2].count = 0; - ar[2].idx = -1; - } else { - /* Not using MRR, only use the first rate */ - ar[1].count = 0; - ar[1].idx = -1; - } - mi->total_packets++; /* wraparound */ @@ -788,6 +798,16 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, mi->total_packets = 0; mi->sample_packets = 0; } + + if (sample_idx < 0) + return; + + sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + rate->idx = sample_idx % MCS_GROUP_RATES + + (sample_group->streams - 1) * MCS_GROUP_RATES; + rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; + rate->count = 1; } static void @@ -837,6 +857,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, msp->is_ht = true; memset(mi, 0, sizeof(*mi)); + + mi->sta = sta; mi->stats_update = jiffies; ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1); @@ -898,6 +920,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, if (!n_supported) goto use_legacy; + /* create an initial rate table with the lowest supported rates */ + minstrel_ht_update_stats(mp, mi); + minstrel_ht_update_rates(mp, mi); + return; use_legacy: |