Commit a0497f9f authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg

mac80211/minstrel_ht: add support for using CCK rates

When MCS rates start to get bad in 2.4 GHz because of long range or
strong interference, CCK rates can be a lot more robust.

This patch adds a pseudo MCS group containing CCK rates (long preamble
in the lower 4 slots, short preamble in the upper slots).
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
[make minstrel_ht_get_stats static]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 6719429d
...@@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) ...@@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
kfree(mi); kfree(mi);
} }
static void
minstrel_init_cck_rates(struct minstrel_priv *mp)
{
static const int bitrates[4] = { 10, 20, 55, 110 };
struct ieee80211_supported_band *sband;
int i, j;
sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
return;
for (i = 0, j = 0; i < sband->n_bitrates; i++) {
struct ieee80211_rate *rate = &sband->bitrates[i];
if (rate->flags & IEEE80211_RATE_ERP_G)
continue;
for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
if (rate->bitrate != bitrates[j])
continue;
mp->cck_rates[j] = i;
break;
}
}
}
static void * static void *
minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{ {
...@@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) ...@@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx);
#endif #endif
minstrel_init_cck_rates(mp);
return mp; return mp;
} }
......
...@@ -79,6 +79,8 @@ struct minstrel_priv { ...@@ -79,6 +79,8 @@ struct minstrel_priv {
unsigned int lookaround_rate; unsigned int lookaround_rate;
unsigned int lookaround_rate_mrr; unsigned int lookaround_rate_mrr;
u8 cck_rates[4];
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
/* /*
* enable fixed rate processing per RC * enable fixed rate processing per RC
......
/* /*
* Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -63,6 +63,30 @@ ...@@ -63,6 +63,30 @@
} \ } \
} }
#define CCK_DURATION(_bitrate, _short, _len) \
(10 /* SIFS */ + \
(_short ? 72 + 24 : 144 + 48 ) + \
(8 * (_len + 4) * 10) / (_bitrate))
#define CCK_ACK_DURATION(_bitrate, _short) \
(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
#define CCK_DURATION_LIST(_short) \
CCK_ACK_DURATION(10, _short), \
CCK_ACK_DURATION(20, _short), \
CCK_ACK_DURATION(55, _short), \
CCK_ACK_DURATION(110, _short)
#define CCK_GROUP \
[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \
.streams = 0, \
.duration = { \
CCK_DURATION_LIST(false), \
CCK_DURATION_LIST(true) \
} \
}
/* /*
* To enable sufficiently targeted rate sampling, MCS rates are divided into * To enable sufficiently targeted rate sampling, MCS rates are divided into
* groups, based on the number of streams and flags (HT40, SGI) that they * groups, based on the number of streams and flags (HT40, SGI) that they
...@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { ...@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = {
#if MINSTREL_MAX_STREAMS >= 3 #if MINSTREL_MAX_STREAMS >= 3
MCS_GROUP(3, 1, 1), MCS_GROUP(3, 1, 1),
#endif #endif
/* must be last */
CCK_GROUP
}; };
#define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1)
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
/* /*
...@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) ...@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
!!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
} }
static struct minstrel_rate_stats *
minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_tx_rate *rate)
{
int group, idx;
if (rate->flags & IEEE80211_TX_RC_MCS) {
group = minstrel_ht_get_group_idx(rate);
idx = rate->idx % MCS_GROUP_RATES;
} else {
group = MINSTREL_CCK_GROUP;
for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++)
if (rate->idx == mp->cck_rates[idx])
break;
/* short preamble */
if (!(mi->groups[group].supported & BIT(idx)))
idx += 4;
}
return &mi->groups[group].rates[idx];
}
static inline struct minstrel_rate_stats * static inline struct minstrel_rate_stats *
minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
{ {
...@@ -159,7 +211,7 @@ static void ...@@ -159,7 +211,7 @@ 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;
unsigned int usecs; unsigned int usecs = 0;
mr = &mi->groups[group].rates[rate]; mr = &mi->groups[group].rates[rate];
...@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) ...@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
return; return;
} }
if (group != MINSTREL_CCK_GROUP)
usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
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);
} }
...@@ -293,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ...@@ -293,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
} }
static bool static bool
minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate)
{ {
if (rate->idx < 0) if (rate->idx < 0)
return false; return false;
...@@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) ...@@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
if (!rate->count) if (!rate->count)
return false; return false;
return !!(rate->flags & IEEE80211_TX_RC_MCS); if (rate->flags & IEEE80211_TX_RC_MCS)
return true;
return rate->idx == mp->cck_rates[0] ||
rate->idx == mp->cck_rates[1] ||
rate->idx == mp->cck_rates[2] ||
rate->idx == mp->cck_rates[3];
} }
static void static void
...@@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, ...@@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct minstrel_rate_stats *rate, *rate2; struct minstrel_rate_stats *rate, *rate2;
struct minstrel_priv *mp = priv; struct minstrel_priv *mp = priv;
bool last; bool last;
int group;
int i; int i;
if (!msp->is_ht) if (!msp->is_ht)
...@@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, ...@@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
mi->sample_packets += info->status.ampdu_len; mi->sample_packets += info->status.ampdu_len;
last = !minstrel_ht_txstat_valid(&ar[0]); last = !minstrel_ht_txstat_valid(mp, &ar[0]);
for (i = 0; !last; i++) { for (i = 0; !last; i++) {
last = (i == IEEE80211_TX_MAX_RATES - 1) || last = (i == IEEE80211_TX_MAX_RATES - 1) ||
!minstrel_ht_txstat_valid(&ar[i + 1]); !minstrel_ht_txstat_valid(mp, &ar[i + 1]);
group = minstrel_ht_get_group_idx(&ar[i]); rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
rate = &mi->groups[group].rates[ar[i].idx % 8];
if (last) if (last)
rate->success += info->status.ampdu_ack_len; rate->success += info->status.ampdu_ack_len;
...@@ -447,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, ...@@ -447,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
minstrel_ht_update_stats(mp, mi); minstrel_ht_update_stats(mp, mi);
if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
minstrel_aggr_check(sta, skb); minstrel_aggr_check(sta, skb);
} }
} }
...@@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ...@@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
unsigned int ctime = 0; unsigned int ctime = 0;
unsigned int t_slot = 9; /* FIXME */ unsigned int t_slot = 9; /* FIXME */
unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
unsigned int overhead = 0, overhead_rtscts = 0;
mr = minstrel_get_ratestats(mi, index); mr = minstrel_get_ratestats(mi, index);
if (mr->probability < MINSTREL_FRAC(1, 10)) { if (mr->probability < MINSTREL_FRAC(1, 10)) {
...@@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ...@@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
ctime += (t_slot * cw) >> 1; ctime += (t_slot * cw) >> 1;
cw = min((cw << 1) | 1, mp->cw_max); cw = min((cw << 1) | 1, mp->cw_max);
if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) {
overhead = mi->overhead;
overhead_rtscts = mi->overhead_rtscts;
}
/* Total TX time for data and Contention after first 2 tries */ /* Total TX time for data and Contention after first 2 tries */
tx_time = ctime + 2 * (mi->overhead + tx_time_data); tx_time = ctime + 2 * (overhead + tx_time_data);
tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data);
/* See how many more tries we can fit inside segment size */ /* See how many more tries we can fit inside segment size */
do { do {
...@@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ...@@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
cw = min((cw << 1) | 1, mp->cw_max); cw = min((cw << 1) | 1, mp->cw_max);
/* Total TX time after this try */ /* Total TX time after this try */
tx_time += ctime + mi->overhead + tx_time_data; tx_time += ctime + overhead + tx_time_data;
tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;
if (tx_time_rtscts < mp->segment_size) if (tx_time_rtscts < mp->segment_size)
mr->retry_count_rtscts++; mr->retry_count_rtscts++;
...@@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ...@@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
else else
rate->count = mr->retry_count; rate->count = mr->retry_count;
rate->flags = IEEE80211_TX_RC_MCS | group->flags; rate->flags = 0;
if (rtscts) if (rtscts)
rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
return;
}
rate->flags |= IEEE80211_TX_RC_MCS | group->flags;
rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
} }
...@@ -591,6 +663,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ...@@ -591,6 +663,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
return sample_idx; return sample_idx;
} }
static void
minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp,
struct minstrel_ht_sta *mi, bool val)
{
u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported;
if (!supported || !mi->cck_supported_short)
return;
if (supported & (mi->cck_supported_short << (val * 4)))
return;
supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4);
mi->groups[MINSTREL_CCK_GROUP].supported = supported;
}
static void static void
minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate_control *txrc) struct ieee80211_tx_rate_control *txrc)
...@@ -610,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ...@@ -610,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
info->flags |= mi->tx_flags; info->flags |= mi->tx_flags;
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
/* Don't use EAPOL frames for sampling on non-mrr hw */ /* Don't use EAPOL frames for sampling on non-mrr hw */
if (mp->hw->max_rates == 1 && if (mp->hw->max_rates == 1 &&
...@@ -682,6 +771,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ...@@ -682,6 +771,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
} }
} }
static void
minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta)
{
int i;
if (sband->band != IEEE80211_BAND_2GHZ)
return;
mi->cck_supported = 0;
mi->cck_supported_short = 0;
for (i = 0; i < 4; i++) {
if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
continue;
mi->cck_supported |= BIT(i);
if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
mi->cck_supported_short |= BIT(i);
}
mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported;
}
static void static void
minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta) struct ieee80211_sta *sta, void *priv_sta)
...@@ -702,7 +815,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, ...@@ -702,7 +815,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
goto use_legacy; goto use_legacy;
BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
msp->is_ht = true; msp->is_ht = true;
memset(mi, 0, sizeof(*mi)); memset(mi, 0, sizeof(*mi));
...@@ -738,6 +851,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, ...@@ -738,6 +851,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
u16 req = 0; u16 req = 0;
mi->groups[i].supported = 0; mi->groups[i].supported = 0;
if (i == MINSTREL_CCK_GROUP) {
minstrel_ht_update_cck(mp, mi, sband, sta);
continue;
}
if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
req |= IEEE80211_HT_CAP_SGI_40; req |= IEEE80211_HT_CAP_SGI_40;
......
...@@ -107,8 +107,11 @@ struct minstrel_ht_sta { ...@@ -107,8 +107,11 @@ struct minstrel_ht_sta {
/* current MCS group to be sampled */ /* current MCS group to be sampled */
u8 sample_group; u8 sample_group;
u8 cck_supported;
u8 cck_supported_short;
/* MCS rate group info and statistics */ /* MCS rate group info and statistics */
struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1];
}; };
struct minstrel_ht_sta_priv { struct minstrel_ht_sta_priv {
......
...@@ -15,57 +15,48 @@ ...@@ -15,57 +15,48 @@
#include "rc80211_minstrel.h" #include "rc80211_minstrel.h"
#include "rc80211_minstrel_ht.h" #include "rc80211_minstrel_ht.h"
static int static char *
minstrel_ht_stats_open(struct inode *inode, struct file *file) minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{ {
struct minstrel_ht_sta_priv *msp = inode->i_private; unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
struct minstrel_ht_sta *mi = &msp->ht; const struct mcs_group *mg;
struct minstrel_debugfs_info *ms; unsigned int j, tp, prob, eprob;
unsigned int i, j, tp, prob, eprob;
char *p;
int ret;
if (!msp->is_ht) {
inode->i_private = &msp->legacy;
ret = minstrel_stats_open(inode, file);
inode->i_private = msp;
return ret;
}
ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
if (!ms)
return -ENOMEM;
file->private_data = ms;
p = ms->buf;
p += sprintf(p, "type rate throughput ewma prob this prob "
"retry this succ/attempt success attempts\n");
for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
char htmode = '2'; char htmode = '2';
char gimode = 'L'; char gimode = 'L';
if (!mi->groups[i].supported) if (!mi->groups[i].supported)
continue; return p;
if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) mg = &minstrel_mcs_groups[i];
if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
htmode = '4'; htmode = '4';
if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) if (mg->flags & IEEE80211_TX_RC_SHORT_GI)
gimode = 'S'; gimode = 'S';
for (j = 0; j < MCS_GROUP_RATES; j++) { for (j = 0; j < MCS_GROUP_RATES; j++) {
struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
static const int bitrates[4] = { 10, 20, 55, 110 };
int idx = i * MCS_GROUP_RATES + j; int idx = i * MCS_GROUP_RATES + j;
if (!(mi->groups[i].supported & BIT(j))) if (!(mi->groups[i].supported & BIT(j)))
continue; continue;
if (i == max_mcs)
p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S');
else
p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
*(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
*(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
if (i == max_mcs) {
int r = bitrates[j % 4];
p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
} else {
p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
MCS_GROUP_RATES + j); MCS_GROUP_RATES + j);
}
tp = mr->cur_tp / 10; tp = mr->cur_tp / 10;
prob = MINSTREL_TRUNC(mr->cur_prob * 1000); prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
...@@ -82,7 +73,41 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) ...@@ -82,7 +73,41 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
(unsigned long long)mr->succ_hist, (unsigned long long)mr->succ_hist,
(unsigned long long)mr->att_hist); (unsigned long long)mr->att_hist);
} }
return p;
}
static int
minstrel_ht_stats_open(struct inode *inode, struct file *file)
{
struct minstrel_ht_sta_priv *msp = inode->i_private;
struct minstrel_ht_sta *mi = &msp->ht;
struct minstrel_debugfs_info *ms;
unsigned int i;
unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
char *p;
int ret;
if (!msp->is_ht) {
inode->i_private = &msp->legacy;
ret = minstrel_stats_open(inode, file);
inode->i_private = msp;
return ret;
} }
ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
if (!ms)
return -ENOMEM;
file->private_data = ms;
p = ms->buf;
p += sprintf(p, "type rate throughput ewma prob this prob "
"retry this succ/attempt success attempts\n");
p = minstrel_ht_stats_dump(mi, max_mcs, p);
for (i = 0; i < max_mcs; i++)
p = minstrel_ht_stats_dump(mi, i, p);
p += sprintf(p, "\nTotal packet count:: ideal %d " p += sprintf(p, "\nTotal packet count:: ideal %d "
"lookaround %d\n", "lookaround %d\n",
max(0, (int) mi->total_packets - (int) mi->sample_packets), max(0, (int) mi->total_packets - (int) mi->sample_packets),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment