1 /* 2 * Simple 802.11 rate-control algorithm for gPXE. 3 * 4 * Copyright (c) 2009 Joshua Oreman <oremanj (at) rwcr.net>. 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 <gpxe/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 gPXE'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 gPXE 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 } 372