aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThomas Huehn <thomas@net.t-labs.tu-berlin.de>2015-03-24 16:09:41 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-04-01 14:44:32 -0400
commit50e55a8ea76fb593403cc09767b6371c17364ba8 (patch)
tree54362ad0fe0bf1506ee1a3cedf213108b60f4e86 /net
parent6a27b2c40b4829e625bc1dfdd0705c5ece720ab4 (diff)
mac80211: add max lossless throughput per rate
This patch adds the new statistic "maximum possible lossless throughput" to Minstrels and Minstrel-HTs rc_stats (in debugfs). This enables comprehensive comparison between current per-rate throughput and max. achievable per-rate throughput. Signed-off-by: Thomas Huehn <thomas@net.t-labs.tu-berlin.de> Acked-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/rc80211_minstrel.c27
-rw-r--r--net/mac80211/rc80211_minstrel.h2
-rw-r--r--net/mac80211/rc80211_minstrel_debugfs.c22
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c84
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h3
-rw-r--r--net/mac80211/rc80211_minstrel_ht_debugfs.c24
6 files changed, 93 insertions, 69 deletions
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 61a857bca971..c4a3477812ee 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
70} 70}
71 71
72/* return current EMWA throughput */ 72/* return current EMWA throughput */
73int minstrel_get_tp_avg(struct minstrel_rate *mr) 73int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
74{ 74{
75 int usecs; 75 int usecs;
76 76
@@ -81,8 +81,11 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
81 /* reset thr. below 10% success */ 81 /* reset thr. below 10% success */
82 if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) 82 if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
83 return 0; 83 return 0;
84
85 if (prob_ewma > MINSTREL_FRAC(90, 100))
86 return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
84 else 87 else
85 return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs)); 88 return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
86} 89}
87 90
88/* find & sort topmost throughput rates */ 91/* find & sort topmost throughput rates */
@@ -90,10 +93,14 @@ static inline void
90minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) 93minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
91{ 94{
92 int j = MAX_THR_RATES; 95 int j = MAX_THR_RATES;
96 struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats;
97 struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
93 98
94 while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) > 99 while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
95 minstrel_get_tp_avg(&mi->r[tp_list[j - 1]]))) 100 minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
96 j--; 101 j--;
102 tmp_mrs = &mi->r[tp_list[j - 1]].stats;
103 }
97 104
98 if (j < MAX_THR_RATES - 1) 105 if (j < MAX_THR_RATES - 1)
99 memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); 106 memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
@@ -184,6 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
184 for (i = 0; i < mi->n_rates; i++) { 191 for (i = 0; i < mi->n_rates; i++) {
185 struct minstrel_rate *mr = &mi->r[i]; 192 struct minstrel_rate *mr = &mi->r[i];
186 struct minstrel_rate_stats *mrs = &mi->r[i].stats; 193 struct minstrel_rate_stats *mrs = &mi->r[i].stats;
194 struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
187 195
188 /* Update success probabilities per rate */ 196 /* Update success probabilities per rate */
189 minstrel_calc_rate_stats(mrs); 197 minstrel_calc_rate_stats(mrs);
@@ -212,12 +220,13 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
212 * (2) if all success probabilities < 95%, the rate with 220 * (2) if all success probabilities < 95%, the rate with
213 * highest success probability is chosen as max_prob_rate */ 221 * highest success probability is chosen as max_prob_rate */
214 if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { 222 if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
215 tmp_cur_tp = minstrel_get_tp_avg(mr); 223 tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
216 tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate]); 224 tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
225 tmp_mrs->prob_ewma);
217 if (tmp_cur_tp >= tmp_prob_tp) 226 if (tmp_cur_tp >= tmp_prob_tp)
218 tmp_prob_rate = i; 227 tmp_prob_rate = i;
219 } else { 228 } else {
220 if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma) 229 if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
221 tmp_prob_rate = i; 230 tmp_prob_rate = i;
222 } 231 }
223 } 232 }
@@ -684,13 +693,15 @@ minstrel_free(void *priv)
684static u32 minstrel_get_expected_throughput(void *priv_sta) 693static u32 minstrel_get_expected_throughput(void *priv_sta)
685{ 694{
686 struct minstrel_sta_info *mi = priv_sta; 695 struct minstrel_sta_info *mi = priv_sta;
696 struct minstrel_rate_stats *tmp_mrs;
687 int idx = mi->max_tp_rate[0]; 697 int idx = mi->max_tp_rate[0];
688 int tmp_cur_tp; 698 int tmp_cur_tp;
689 699
690 /* convert pkt per sec in kbps (1200 is the average pkt size used for 700 /* convert pkt per sec in kbps (1200 is the average pkt size used for
691 * computing cur_tp 701 * computing cur_tp
692 */ 702 */
693 tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx]); 703 tmp_mrs = &mi->r[idx].stats;
704 tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma);
694 tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; 705 tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
695 706
696 return tmp_cur_tp; 707 return tmp_cur_tp;
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 490df3b1f3ec..0083036161af 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -134,7 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
134 134
135/* Recalculate success probabilities and counters for a given rate using EWMA */ 135/* Recalculate success probabilities and counters for a given rate using EWMA */
136void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); 136void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
137int minstrel_get_tp_avg(struct minstrel_rate *mr); 137int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
138 138
139/* debugfs */ 139/* debugfs */
140int minstrel_stats_open(struct inode *inode, struct file *file); 140int minstrel_stats_open(struct inode *inode, struct file *file);
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index 188e9858713f..617b81f72226 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
75{ 75{
76 struct minstrel_sta_info *mi = inode->i_private; 76 struct minstrel_sta_info *mi = inode->i_private;
77 struct minstrel_debugfs_info *ms; 77 struct minstrel_debugfs_info *ms;
78 unsigned int i, tp_avg, prob, eprob; 78 unsigned int i, tp_max, tp_avg, prob, eprob;
79 char *p; 79 char *p;
80 80
81 ms = kmalloc(2048, GFP_KERNEL); 81 ms = kmalloc(2048, GFP_KERNEL);
@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file)
85 file->private_data = ms; 85 file->private_data = ms;
86 p = ms->buf; 86 p = ms->buf;
87 p += sprintf(p, "\n"); 87 p += sprintf(p, "\n");
88 p += sprintf(p, "best _______rate_____ __statistics__ " 88 p += sprintf(p, "best __________rate_________ __statistics__ "
89 "________last_______ ______sum-of________\n"); 89 "________last_______ ______sum-of________\n");
90 p += sprintf(p, "rate [name idx airtime] [ ø(tp) ø(prob)] " 90 p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] "
91 "[prob.|retry|suc|att] [#success | #attempts]\n"); 91 "[prob.|retry|suc|att] [#success | #attempts]\n");
92 92
93 for (i = 0; i < mi->n_rates; i++) { 93 for (i = 0; i < mi->n_rates; i++) {
@@ -103,14 +103,16 @@ minstrel_stats_open(struct inode *inode, struct file *file)
103 p += sprintf(p, " %3u%s ", mr->bitrate / 2, 103 p += sprintf(p, " %3u%s ", mr->bitrate / 2,
104 (mr->bitrate & 1 ? ".5" : " ")); 104 (mr->bitrate & 1 ? ".5" : " "));
105 p += sprintf(p, "%3u ", i); 105 p += sprintf(p, "%3u ", i);
106 p += sprintf(p, "%6u ", mr->perfect_tx_time); 106 p += sprintf(p, "%6u ", mr->perfect_tx_time);
107 107
108 tp_avg = minstrel_get_tp_avg(mr); 108 tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
109 tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
109 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 110 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
110 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 111 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
111 112
112 p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u" 113 p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u"
113 " %3u %-3u %9llu %-9llu\n", 114 " %3u %-3u %9llu %-9llu\n",
115 tp_max / 10, tp_max % 10,
114 tp_avg / 10, tp_avg % 10, 116 tp_avg / 10, tp_avg % 10,
115 eprob / 10, eprob % 10, 117 eprob / 10, eprob % 10,
116 prob / 10, prob % 10, 118 prob / 10, prob % 10,
@@ -144,7 +146,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
144{ 146{
145 struct minstrel_sta_info *mi = inode->i_private; 147 struct minstrel_sta_info *mi = inode->i_private;
146 struct minstrel_debugfs_info *ms; 148 struct minstrel_debugfs_info *ms;
147 unsigned int i, tp_avg, prob, eprob; 149 unsigned int i, tp_max, tp_avg, prob, eprob;
148 char *p; 150 char *p;
149 151
150 ms = kmalloc(2048, GFP_KERNEL); 152 ms = kmalloc(2048, GFP_KERNEL);
@@ -169,12 +171,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
169 p += sprintf(p, "%u,", i); 171 p += sprintf(p, "%u,", i);
170 p += sprintf(p, "%u,",mr->perfect_tx_time); 172 p += sprintf(p, "%u,",mr->perfect_tx_time);
171 173
172 tp_avg = minstrel_get_tp_avg(mr); 174 tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
175 tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
173 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 176 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
174 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 177 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
175 178
176 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," 179 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
177 "%llu,%llu,%d,%d\n", 180 "%llu,%llu,%d,%d\n",
181 tp_max / 10, tp_max % 10,
178 tp_avg / 10, tp_avg % 10, 182 tp_avg / 10, tp_avg % 10,
179 eprob / 10, eprob % 10, 183 eprob / 10, eprob % 10,
180 prob / 10, prob % 10, 184 prob / 10, prob % 10,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 7202e34ec04c..7430a1df2ab1 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
318 * account the expected number of retransmissions and their expected length 318 * account the expected number of retransmissions and their expected length
319 */ 319 */
320int 320int
321minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate) 321minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
322 int prob_ewma)
322{ 323{
323 struct minstrel_rate_stats *mrs;
324 unsigned int nsecs = 0; 324 unsigned int nsecs = 0;
325 unsigned int tmp_prob_ewma;
326
327 mrs = &mi->groups[group].rates[rate];
328 tmp_prob_ewma = mrs->prob_ewma;
329 325
330 /* do not account throughput if sucess prob is below 10% */ 326 /* do not account throughput if sucess prob is below 10% */
331 if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) 327 if (prob_ewma < MINSTREL_FRAC(10, 100))
332 return 0; 328 return 0;
333 329
334 /*
335 * For the throughput calculation, limit the probability value to 90% to
336 * account for collision related packet error rate fluctuation
337 */
338 if (mrs->prob_ewma > MINSTREL_FRAC(90, 100))
339 tmp_prob_ewma = MINSTREL_FRAC(90, 100);
340
341 if (group != MINSTREL_CCK_GROUP) 330 if (group != MINSTREL_CCK_GROUP)
342 nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); 331 nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
343 332
344 nsecs += minstrel_mcs_groups[group].duration[rate]; 333 nsecs += minstrel_mcs_groups[group].duration[rate];
345 334
346 /* prob is scaled - see MINSTREL_FRAC above */ 335 /*
347 return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs)); 336 * For the throughput calculation, limit the probability value to 90% to
337 * account for collision related packet error rate fluctuation
338 * (prob is scaled - see MINSTREL_FRAC above)
339 */
340 if (prob_ewma > MINSTREL_FRAC(90, 100))
341 return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
342 / nsecs));
343 else
344 return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
348} 345}
349 346
350/* 347/*
@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
364 361
365 cur_group = index / MCS_GROUP_RATES; 362 cur_group = index / MCS_GROUP_RATES;
366 cur_idx = index % MCS_GROUP_RATES; 363 cur_idx = index % MCS_GROUP_RATES;
367 cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
368 cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; 364 cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
365 cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
369 366
370 do { 367 do {
371 tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; 368 tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
372 tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; 369 tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
373 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
374 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 370 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
371 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
372 tmp_prob);
375 if (cur_tp_avg < tmp_tp_avg || 373 if (cur_tp_avg < tmp_tp_avg ||
376 (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) 374 (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
377 break; 375 break;
@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
396 struct minstrel_rate_stats *mrs; 394 struct minstrel_rate_stats *mrs;
397 int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; 395 int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
398 int max_tp_group, cur_tp_avg, cur_group, cur_idx; 396 int max_tp_group, cur_tp_avg, cur_group, cur_idx;
399 int max_group_prob_rate_group, max_group_prob_rate_idx; 397 int max_gpr_group, max_gpr_idx;
400 int max_group_prob_rate_tp_avg; 398 int max_gpr_tp_avg, max_gpr_prob;
401 399
402 cur_group = index / MCS_GROUP_RATES; 400 cur_group = index / MCS_GROUP_RATES;
403 cur_idx = index % MCS_GROUP_RATES; 401 cur_idx = index % MCS_GROUP_RATES;
@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
406 404
407 tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; 405 tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
408 tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; 406 tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
409 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
410 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 407 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
408 tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
411 409
412 /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from 410 /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
413 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ 411 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */
@@ -417,18 +415,18 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
417 return; 415 return;
418 416
419 if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { 417 if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
420 cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx); 418 cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
419 mrs->prob_ewma);
421 if (cur_tp_avg > tmp_tp_avg) 420 if (cur_tp_avg > tmp_tp_avg)
422 mi->max_prob_rate = index; 421 mi->max_prob_rate = index;
423 422
424 max_group_prob_rate_group = mg->max_group_prob_rate / 423 max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
425 MCS_GROUP_RATES; 424 max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
426 max_group_prob_rate_idx = mg->max_group_prob_rate % 425 max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
427 MCS_GROUP_RATES; 426 max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
428 max_group_prob_rate_tp_avg = minstrel_ht_get_tp_avg(mi, 427 max_gpr_idx,
429 max_group_prob_rate_group, 428 max_gpr_prob);
430 max_group_prob_rate_idx); 429 if (cur_tp_avg > max_gpr_tp_avg)
431 if (cur_tp_avg > max_group_prob_rate_tp_avg)
432 mg->max_group_prob_rate = index; 430 mg->max_group_prob_rate = index;
433 } else { 431 } else {
434 if (mrs->prob_ewma > tmp_prob) 432 if (mrs->prob_ewma > tmp_prob)
@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
450 u16 tmp_mcs_tp_rate[MAX_THR_RATES], 448 u16 tmp_mcs_tp_rate[MAX_THR_RATES],
451 u16 tmp_cck_tp_rate[MAX_THR_RATES]) 449 u16 tmp_cck_tp_rate[MAX_THR_RATES])
452{ 450{
453 unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; 451 unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob;
454 int i; 452 int i;
455 453
456 tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; 454 tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
457 tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; 455 tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
458 tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); 456 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
457 tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
459 458
460 tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; 459 tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
461 tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; 460 tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
462 tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); 461 tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
462 tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
463 463
464 if (tmp_cck_tp > tmp_mcs_tp) { 464 if (tmp_cck_tp > tmp_mcs_tp) {
465 for(i = 0; i < MAX_THR_RATES; i++) { 465 for(i = 0; i < MAX_THR_RATES; i++) {
@@ -478,7 +478,7 @@ static inline void
478minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) 478minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
479{ 479{
480 struct minstrel_mcs_group_data *mg; 480 struct minstrel_mcs_group_data *mg;
481 int tmp_max_streams, group, tmp_idx; 481 int tmp_max_streams, group, tmp_idx, tmp_prob;
482 int tmp_tp = 0; 482 int tmp_tp = 0;
483 483
484 tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / 484 tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
@@ -489,12 +489,14 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
489 continue; 489 continue;
490 490
491 tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; 491 tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
492 tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
492 493
493 if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx) && 494 if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
494 (minstrel_mcs_groups[group].streams < tmp_max_streams)) { 495 (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
495 mi->max_prob_rate = mg->max_group_prob_rate; 496 mi->max_prob_rate = mg->max_group_prob_rate;
496 tmp_tp = minstrel_ht_get_tp_avg(mi, group, 497 tmp_tp = minstrel_ht_get_tp_avg(mi, group,
497 tmp_idx); 498 tmp_idx,
499 tmp_prob);
498 } 500 }
499 } 501 }
500} 502}
@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
513{ 515{
514 struct minstrel_mcs_group_data *mg; 516 struct minstrel_mcs_group_data *mg;
515 struct minstrel_rate_stats *mrs; 517 struct minstrel_rate_stats *mrs;
516 int group, i, j; 518 int group, i, j, cur_prob;
517 u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; 519 u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
518 u16 tmp_cck_tp_rate[MAX_THR_RATES], index; 520 u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
519 521
@@ -555,8 +557,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
555 mrs = &mg->rates[i]; 557 mrs = &mg->rates[i];
556 mrs->retry_updated = false; 558 mrs->retry_updated = false;
557 minstrel_calc_rate_stats(mrs); 559 minstrel_calc_rate_stats(mrs);
560 cur_prob = mrs->prob_ewma;
558 561
559 if (minstrel_ht_get_tp_avg(mi, group, i) == 0) 562 if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
560 continue; 563 continue;
561 564
562 /* Find max throughput rate set */ 565 /* Find max throughput rate set */
@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
1315{ 1318{
1316 struct minstrel_ht_sta_priv *msp = priv_sta; 1319 struct minstrel_ht_sta_priv *msp = priv_sta;
1317 struct minstrel_ht_sta *mi = &msp->ht; 1320 struct minstrel_ht_sta *mi = &msp->ht;
1318 int i, j, tp_avg; 1321 int i, j, prob, tp_avg;
1319 1322
1320 if (!msp->is_ht) 1323 if (!msp->is_ht)
1321 return mac80211_minstrel.get_expected_throughput(priv_sta); 1324 return mac80211_minstrel.get_expected_throughput(priv_sta);
1322 1325
1323 i = mi->max_tp_rate[0] / MCS_GROUP_RATES; 1326 i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
1324 j = mi->max_tp_rate[0] % MCS_GROUP_RATES; 1327 j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
1328 prob = mi->groups[i].rates[j].prob_ewma;
1325 1329
1326 /* convert tp_avg from pkt per second in kbps */ 1330 /* convert tp_avg from pkt per second in kbps */
1327 tp_avg = minstrel_ht_get_tp_avg(mi, i, j) * AVG_PKT_SIZE * 8 / 1024; 1331 tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
1328 1332
1329 return tp_avg; 1333 return tp_avg;
1330} 1334}
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 68dce4f8641c..e8b52a94d24b 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -121,6 +121,7 @@ struct minstrel_ht_sta_priv {
121 121
122void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 122void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
123void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); 123void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
124int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate); 124int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
125 int prob_ewma);
125 126
126#endif 127#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index 721cf74ea9a6..135ed39790c0 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -19,7 +19,7 @@ static char *
19minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) 19minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
20{ 20{
21 const struct mcs_group *mg; 21 const struct mcs_group *mg;
22 unsigned int j, tp_avg, prob, eprob, tx_time; 22 unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
23 char htmode = '2'; 23 char htmode = '2';
24 char gimode = 'L'; 24 char gimode = 'L';
25 u32 gflags; 25 u32 gflags;
@@ -79,14 +79,16 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
79 79
80 /* tx_time[rate(i)] in usec */ 80 /* tx_time[rate(i)] in usec */
81 tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); 81 tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
82 p += sprintf(p, "%6u ", tx_time); 82 p += sprintf(p, "%6u ", tx_time);
83 83
84 tp_avg = minstrel_ht_get_tp_avg(mi, i, j); 84 tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
85 tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
85 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 86 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
86 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 87 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
87 88
88 p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u " 89 p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u "
89 "%3u %3u %-3u %9llu %-9llu\n", 90 "%3u %3u %-3u %9llu %-9llu\n",
91 tp_max / 10, tp_max % 10,
90 tp_avg / 10, tp_avg % 10, 92 tp_avg / 10, tp_avg % 10,
91 eprob / 10, eprob % 10, 93 eprob / 10, eprob % 10,
92 prob / 10, prob % 10, 94 prob / 10, prob % 10,
@@ -125,11 +127,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
125 p = ms->buf; 127 p = ms->buf;
126 128
127 p += sprintf(p, "\n"); 129 p += sprintf(p, "\n");
128 p += sprintf(p, " best ________rate______ " 130 p += sprintf(p, " best ____________rate__________ "
129 "__statistics__ ________last_______ " 131 "__statistics__ ________last_______ "
130 "______sum-of________\n"); 132 "______sum-of________\n");
131 p += sprintf(p, "mode guard # rate [name idx airtime] [ ø(tp) " 133 p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
132 "ø(prob)] [prob.|retry|suc|att] [#success | " 134 "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | "
133 "#attempts]\n"); 135 "#attempts]\n");
134 136
135 p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); 137 p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
@@ -163,7 +165,7 @@ static char *
163minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) 165minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
164{ 166{
165 const struct mcs_group *mg; 167 const struct mcs_group *mg;
166 unsigned int j, tp_avg, prob, eprob, tx_time; 168 unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
167 char htmode = '2'; 169 char htmode = '2';
168 char gimode = 'L'; 170 char gimode = 'L';
169 u32 gflags; 171 u32 gflags;
@@ -222,11 +224,13 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
222 tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); 224 tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
223 p += sprintf(p, "%u,", tx_time); 225 p += sprintf(p, "%u,", tx_time);
224 226
225 tp_avg = minstrel_ht_get_tp_avg(mi, i, j); 227 tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
228 tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
226 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 229 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
227 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 230 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
228 231
229 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,", 232 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
233 tp_max / 10, tp_max % 10,
230 tp_avg / 10, tp_avg % 10, 234 tp_avg / 10, tp_avg % 10,
231 eprob / 10, eprob % 10, 235 eprob / 10, eprob % 10,
232 prob / 10, prob % 10, 236 prob / 10, prob % 10,