source: branches/backfire/package/mac80211/patches/530-minstrel_ht.patch @ 21354

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

[backfire] backport mac80211 and hostapd from trunk

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