mac80211: merge upstream legacy minstrel improvements
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 36334
This commit is contained in:
parent
604395650a
commit
fb79dbfb7b
1 changed files with 482 additions and 14 deletions
|
@ -634,7 +634,16 @@
|
||||||
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||||
@@ -26,11 +26,11 @@
|
@@ -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 */
|
/* Number of symbols for a packet with (bps) bits per symbol */
|
||||||
#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
|
#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
|
||||||
|
|
||||||
|
@ -649,7 +658,7 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Transmit duration for the raw data part of an average sized packet */
|
/* Transmit duration for the raw data part of an average sized packet */
|
||||||
@@ -64,9 +64,9 @@
|
@@ -64,9 +62,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CCK_DURATION(_bitrate, _short, _len) \
|
#define CCK_DURATION(_bitrate, _short, _len) \
|
||||||
|
@ -661,7 +670,23 @@
|
||||||
|
|
||||||
#define CCK_ACK_DURATION(_bitrate, _short) \
|
#define CCK_ACK_DURATION(_bitrate, _short) \
|
||||||
(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
|
(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
|
||||||
@@ -211,20 +211,32 @@ static void
|
@@ -129,15 +127,6 @@ const struct mcs_group minstrel_mcs_grou
|
||||||
|
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;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/*
|
||||||
|
* Look up an MCS group index based on mac80211 rate information
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
@@ -211,20 +200,32 @@ static void
|
||||||
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
|
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
|
||||||
{
|
{
|
||||||
struct minstrel_rate_stats *mr;
|
struct minstrel_rate_stats *mr;
|
||||||
|
@ -689,17 +714,17 @@
|
||||||
if (group != MINSTREL_CCK_GROUP)
|
if (group != MINSTREL_CCK_GROUP)
|
||||||
- usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
- usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||||
+ nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
+ nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||||
|
+
|
||||||
|
+ nsecs += minstrel_mcs_groups[group].duration[rate];
|
||||||
|
+ tp = 1000000 * ((mr->probability * 1000) / nsecs);
|
||||||
|
|
||||||
- usecs += minstrel_mcs_groups[group].duration[rate];
|
- usecs += minstrel_mcs_groups[group].duration[rate];
|
||||||
- mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
|
- 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);
|
+ mr->cur_tp = MINSTREL_TRUNC(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -308,8 +320,8 @@ minstrel_ht_update_stats(struct minstrel
|
@@ -308,8 +309,8 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,7 +735,7 @@
|
||||||
|
|
||||||
cur_prob = 0;
|
cur_prob = 0;
|
||||||
cur_prob_tp = 0;
|
cur_prob_tp = 0;
|
||||||
@@ -320,20 +332,13 @@ minstrel_ht_update_stats(struct minstrel
|
@@ -320,20 +321,13 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
if (!mg->supported)
|
if (!mg->supported)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -732,7 +757,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
|
mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
|
||||||
@@ -343,6 +348,23 @@ minstrel_ht_update_stats(struct minstrel
|
@@ -343,6 +337,23 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,7 +781,7 @@
|
||||||
mi->stats_update = jiffies;
|
mi->stats_update = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +489,7 @@ minstrel_ht_tx_status(void *priv, struct
|
@@ -467,7 +478,7 @@ minstrel_ht_tx_status(void *priv, struct
|
||||||
|
|
||||||
if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
|
if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
|
||||||
mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
|
mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||||
|
@ -765,7 +790,7 @@
|
||||||
mi->sample_count--;
|
mi->sample_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +558,7 @@ minstrel_calc_retransmit(struct minstrel
|
@@ -536,7 +547,7 @@ minstrel_calc_retransmit(struct minstrel
|
||||||
mr->retry_updated = true;
|
mr->retry_updated = true;
|
||||||
|
|
||||||
group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
||||||
|
@ -774,7 +799,7 @@
|
||||||
|
|
||||||
/* Contention time for first 2 tries */
|
/* Contention time for first 2 tries */
|
||||||
ctime = (t_slot * cw) >> 1;
|
ctime = (t_slot * cw) >> 1;
|
||||||
@@ -616,6 +638,7 @@ minstrel_get_sample_rate(struct minstrel
|
@@ -616,6 +627,7 @@ minstrel_get_sample_rate(struct minstrel
|
||||||
{
|
{
|
||||||
struct minstrel_rate_stats *mr;
|
struct minstrel_rate_stats *mr;
|
||||||
struct minstrel_mcs_group_data *mg;
|
struct minstrel_mcs_group_data *mg;
|
||||||
|
@ -782,7 +807,7 @@
|
||||||
int sample_idx = 0;
|
int sample_idx = 0;
|
||||||
|
|
||||||
if (mi->sample_wait > 0) {
|
if (mi->sample_wait > 0) {
|
||||||
@@ -626,39 +649,46 @@ minstrel_get_sample_rate(struct minstrel
|
@@ -626,39 +638,46 @@ minstrel_get_sample_rate(struct minstrel
|
||||||
if (!mi->sample_tries)
|
if (!mi->sample_tries)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -840,7 +865,19 @@
|
||||||
}
|
}
|
||||||
--- a/net/mac80211/rc80211_minstrel_ht.h
|
--- a/net/mac80211/rc80211_minstrel_ht.h
|
||||||
+++ b/net/mac80211/rc80211_minstrel_ht.h
|
+++ b/net/mac80211/rc80211_minstrel_ht.h
|
||||||
@@ -85,6 +85,7 @@ struct minstrel_ht_sta {
|
@@ -16,11 +16,6 @@
|
||||||
|
#define MINSTREL_MAX_STREAMS 3
|
||||||
|
#define MINSTREL_STREAM_GROUPS 4
|
||||||
|
|
||||||
|
-/* scaled fraction values */
|
||||||
|
-#define MINSTREL_SCALE 16
|
||||||
|
-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||||
|
-#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||||
|
-
|
||||||
|
#define MCS_GROUP_RATES 8
|
||||||
|
|
||||||
|
struct mcs_group {
|
||||||
|
@@ -85,6 +80,7 @@ struct minstrel_ht_sta {
|
||||||
|
|
||||||
/* best probability rate */
|
/* best probability rate */
|
||||||
unsigned int max_prob_rate;
|
unsigned int max_prob_rate;
|
||||||
|
@ -1161,3 +1198,434 @@
|
||||||
|
|
||||||
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
|
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
|
--- a/net/mac80211/rc80211_minstrel.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel.c
|
||||||
|
@@ -55,7 +55,6 @@
|
||||||
|
#include "rate.h"
|
||||||
|
#include "rc80211_minstrel.h"
|
||||||
|
|
||||||
|
-#define SAMPLE_COLUMNS 10
|
||||||
|
#define SAMPLE_TBL(_mi, _idx, _col) \
|
||||||
|
_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
|
||||||
|
|
||||||
|
@@ -70,16 +69,31 @@ rix_to_ndx(struct minstrel_sta_info *mi,
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* find & sort topmost throughput rates */
|
||||||
|
+static inline void
|
||||||
|
+minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
|
||||||
|
+{
|
||||||
|
+ int j = MAX_THR_RATES;
|
||||||
|
+
|
||||||
|
+ while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp)
|
||||||
|
+ j--;
|
||||||
|
+ if (j < MAX_THR_RATES - 1)
|
||||||
|
+ memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
|
||||||
|
+ if (j < MAX_THR_RATES)
|
||||||
|
+ tp_list[j] = i;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
||||||
|
{
|
||||||
|
- u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
|
||||||
|
- u32 max_prob = 0, index_max_prob = 0;
|
||||||
|
+ u8 tmp_tp_rate[MAX_THR_RATES];
|
||||||
|
+ u8 tmp_prob_rate = 0;
|
||||||
|
u32 usecs;
|
||||||
|
- u32 p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
- mi->stats_update = jiffies;
|
||||||
|
+ for (i=0; i < MAX_THR_RATES; i++)
|
||||||
|
+ tmp_tp_rate[i] = 0;
|
||||||
|
+
|
||||||
|
for (i = 0; i < mi->n_rates; i++) {
|
||||||
|
struct minstrel_rate *mr = &mi->r[i];
|
||||||
|
|
||||||
|
@@ -87,27 +101,32 @@ minstrel_update_stats(struct minstrel_pr
|
||||||
|
if (!usecs)
|
||||||
|
usecs = 1000000;
|
||||||
|
|
||||||
|
- /* To avoid rounding issues, probabilities scale from 0 (0%)
|
||||||
|
- * to 18000 (100%) */
|
||||||
|
- if (mr->attempts) {
|
||||||
|
- p = (mr->success * 18000) / mr->attempts;
|
||||||
|
+ if (unlikely(mr->attempts > 0)) {
|
||||||
|
+ mr->sample_skipped = 0;
|
||||||
|
+ mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
|
||||||
|
mr->succ_hist += mr->success;
|
||||||
|
mr->att_hist += mr->attempts;
|
||||||
|
- mr->cur_prob = p;
|
||||||
|
- p = ((p * (100 - mp->ewma_level)) + (mr->probability *
|
||||||
|
- mp->ewma_level)) / 100;
|
||||||
|
- mr->probability = p;
|
||||||
|
- mr->cur_tp = p * (1000000 / usecs);
|
||||||
|
- }
|
||||||
|
+ mr->probability = minstrel_ewma(mr->probability,
|
||||||
|
+ mr->cur_prob,
|
||||||
|
+ EWMA_LEVEL);
|
||||||
|
+ } else
|
||||||
|
+ mr->sample_skipped++;
|
||||||
|
|
||||||
|
mr->last_success = mr->success;
|
||||||
|
mr->last_attempts = mr->attempts;
|
||||||
|
mr->success = 0;
|
||||||
|
mr->attempts = 0;
|
||||||
|
|
||||||
|
+ /* Update throughput per rate, reset thr. below 10% success */
|
||||||
|
+ if (mr->probability < MINSTREL_FRAC(10, 100))
|
||||||
|
+ mr->cur_tp = 0;
|
||||||
|
+ else
|
||||||
|
+ mr->cur_tp = mr->probability * (1000000 / usecs);
|
||||||
|
+
|
||||||
|
/* Sample less often below the 10% chance of success.
|
||||||
|
* Sample less often above the 95% chance of success. */
|
||||||
|
- if ((mr->probability > 17100) || (mr->probability < 1800)) {
|
||||||
|
+ if (mr->probability > MINSTREL_FRAC(95, 100) ||
|
||||||
|
+ mr->probability < MINSTREL_FRAC(10, 100)) {
|
||||||
|
mr->adjusted_retry_count = mr->retry_count >> 1;
|
||||||
|
if (mr->adjusted_retry_count > 2)
|
||||||
|
mr->adjusted_retry_count = 2;
|
||||||
|
@@ -118,35 +137,30 @@ minstrel_update_stats(struct minstrel_pr
|
||||||
|
}
|
||||||
|
if (!mr->adjusted_retry_count)
|
||||||
|
mr->adjusted_retry_count = 2;
|
||||||
|
- }
|
||||||
|
|
||||||
|
- for (i = 0; i < mi->n_rates; i++) {
|
||||||
|
- struct minstrel_rate *mr = &mi->r[i];
|
||||||
|
- if (max_tp < mr->cur_tp) {
|
||||||
|
- index_max_tp = i;
|
||||||
|
- max_tp = mr->cur_tp;
|
||||||
|
- }
|
||||||
|
- if (max_prob < mr->probability) {
|
||||||
|
- index_max_prob = i;
|
||||||
|
- max_prob = mr->probability;
|
||||||
|
+ minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate);
|
||||||
|
+
|
||||||
|
+ /* To determine the most robust rate (max_prob_rate) used at
|
||||||
|
+ * 3rd mmr stage we distinct between two cases:
|
||||||
|
+ * (1) if any success probabilitiy >= 95%, out of those rates
|
||||||
|
+ * choose the maximum throughput rate as max_prob_rate
|
||||||
|
+ * (2) if all success probabilities < 95%, the rate with
|
||||||
|
+ * highest success probability is choosen as max_prob_rate */
|
||||||
|
+ if (mr->probability >= MINSTREL_FRAC(95,100)) {
|
||||||
|
+ if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
|
||||||
|
+ tmp_prob_rate = i;
|
||||||
|
+ } else {
|
||||||
|
+ if (mr->probability >= mi->r[tmp_prob_rate].probability)
|
||||||
|
+ tmp_prob_rate = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- max_tp = 0;
|
||||||
|
- for (i = 0; i < mi->n_rates; i++) {
|
||||||
|
- struct minstrel_rate *mr = &mi->r[i];
|
||||||
|
-
|
||||||
|
- if (i == index_max_tp)
|
||||||
|
- continue;
|
||||||
|
+ /* Assign the new rate set */
|
||||||
|
+ memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
|
||||||
|
+ mi->max_prob_rate = tmp_prob_rate;
|
||||||
|
|
||||||
|
- if (max_tp < mr->cur_tp) {
|
||||||
|
- index_max_tp2 = i;
|
||||||
|
- max_tp = mr->cur_tp;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- mi->max_tp_rate = index_max_tp;
|
||||||
|
- mi->max_tp_rate2 = index_max_tp2;
|
||||||
|
- mi->max_prob_rate = index_max_prob;
|
||||||
|
+ /* Reset update timer */
|
||||||
|
+ mi->stats_update = jiffies;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
@@ -207,10 +221,10 @@ static int
|
||||||
|
minstrel_get_next_sample(struct minstrel_sta_info *mi)
|
||||||
|
{
|
||||||
|
unsigned int sample_ndx;
|
||||||
|
- sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
|
||||||
|
- mi->sample_idx++;
|
||||||
|
- if ((int) mi->sample_idx > (mi->n_rates - 2)) {
|
||||||
|
- mi->sample_idx = 0;
|
||||||
|
+ sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column);
|
||||||
|
+ mi->sample_row++;
|
||||||
|
+ if ((int) mi->sample_row >= mi->n_rates) {
|
||||||
|
+ mi->sample_row = 0;
|
||||||
|
mi->sample_column++;
|
||||||
|
if (mi->sample_column >= SAMPLE_COLUMNS)
|
||||||
|
mi->sample_column = 0;
|
||||||
|
@@ -228,31 +242,37 @@ minstrel_get_rate(void *priv, struct iee
|
||||||
|
struct minstrel_priv *mp = priv;
|
||||||
|
struct ieee80211_tx_rate *ar = info->control.rates;
|
||||||
|
unsigned int ndx, sample_ndx = 0;
|
||||||
|
- bool mrr;
|
||||||
|
- bool sample_slower = false;
|
||||||
|
- bool sample = false;
|
||||||
|
+ bool mrr_capable;
|
||||||
|
+ bool indirect_rate_sampling = false;
|
||||||
|
+ bool rate_sampling = false;
|
||||||
|
int i, delta;
|
||||||
|
int mrr_ndx[3];
|
||||||
|
- int sample_rate;
|
||||||
|
+ int sampling_ratio;
|
||||||
|
|
||||||
|
+ /* management/no-ack frames do not use rate control */
|
||||||
|
if (rate_control_send_low(sta, priv_sta, txrc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
- mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
|
||||||
|
-
|
||||||
|
- ndx = mi->max_tp_rate;
|
||||||
|
-
|
||||||
|
- if (mrr)
|
||||||
|
- sample_rate = mp->lookaround_rate_mrr;
|
||||||
|
+ /* check multi-rate-retry capabilities & adjust lookaround_rate */
|
||||||
|
+ mrr_capable = mp->has_mrr &&
|
||||||
|
+ !txrc->rts &&
|
||||||
|
+ !txrc->bss_conf->use_cts_prot;
|
||||||
|
+ if (mrr_capable)
|
||||||
|
+ sampling_ratio = mp->lookaround_rate_mrr;
|
||||||
|
else
|
||||||
|
- sample_rate = mp->lookaround_rate;
|
||||||
|
+ sampling_ratio = mp->lookaround_rate;
|
||||||
|
+
|
||||||
|
+ /* init rateindex [ndx] with max throughput rate */
|
||||||
|
+ ndx = mi->max_tp_rate[0];
|
||||||
|
|
||||||
|
+ /* increase sum packet counter */
|
||||||
|
mi->packet_count++;
|
||||||
|
- delta = (mi->packet_count * sample_rate / 100) -
|
||||||
|
+
|
||||||
|
+ delta = (mi->packet_count * sampling_ratio / 100) -
|
||||||
|
(mi->sample_count + mi->sample_deferred / 2);
|
||||||
|
|
||||||
|
/* delta > 0: sampling required */
|
||||||
|
- if ((delta > 0) && (mrr || !mi->prev_sample)) {
|
||||||
|
+ if ((delta > 0) && (mrr_capable || !mi->prev_sample)) {
|
||||||
|
struct minstrel_rate *msr;
|
||||||
|
if (mi->packet_count >= 10000) {
|
||||||
|
mi->sample_deferred = 0;
|
||||||
|
@@ -271,21 +291,28 @@ minstrel_get_rate(void *priv, struct iee
|
||||||
|
mi->sample_count += (delta - mi->n_rates * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* get next random rate sample */
|
||||||
|
sample_ndx = minstrel_get_next_sample(mi);
|
||||||
|
msr = &mi->r[sample_ndx];
|
||||||
|
- sample = true;
|
||||||
|
- sample_slower = mrr && (msr->perfect_tx_time >
|
||||||
|
- mi->r[ndx].perfect_tx_time);
|
||||||
|
+ rate_sampling = true;
|
||||||
|
|
||||||
|
- if (!sample_slower) {
|
||||||
|
+ /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
|
||||||
|
+ * rate sampling method should be used.
|
||||||
|
+ * Respect such rates that are not sampled for 20 interations.
|
||||||
|
+ */
|
||||||
|
+ if (mrr_capable &&
|
||||||
|
+ msr->perfect_tx_time > mi->r[ndx].perfect_tx_time &&
|
||||||
|
+ msr->sample_skipped < 20)
|
||||||
|
+ indirect_rate_sampling = true;
|
||||||
|
+
|
||||||
|
+ if (!indirect_rate_sampling) {
|
||||||
|
if (msr->sample_limit != 0) {
|
||||||
|
ndx = sample_ndx;
|
||||||
|
mi->sample_count++;
|
||||||
|
if (msr->sample_limit > 0)
|
||||||
|
msr->sample_limit--;
|
||||||
|
- } else {
|
||||||
|
- sample = false;
|
||||||
|
- }
|
||||||
|
+ } else
|
||||||
|
+ rate_sampling = false;
|
||||||
|
} else {
|
||||||
|
/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
|
||||||
|
* packets that have the sampling rate deferred to the
|
||||||
|
@@ -297,34 +324,39 @@ minstrel_get_rate(void *priv, struct iee
|
||||||
|
mi->sample_deferred++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- mi->prev_sample = sample;
|
||||||
|
+ mi->prev_sample = rate_sampling;
|
||||||
|
|
||||||
|
/* If we're not using MRR and the sampling rate already
|
||||||
|
* has a probability of >95%, we shouldn't be attempting
|
||||||
|
* to use it, as this only wastes precious airtime */
|
||||||
|
- if (!mrr && sample && (mi->r[ndx].probability > 17100))
|
||||||
|
- ndx = mi->max_tp_rate;
|
||||||
|
+ if (!mrr_capable && rate_sampling &&
|
||||||
|
+ (mi->r[ndx].probability > MINSTREL_FRAC(95, 100)))
|
||||||
|
+ ndx = mi->max_tp_rate[0];
|
||||||
|
|
||||||
|
+ /* mrr setup for 1st stage */
|
||||||
|
ar[0].idx = mi->r[ndx].rix;
|
||||||
|
ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
|
||||||
|
|
||||||
|
- if (!mrr) {
|
||||||
|
- if (!sample)
|
||||||
|
+ /* non mrr setup for 2nd stage */
|
||||||
|
+ if (!mrr_capable) {
|
||||||
|
+ if (!rate_sampling)
|
||||||
|
ar[0].count = mp->max_retry;
|
||||||
|
ar[1].idx = mi->lowest_rix;
|
||||||
|
ar[1].count = mp->max_retry;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* MRR setup */
|
||||||
|
- if (sample) {
|
||||||
|
- if (sample_slower)
|
||||||
|
+ /* mrr setup for 2nd stage */
|
||||||
|
+ if (rate_sampling) {
|
||||||
|
+ if (indirect_rate_sampling)
|
||||||
|
mrr_ndx[0] = sample_ndx;
|
||||||
|
else
|
||||||
|
- mrr_ndx[0] = mi->max_tp_rate;
|
||||||
|
+ mrr_ndx[0] = mi->max_tp_rate[0];
|
||||||
|
} else {
|
||||||
|
- mrr_ndx[0] = mi->max_tp_rate2;
|
||||||
|
+ mrr_ndx[0] = mi->max_tp_rate[1];
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /* mrr setup for 3rd & 4th stage */
|
||||||
|
mrr_ndx[1] = mi->max_prob_rate;
|
||||||
|
mrr_ndx[2] = 0;
|
||||||
|
for (i = 1; i < 4; i++) {
|
||||||
|
@@ -351,26 +383,21 @@ static void
|
||||||
|
init_sample_table(struct minstrel_sta_info *mi)
|
||||||
|
{
|
||||||
|
unsigned int i, col, new_idx;
|
||||||
|
- unsigned int n_srates = mi->n_rates - 1;
|
||||||
|
u8 rnd[8];
|
||||||
|
|
||||||
|
mi->sample_column = 0;
|
||||||
|
- mi->sample_idx = 0;
|
||||||
|
- memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
|
||||||
|
+ mi->sample_row = 0;
|
||||||
|
+ memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
|
||||||
|
|
||||||
|
for (col = 0; col < SAMPLE_COLUMNS; col++) {
|
||||||
|
- for (i = 0; i < n_srates; i++) {
|
||||||
|
+ for (i = 0; i < mi->n_rates; i++) {
|
||||||
|
get_random_bytes(rnd, sizeof(rnd));
|
||||||
|
- new_idx = (i + rnd[i & 7]) % n_srates;
|
||||||
|
+ new_idx = (i + rnd[i & 7]) % mi->n_rates;
|
||||||
|
|
||||||
|
- while (SAMPLE_TBL(mi, new_idx, col) != 0)
|
||||||
|
- new_idx = (new_idx + 1) % n_srates;
|
||||||
|
+ while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
|
||||||
|
+ new_idx = (new_idx + 1) % mi->n_rates;
|
||||||
|
|
||||||
|
- /* Don't sample the slowest rate (i.e. slowest base
|
||||||
|
- * rate). We must presume that the slowest rate works
|
||||||
|
- * fine, or else other management frames will also be
|
||||||
|
- * failing and the link will break */
|
||||||
|
- SAMPLE_TBL(mi, new_idx, col) = i + 1;
|
||||||
|
+ SAMPLE_TBL(mi, new_idx, col) = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -542,9 +569,6 @@ minstrel_alloc(struct ieee80211_hw *hw,
|
||||||
|
mp->lookaround_rate = 5;
|
||||||
|
mp->lookaround_rate_mrr = 10;
|
||||||
|
|
||||||
|
- /* moving average weight for EWMA */
|
||||||
|
- mp->ewma_level = 75;
|
||||||
|
-
|
||||||
|
/* maximum time that the hw is allowed to stay in one MRR segment */
|
||||||
|
mp->segment_size = 6000;
|
||||||
|
|
||||||
|
--- a/net/mac80211/rc80211_minstrel.h
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel.h
|
||||||
|
@@ -9,6 +9,28 @@
|
||||||
|
#ifndef __RC_MINSTREL_H
|
||||||
|
#define __RC_MINSTREL_H
|
||||||
|
|
||||||
|
+#define EWMA_LEVEL 75 /* ewma weighting factor [%] */
|
||||||
|
+#define SAMPLE_COLUMNS 10 /* number of columns in sample table */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/* scaled fraction values */
|
||||||
|
+#define MINSTREL_SCALE 16
|
||||||
|
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||||
|
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||||
|
+
|
||||||
|
+/* number of highest throughput rates to consider*/
|
||||||
|
+#define MAX_THR_RATES 4
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
|
||||||
|
+ */
|
||||||
|
+static inline int
|
||||||
|
+minstrel_ewma(int old, int new, int weight)
|
||||||
|
+{
|
||||||
|
+ return (new * (100 - weight) + old * weight) / 100;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
struct minstrel_rate {
|
||||||
|
int bitrate;
|
||||||
|
int rix;
|
||||||
|
@@ -26,6 +48,7 @@ struct minstrel_rate {
|
||||||
|
u32 attempts;
|
||||||
|
u32 last_attempts;
|
||||||
|
u32 last_success;
|
||||||
|
+ u8 sample_skipped;
|
||||||
|
|
||||||
|
/* parts per thousand */
|
||||||
|
u32 cur_prob;
|
||||||
|
@@ -45,14 +68,13 @@ struct minstrel_sta_info {
|
||||||
|
|
||||||
|
unsigned int lowest_rix;
|
||||||
|
|
||||||
|
- unsigned int max_tp_rate;
|
||||||
|
- unsigned int max_tp_rate2;
|
||||||
|
- unsigned int max_prob_rate;
|
||||||
|
+ u8 max_tp_rate[MAX_THR_RATES];
|
||||||
|
+ u8 max_prob_rate;
|
||||||
|
unsigned int packet_count;
|
||||||
|
unsigned int sample_count;
|
||||||
|
int sample_deferred;
|
||||||
|
|
||||||
|
- unsigned int sample_idx;
|
||||||
|
+ unsigned int sample_row;
|
||||||
|
unsigned int sample_column;
|
||||||
|
|
||||||
|
int n_rates;
|
||||||
|
@@ -73,7 +95,6 @@ struct minstrel_priv {
|
||||||
|
unsigned int cw_min;
|
||||||
|
unsigned int cw_max;
|
||||||
|
unsigned int max_retry;
|
||||||
|
- unsigned int ewma_level;
|
||||||
|
unsigned int segment_size;
|
||||||
|
unsigned int update_interval;
|
||||||
|
unsigned int lookaround_rate;
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_debugfs.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
|
||||||
|
@@ -73,15 +73,17 @@ minstrel_stats_open(struct inode *inode,
|
||||||
|
for (i = 0; i < mi->n_rates; i++) {
|
||||||
|
struct minstrel_rate *mr = &mi->r[i];
|
||||||
|
|
||||||
|
- *(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
|
||||||
|
- *(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
|
||||||
|
+ *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
|
||||||
|
+ *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
|
||||||
|
+ *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' ';
|
||||||
|
+ *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' ';
|
||||||
|
*(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
|
||||||
|
p += sprintf(p, "%3u%s", mr->bitrate / 2,
|
||||||
|
(mr->bitrate & 1 ? ".5" : " "));
|
||||||
|
|
||||||
|
- tp = mr->cur_tp / ((18000 << 10) / 96);
|
||||||
|
- prob = mr->cur_prob / 18;
|
||||||
|
- eprob = mr->probability / 18;
|
||||||
|
+ tp = MINSTREL_TRUNC(mr->cur_tp / 10);
|
||||||
|
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
|
||||||
|
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
|
||||||
|
|
||||||
|
p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
|
||||||
|
"%3u(%3u) %8llu %8llu\n",
|
||||||
|
|
Loading…
Reference in a new issue