Annotation of qemu/roms/ipxe/src/net/80211/rc80211.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Simple 802.11 rate-control algorithm for iPXE.
        !             3:  *
        !             4:  * Copyright (c) 2009 Joshua Oreman <[email protected]>.
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or
        !             7:  * modify it under the terms of the GNU General Public License as
        !             8:  * published by the Free Software Foundation; either version 2 of the
        !             9:  * License, or any later version.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14:  * General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU General Public License
        !            17:  * along with this program; if not, write to the Free Software
        !            18:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            19:  */
        !            20: 
        !            21: FILE_LICENCE ( GPL2_OR_LATER );
        !            22: 
        !            23: #include <stdlib.h>
        !            24: #include <ipxe/net80211.h>
        !            25: 
        !            26: /**
        !            27:  * @file
        !            28:  *
        !            29:  * Simple 802.11 rate-control algorithm
        !            30:  */
        !            31: 
        !            32: /** @page rc80211 Rate control philosophy
        !            33:  *
        !            34:  * We want to maximize our transmission speed, to the extent that we
        !            35:  * can do that without dropping undue numbers of packets. We also
        !            36:  * don't want to take up very much code space, so our algorithm has to
        !            37:  * be pretty simple
        !            38:  *
        !            39:  * When we receive a packet, we know what rate it was transmitted at,
        !            40:  * and whether it had to be retransmitted to get to us.
        !            41:  *
        !            42:  * When we send a packet, we hear back how many times it had to be
        !            43:  * retried to get through, and whether it got through at all.
        !            44:  *
        !            45:  * Indications of TX success are more reliable than RX success, but RX
        !            46:  * information helps us know where to start.
        !            47:  *
        !            48:  * To handle all of this, we keep for each rate and each direction (TX
        !            49:  * and RX separately) some state information for the most recent
        !            50:  * packets on that rate and the number of packets for which we have
        !            51:  * information. The state is a 32-bit unsigned integer in which two
        !            52:  * bits represent a packet: 11 if it went through well, 10 if it went
        !            53:  * through with one retry, 01 if it went through with more than one
        !            54:  * retry, or 00 if it didn't go through at all. We define the
        !            55:  * "goodness" for a particular (rate, direction) combination as the
        !            56:  * sum of all the 2-bit fields, times 33, divided by the number of
        !            57:  * 2-bit fields containing valid information (16 except when we're
        !            58:  * starting out). The number produced is between 0 and 99; we use -1
        !            59:  * for rates with less than 4 RX packets or 1 TX, as an indicator that
        !            60:  * we do not have enough information to rely on them.
        !            61:  *
        !            62:  * In deciding which rates are best, we find the weighted average of
        !            63:  * TX and RX goodness, where the weighting is by number of packets
        !            64:  * with data and TX packets are worth 4 times as much as RX packets.
        !            65:  * The weighted average is called "net goodness" and is also a number
        !            66:  * between 0 and 99.  If 3 consecutive packets fail transmission
        !            67:  * outright, we automatically ratchet down the rate; otherwise, we
        !            68:  * switch to the best rate whenever the current rate's goodness falls
        !            69:  * below some threshold, and try increasing our rate when the goodness
        !            70:  * is very high.
        !            71:  *
        !            72:  * This system is optimized for iPXE's style of usage. Because normal
        !            73:  * operation always involves receiving something, we'll make our way
        !            74:  * to the best rate pretty quickly. We tend to follow the lead of the
        !            75:  * sending AP in choosing rates, but we won't use rates for long that
        !            76:  * don't work well for us in transmission. We assume iPXE won't be
        !            77:  * running for long enough that rate patterns will change much, so we
        !            78:  * don't have to keep time counters or the like.  And if this doesn't
        !            79:  * work well in practice there are many ways it could be tweaked.
        !            80:  *
        !            81:  * To avoid staying at 1Mbps for a long time, we don't track any
        !            82:  * transmitted packets until we've set our rate based on received
        !            83:  * packets.
        !            84:  */
        !            85: 
        !            86: /** Two-bit packet status indicator for a packet with no retries */
        !            87: #define RC_PKT_OK              0x3
        !            88: 
        !            89: /** Two-bit packet status indicator for a packet with one retry */
        !            90: #define RC_PKT_RETRIED_ONCE    0x2
        !            91: 
        !            92: /** Two-bit packet status indicator for a TX packet with multiple retries
        !            93:  *
        !            94:  * It is not possible to tell whether an RX packet had one or multiple
        !            95:  * retries; we rely instead on the fact that failed RX packets won't
        !            96:  * get to us at all, so if we receive a lot of RX packets on a certain
        !            97:  * rate it must be pretty good.
        !            98:  */
        !            99: #define RC_PKT_RETRIED_MULTI   0x1
        !           100: 
        !           101: /** Two-bit packet status indicator for a TX packet that was never ACKed
        !           102:  *
        !           103:  * It is not possible to tell whether an RX packet was setn if it
        !           104:  * didn't get through to us, but if we don't see one we won't increase
        !           105:  * the goodness for its rate. This asymmetry is part of why TX packets
        !           106:  * are weighted much more heavily than RX.
        !           107:  */
        !           108: #define RC_PKT_FAILED          0x0
        !           109: 
        !           110: /** Number of times to weight TX packets more heavily than RX packets */
        !           111: #define RC_TX_FACTOR           4
        !           112: 
        !           113: /** Number of consecutive failed TX packets that cause an automatic rate drop */
        !           114: #define RC_TX_EMERG_FAIL       3
        !           115: 
        !           116: /** Minimum net goodness below which we will search for a better rate */
        !           117: #define RC_GOODNESS_MIN                85
        !           118: 
        !           119: /** Maximum net goodness above which we will try to increase our rate */
        !           120: #define RC_GOODNESS_MAX                95
        !           121: 
        !           122: /** Minimum (num RX + @c RC_TX_FACTOR * num TX) to use a certain rate */
        !           123: #define RC_UNCERTAINTY_THRESH  4
        !           124: 
        !           125: /** TX direction */
        !           126: #define TX     0
        !           127: 
        !           128: /** RX direction */
        !           129: #define RX     1
        !           130: 
        !           131: /** A rate control context */
        !           132: struct rc80211_ctx
        !           133: {
        !           134:        /** Goodness state for each rate, TX and RX */
        !           135:        u32 goodness[2][NET80211_MAX_RATES];
        !           136: 
        !           137:        /** Number of packets recorded for each rate */
        !           138:        u8 count[2][NET80211_MAX_RATES];
        !           139: 
        !           140:        /** Indication of whether we've set the device rate yet */
        !           141:        int started;
        !           142: 
        !           143:        /** Counter of all packets sent and received */
        !           144:        int packets;
        !           145: };
        !           146: 
        !           147: /**
        !           148:  * Initialize rate-control algorithm
        !           149:  *
        !           150:  * @v dev      802.11 device
        !           151:  * @ret ctx    Rate-control context, to be stored in @c dev->rctl
        !           152:  */
        !           153: struct rc80211_ctx * rc80211_init ( struct net80211_device *dev __unused )
        !           154: {
        !           155:        struct rc80211_ctx *ret = zalloc ( sizeof ( *ret ) );
        !           156:        return ret;
        !           157: }
        !           158: 
        !           159: /**
        !           160:  * Calculate net goodness for a certain rate
        !           161:  *
        !           162:  * @v ctx      Rate-control context
        !           163:  * @v rate_idx Index of rate to calculate net goodness for
        !           164:  */
        !           165: static int rc80211_calc_net_goodness ( struct rc80211_ctx *ctx,
        !           166:                                       int rate_idx )
        !           167: {
        !           168:        int sum[2], num[2], dir, pkt;
        !           169: 
        !           170:        for ( dir = 0; dir < 2; dir++ ) {
        !           171:                u32 good = ctx->goodness[dir][rate_idx];
        !           172: 
        !           173:                num[dir] = ctx->count[dir][rate_idx];
        !           174:                sum[dir] = 0;
        !           175: 
        !           176:                for ( pkt = 0; pkt < num[dir]; pkt++ )
        !           177:                        sum[dir] += ( good >> ( 2 * pkt ) ) & 0x3;
        !           178:        }
        !           179: 
        !           180:        if ( ( num[TX] * RC_TX_FACTOR + num[RX] ) < RC_UNCERTAINTY_THRESH )
        !           181:                return -1;
        !           182: 
        !           183:        return ( 33 * ( sum[TX] * RC_TX_FACTOR + sum[RX] ) /
        !           184:                      ( num[TX] * RC_TX_FACTOR + num[RX] ) );
        !           185: }
        !           186: 
        !           187: /**
        !           188:  * Determine the best rate to switch to and return it
        !           189:  *
        !           190:  * @v dev              802.11 device
        !           191:  * @ret rate_idx       Index of the best rate to switch to
        !           192:  */
        !           193: static int rc80211_pick_best ( struct net80211_device *dev )
        !           194: {
        !           195:        struct rc80211_ctx *ctx = dev->rctl;
        !           196:        int best_net_good = 0, best_rate = -1, i;
        !           197: 
        !           198:        for ( i = 0; i < dev->nr_rates; i++ ) {
        !           199:                int net_good = rc80211_calc_net_goodness ( ctx, i );
        !           200: 
        !           201:                if ( net_good > best_net_good ||
        !           202:                     ( best_net_good > RC_GOODNESS_MIN &&
        !           203:                       net_good > RC_GOODNESS_MIN ) ) {
        !           204:                        best_net_good = net_good;
        !           205:                        best_rate = i;
        !           206:                }
        !           207:        }
        !           208: 
        !           209:        if ( best_rate >= 0 ) {
        !           210:                int old_good = rc80211_calc_net_goodness ( ctx, dev->rate );
        !           211:                if ( old_good != best_net_good )
        !           212:                        DBGC ( ctx, "802.11 RC %p switching from goodness "
        !           213:                               "%d to %d\n", ctx, old_good, best_net_good );
        !           214: 
        !           215:                ctx->started = 1;
        !           216:                return best_rate;
        !           217:        }
        !           218: 
        !           219:        return dev->rate;
        !           220: }
        !           221: 
        !           222: /**
        !           223:  * Set 802.11 device rate
        !           224:  *
        !           225:  * @v dev      802.11 device
        !           226:  * @v rate_idx Index of rate to switch to
        !           227:  *
        !           228:  * This is a thin wrapper around net80211_set_rate_idx to insert a
        !           229:  * debugging message where appropriate.
        !           230:  */
        !           231: static inline void rc80211_set_rate ( struct net80211_device *dev,
        !           232:                                      int rate_idx )
        !           233: {
        !           234:        DBGC ( dev->rctl, "802.11 RC %p changing rate %d->%d Mbps\n", dev->rctl,
        !           235:               dev->rates[dev->rate] / 10, dev->rates[rate_idx] / 10 );
        !           236: 
        !           237:        net80211_set_rate_idx ( dev, rate_idx );
        !           238: }
        !           239: 
        !           240: /**
        !           241:  * Check rate-control state and change rate if necessary
        !           242:  *
        !           243:  * @v dev      802.11 device
        !           244:  */
        !           245: static void rc80211_maybe_set_new ( struct net80211_device *dev )
        !           246: {
        !           247:        struct rc80211_ctx *ctx = dev->rctl;
        !           248:        int net_good;
        !           249: 
        !           250:        net_good = rc80211_calc_net_goodness ( ctx, dev->rate );
        !           251: 
        !           252:        if ( ! ctx->started ) {
        !           253:                rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
        !           254:                return;
        !           255:        }
        !           256: 
        !           257:        if ( net_good < 0 )     /* insufficient data */
        !           258:                return;
        !           259: 
        !           260:        if ( net_good > RC_GOODNESS_MAX && dev->rate + 1 < dev->nr_rates ) {
        !           261:                int higher = rc80211_calc_net_goodness ( ctx, dev->rate + 1 );
        !           262:                if ( higher > net_good || higher < 0 )
        !           263:                        rc80211_set_rate ( dev, dev->rate + 1 );
        !           264:                else
        !           265:                        rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
        !           266:        }
        !           267: 
        !           268:        if ( net_good < RC_GOODNESS_MIN ) {
        !           269:                rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
        !           270:        }
        !           271: }
        !           272: 
        !           273: /**
        !           274:  * Update rate-control state
        !           275:  *
        !           276:  * @v dev              802.11 device
        !           277:  * @v direction                One of the direction constants TX or RX
        !           278:  * @v rate_idx         Index of rate at which packet was sent or received
        !           279:  * @v retries          Number of times packet was retried before success
        !           280:  * @v failed           If nonzero, the packet failed to get through
        !           281:  */
        !           282: static void rc80211_update ( struct net80211_device *dev, int direction,
        !           283:                             int rate_idx, int retries, int failed )
        !           284: {
        !           285:        struct rc80211_ctx *ctx = dev->rctl;
        !           286:        u32 goodness = ctx->goodness[direction][rate_idx];
        !           287: 
        !           288:        if ( ctx->count[direction][rate_idx] < 16 )
        !           289:                ctx->count[direction][rate_idx]++;
        !           290: 
        !           291:        goodness <<= 2;
        !           292:        if ( failed )
        !           293:                goodness |= RC_PKT_FAILED;
        !           294:        else if ( retries > 1 )
        !           295:                goodness |= RC_PKT_RETRIED_MULTI;
        !           296:        else if ( retries )
        !           297:                goodness |= RC_PKT_RETRIED_ONCE;
        !           298:        else
        !           299:                goodness |= RC_PKT_OK;
        !           300: 
        !           301:        ctx->goodness[direction][rate_idx] = goodness;
        !           302: 
        !           303:        ctx->packets++;
        !           304: 
        !           305:        rc80211_maybe_set_new ( dev );
        !           306: }
        !           307: 
        !           308: /**
        !           309:  * Update rate-control state for transmitted packet
        !           310:  *
        !           311:  * @v dev      802.11 device
        !           312:  * @v retries  Number of times packet was transmitted before success
        !           313:  * @v rc       Return status code for transmission
        !           314:  */
        !           315: void rc80211_update_tx ( struct net80211_device *dev, int retries, int rc )
        !           316: {
        !           317:        struct rc80211_ctx *ctx = dev->rctl;
        !           318: 
        !           319:        if ( ! ctx->started )
        !           320:                return;
        !           321: 
        !           322:        rc80211_update ( dev, TX, dev->rate, retries, rc );
        !           323: 
        !           324:        /* Check if the last RC_TX_EMERG_FAIL packets have all failed */
        !           325:        if ( ! ( ctx->goodness[TX][dev->rate] &
        !           326:                 ( ( 1 << ( 2 * RC_TX_EMERG_FAIL ) ) - 1 ) ) ) {
        !           327:                if ( dev->rate == 0 )
        !           328:                        DBGC ( dev->rctl, "802.11 RC %p saw %d consecutive "
        !           329:                               "failed TX, but cannot lower rate any further\n",
        !           330:                               dev->rctl, RC_TX_EMERG_FAIL );
        !           331:                else {
        !           332:                        DBGC ( dev->rctl, "802.11 RC %p lowering rate (%d->%d "
        !           333:                               "Mbps) due to %d consecutive TX failures\n",
        !           334:                               dev->rctl, dev->rates[dev->rate] / 10,
        !           335:                               dev->rates[dev->rate - 1] / 10,
        !           336:                               RC_TX_EMERG_FAIL );
        !           337: 
        !           338:                        rc80211_set_rate ( dev, dev->rate - 1 );
        !           339:                }
        !           340:        }
        !           341: }
        !           342: 
        !           343: /**
        !           344:  * Update rate-control state for received packet
        !           345:  *
        !           346:  * @v dev      802.11 device
        !           347:  * @v retry    Whether the received packet had been retransmitted
        !           348:  * @v rate     Rate at which packet was received, in 100 kbps units
        !           349:  */
        !           350: void rc80211_update_rx ( struct net80211_device *dev, int retry, u16 rate )
        !           351: {
        !           352:        int ridx;
        !           353: 
        !           354:        for ( ridx = 0; ridx < dev->nr_rates && dev->rates[ridx] != rate;
        !           355:              ridx++ )
        !           356:                ;
        !           357:        if ( ridx >= dev->nr_rates )
        !           358:                return;         /* couldn't find the rate */
        !           359: 
        !           360:        rc80211_update ( dev, RX, ridx, retry, 0 );
        !           361: }
        !           362: 
        !           363: /**
        !           364:  * Free rate-control context
        !           365:  *
        !           366:  * @v ctx      Rate-control context
        !           367:  */
        !           368: void rc80211_free ( struct rc80211_ctx *ctx )
        !           369: {
        !           370:        free ( ctx );
        !           371: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.