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

Last change on this file since 20034 was 20034, checked in by nbd, 6 years ago

mac80211: increase minstrel_ht precision by properly using a-mpdu frame stats

File size: 30.5 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) / 5 :       /* 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#define MINSTREL_INTFL_SAMPLE_SLOT0     BIT(30) 
     58#define MINSTREL_INTFL_SAMPLE_SLOT1     BIT(31) 
     59 
     60/* 
     61 * To enable sufficiently targeted rate sampling, MCS rates are divided into 
     62 * groups, based on the number of streams and flags (HT40, SGI) that they 
     63 * use. 
     64 */ 
     65const struct mcs_group minstrel_mcs_groups[] = { 
     66        MCS_GROUP(1, 0, 0), 
     67        MCS_GROUP(2, 0, 0), 
     68#if MINSTREL_MAX_STREAMS >= 3 
     69        MCS_GROUP(3, 0, 0), 
     70#endif 
     71 
     72        MCS_GROUP(1, 1, 0), 
     73        MCS_GROUP(2, 1, 0), 
     74#if MINSTREL_MAX_STREAMS >= 3 
     75        MCS_GROUP(3, 1, 0), 
     76#endif 
     77 
     78        MCS_GROUP(1, 0, 1), 
     79        MCS_GROUP(2, 0, 1), 
     80#if MINSTREL_MAX_STREAMS >= 3 
     81        MCS_GROUP(3, 0, 1), 
     82#endif 
     83 
     84        MCS_GROUP(1, 1, 1), 
     85        MCS_GROUP(2, 1, 1), 
     86#if MINSTREL_MAX_STREAMS >= 3 
     87        MCS_GROUP(3, 1, 1), 
     88#endif 
     89}; 
     90 
     91static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; 
     92 
     93/* 
     94 * Perform EWMA (Exponentially Weighted Moving Average) calculation 
     95 */ 
     96static int 
     97minstrel_ewma(int old, int new, int weight) 
     98{ 
     99        return (new * (100 - weight) + old * weight) / 100; 
     100} 
     101 
     102/* 
     103 * Look up an MCS group index based on mac80211 rate information 
     104 */ 
     105static int 
     106minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) 
     107{ 
     108        int streams = (rate->idx / MCS_GROUP_RATES) + 1; 
     109        u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH; 
     110        int i; 
     111 
     112        for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { 
     113                if (minstrel_mcs_groups[i].streams != streams) 
     114                        continue; 
     115                if (minstrel_mcs_groups[i].flags != (rate->flags & flags)) 
     116                        continue; 
     117 
     118                return i; 
     119        } 
     120 
     121        WARN_ON(1); 
     122        return 0; 
     123} 
     124 
     125static inline struct minstrel_rate_stats * 
     126minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) 
     127{ 
     128        return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; 
     129} 
     130 
     131 
     132/* 
     133 * Recalculate success probabilities and counters for a rate using EWMA 
     134 */ 
     135static void 
     136minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr) 
     137{ 
     138        if (mr->attempts) { 
     139                mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); 
     140                if (!mr->att_hist) 
     141                        mr->probability = mr->cur_prob; 
     142                else 
     143                        mr->probability = minstrel_ewma(mr->probability, 
     144                                mr->cur_prob, EWMA_LEVEL); 
     145                mr->att_hist += mr->attempts; 
     146                mr->succ_hist += mr->success; 
     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->max_tp_rate = 0; 
     195        mi->max_tp_rate2 = 0; 
     196        mi->max_prob_rate = 0; 
     197 
     198        for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { 
     199                cur_prob = 0; 
     200                cur_prob_tp = 0; 
     201                cur_tp = 0; 
     202                cur_tp2 = 0; 
     203 
     204                mg = &mi->groups[group]; 
     205                if (!mg->supported) 
     206                        continue; 
     207 
     208                mg->max_tp_rate = 0; 
     209                mg->max_tp_rate2 = 0; 
     210                mg->max_prob_rate = 0; 
     211 
     212                for (i = 0; i < MCS_GROUP_RATES; i++) { 
     213                        if (!(mg->supported & BIT(i))) 
     214                                continue; 
     215 
     216                        mr = &mg->rates[i]; 
     217                        mr->retry_updated = false; 
     218                        index = MCS_GROUP_RATES * group + i; 
     219                        minstrel_calc_rate_ewma(mp, mr); 
     220                        minstrel_ht_calc_tp(mp, mi, group, i); 
     221 
     222                        if (!mr->cur_tp) 
     223                                continue; 
     224 
     225                        /* ignore the lowest rate of each single-stream group */ 
     226                        if (!i && minstrel_mcs_groups[group].streams == 1) 
     227                                continue; 
     228 
     229                        if ((mr->cur_tp > cur_prob_tp && mr->probability > 
     230                             MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { 
     231                                mg->max_prob_rate = index; 
     232                                cur_prob = mr->probability; 
     233                        } 
     234 
     235                        if (mr->cur_tp > cur_tp) { 
     236                                swap(index, mg->max_tp_rate); 
     237                                cur_tp = mr->cur_tp; 
     238                                mr = minstrel_get_ratestats(mi, index); 
     239                        } 
     240 
     241                        if (index == mg->max_tp_rate) 
     242                                continue; 
     243 
     244                        if (mr->cur_tp > cur_tp2) { 
     245                                mg->max_tp_rate2 = index; 
     246                                cur_tp2 = mr->cur_tp; 
     247                        } 
     248                } 
     249        } 
     250 
     251        cur_prob = 0; 
     252        cur_prob_tp = 0; 
     253        cur_tp = 0; 
     254        cur_tp2 = 0; 
     255        for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { 
     256                mg = &mi->groups[group]; 
     257                if (!mg->supported) 
     258                        continue; 
     259 
     260                mr = minstrel_get_ratestats(mi, mg->max_prob_rate); 
     261                if (cur_prob_tp < mr->cur_tp && 
     262                    minstrel_mcs_groups[group].streams == 1) { 
     263                        mi->max_prob_rate = mg->max_prob_rate; 
     264                        cur_prob = mr->cur_prob; 
     265                } 
     266 
     267                mr = minstrel_get_ratestats(mi, mg->max_tp_rate); 
     268                if (cur_tp < mr->cur_tp) { 
     269                        mi->max_tp_rate = mg->max_tp_rate; 
     270                        cur_tp = mr->cur_tp; 
     271                } 
     272 
     273                mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); 
     274                if (cur_tp2 < mr->cur_tp) { 
     275                        mi->max_tp_rate2 = mg->max_tp_rate2; 
     276                        cur_tp2 = mr->cur_tp; 
     277                } 
     278        } 
     279 
     280        mi->stats_update = jiffies; 
     281} 
     282 
     283static bool 
     284minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) 
     285{ 
     286        if (!rate->count) 
     287                return false; 
     288 
     289        if (rate->idx < 0) 
     290                return false; 
     291 
     292        return !!(rate->flags & IEEE80211_TX_RC_MCS); 
     293} 
     294 
     295static void 
     296minstrel_next_sample_idx(struct minstrel_ht_sta *mi) 
     297{ 
     298        struct minstrel_mcs_group_data *mg; 
     299 
     300        for (;;) { 
     301                mi->sample_group++; 
     302                mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups); 
     303                mg = &mi->groups[mi->sample_group]; 
     304 
     305                if (!mg->supported) 
     306                        continue; 
     307 
     308                if (++mg->index > MCS_GROUP_RATES) { 
     309                        mg->index = 0; 
     310                        if (++mg->column > ARRAY_SIZE(sample_table)) 
     311                                mg->column = 0; 
     312                } 
     313                break; 
     314        } 
     315} 
     316 
     317static void 
     318minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, int type) 
     319{ 
     320        int group, orig_group; 
     321 
     322        orig_group = group = *idx / MCS_GROUP_RATES; 
     323        while (group > 0) { 
     324                group--; 
     325 
     326                if (!mi->groups[group].supported) 
     327                        continue; 
     328 
     329                if (minstrel_mcs_groups[group].streams >= 
     330                    minstrel_mcs_groups[orig_group].streams) 
     331                        continue; 
     332 
     333                switch(type) { 
     334                case 0: 
     335                        *idx = mi->groups[group].max_tp_rate; 
     336                        break; 
     337                case 1: 
     338                        *idx = mi->groups[group].max_tp_rate2; 
     339                        break; 
     340                } 
     341                break; 
     342        } 
     343} 
     344 
     345 
     346static void 
     347minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, 
     348                      struct ieee80211_sta *sta, void *priv_sta, 
     349                      struct sk_buff *skb) 
     350{ 
     351        struct minstrel_ht_sta_priv *msp = priv_sta; 
     352        struct minstrel_ht_sta *mi = &msp->ht; 
     353        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 
     354        struct ieee80211_tx_rate *ar = info->status.rates; 
     355        struct minstrel_rate_stats *rate, *rate2; 
     356        struct minstrel_priv *mp = priv; 
     357        bool last = false; 
     358        int group; 
     359        int i = 0; 
     360 
     361        if (!msp->is_ht) 
     362                return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); 
     363 
     364        /* This packet was aggregated but doesn't carry status info */ 
     365        if ((info->flags & IEEE80211_TX_CTL_AMPDU) && 
     366            !(info->flags & IEEE80211_TX_STAT_AMPDU)) 
     367                return; 
     368 
     369        if (!info->status.ampdu_len) { 
     370                info->status.ampdu_ack_len = 1; 
     371                info->status.ampdu_len = 1; 
     372        } 
     373 
     374        mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, 
     375                MINSTREL_FRAC(info->status.ampdu_len, 1), 90); 
     376 
     377        for (i = 0; !last; i++) { 
     378                last = (i == IEEE80211_TX_MAX_RATES - 1) || 
     379                       !minstrel_ht_txstat_valid(&ar[i + 1]); 
     380 
     381                if (!minstrel_ht_txstat_valid(&ar[i])) 
     382                        break; 
     383 
     384                if ((i == 0 && (info->flags & MINSTREL_INTFL_SAMPLE_SLOT0)) || 
     385                    (i == 1 && (info->flags & MINSTREL_INTFL_SAMPLE_SLOT1))) { 
     386                        if (mi->sample_pending > 0) 
     387                                mi->sample_pending--; 
     388                        mi->sample_packets++; 
     389                        minstrel_next_sample_idx(mi); 
     390                } 
     391 
     392                group = minstrel_ht_get_group_idx(&ar[i]); 
     393                rate = &mi->groups[group].rates[ar[i].idx % 8]; 
     394 
     395                if (last && (info->flags & IEEE80211_TX_STAT_ACK)) 
     396                        rate->success += info->status.ampdu_ack_len; 
     397 
     398                rate->attempts += ar[i].count * info->status.ampdu_len; 
     399        } 
     400 
     401 
     402        /* 
     403         * check for sudden death of spatial multiplexing, 
     404         * downgrade to a lower number of streams if necessary. 
     405         */ 
     406        rate = minstrel_get_ratestats(mi, mi->max_tp_rate); 
     407        if (MINSTREL_FRAC(rate->success, rate->attempts) < 
     408            MINSTREL_FRAC(20, 100) && rate->attempts > 15) 
     409                minstrel_downgrade_rate(mi, &mi->max_tp_rate, 0); 
     410 
     411        rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); 
     412        if (MINSTREL_FRAC(rate->success, rate->attempts) < 
     413            MINSTREL_FRAC(20, 100) && rate->attempts > 15) 
     414                minstrel_downgrade_rate(mi, &mi->max_tp_rate2, 1); 
     415 
     416        if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) 
     417                minstrel_ht_update_stats(mp, mi); 
     418} 
     419 
     420static void 
     421minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     422                         int index) 
     423{ 
     424        struct minstrel_rate_stats *mr; 
     425        const struct mcs_group *group; 
     426        unsigned int tx_time, tx_time_rtscts, tx_time_data; 
     427        unsigned int cw = mp->cw_min; 
     428        unsigned int t_slot = 9; /* FIXME */ 
     429        unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); 
     430 
     431        mr = minstrel_get_ratestats(mi, index); 
     432        if (mr->probability < MINSTREL_FRAC(1, 10)) { 
     433                mr->retry_count = 1; 
     434                mr->retry_count_rtscts = 1; 
     435                return; 
     436        } 
     437 
     438        mr->retry_count = 2; 
     439        mr->retry_count_rtscts = 2; 
     440        mr->retry_updated = true; 
     441 
     442        group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     443        tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; 
     444        tx_time = 2 * (t_slot + mi->overhead + tx_time_data); 
     445        tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data); 
     446        do { 
     447                cw = (cw << 1) | 1; 
     448                cw = min(cw, mp->cw_max); 
     449                tx_time += cw + t_slot + mi->overhead; 
     450                tx_time_rtscts += cw + t_slot + mi->overhead_rtscts; 
     451                if (tx_time_rtscts < mp->segment_size) 
     452                        mr->retry_count_rtscts++; 
     453        } while ((tx_time < mp->segment_size) && 
     454                 (++mr->retry_count < mp->max_retry)); 
     455} 
     456 
     457 
     458static void 
     459minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     460                     struct ieee80211_tx_rate *rate, int index, 
     461                     struct ieee80211_tx_rate_control *txrc, 
     462                     bool sample, bool rtscts) 
     463{ 
     464        const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     465        struct minstrel_rate_stats *mr; 
     466 
     467        mr = minstrel_get_ratestats(mi, index); 
     468        if (!mr->retry_updated) 
     469                minstrel_calc_retransmit(mp, mi, index); 
     470 
     471        if (rtscts) 
     472                rate->count = mr->retry_count_rtscts; 
     473        else 
     474                rate->count = mr->retry_count; 
     475 
     476        rate->flags = IEEE80211_TX_RC_MCS | group->flags; 
     477        if (txrc->short_preamble) 
     478                rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; 
     479        if (txrc->rts || rtscts) 
     480                rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; 
     481        rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; 
     482} 
     483 
     484static inline int 
     485minstrel_get_duration(int index) 
     486{ 
     487        const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 
     488        return group->duration[index % MCS_GROUP_RATES]; 
     489} 
     490 
     491static int 
     492minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 
     493                         bool *defer) 
     494{ 
     495        struct minstrel_rate_stats *mr; 
     496        struct minstrel_mcs_group_data *mg; 
     497        int sample_idx = 0; 
     498        int sample_rate; 
     499        int delta; 
     500 
     501        if (mp->has_mrr) 
     502                sample_rate = mp->lookaround_rate_mrr; 
     503        else 
     504                sample_rate = mp->lookaround_rate; 
     505 
     506        delta = (mi->total_packets * sample_rate) / 100 - mi->sample_packets; 
     507        delta -= mi->sample_pending / 2; 
     508 
     509        if (delta <= 0) 
     510                return -1; 
     511 
     512        delta -= 16; 
     513        if (delta > 1) { 
     514                /* With multi-rate retry, not every planned sample 
     515                * attempt actually gets used, due to the way the retry 
     516                * chain is set up - [max_tp,sample,prob,lowest] for 
     517                * sample_rate < max_tp. 
     518                * 
     519                * If there's too much sampling backlog and the link 
     520                * starts getting worse, minstrel would start bursting 
     521                * out lots of sampling frames, which would result 
     522                * in a large throughput loss. 
     523                */ 
     524                mi->sample_packets += delta - 1; 
     525        } 
     526 
     527        mg = &mi->groups[mi->sample_group]; 
     528        sample_idx = sample_table[mg->column][mg->index]; 
     529        mr = &mg->rates[sample_idx]; 
     530        sample_idx += mi->sample_group * MCS_GROUP_RATES; 
     531 
     532        /* 
     533         * When not using MRR, do not sample if the probability is already 
     534         * higher than 95% to avoid wasting airtime 
     535         */ 
     536        if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100))) 
     537                return -1; 
     538 
     539        if (minstrel_get_duration(sample_idx) > 
     540            minstrel_get_duration(mi->max_tp_rate)) { 
     541                /* 
     542                 * Make sure that lower rates get sampled occasionally, even 
     543                 * if the link is working perfectly. Some drivers such as ath9k 
     544                 * severely limit aggregation size if the MRR chain contains low 
     545                 * rates 
     546                 * 
     547                 * If the lower rate has already been tried a few times, there's 
     548                 * no point in forcing it to be sampled again, so skip to the 
     549                 * next sampling index after applying this one in the tx control 
     550                 */ 
     551                if (mr->att_hist > 15) { 
     552                        *defer = true; 
     553                        minstrel_next_sample_idx(mi); 
     554                } 
     555        } 
     556 
     557        return sample_idx; 
     558} 
     559 
     560static void 
     561minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb) 
     562{ 
     563        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 
     564        struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 
     565        u16 tid; 
     566 
     567        if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) 
     568                return; 
     569 
     570        if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) 
     571                return; 
     572 
     573        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 
     574        if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE)) 
     575                return; 
     576 
     577        ieee80211_start_tx_ba_session(pubsta, tid); 
     578} 
     579 
     580static void 
     581minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, 
     582                     struct ieee80211_tx_rate_control *txrc) 
     583{ 
     584        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); 
     585        struct ieee80211_tx_rate *ar = info->status.rates; 
     586        struct minstrel_ht_sta_priv *msp = priv_sta; 
     587        struct minstrel_ht_sta *mi = &msp->ht; 
     588        struct minstrel_priv *mp = priv; 
     589        bool sample_defer = false; 
     590        int sample_idx; 
     591 
     592        if (rate_control_send_low(sta, priv_sta, txrc)) 
     593                return; 
     594 
     595        if (!msp->is_ht) 
     596                return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); 
     597 
     598        minstrel_aggr_check(mp, sta, txrc->skb); 
     599 
     600        sample_idx = minstrel_get_sample_rate(mp, mi, &sample_defer); 
     601        if (sample_idx >= 0) { 
     602                if (sample_defer) { 
     603                        minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, 
     604                                txrc, false, false); 
     605                        minstrel_ht_set_rate(mp, mi, &ar[1], sample_idx, 
     606                                txrc, true, true); 
     607                        info->flags |= MINSTREL_INTFL_SAMPLE_SLOT1; 
     608                } else { 
     609                        minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, 
     610                                txrc, true, false); 
     611                        minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, 
     612                                txrc, false, true); 
     613                        info->flags |= MINSTREL_INTFL_SAMPLE_SLOT0; 
     614                } 
     615                mi->sample_pending++; 
     616        } else { 
     617                minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, 
     618                        txrc, false, false); 
     619                minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, 
     620                        txrc, false, true); 
     621        } 
     622        minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true); 
     623 
     624        ar[3].count = 0; 
     625        ar[3].idx = -1; 
     626 
     627        mi->total_packets++; 
     628 
     629        /* wraparound */ 
     630        if (mi->total_packets >= 100000) { 
     631                mi->total_packets = 0; 
     632                mi->sample_packets = 0; 
     633                mi->sample_pending = 0; 
     634        } 
     635} 
     636 
     637static void 
     638minstrel_ht_update_cap(struct minstrel_ht_sta *mi, struct ieee80211_sta *sta, 
     639                       enum nl80211_channel_type oper_chan_type) 
     640{ 
     641        struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; 
     642        u16 sta_cap = sta->ht_cap.cap; 
     643        int i; 
     644 
     645        if (oper_chan_type != NL80211_CHAN_HT40MINUS && 
     646            oper_chan_type != NL80211_CHAN_HT40PLUS) 
     647                sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 
     648 
     649        for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { 
     650                u16 req = 0; 
     651 
     652                mi->groups[i].supported = 0; 
     653                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { 
     654                        if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 
     655                                req |= IEEE80211_HT_CAP_SGI_40; 
     656                        else 
     657                                req |= IEEE80211_HT_CAP_SGI_20; 
     658                } 
     659 
     660                if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 
     661                        req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 
     662 
     663                if ((sta_cap & req) != req) 
     664                        continue; 
     665 
     666                mi->groups[i].supported = 
     667                        mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; 
     668        } 
     669} 
     670 
     671static void 
     672minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, 
     673                      struct ieee80211_sta *sta, void *priv_sta) 
     674{ 
     675        struct minstrel_priv *mp = priv; 
     676        struct minstrel_ht_sta_priv *msp = priv_sta; 
     677        struct minstrel_ht_sta *mi = &msp->ht; 
     678        struct ieee80211_local *local = hw_to_local(mp->hw); 
     679        int ack_dur; 
     680 
     681        /* fall back to the old minstrel for legacy stations */ 
     682        if (sta && !sta->ht_cap.ht_supported) { 
     683                msp->is_ht = false; 
     684                memset(&msp->legacy, 0, sizeof(msp->legacy)); 
     685                msp->legacy.r = msp->ratelist; 
     686                msp->legacy.sample_table = msp->sample_table; 
     687                return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); 
     688        } 
     689 
     690        BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != 
     691                MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); 
     692 
     693        msp->is_ht = true; 
     694        memset(mi, 0, sizeof(*mi)); 
     695        mi->stats_update = jiffies; 
     696 
     697        ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1); 
     698        mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur; 
     699        mi->overhead_rtscts = mi->overhead + 2 * ack_dur; 
     700 
     701        mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); 
     702 
     703        minstrel_ht_update_cap(mi, sta, mp->hw->conf.channel_type); 
     704} 
     705 
     706static void 
     707minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, 
     708                        struct ieee80211_sta *sta, void *priv_sta, 
     709                        u32 changed, enum nl80211_channel_type oper_chan_type) 
     710{ 
     711        struct minstrel_ht_sta_priv *msp = priv_sta; 
     712        struct minstrel_ht_sta *mi = &msp->ht; 
     713 
     714        minstrel_ht_update_cap(mi, sta, oper_chan_type); 
     715} 
     716 
     717static void * 
     718minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) 
     719{ 
     720        struct ieee80211_supported_band *sband; 
     721        struct minstrel_ht_sta_priv *msp; 
     722        struct minstrel_priv *mp = priv; 
     723        struct ieee80211_hw *hw = mp->hw; 
     724        int max_rates = 0; 
     725        int i; 
     726 
     727        for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 
     728                sband = hw->wiphy->bands[i]; 
     729                if (sband && sband->n_bitrates > max_rates) 
     730                        max_rates = sband->n_bitrates; 
     731        } 
     732 
     733        msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp); 
     734        if (!msp) 
     735                return NULL; 
     736 
     737        msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp); 
     738        if (!msp->ratelist) 
     739                goto error; 
     740 
     741        msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp); 
     742        if (!msp->sample_table) 
     743                goto error1; 
     744 
     745        return msp; 
     746 
     747error1: 
     748        kfree(msp->sample_table); 
     749error: 
     750        kfree(msp); 
     751        return NULL; 
     752} 
     753 
     754static void 
     755minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) 
     756{ 
     757        struct minstrel_ht_sta_priv *msp = priv_sta; 
     758 
     759        kfree(msp->sample_table); 
     760        kfree(msp->ratelist); 
     761        kfree(msp); 
     762} 
     763 
     764static void * 
     765minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) 
     766{ 
     767        return mac80211_minstrel.alloc(hw, debugfsdir); 
     768} 
     769 
     770static void 
     771minstrel_ht_free(void *priv) 
     772{ 
     773        mac80211_minstrel.free(priv); 
     774} 
     775 
     776static struct rate_control_ops mac80211_minstrel_ht = { 
     777        .name = "minstrel_ht", 
     778        .tx_status = minstrel_ht_tx_status, 
     779        .get_rate = minstrel_ht_get_rate, 
     780        .rate_init = minstrel_ht_rate_init, 
     781        .rate_update = minstrel_ht_rate_update, 
     782        .alloc_sta = minstrel_ht_alloc_sta, 
     783        .free_sta = minstrel_ht_free_sta, 
     784        .alloc = minstrel_ht_alloc, 
     785        .free = minstrel_ht_free, 
     786#ifdef CONFIG_MAC80211_DEBUGFS 
     787        .add_sta_debugfs = minstrel_ht_add_sta_debugfs, 
     788        .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, 
     789#endif 
     790}; 
     791 
     792 
     793static void 
     794init_sample_table(void) 
     795{ 
     796        int col, i, new_idx; 
     797        u8 rnd[MCS_GROUP_RATES]; 
     798 
     799        memset(sample_table, 0xff, sizeof(sample_table)); 
     800        for (col = 0; col < SAMPLE_COLUMNS; col++) { 
     801                for (i = 0; i < MCS_GROUP_RATES; i++) { 
     802                        get_random_bytes(rnd, sizeof(rnd)); 
     803                        new_idx = (i + rnd[i]) % MCS_GROUP_RATES; 
     804 
     805                        while (sample_table[col][new_idx] != 0xff) 
     806                                new_idx = (new_idx + 1) % MCS_GROUP_RATES; 
     807 
     808                        sample_table[col][new_idx] = i; 
     809                } 
     810        } 
     811} 
     812 
     813int __init 
     814rc80211_minstrel_ht_init(void) 
     815{ 
     816        init_sample_table(); 
     817        return ieee80211_rate_control_register(&mac80211_minstrel_ht); 
     818} 
     819 
     820void 
     821rc80211_minstrel_ht_exit(void) 
     822{ 
     823        ieee80211_rate_control_unregister(&mac80211_minstrel_ht); 
     824} 
  • 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        bool retry_updated; 
     48        unsigned int retry_count; 
     49        unsigned int retry_count_rtscts; 
     50}; 
     51 
     52struct minstrel_mcs_group_data { 
     53        u8 index; 
     54        u8 column; 
     55 
     56        /* bitfield of supported MCS rates of this group */ 
     57        u8 supported; 
     58 
     59        /* selected primary rates */ 
     60        unsigned int max_tp_rate; 
     61        unsigned int max_tp_rate2; 
     62        unsigned int max_prob_rate; 
     63 
     64        /* MCS rate statistics */ 
     65        struct minstrel_rate_stats rates[MCS_GROUP_RATES]; 
     66}; 
     67 
     68struct minstrel_ht_sta { 
     69        /* ampdu length average (EWMA) */ 
     70        unsigned int avg_ampdu_len; 
     71 
     72        /* best throughput rate */ 
     73        unsigned int max_tp_rate; 
     74 
     75        /* second best throughput rate */ 
     76        unsigned int max_tp_rate2; 
     77 
     78        /* best probability rate */ 
     79        unsigned int max_prob_rate; 
     80 
     81        /* time of last status update */ 
     82        unsigned long stats_update; 
     83 
     84        /* overhead time in usec for each frame */ 
     85        unsigned int overhead; 
     86        unsigned int overhead_rtscts; 
     87 
     88        unsigned int total_packets; 
     89        unsigned int sample_packets; 
     90        unsigned int sample_pending; 
     91 
     92        /* current MCS group to be sampled */ 
     93        unsigned int sample_group; 
     94 
     95        /* MCS rate group info and statistics */ 
     96        struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; 
     97}; 
     98 
     99struct minstrel_ht_sta_priv { 
     100        union { 
     101                struct minstrel_ht_sta ht; 
     102                struct minstrel_sta_info legacy; 
     103        }; 
     104#ifdef CONFIG_MAC80211_DEBUGFS 
     105        struct dentry *dbg_stats; 
     106#endif 
     107        void *ratelist; 
     108        void *sample_table; 
     109        bool is_ht; 
     110}; 
     111 
     112void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 
     113void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); 
     114 
     115#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.