source: trunk/package/mac80211/patches/560-minstrel_ht.patch @ 20114

Last change on this file since 20114 was 20114, checked in by nbd, 7 years ago

mac80211/ath9k: fix duration calculation for short-guard-interval frames (thanks to Duy Nguyen for pointing this out)

File size: 29.9 KB
  • net/mac80211/Makefile

    a b CFLAGS_driver-trace.o := -I$(src) 
    4747rc80211_pid-y := rc80211_pid_algo.o 
    4848rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o 
    4949 
    50 rc80211_minstrel-y := rc80211_minstrel.o 
    51 rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o 
     50rc80211_minstrel-y := rc80211_minstrel.o rc80211_minstrel_ht.o 
     51rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o rc80211_minstrel_ht_debugfs.o 
    5252 
    5353mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) 
    5454mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) 
  • net/mac80211/main.c

    a b static int __init ieee80211_init(void) 
    714714        if (ret) 
    715715                return ret; 
    716716 
     717        ret = rc80211_minstrel_ht_init(); 
     718        if (ret) 
     719                goto err_minstrel; 
     720 
    717721        ret = rc80211_pid_init(); 
    718722        if (ret) 
    719723                goto err_pid; 
    static int __init ieee80211_init(void) 
    726730 err_netdev: 
    727731        rc80211_pid_exit(); 
    728732 err_pid: 
     733        rc80211_minstrel_ht_exit(); 
     734 err_minstrel: 
    729735        rc80211_minstrel_exit(); 
    730736 
    731737        return ret; 
    static int __init ieee80211_init(void) 
    734740static void __exit ieee80211_exit(void) 
    735741{ 
    736742        rc80211_pid_exit(); 
     743        rc80211_minstrel_ht_exit(); 
    737744        rc80211_minstrel_exit(); 
    738745 
    739746        /* 
  • net/mac80211/rate.h

    a b static inline void rc80211_pid_exit(void 
    137137#ifdef CONFIG_MAC80211_RC_MINSTREL 
    138138extern int rc80211_minstrel_init(void); 
    139139extern void rc80211_minstrel_exit(void); 
     140extern int rc80211_minstrel_ht_init(void); 
     141extern void rc80211_minstrel_ht_exit(void); 
    140142#else 
    141143static inline int rc80211_minstrel_init(void) 
    142144{ 
    static inline int rc80211_minstrel_init( 
    145147static inline void rc80211_minstrel_exit(void) 
    146148{ 
    147149} 
     150static inline int rc80211_minstrel_ht_init(void) 
     151{ 
     152        return 0; 
     153} 
     154static inline void rc80211_minstrel_ht_exit(void) 
     155{ 
     156} 
    148157#endif 
    149158 
    150159 
  • new file net/mac80211/rc80211_minstrel_ht.c

    - +  
     1/* 
     2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 
     3 * 
     4 * This program is free software; you can redistribute it and/or modify 
     5 * it under the terms of the GNU General Public License version 2 as 
     6 * published by the Free Software Foundation. 
     7 */ 
     8#include <linux/netdevice.h> 
     9#include <linux/types.h> 
     10#include <linux/skbuff.h> 
     11#include <linux/debugfs.h> 
     12#include <linux/random.h> 
     13#include <linux/ieee80211.h> 
     14#include <net/mac80211.h> 
     15#include "rate.h" 
     16#include "rc80211_minstrel.h" 
     17#include "rc80211_minstrel_ht.h" 
     18 
     19#define AVG_PKT_SIZE    1200 
     20#define SAMPLE_COLUMNS  10 
     21#define EWMA_LEVEL              75 
     22 
     23/* Number of bits for an average sized packet */ 
     24#define MCS_NBITS (AVG_PKT_SIZE << 3) 
     25 
     26/* Number of symbols for a packet with (bps) bits per symbol */ 
     27#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) 
     28 
     29/* Transmission time for a packet containing (syms) symbols */ 
     30#define MCS_SYMBOL_TIME(sgi, syms)                                      \ 
     31        (sgi ?                                                          \ 
     32          ((syms) * 18 + 4) / 6 :       /* syms * 3.6 us */             \ 
     33          (syms) << 2                   /* syms * 4 us */               \ 
     34        ) 
     35 
     36/* Transmit duration for the raw data part of an average sized packet */ 
     37#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) 
     38 
     39/* MCS rate information for an MCS group */ 
     40#define MCS_GROUP(_streams, _sgi, _ht40) {                              \ 
     41        .streams = _streams,                                            \ 
     42        .flags =                                                        \ 
     43                (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |                 \ 
     44                (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),             \ 
     45        .duration = {                                                   \ 
     46                MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26),          \ 
     47                MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52),         \ 
     48                MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78),         \ 
     49                MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104),        \ 
     50                MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156),        \ 
     51                MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208),        \ 
     52                MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234),        \ 
     53                MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260)         \ 
     54        }                                                               \ 
     55} 
     56 
     57/* 
     58 * To enable sufficiently targeted rate sampling, MCS rates are divided into 
     59 * groups, based on the number of streams and flags (HT40, SGI) that they 
     60 * use. 
     61 */ 
     62const struct mcs_group minstrel_mcs_groups[] = { 
     63        MCS_GROUP(1, 0, 0), 
     64        MCS_GROUP(2, 0, 0), 
     65#if MINSTREL_MAX_STREAMS >= 3 
     66        MCS_GROUP(3, 0, 0), 
     67#endif 
     68 
     69        MCS_GROUP(1, 1, 0), 
     70        MCS_GROUP(2, 1, 0), 
     71#if MINSTREL_MAX_STREAMS >= 3 
     72        MCS_GROUP(3, 1, 0), 
     73#endif 
     74 
     75        MCS_GROUP(1, 0, 1), 
     76        MCS_GROUP(2, 0, 1), 
     77#if MINSTREL_MAX_STREAMS >= 3 
     78        MCS_GROUP(3, 0, 1), 
     79#endif 
     80 
     81        MCS_GROUP(1, 1, 1), 
     82        MCS_GROUP(2, 1, 1), 
     83#if MINSTREL_MAX_STREAMS >= 3 
     84        MCS_GROUP(3, 1, 1), 
     85#endif 
     86}; 
     87 
     88static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; 
     89 
     90/* 
     91 * Perform EWMA (Exponentially Weighted Moving Average) calculation 
     92 */ 
     93static int 
     94minstrel_ewma(int old, int new, int weight) 
     95{ 
     96        return (new * (100 - weight) + old * weight) / 100; 
     97} 
     98 
     99/* 
     100 * Look up an MCS group index based on mac80211 rate information 
     101 */ 
     102static int 
     103minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) 
     104{ 
     105        int streams = (rate->idx / MCS_GROUP_RATES) + 1; 
     106        u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH; 
     107        int i; 
     108 
     109        for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { 
     110                if (minstrel_mcs_groups[i].streams != streams) 
     111                        continue; 
     112                if (minstrel_mcs_groups[i].flags != (rate->flags & flags)) 
     113                        continue; 
     114 
     115                return i; 
     116        } 
     117 
     118        WARN_ON(1); 
     119        return 0; 
     120} 
     121 
     122static inline struct minstrel_rate_stats * 
     123minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) 
     124{ 
     125        return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; 
     126} 
     127 
     128 
     129/* 
     130 * Recalculate success probabilities and counters for a rate using EWMA 
     131 */ 
     132static void 
     133minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr) 
     134{ 
     135        if (unlikely(mr->attempts > 0)) { 
     136                mr->sample_skipped = 0; 
     137                mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); 
     138                if (!mr->att_hist) 
     139                        mr->probability = mr->cur_prob; 
     140                else 
     141                        mr->probability = minstrel_ewma(mr->probability, 
     142                                mr->cur_prob, EWMA_LEVEL); 
     143                mr->att_hist += mr->attempts; 
     144                mr->succ_hist += mr->success; 
     145        } else { 
     146                mr->sample_skipped++; 
     147        } 
     148        mr->last_success = mr->success; 
     149        mr->last_attempts = mr->attempts; 
     150        mr->success = 0; 
     151        mr->attempts = 0; 
     152} 
     153 
     154/* 
     155 * Calculate throughput based on the average A-MPDU length, taking into account 
     156 * the expected number of retransmissions and their expected length 
     157 */ 
     158static void 
     159minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     160                    int group, int rate) 
     161{ 
     162        struct minstrel_rate_stats *mr; 
     163        unsigned int usecs; 
     164 
     165        mr = &mi->groups[group].rates[rate]; 
     166 
     167        if (mr->probability < MINSTREL_FRAC(1, 10)) { 
     168                mr->cur_tp = 0; 
     169                return; 
     170        } 
     171 
     172        usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); 
     173        usecs += minstrel_mcs_groups[group].duration[rate]; 
     174        mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); 
     175} 
     176 
     177/* 
     178 * Update rate statistics and select new primary rates 
     179 * 
     180 * Rules for rate selection: 
     181 *  - max_prob_rate must use only one stream, as a tradeoff between delivery 
     182 *    probability and throughput during strong fluctuations 
     183 *  - as long as the max prob rate has a probability of more than 3/4, pick 
     184 *    higher throughput rates, even if the probablity is a bit lower 
     185 */ 
     186static void 
     187minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) 
     188{ 
     189        struct minstrel_mcs_group_data *mg; 
     190        struct minstrel_rate_stats *mr; 
     191        int cur_prob, cur_prob_tp, cur_tp, cur_tp2; 
     192        int group, i, index; 
     193 
     194        mi->sample_slow = 0; 
     195        mi->sample_count = 0; 
     196        mi->max_tp_rate = 0; 
     197        mi->max_tp_rate2 = 0; 
     198        mi->max_prob_rate = 0; 
     199 
     200        for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { 
     201                cur_prob = 0; 
     202                cur_prob_tp = 0; 
     203                cur_tp = 0; 
     204                cur_tp2 = 0; 
     205 
     206                mg = &mi->groups[group]; 
     207                if (!mg->supported) 
     208                        continue; 
     209 
     210                mg->max_tp_rate = 0; 
     211                mg->max_tp_rate2 = 0; 
     212                mg->max_prob_rate = 0; 
     213                mi->sample_count++; 
     214 
     215                for (i = 0; i < MCS_GROUP_RATES; i++) { 
     216                        if (!(mg->supported & BIT(i))) 
     217                                continue; 
     218 
     219                        mr = &mg->rates[i]; 
     220                        mr->retry_updated = false; 
     221                        index = MCS_GROUP_RATES * group + i; 
     222                        minstrel_calc_rate_ewma(mp, mr); 
     223                        minstrel_ht_calc_tp(mp, mi, group, i); 
     224 
     225                        if (!mr->cur_tp) 
     226                                continue; 
     227 
     228                        /* ignore the lowest rate of each single-stream group */ 
     229                        if (!i && minstrel_mcs_groups[group].streams == 1) 
     230                                continue; 
     231 
     232                        if ((mr->cur_tp > cur_prob_tp && mr->probability > 
     233                             MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { 
     234                                mg->max_prob_rate = index; 
     235                                cur_prob = mr->probability; 
     236                        } 
     237 
     238                        if (mr->cur_tp > cur_tp) { 
     239                                swap(index, mg->max_tp_rate); 
     240                                cur_tp = mr->cur_tp; 
     241                                mr = minstrel_get_ratestats(mi, index); 
     242                        } 
     243 
     244                        if (index >= mg->max_tp_rate) 
     245                                continue; 
     246 
     247                        if (mr->cur_tp > cur_tp2) { 
     248                                mg->max_tp_rate2 = index; 
     249                                cur_tp2 = mr->cur_tp; 
     250                        } 
     251                } 
     252        } 
     253 
     254        /* try to sample up to half of the availble rates during each interval */ 
     255        mi->sample_count *= 4; 
     256 
     257        cur_prob = 0; 
     258        cur_prob_tp = 0; 
     259        cur_tp = 0; 
     260        cur_tp2 = 0; 
     261        for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { 
     262                mg = &mi->groups[group]; 
     263                if (!mg->supported) 
     264                        continue; 
     265 
     266                mr = minstrel_get_ratestats(mi, mg->max_prob_rate); 
     267                if (cur_prob_tp < mr->cur_tp && 
     268                    minstrel_mcs_groups[group].streams == 1) { 
     269                        mi->max_prob_rate = mg->max_prob_rate; 
     270                        cur_prob = mr->cur_prob; 
     271                } 
     272 
     273                mr = minstrel_get_ratestats(mi, mg->max_tp_rate); 
     274                if (cur_tp < mr->cur_tp) { 
     275                        mi->max_tp_rate = mg->max_tp_rate; 
     276                        cur_tp = mr->cur_tp; 
     277                } 
     278 
     279                mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); 
     280                if (cur_tp2 < mr->cur_tp) { 
     281                        mi->max_tp_rate2 = mg->max_tp_rate2; 
     282                        cur_tp2 = mr->cur_tp; 
     283                } 
     284        } 
     285 
     286        mi->stats_update = jiffies; 
     287} 
     288 
     289static bool 
     290minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) 
     291{ 
     292        if (!rate->count) 
     293                return false; 
     294 
     295        if (rate->idx < 0) 
     296                return false; 
     297 
     298        return !!(rate->flags & IEEE80211_TX_RC_MCS); 
     299} 
     300 
     301static void 
     302minstrel_next_sample_idx(struct minstrel_ht_sta *mi) 
     303{ 
     304        struct minstrel_mcs_group_data *mg; 
     305 
     306        for (;;) { 
     307                mi->sample_group++; 
     308                mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups); 
     309                mg = &mi->groups[mi->sample_group]; 
     310 
     311                if (!mg->supported) 
     312                        continue; 
     313 
     314                if (++mg->index > MCS_GROUP_RATES) { 
     315                        mg->index = 0; 
     316                        if (++mg->column > ARRAY_SIZE(sample_table)) 
     317                                mg->column = 0; 
     318                } 
     319                break; 
     320        } 
     321} 
     322 
     323static void 
     324minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary) 
     325{ 
     326        int group, orig_group; 
     327 
     328        orig_group = group = *idx / MCS_GROUP_RATES; 
     329        while (group > 0) { 
     330                group--; 
     331 
     332                if (!mi->groups[group].supported) 
     333                        continue; 
     334 
     335                if (minstrel_mcs_groups[group].streams > 
     336                    minstrel_mcs_groups[orig_group].streams) 
     337                        continue; 
     338 
     339                if (primary) 
     340                        *idx = mi->groups[group].max_tp_rate; 
     341                else 
     342                        *idx = mi->groups[group].max_tp_rate2; 
     343                break; 
     344        } 
     345} 
     346 
     347 
     348static void 
     349minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, 
     350                      struct ieee80211_sta *sta, void *priv_sta, 
     351                      struct sk_buff *skb) 
     352{ 
     353        struct minstrel_ht_sta_priv *msp = priv_sta; 
     354        struct minstrel_ht_sta *mi = &msp->ht; 
     355        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 
     356        struct ieee80211_tx_rate *ar = info->status.rates; 
     357        struct minstrel_rate_stats *rate, *rate2; 
     358        struct minstrel_priv *mp = priv; 
     359        bool last = false; 
     360        int group; 
     361        int i = 0; 
     362 
     363        if (!msp->is_ht) 
     364                return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); 
     365 
     366        /* This packet was aggregated but doesn't carry status info */ 
     367        if ((info->flags & IEEE80211_TX_CTL_AMPDU) && 
     368            !(info->flags & IEEE80211_TX_STAT_AMPDU)) 
     369                return; 
     370 
     371        if (!info->status.ampdu_len) { 
     372                info->status.ampdu_ack_len = 1; 
     373                info->status.ampdu_len = 1; 
     374        } 
     375 
     376        mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, 
     377                MINSTREL_FRAC(info->status.ampdu_len, 1), 90); 
     378 
     379        if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { 
     380                mi->sample_wait = 4 + MINSTREL_TRUNC(mi->avg_ampdu_len); 
     381                mi->sample_tries = 3; 
     382                mi->sample_count--; 
     383        } 
     384 
     385        if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { 
     386                mi->sample_packets += info->status.ampdu_len; 
     387                minstrel_next_sample_idx(mi); 
     388        } 
     389 
     390        for (i = 0; !last; i++) { 
     391                last = (i == IEEE80211_TX_MAX_RATES - 1) || 
     392                       !minstrel_ht_txstat_valid(&ar[i + 1]); 
     393 
     394                if (!minstrel_ht_txstat_valid(&ar[i])) 
     395                        break; 
     396 
     397                group = minstrel_ht_get_group_idx(&ar[i]); 
     398                rate = &mi->groups[group].rates[ar[i].idx % 8]; 
     399 
     400                if (last && (info->flags & IEEE80211_TX_STAT_ACK)) 
     401                        rate->success += info->status.ampdu_ack_len; 
     402 
     403                rate->attempts += ar[i].count * info->status.ampdu_len; 
     404        } 
     405 
     406        /* 
     407         * check for sudden death of spatial multiplexing, 
     408         * downgrade to a lower number of streams if necessary. 
     409         */ 
     410        rate = minstrel_get_ratestats(mi, mi->max_tp_rate); 
     411        if (rate->attempts > 30 && 
     412            MINSTREL_FRAC(rate->success, rate->attempts) < 
     413            MINSTREL_FRAC(20, 100)) 
     414                minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); 
     415 
     416        rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); 
     417        if (rate->attempts > 30 && 
     418            MINSTREL_FRAC(rate->success, rate->attempts) < 
     419            MINSTREL_FRAC(20, 100)) 
     420                minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); 
     421 
     422        if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) 
     423                minstrel_ht_update_stats(mp, mi); 
     424} 
     425 
     426static void 
     427minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     428                         int index) 
     429{ 
     430        struct minstrel_rate_stats *mr; 
     431        const struct mcs_group *group; 
     432        unsigned int tx_time, tx_time_rtscts, tx_time_data; 
     433        unsigned int cw = mp->cw_min; 
     434        unsigned int t_slot = 9; /* FIXME */ 
     435        unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); 
     436 
     437        mr = minstrel_get_ratestats(mi, index); 
     438        if (mr->probability < MINSTREL_FRAC(1, 10)) { 
     439                mr->retry_count = 1; 
     440                mr->retry_count_rtscts = 1; 
     441                return; 
     442        } 
     443 
     444        mr->retry_count = 2; 
     445        mr->retry_count_rtscts = 2; 
     446        mr->retry_updated = true; 
     447 
     448        group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     449        tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; 
     450        tx_time = 2 * (t_slot + mi->overhead + tx_time_data); 
     451        tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data); 
     452        do { 
     453                cw = (cw << 1) | 1; 
     454                cw = min(cw, mp->cw_max); 
     455                tx_time += cw + t_slot + mi->overhead; 
     456                tx_time_rtscts += cw + t_slot + mi->overhead_rtscts; 
     457                if (tx_time_rtscts < mp->segment_size) 
     458                        mr->retry_count_rtscts++; 
     459        } while ((tx_time < mp->segment_size) && 
     460                 (++mr->retry_count < mp->max_retry)); 
     461} 
     462 
     463 
     464static void 
     465minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     466                     struct ieee80211_tx_rate *rate, int index, 
     467                     struct ieee80211_tx_rate_control *txrc, 
     468                     bool sample, bool rtscts) 
     469{ 
     470        const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     471        struct minstrel_rate_stats *mr; 
     472 
     473        mr = minstrel_get_ratestats(mi, index); 
     474        if (!mr->retry_updated) 
     475                minstrel_calc_retransmit(mp, mi, index); 
     476 
     477        if (mr->probability < MINSTREL_FRAC(20, 100)) 
     478                rate->count = 2; 
     479        else if (rtscts) 
     480                rate->count = mr->retry_count_rtscts; 
     481        else 
     482                rate->count = mr->retry_count; 
     483 
     484        rate->flags = IEEE80211_TX_RC_MCS | group->flags; 
     485        if (txrc->short_preamble) 
     486                rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; 
     487        if (txrc->rts || rtscts) 
     488                rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; 
     489        rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; 
     490} 
     491 
     492static inline int 
     493minstrel_get_duration(int index) 
     494{ 
     495        const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     496        return group->duration[index % MCS_GROUP_RATES]; 
     497} 
     498 
     499static int 
     500minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) 
     501{ 
     502        struct minstrel_rate_stats *mr; 
     503        struct minstrel_mcs_group_data *mg; 
     504        int sample_idx = 0; 
     505 
     506        if (mi->sample_wait > 0) { 
     507                mi->sample_wait--; 
     508                return -1; 
     509        } 
     510 
     511        if (!mi->sample_tries) 
     512                return -1; 
     513 
     514        mi->sample_tries--; 
     515        mg = &mi->groups[mi->sample_group]; 
     516        sample_idx = sample_table[mg->column][mg->index]; 
     517        mr = &mg->rates[sample_idx]; 
     518        sample_idx += mi->sample_group * MCS_GROUP_RATES; 
     519 
     520        /* 
     521         * When not using MRR, do not sample if the probability is already 
     522         * higher than 95% to avoid wasting airtime 
     523         */ 
     524        if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100))) 
     525                goto next; 
     526 
     527        /* 
     528         * Make sure that lower rates get sampled only occasionally, 
     529         * if the link is working perfectly. 
     530         */ 
     531        if (minstrel_get_duration(sample_idx) > 
     532            minstrel_get_duration(mi->max_tp_rate)) { 
     533                if (mr->sample_skipped < 10) 
     534                        goto next; 
     535 
     536                if (mi->sample_slow++ > 2) 
     537                        goto next; 
     538        } 
     539 
     540        return sample_idx; 
     541 
     542next: 
     543        minstrel_next_sample_idx(mi); 
     544        return -1; 
     545} 
     546 
     547static void 
     548minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb) 
     549{ 
     550        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 
     551        struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 
     552        u16 tid; 
     553 
     554        if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) 
     555                return; 
     556 
     557        if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) 
     558                return; 
     559 
     560        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 
     561        if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE)) 
     562                return; 
     563 
     564        ieee80211_start_tx_ba_session(pubsta, tid); 
     565} 
     566 
     567static void 
     568minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, 
     569                     struct ieee80211_tx_rate_control *txrc) 
     570{ 
     571        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); 
     572        struct ieee80211_tx_rate *ar = info->status.rates; 
     573        struct minstrel_ht_sta_priv *msp = priv_sta; 
     574        struct minstrel_ht_sta *mi = &msp->ht; 
     575        struct minstrel_priv *mp = priv; 
     576        int sample_idx; 
     577 
     578        if (rate_control_send_low(sta, priv_sta, txrc)) 
     579                return; 
     580 
     581        if (!msp->is_ht) 
     582                return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); 
     583 
     584        minstrel_aggr_check(mp, sta, txrc->skb); 
     585 
     586        sample_idx = minstrel_get_sample_rate(mp, mi); 
     587        if (sample_idx >= 0) { 
     588                minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, 
     589                        txrc, true, false); 
     590                minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, 
     591                        txrc, false, true); 
     592                info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; 
     593        } else { 
     594                minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, 
     595                        txrc, false, false); 
     596                minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, 
     597                        txrc, false, true); 
     598        } 
     599        minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true); 
     600 
     601        ar[3].count = 0; 
     602        ar[3].idx = -1; 
     603 
     604        mi->total_packets++; 
     605 
     606        /* wraparound */ 
     607        if (mi->total_packets == ~0) { 
     608                mi->total_packets = 0; 
     609                mi->sample_packets = 0; 
     610        } 
     611} 
     612 
     613static void 
     614minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, 
     615                        struct ieee80211_sta *sta, void *priv_sta, 
     616                        enum nl80211_channel_type oper_chan_type) 
     617{ 
     618        struct minstrel_priv *mp = priv; 
     619        struct minstrel_ht_sta_priv *msp = priv_sta; 
     620        struct minstrel_ht_sta *mi = &msp->ht; 
     621        struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; 
     622        struct ieee80211_local *local = hw_to_local(mp->hw); 
     623        u16 sta_cap = sta->ht_cap.cap; 
     624        int ack_dur; 
     625        int i; 
     626 
     627        /* fall back to the old minstrel for legacy stations */ 
     628        if (sta && !sta->ht_cap.ht_supported) { 
     629                msp->is_ht = false; 
     630                memset(&msp->legacy, 0, sizeof(msp->legacy)); 
     631                msp->legacy.r = msp->ratelist; 
     632                msp->legacy.sample_table = msp->sample_table; 
     633                return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); 
     634        } 
     635 
     636        BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != 
     637                MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); 
     638 
     639        msp->is_ht = true; 
     640        memset(mi, 0, sizeof(*mi)); 
     641        mi->stats_update = jiffies; 
     642 
     643        ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1); 
     644        mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur; 
     645        mi->overhead_rtscts = mi->overhead + 2 * ack_dur; 
     646 
     647        mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); 
     648 
     649        /* When using MRR, sample more on the first attempt, without delay */ 
     650        if (mp->has_mrr) { 
     651                mi->sample_count = 16; 
     652                mi->sample_wait = 0; 
     653        } else { 
     654                mi->sample_count = 8; 
     655                mi->sample_wait = 8; 
     656        } 
     657        mi->sample_tries = 4; 
     658 
     659        if (oper_chan_type != NL80211_CHAN_HT40MINUS && 
     660            oper_chan_type != NL80211_CHAN_HT40PLUS) 
     661                sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 
     662 
     663        for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { 
     664                u16 req = 0; 
     665 
     666                mi->groups[i].supported = 0; 
     667                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { 
     668                        if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 
     669                                req |= IEEE80211_HT_CAP_SGI_40; 
     670                        else 
     671                                req |= IEEE80211_HT_CAP_SGI_20; 
     672                } 
     673 
     674                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 
     675                        req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 
     676 
     677                if ((sta_cap & req) != req) 
     678                        continue; 
     679 
     680                mi->groups[i].supported = 
     681                        mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; 
     682        } 
     683} 
     684 
     685static void 
     686minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, 
     687                      struct ieee80211_sta *sta, void *priv_sta) 
     688{ 
     689        struct minstrel_priv *mp = priv; 
     690 
     691        minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type); 
     692} 
     693 
     694static void 
     695minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, 
     696                        struct ieee80211_sta *sta, void *priv_sta, 
     697                        u32 changed, enum nl80211_channel_type oper_chan_type) 
     698{ 
     699        minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type); 
     700} 
     701 
     702static void * 
     703minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) 
     704{ 
     705        struct ieee80211_supported_band *sband; 
     706        struct minstrel_ht_sta_priv *msp; 
     707        struct minstrel_priv *mp = priv; 
     708        struct ieee80211_hw *hw = mp->hw; 
     709        int max_rates = 0; 
     710        int i; 
     711 
     712        for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 
     713                sband = hw->wiphy->bands[i]; 
     714                if (sband && sband->n_bitrates > max_rates) 
     715                        max_rates = sband->n_bitrates; 
     716        } 
     717 
     718        msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp); 
     719        if (!msp) 
     720                return NULL; 
     721 
     722        msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp); 
     723        if (!msp->ratelist) 
     724                goto error; 
     725 
     726        msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp); 
     727        if (!msp->sample_table) 
     728                goto error1; 
     729 
     730        return msp; 
     731 
     732error1: 
     733        kfree(msp->sample_table); 
     734error: 
     735        kfree(msp); 
     736        return NULL; 
     737} 
     738 
     739static void 
     740minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) 
     741{ 
     742        struct minstrel_ht_sta_priv *msp = priv_sta; 
     743 
     744        kfree(msp->sample_table); 
     745        kfree(msp->ratelist); 
     746        kfree(msp); 
     747} 
     748 
     749static void * 
     750minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) 
     751{ 
     752        return mac80211_minstrel.alloc(hw, debugfsdir); 
     753} 
     754 
     755static void 
     756minstrel_ht_free(void *priv) 
     757{ 
     758        mac80211_minstrel.free(priv); 
     759} 
     760 
     761static struct rate_control_ops mac80211_minstrel_ht = { 
     762        .name = "minstrel_ht", 
     763        .tx_status = minstrel_ht_tx_status, 
     764        .get_rate = minstrel_ht_get_rate, 
     765        .rate_init = minstrel_ht_rate_init, 
     766        .rate_update = minstrel_ht_rate_update, 
     767        .alloc_sta = minstrel_ht_alloc_sta, 
     768        .free_sta = minstrel_ht_free_sta, 
     769        .alloc = minstrel_ht_alloc, 
     770        .free = minstrel_ht_free, 
     771#ifdef CONFIG_MAC80211_DEBUGFS 
     772        .add_sta_debugfs = minstrel_ht_add_sta_debugfs, 
     773        .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, 
     774#endif 
     775}; 
     776 
     777 
     778static void 
     779init_sample_table(void) 
     780{ 
     781        int col, i, new_idx; 
     782        u8 rnd[MCS_GROUP_RATES]; 
     783 
     784        memset(sample_table, 0xff, sizeof(sample_table)); 
     785        for (col = 0; col < SAMPLE_COLUMNS; col++) { 
     786                for (i = 0; i < MCS_GROUP_RATES; i++) { 
     787                        get_random_bytes(rnd, sizeof(rnd)); 
     788                        new_idx = (i + rnd[i]) % MCS_GROUP_RATES; 
     789 
     790                        while (sample_table[col][new_idx] != 0xff) 
     791                                new_idx = (new_idx + 1) % MCS_GROUP_RATES; 
     792 
     793                        sample_table[col][new_idx] = i; 
     794                } 
     795        } 
     796} 
     797 
     798int __init 
     799rc80211_minstrel_ht_init(void) 
     800{ 
     801        init_sample_table(); 
     802        return ieee80211_rate_control_register(&mac80211_minstrel_ht); 
     803} 
     804 
     805void 
     806rc80211_minstrel_ht_exit(void) 
     807{ 
     808        ieee80211_rate_control_unregister(&mac80211_minstrel_ht); 
     809} 
  • new file net/mac80211/rc80211_minstrel_ht.h

    - +  
     1/* 
     2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 
     3 * 
     4 * This program is free software; you can redistribute it and/or modify 
     5 * it under the terms of the GNU General Public License version 2 as 
     6 * published by the Free Software Foundation. 
     7 */ 
     8 
     9#ifndef __RC_MINSTREL_HT_H 
     10#define __RC_MINSTREL_HT_H 
     11 
     12/* 
     13 * maximum number of spatial streams to make use of 
     14 * set this value to 3 once we have drivers that support it 
     15 */ 
     16#define MINSTREL_MAX_STREAMS    2 
     17#define MINSTREL_STREAM_GROUPS  4 
     18 
     19/* scaled fraction values */ 
     20#define MINSTREL_SCALE  16 
     21#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) 
     22#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) 
     23 
     24#define MCS_GROUP_RATES 8 
     25 
     26struct mcs_group { 
     27        u32 flags; 
     28        unsigned int streams; 
     29        unsigned int duration[MCS_GROUP_RATES]; 
     30}; 
     31 
     32struct minstrel_rate_stats { 
     33        /* current / last sampling period attempts/success counters */ 
     34        unsigned int attempts, last_attempts; 
     35        unsigned int success, last_success; 
     36 
     37        /* total attempts/success counters */ 
     38        u64 att_hist, succ_hist; 
     39 
     40        /* current throughput */ 
     41        unsigned int cur_tp; 
     42 
     43        /* packet delivery probabilities */ 
     44        unsigned int cur_prob, probability; 
     45 
     46        /* maximum retry counts */ 
     47        unsigned int retry_count; 
     48        unsigned int retry_count_rtscts; 
     49 
     50        bool retry_updated; 
     51        u8 sample_skipped; 
     52}; 
     53 
     54struct minstrel_mcs_group_data { 
     55        u8 index; 
     56        u8 column; 
     57 
     58        /* bitfield of supported MCS rates of this group */ 
     59        u8 supported; 
     60 
     61        /* selected primary rates */ 
     62        unsigned int max_tp_rate; 
     63        unsigned int max_tp_rate2; 
     64        unsigned int max_prob_rate; 
     65 
     66        /* MCS rate statistics */ 
     67        struct minstrel_rate_stats rates[MCS_GROUP_RATES]; 
     68}; 
     69 
     70struct minstrel_ht_sta { 
     71        /* ampdu length average (EWMA) */ 
     72        unsigned int avg_ampdu_len; 
     73 
     74        /* best throughput rate */ 
     75        unsigned int max_tp_rate; 
     76 
     77        /* second best throughput rate */ 
     78        unsigned int max_tp_rate2; 
     79 
     80        /* best probability rate */ 
     81        unsigned int max_prob_rate; 
     82 
     83        /* time of last status update */ 
     84        unsigned long stats_update; 
     85 
     86        /* overhead time in usec for each frame */ 
     87        unsigned int overhead; 
     88        unsigned int overhead_rtscts; 
     89 
     90        unsigned int total_packets; 
     91        unsigned int sample_packets; 
     92 
     93        u8 sample_wait; 
     94        u8 sample_tries; 
     95        u8 sample_count; 
     96        u8 sample_slow; 
     97 
     98        /* current MCS group to be sampled */ 
     99        u8 sample_group; 
     100 
     101        /* MCS rate group info and statistics */ 
     102        struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; 
     103}; 
     104 
     105struct minstrel_ht_sta_priv { 
     106        union { 
     107                struct minstrel_ht_sta ht; 
     108                struct minstrel_sta_info legacy; 
     109        }; 
     110#ifdef CONFIG_MAC80211_DEBUGFS 
     111        struct dentry *dbg_stats; 
     112#endif 
     113        void *ratelist; 
     114        void *sample_table; 
     115        bool is_ht; 
     116}; 
     117 
     118void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 
     119void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); 
     120 
     121#endif 
  • new file net/mac80211/rc80211_minstrel_ht_debugfs.c

    - +  
     1/* 
     2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 
     3 * 
     4 * This program is free software; you can redistribute it and/or modify 
     5 * it under the terms of the GNU General Public License version 2 as 
     6 * published by the Free Software Foundation. 
     7 */ 
     8#include <linux/netdevice.h> 
     9#include <linux/types.h> 
     10#include <linux/skbuff.h> 
     11#include <linux/debugfs.h> 
     12#include <linux/ieee80211.h> 
     13#include <net/mac80211.h> 
     14#include "rc80211_minstrel.h" 
     15#include "rc80211_minstrel_ht.h" 
     16 
     17extern const struct mcs_group minstrel_mcs_groups[]; 
     18 
     19static int 
     20minstrel_ht_stats_open(struct inode *inode, struct file *file) 
     21{ 
     22        struct minstrel_ht_sta_priv *msp = inode->i_private; 
     23        struct minstrel_ht_sta *mi = &msp->ht; 
     24        struct minstrel_debugfs_info *ms; 
     25        unsigned int i, j, tp, prob, eprob; 
     26        char *p; 
     27        int ret; 
     28 
     29        if (!msp->is_ht) { 
     30                inode->i_private = &msp->legacy; 
     31                ret = minstrel_stats_open(inode, file); 
     32                inode->i_private = msp; 
     33                return ret; 
     34        } 
     35 
     36        ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL); 
     37        if (!ms) 
     38                return -ENOMEM; 
     39 
     40        file->private_data = ms; 
     41        p = ms->buf; 
     42        p += sprintf(p, "type      rate     throughput  ewma prob   this prob  " 
     43                        "this succ/attempt   success    attempts\n"); 
     44        for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) { 
     45                char htmode = '2'; 
     46                char gimode = 'L'; 
     47 
     48                if (!mi->groups[i].supported) 
     49                        continue; 
     50 
     51                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 
     52                        htmode = '4'; 
     53                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) 
     54                        gimode = 'S'; 
     55 
     56                for (j = 0; j < MCS_GROUP_RATES; j++) { 
     57                        struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; 
     58                        int idx = i * MCS_GROUP_RATES + j; 
     59 
     60                        if (!(mi->groups[i].supported & BIT(j))) 
     61                                continue; 
     62 
     63                        p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); 
     64 
     65                        *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; 
     66                        *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; 
     67                        *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; 
     68                        p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * 
     69                                        MCS_GROUP_RATES + j); 
     70 
     71                        tp = mr->cur_tp / 10; 
     72                        prob = MINSTREL_TRUNC(mr->cur_prob * 1000); 
     73                        eprob = MINSTREL_TRUNC(mr->probability * 1000); 
     74 
     75                        p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        " 
     76                                        "%3u(%3u)   %8llu    %8llu\n", 
     77                                        tp / 10, tp % 10, 
     78                                        eprob / 10, eprob % 10, 
     79                                        prob / 10, prob % 10, 
     80                                        mr->last_success, 
     81                                        mr->last_attempts, 
     82                                        (unsigned long long)mr->succ_hist, 
     83                                        (unsigned long long)mr->att_hist); 
     84                } 
     85        } 
     86        p += sprintf(p, "\nTotal packet count::    ideal %d      " 
     87                        "lookaround %d\n", 
     88                        max(0, (int) mi->total_packets - (int) mi->sample_packets), 
     89                        mi->sample_packets); 
     90        p += sprintf(p, "Average A-MPDU length: %d.%d\n", 
     91                MINSTREL_TRUNC(mi->avg_ampdu_len), 
     92                MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); 
     93        ms->len = p - ms->buf; 
     94 
     95        return 0; 
     96} 
     97 
     98static const struct file_operations minstrel_ht_stat_fops = { 
     99        .owner = THIS_MODULE, 
     100        .open = minstrel_ht_stats_open, 
     101        .read = minstrel_stats_read, 
     102        .release = minstrel_stats_release, 
     103}; 
     104 
     105void 
     106minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) 
     107{ 
     108        struct minstrel_ht_sta_priv *msp = priv_sta; 
     109 
     110        msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp, 
     111                        &minstrel_ht_stat_fops); 
     112} 
     113 
     114void 
     115minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta) 
     116{ 
     117        struct minstrel_ht_sta_priv *msp = priv_sta; 
     118 
     119        debugfs_remove(msp->dbg_stats); 
     120} 
Note: See TracBrowser for help on using the repository browser.