diff options
Diffstat (limited to 'net/mac80211/rc80211_minstrel_ht.c')
| -rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 273 | 
1 files changed, 159 insertions, 114 deletions
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 3af141c6971..5b2d3012b98 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -17,8 +17,6 @@  #include "rc80211_minstrel_ht.h"  #define AVG_PKT_SIZE	1200 -#define SAMPLE_COLUMNS	10 -#define EWMA_LEVEL		75  /* Number of bits for an average sized packet */  #define MCS_NBITS (AVG_PKT_SIZE << 3) @@ -26,11 +24,11 @@  /* Number of symbols for a packet with (bps) bits per symbol */  #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) -/* Transmission time for a packet containing (syms) symbols */ +/* Transmission time (nanoseconds) for a packet containing (syms) symbols */  #define MCS_SYMBOL_TIME(sgi, syms)					\  	(sgi ?								\ -	  ((syms) * 18 + 4) / 5 :	/* syms * 3.6 us */		\ -	  (syms) << 2			/* syms * 4 us */		\ +	  ((syms) * 18000 + 4000) / 5 :	/* syms * 3.6 us */		\ +	  ((syms) * 1000) << 2		/* syms * 4 us */		\  	)  /* Transmit duration for the raw data part of an average sized packet */ @@ -64,9 +62,9 @@  }  #define CCK_DURATION(_bitrate, _short, _len)		\ -	(10 /* SIFS */ +				\ +	(1000 * (10 /* SIFS */ +			\  	 (_short ? 72 + 24 : 144 + 48 ) +		\ -	 (8 * (_len + 4) * 10) / (_bitrate)) +	 (8 * (_len + 4) * 10) / (_bitrate)))  #define CCK_ACK_DURATION(_bitrate, _short)			\  	(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) +	\ @@ -128,14 +126,8 @@ const struct mcs_group minstrel_mcs_groups[] = {  static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; -/* - * Perform EWMA (Exponentially Weighted Moving Average) calculation - */ -static int -minstrel_ewma(int old, int new, int weight) -{ -	return (new * (100 - weight) + old * weight) / 100; -} +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 @@ -211,20 +203,32 @@ static void  minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)  {  	struct minstrel_rate_stats *mr; -	unsigned int usecs = 0; +	unsigned int nsecs = 0; +	unsigned int tp; +	unsigned int prob;  	mr = &mi->groups[group].rates[rate]; +	prob = mr->probability; -	if (mr->probability < MINSTREL_FRAC(1, 10)) { +	if (prob < MINSTREL_FRAC(1, 10)) {  		mr->cur_tp = 0;  		return;  	} +	/* +	 * For the throughput calculation, limit the probability value to 90% to +	 * account for collision related packet error rate fluctuation +	 */ +	if (prob > MINSTREL_FRAC(9, 10)) +		prob = MINSTREL_FRAC(9, 10); +  	if (group != MINSTREL_CCK_GROUP) -		usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); +		nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); -	usecs += minstrel_mcs_groups[group].duration[rate]; -	mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); +	nsecs += minstrel_mcs_groups[group].duration[rate]; +	tp = 1000000 * ((mr->probability * 1000) / nsecs); + +	mr->cur_tp = MINSTREL_TRUNC(tp);  }  /* @@ -243,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, @@ -253,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; @@ -267,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; @@ -308,8 +321,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)  		}  	} -	/* try to sample up to half of the available rates during each interval */ -	mi->sample_count *= 4; +	/* try to sample all available rates during each interval */ +	mi->sample_count *= 8;  	cur_prob = 0;  	cur_prob_tp = 0; @@ -320,20 +333,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)  		if (!mg->supported)  			continue; -		mr = minstrel_get_ratestats(mi, mg->max_prob_rate); -		if (cur_prob_tp < mr->cur_tp && -		    minstrel_mcs_groups[group].streams == 1) { -			mi->max_prob_rate = mg->max_prob_rate; -			cur_prob = mr->cur_prob; -			cur_prob_tp = mr->cur_tp; -		} -  		mr = minstrel_get_ratestats(mi, mg->max_tp_rate);  		if (cur_tp < mr->cur_tp) {  			mi->max_tp_rate2 = mi->max_tp_rate;  			cur_tp2 = cur_tp;  			mi->max_tp_rate = mg->max_tp_rate;  			cur_tp = mr->cur_tp; +			mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1;  		}  		mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); @@ -343,6 +349,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)  		}  	} +	if (mi->max_prob_streams < 1) +		mi->max_prob_streams = 1; + +	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { +		mg = &mi->groups[group]; +		if (!mg->supported) +			continue; +		mr = minstrel_get_ratestats(mi, mg->max_prob_rate); +		if (cur_prob_tp < mr->cur_tp && +		    minstrel_mcs_groups[group].streams <= mi->max_prob_streams) { +			mi->max_prob_rate = mg->max_prob_rate; +			cur_prob = mr->cur_prob; +			cur_prob_tp = mr->cur_tp; +		} +	} + +  	mi->stats_update = jiffies;  } @@ -445,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) @@ -467,7 +490,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,  	if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {  		mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); -		mi->sample_tries = 2; +		mi->sample_tries = 1;  		mi->sample_count--;  	} @@ -494,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 @@ -536,7 +567,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,  	mr->retry_updated = true;  	group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; -	tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; +	tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;  	/* Contention time for first 2 tries */  	ctime = (t_slot * cw) >> 1; @@ -572,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);  	} -	rate->flags |= IEEE80211_TX_RC_MCS | group->flags; -	rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; +	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); +	} + +	rates->rate[i].idx = -1; +	rate_control_set_rates(mp->hw, mi->sta, rates);  }  static inline int @@ -616,6 +682,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)  {  	struct minstrel_rate_stats *mr;  	struct minstrel_mcs_group_data *mg; +	unsigned int sample_dur, sample_group;  	int sample_idx = 0;  	if (mi->sample_wait > 0) { @@ -626,39 +693,46 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)  	if (!mi->sample_tries)  		return -1; -	mi->sample_tries--;  	mg = &mi->groups[mi->sample_group];  	sample_idx = sample_table[mg->column][mg->index];  	mr = &mg->rates[sample_idx]; -	sample_idx += mi->sample_group * MCS_GROUP_RATES; +	sample_group = mi->sample_group; +	sample_idx += sample_group * MCS_GROUP_RATES;  	minstrel_next_sample_idx(mi);  	/*  	 * Sampling might add some overhead (RTS, no aggregation)  	 * to the frame. Hence, don't use sampling for the currently -	 * used max TP rate. +	 * used rates.  	 */ -	if (sample_idx == mi->max_tp_rate) +	if (sample_idx == mi->max_tp_rate || +	    sample_idx == mi->max_tp_rate2 || +	    sample_idx == mi->max_prob_rate)  		return -1; +  	/* -	 * When not using MRR, do not sample if the probability is already -	 * higher than 95% to avoid wasting airtime +	 * Do not sample if the probability is already higher than 95% +	 * to avoid wasting airtime.  	 */ -	if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100))) +	if (mr->probability > MINSTREL_FRAC(95, 100))  		return -1;  	/*  	 * Make sure that lower rates get sampled only occasionally,  	 * if the link is working perfectly.  	 */ -	if (minstrel_get_duration(sample_idx) > -	    minstrel_get_duration(mi->max_tp_rate)) { +	sample_dur = minstrel_get_duration(sample_idx); +	if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) && +	    (mi->max_prob_streams < +	     minstrel_mcs_groups[sample_group].streams || +	     sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {  		if (mr->sample_skipped < 20)  			return -1;  		if (mi->sample_slow++ > 2)  			return -1;  	} +	mi->sample_tries--;  	return sample_idx;  } @@ -683,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; @@ -717,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 */ @@ -769,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 @@ -818,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); @@ -879,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:  |