* [PATCH 1/3] mac80211/minstrel_ht: show the number of retries for each rate in debugfs @ 2013-02-08 12:38 Felix Fietkau 2013-02-08 12:38 ` [PATCH 2/3] mac80211/minstrel_ht: remove the sampling bypass check for the lowest rate Felix Fietkau 0 siblings, 1 reply; 5+ messages in thread From: Felix Fietkau @ 2013-02-08 12:38 UTC (permalink / raw) To: linux-wireless; +Cc: johannes Signed-off-by: Felix Fietkau <nbd@openwrt.org> --- net/mac80211/rc80211_minstrel_ht_debugfs.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index e788f76..f2b7d26 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -38,8 +38,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) file->private_data = ms; p = ms->buf; - p += sprintf(p, "type rate throughput ewma prob this prob " - "this succ/attempt success attempts\n"); + 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 gimode = 'L'; @@ -64,18 +64,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; - p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * + p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * MCS_GROUP_RATES + j); tp = 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", + p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " + "%3u %3u(%3u) %8llu %8llu\n", tp / 10, tp % 10, eprob / 10, eprob % 10, prob / 10, prob % 10, + mr->retry_count, mr->last_success, mr->last_attempts, (unsigned long long)mr->succ_hist, -- 1.8.0.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] mac80211/minstrel_ht: remove the sampling bypass check for the lowest rate 2013-02-08 12:38 [PATCH 1/3] mac80211/minstrel_ht: show the number of retries for each rate in debugfs Felix Fietkau @ 2013-02-08 12:38 ` Felix Fietkau 2013-02-08 12:38 ` [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates Felix Fietkau 0 siblings, 1 reply; 5+ messages in thread From: Felix Fietkau @ 2013-02-08 12:38 UTC (permalink / raw) To: linux-wireless; +Cc: johannes It's more of an unnecessary micro-optimization and it prevents switching from long-GI to short-GI in HT20/single-stream for the lowest rate Signed-off-by: Felix Fietkau <nbd@openwrt.org> --- net/mac80211/rc80211_minstrel_ht.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 9f9c453..5bb316a 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -231,10 +231,6 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) if (!mr->cur_tp) continue; - /* ignore the lowest rate of each single-stream group */ - if (!i && minstrel_mcs_groups[group].streams == 1) - continue; - if ((mr->cur_tp > cur_prob_tp && mr->probability > MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { mg->max_prob_rate = index; -- 1.8.0.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates 2013-02-08 12:38 ` [PATCH 2/3] mac80211/minstrel_ht: remove the sampling bypass check for the lowest rate Felix Fietkau @ 2013-02-08 12:38 ` Felix Fietkau 2013-02-08 16:22 ` Paul Stewart 0 siblings, 1 reply; 5+ messages in thread From: Felix Fietkau @ 2013-02-08 12:38 UTC (permalink / raw) To: linux-wireless; +Cc: johannes 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: Felix Fietkau <nbd@openwrt.org> --- net/mac80211/rc80211_minstrel.c | 29 ++++++ net/mac80211/rc80211_minstrel.h | 2 + net/mac80211/rc80211_minstrel_ht.c | 152 +++++++++++++++++++++++++---- net/mac80211/rc80211_minstrel_ht.h | 5 +- net/mac80211/rc80211_minstrel_ht_debugfs.c | 109 +++++++++++++-------- 5 files changed, 237 insertions(+), 60 deletions(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8c5acdc..eea45a2 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) 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 * 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); #endif + minstrel_init_cck_rates(mp); + return mp; } diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 5d278ec..5ecf757 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -79,6 +79,8 @@ struct minstrel_priv { unsigned int lookaround_rate; unsigned int lookaround_rate_mrr; + u8 cck_rates[4]; + #ifdef CONFIG_MAC80211_DEBUGFS /* * enable fixed rate processing per RC diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5bb316a..ba32416 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1,5 +1,5 @@ /* - * 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 * it under the terms of the GNU General Public License version 2 as @@ -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 \ + { \ + .streams = 0, \ + .duration = { \ + CCK_DURATION_LIST(false), \ + CCK_DURATION_LIST(true) \ + } \ + } + /* * To enable sufficiently targeted rate sampling, MCS rates are divided into * groups, based on the number of streams and flags (HT40, SGI) that they @@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { #if MINSTREL_MAX_STREAMS >= 3 MCS_GROUP(3, 1, 1), #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]; /* @@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); } +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 == 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 * minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) { @@ -159,7 +211,7 @@ static void minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) { struct minstrel_rate_stats *mr; - unsigned int usecs; + unsigned int usecs = 0; mr = &mi->groups[group].rates[rate]; @@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) return; } - usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); + if (group != MINSTREL_CCK_GROUP) + usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); + usecs += minstrel_mcs_groups[group].duration[rate]; 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) } 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) return false; @@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) if (!rate->count) 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 @@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, struct minstrel_rate_stats *rate, *rate2; struct minstrel_priv *mp = priv; bool last; - int group; int i; if (!msp->is_ht) @@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) 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++) { 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 = &mi->groups[group].rates[ar[i].idx % 8]; + rate = minstrel_ht_get_stats(mp, mi, &ar[i]); if (last) rate->success += info->status.ampdu_ack_len; @@ -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)) { 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); } } @@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, unsigned int ctime = 0; unsigned int t_slot = 9; /* FIXME */ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); + unsigned int overhead = 0, overhead_rtscts = 0; mr = minstrel_get_ratestats(mi, index); if (mr->probability < MINSTREL_FRAC(1, 10)) { @@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ctime += (t_slot * cw) >> 1; 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 */ - tx_time = ctime + 2 * (mi->overhead + tx_time_data); - tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); + tx_time = ctime + 2 * (overhead + tx_time_data); + tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data); /* See how many more tries we can fit inside segment size */ do { @@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, cw = min((cw << 1) | 1, mp->cw_max); /* Total TX time after this try */ - tx_time += ctime + mi->overhead + tx_time_data; - tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; + tx_time += ctime + overhead + tx_time_data; + tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; if (tx_time_rtscts < mp->segment_size) mr->retry_count_rtscts++; @@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, else rate->count = mr->retry_count; - rate->flags = IEEE80211_TX_RC_MCS | group->flags; + rate->flags = 0; if (rtscts) 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; } @@ -592,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) } 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 minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { @@ -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); 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 */ if (mp->hw->max_rates == 1 && @@ -683,6 +772,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 minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { @@ -702,7 +815,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, goto use_legacy; 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; memset(mi, 0, sizeof(*mi)); @@ -738,6 +851,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, u16 req = 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_40_MHZ_WIDTH) req |= IEEE80211_HT_CAP_SGI_40; diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 462d2b2..302dbd5 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -107,8 +107,11 @@ struct minstrel_ht_sta { /* current MCS group to be sampled */ u8 sample_group; + u8 cck_supported; + u8 cck_supported_short; + /* 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 { diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index f2b7d26..df44a5a 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -15,13 +15,76 @@ #include "rc80211_minstrel.h" #include "rc80211_minstrel_ht.h" +static char * +minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) +{ + unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; + const struct mcs_group *mg; + unsigned int j, tp, prob, eprob; + char htmode = '2'; + char gimode = 'L'; + + if (!mi->groups[i].supported) + return p; + + mg = &minstrel_mcs_groups[i]; + if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + htmode = '4'; + if (mg->flags & IEEE80211_TX_RC_SHORT_GI) + gimode = 'S'; + + for (j = 0; j < MCS_GROUP_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; + + if (!(mi->groups[i].supported & BIT(j))) + continue; + + if (i == max_mcs) + p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); + else + p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); + + *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; + *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; + *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; + + 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); + } + + tp = 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(%3u) %8llu %8llu\n", + tp / 10, tp % 10, + eprob / 10, eprob % 10, + prob / 10, prob % 10, + mr->retry_count, + mr->last_success, + mr->last_attempts, + (unsigned long long)mr->succ_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, j, tp, prob, eprob; + unsigned int i; + unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; char *p; int ret; @@ -40,49 +103,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) 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 gimode = 'L'; - - if (!mi->groups[i].supported) - continue; - - if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - htmode = '4'; - if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) - gimode = 'S'; - for (j = 0; j < MCS_GROUP_RATES; j++) { - struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; - int idx = i * MCS_GROUP_RATES + j; + p = minstrel_ht_stats_dump(mi, max_mcs, p); + for (i = 0; i < max_mcs; i++) + p = minstrel_ht_stats_dump(mi, i, p); - if (!(mi->groups[i].supported & BIT(j))) - continue; - - p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); - - *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; - *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; - *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; - p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * - MCS_GROUP_RATES + j); - - tp = 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(%3u) %8llu %8llu\n", - tp / 10, tp % 10, - eprob / 10, eprob % 10, - prob / 10, prob % 10, - mr->retry_count, - mr->last_success, - mr->last_attempts, - (unsigned long long)mr->succ_hist, - (unsigned long long)mr->att_hist); - } - } p += sprintf(p, "\nTotal packet count:: ideal %d " "lookaround %d\n", max(0, (int) mi->total_packets - (int) mi->sample_packets), -- 1.8.0.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates 2013-02-08 12:38 ` [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates Felix Fietkau @ 2013-02-08 16:22 ` Paul Stewart 2013-02-08 16:32 ` Felix Fietkau 0 siblings, 1 reply; 5+ messages in thread From: Paul Stewart @ 2013-02-08 16:22 UTC (permalink / raw) To: Felix Fietkau; +Cc: linux-wireless, Johannes Berg On Fri, Feb 8, 2013 at 4:38 AM, Felix Fietkau <nbd@openwrt.org> wrote: > > 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: Felix Fietkau <nbd@openwrt.org> > --- > net/mac80211/rc80211_minstrel.c | 29 ++++++ > net/mac80211/rc80211_minstrel.h | 2 + > net/mac80211/rc80211_minstrel_ht.c | 152 +++++++++++++++++++++++++---- > net/mac80211/rc80211_minstrel_ht.h | 5 +- > net/mac80211/rc80211_minstrel_ht_debugfs.c | 109 +++++++++++++-------- > 5 files changed, 237 insertions(+), 60 deletions(-) > > diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c > index 8c5acdc..eea45a2 100644 > --- a/net/mac80211/rc80211_minstrel.c > +++ b/net/mac80211/rc80211_minstrel.c > @@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) > 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 * > 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); > #endif > > + minstrel_init_cck_rates(mp); > + > return mp; > } > > diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h > index 5d278ec..5ecf757 100644 > --- a/net/mac80211/rc80211_minstrel.h > +++ b/net/mac80211/rc80211_minstrel.h > @@ -79,6 +79,8 @@ struct minstrel_priv { > unsigned int lookaround_rate; > unsigned int lookaround_rate_mrr; > > + u8 cck_rates[4]; > + > #ifdef CONFIG_MAC80211_DEBUGFS > /* > * enable fixed rate processing per RC > diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c > index 5bb316a..ba32416 100644 > --- a/net/mac80211/rc80211_minstrel_ht.c > +++ b/net/mac80211/rc80211_minstrel_ht.c > @@ -1,5 +1,5 @@ > /* > - * 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 > * it under the terms of the GNU General Public License version 2 as > @@ -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 \ > + { \ > + .streams = 0, \ > + .duration = { \ > + CCK_DURATION_LIST(false), \ > + CCK_DURATION_LIST(true) \ > + } \ > + } > + > /* > * To enable sufficiently targeted rate sampling, MCS rates are divided into > * groups, based on the number of streams and flags (HT40, SGI) that they > @@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { > #if MINSTREL_MAX_STREAMS >= 3 > MCS_GROUP(3, 1, 1), > #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]; > > /* > @@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) > !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); > } > > +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 == idx) > + break; Either this if statement isn't doing what you think it does (perhaps you wanted rate->idx == mp->cck_rates[i]?) or this whole loop could be simplified with an if statement? > + > + /* short preamble */ > + if (!(mi->groups[group].supported & BIT(idx))) > + idx += 4; > + } > + return &mi->groups[group].rates[idx]; > +} > + > static inline struct minstrel_rate_stats * > minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) > { > @@ -159,7 +211,7 @@ static void > minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) > { > struct minstrel_rate_stats *mr; > - unsigned int usecs; > + unsigned int usecs = 0; > > mr = &mi->groups[group].rates[rate]; > > @@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) > return; > } > > - usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); > + if (group != MINSTREL_CCK_GROUP) > + usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); > + > usecs += minstrel_mcs_groups[group].duration[rate]; > 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) > } > > 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) > return false; > @@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) > if (!rate->count) > 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 > @@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, > struct minstrel_rate_stats *rate, *rate2; > struct minstrel_priv *mp = priv; > bool last; > - int group; > int i; > > if (!msp->is_ht) > @@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, > if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) > 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++) { > 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 = &mi->groups[group].rates[ar[i].idx % 8]; > + rate = minstrel_ht_get_stats(mp, mi, &ar[i]); > > if (last) > rate->success += info->status.ampdu_ack_len; > @@ -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)) { > 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); > } > } > @@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, > unsigned int ctime = 0; > unsigned int t_slot = 9; /* FIXME */ > unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); > + unsigned int overhead = 0, overhead_rtscts = 0; > > mr = minstrel_get_ratestats(mi, index); > if (mr->probability < MINSTREL_FRAC(1, 10)) { > @@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, > ctime += (t_slot * cw) >> 1; > 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 */ > - tx_time = ctime + 2 * (mi->overhead + tx_time_data); > - tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); > + tx_time = ctime + 2 * (overhead + tx_time_data); > + tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data); > > /* See how many more tries we can fit inside segment size */ > do { > @@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, > cw = min((cw << 1) | 1, mp->cw_max); > > /* Total TX time after this try */ > - tx_time += ctime + mi->overhead + tx_time_data; > - tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; > + tx_time += ctime + overhead + tx_time_data; > + tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; > > if (tx_time_rtscts < mp->segment_size) > mr->retry_count_rtscts++; > @@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, > else > rate->count = mr->retry_count; > > - rate->flags = IEEE80211_TX_RC_MCS | group->flags; > + rate->flags = 0; > if (rtscts) > 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; > } > > @@ -592,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) > } > > 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 > minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, > struct ieee80211_tx_rate_control *txrc) > { > @@ -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); > > 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 */ > if (mp->hw->max_rates == 1 && > @@ -683,6 +772,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 > minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, > struct ieee80211_sta *sta, void *priv_sta) > { > @@ -702,7 +815,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, > goto use_legacy; > > 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; > memset(mi, 0, sizeof(*mi)); > @@ -738,6 +851,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, > u16 req = 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_40_MHZ_WIDTH) > req |= IEEE80211_HT_CAP_SGI_40; > diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h > index 462d2b2..302dbd5 100644 > --- a/net/mac80211/rc80211_minstrel_ht.h > +++ b/net/mac80211/rc80211_minstrel_ht.h > @@ -107,8 +107,11 @@ struct minstrel_ht_sta { > /* current MCS group to be sampled */ > u8 sample_group; > > + u8 cck_supported; > + u8 cck_supported_short; > + > /* 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 { > diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c > index f2b7d26..df44a5a 100644 > --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c > +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c > @@ -15,13 +15,76 @@ > #include "rc80211_minstrel.h" > #include "rc80211_minstrel_ht.h" > > +static char * > +minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) > +{ > + unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; > + const struct mcs_group *mg; > + unsigned int j, tp, prob, eprob; > + char htmode = '2'; > + char gimode = 'L'; > + > + if (!mi->groups[i].supported) > + return p; > + > + mg = &minstrel_mcs_groups[i]; > + if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) > + htmode = '4'; > + if (mg->flags & IEEE80211_TX_RC_SHORT_GI) > + gimode = 'S'; > + > + for (j = 0; j < MCS_GROUP_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; > + > + if (!(mi->groups[i].supported & BIT(j))) > + continue; > + > + if (i == max_mcs) > + p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); > + else > + p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); > + > + *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; > + *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; > + *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; > + > + 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); > + } > + > + tp = 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(%3u) %8llu %8llu\n", > + tp / 10, tp % 10, > + eprob / 10, eprob % 10, > + prob / 10, prob % 10, > + mr->retry_count, > + mr->last_success, > + mr->last_attempts, > + (unsigned long long)mr->succ_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, j, tp, prob, eprob; > + unsigned int i; > + unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; > char *p; > int ret; > > @@ -40,49 +103,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) > 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 gimode = 'L'; > - > - if (!mi->groups[i].supported) > - continue; > - > - if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) > - htmode = '4'; > - if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) > - gimode = 'S'; > > - for (j = 0; j < MCS_GROUP_RATES; j++) { > - struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; > - int idx = i * MCS_GROUP_RATES + j; > + p = minstrel_ht_stats_dump(mi, max_mcs, p); > + for (i = 0; i < max_mcs; i++) > + p = minstrel_ht_stats_dump(mi, i, p); > > - if (!(mi->groups[i].supported & BIT(j))) > - continue; > - > - p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); > - > - *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; > - *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; > - *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; > - p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * > - MCS_GROUP_RATES + j); > - > - tp = 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(%3u) %8llu %8llu\n", > - tp / 10, tp % 10, > - eprob / 10, eprob % 10, > - prob / 10, prob % 10, > - mr->retry_count, > - mr->last_success, > - mr->last_attempts, > - (unsigned long long)mr->succ_hist, > - (unsigned long long)mr->att_hist); > - } > - } > p += sprintf(p, "\nTotal packet count:: ideal %d " > "lookaround %d\n", > max(0, (int) mi->total_packets - (int) mi->sample_packets), > -- > 1.8.0.2 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-wireless" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates 2013-02-08 16:22 ` Paul Stewart @ 2013-02-08 16:32 ` Felix Fietkau 0 siblings, 0 replies; 5+ messages in thread From: Felix Fietkau @ 2013-02-08 16:32 UTC (permalink / raw) To: Paul Stewart; +Cc: linux-wireless, Johannes Berg On 2013-02-08 5:22 PM, Paul Stewart wrote: > On Fri, Feb 8, 2013 at 4:38 AM, Felix Fietkau <nbd@openwrt.org> wrote: >> >> 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: Felix Fietkau <nbd@openwrt.org> >> --- >> net/mac80211/rc80211_minstrel.c | 29 ++++++ >> net/mac80211/rc80211_minstrel.h | 2 + >> net/mac80211/rc80211_minstrel_ht.c | 152 +++++++++++++++++++++++++---- >> net/mac80211/rc80211_minstrel_ht.h | 5 +- >> net/mac80211/rc80211_minstrel_ht_debugfs.c | 109 +++++++++++++-------- >> 5 files changed, 237 insertions(+), 60 deletions(-) >> >> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c >> index 8c5acdc..eea45a2 100644 >> --- a/net/mac80211/rc80211_minstrel.c >> +++ b/net/mac80211/rc80211_minstrel.c >> @@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) >> 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 * >> 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); >> #endif >> >> + minstrel_init_cck_rates(mp); >> + >> return mp; >> } >> >> diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h >> index 5d278ec..5ecf757 100644 >> --- a/net/mac80211/rc80211_minstrel.h >> +++ b/net/mac80211/rc80211_minstrel.h >> @@ -79,6 +79,8 @@ struct minstrel_priv { >> unsigned int lookaround_rate; >> unsigned int lookaround_rate_mrr; >> >> + u8 cck_rates[4]; >> + >> #ifdef CONFIG_MAC80211_DEBUGFS >> /* >> * enable fixed rate processing per RC >> diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c >> index 5bb316a..ba32416 100644 >> --- a/net/mac80211/rc80211_minstrel_ht.c >> +++ b/net/mac80211/rc80211_minstrel_ht.c >> @@ -1,5 +1,5 @@ >> /* >> - * 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 >> * it under the terms of the GNU General Public License version 2 as >> @@ -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 \ >> + { \ >> + .streams = 0, \ >> + .duration = { \ >> + CCK_DURATION_LIST(false), \ >> + CCK_DURATION_LIST(true) \ >> + } \ >> + } >> + >> /* >> * To enable sufficiently targeted rate sampling, MCS rates are divided into >> * groups, based on the number of streams and flags (HT40, SGI) that they >> @@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { >> #if MINSTREL_MAX_STREAMS >= 3 >> MCS_GROUP(3, 1, 1), >> #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]; >> >> /* >> @@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) >> !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); >> } >> >> +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 == idx) >> + break; > Either this if statement isn't doing what you think it does (perhaps > you wanted rate->idx == mp->cck_rates[i]?) or this whole loop could be > simplified with an if statement? Right, thanks. By the way, I meant rate->idx == mp->cck_rates[idx]. It happened to work in my tests because both variants are equivalent on ath9k, but that may not be true for other drivers. :) - Felix ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-02-08 16:32 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-02-08 12:38 [PATCH 1/3] mac80211/minstrel_ht: show the number of retries for each rate in debugfs Felix Fietkau 2013-02-08 12:38 ` [PATCH 2/3] mac80211/minstrel_ht: remove the sampling bypass check for the lowest rate Felix Fietkau 2013-02-08 12:38 ` [PATCH 3/3] mac80211/minstrel_ht: add support for using CCK rates Felix Fietkau 2013-02-08 16:22 ` Paul Stewart 2013-02-08 16:32 ` Felix Fietkau
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.