Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.19-rc7 498 lines 14 kB view raw
1/* 2 Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 3 <http://rt2x00.serialmonkey.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19/* 20 Module: rt2x00lib 21 Abstract: rt2x00 generic link tuning routines. 22 */ 23 24#include <linux/kernel.h> 25#include <linux/module.h> 26 27#include "rt2x00.h" 28#include "rt2x00lib.h" 29 30/* 31 * When we lack RSSI information return something less then -80 to 32 * tell the driver to tune the device to maximum sensitivity. 33 */ 34#define DEFAULT_RSSI -128 35 36/* Constants for EWMA calculations. */ 37#define RT2X00_EWMA_FACTOR 1024 38#define RT2X00_EWMA_WEIGHT 8 39 40static inline int rt2x00link_get_avg_rssi(struct ewma *ewma) 41{ 42 unsigned long avg; 43 44 avg = ewma_read(ewma); 45 if (avg) 46 return -avg; 47 48 return DEFAULT_RSSI; 49} 50 51static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) 52{ 53 struct link_ant *ant = &rt2x00dev->link.ant; 54 55 if (rt2x00dev->link.qual.rx_success) 56 return rt2x00link_get_avg_rssi(&ant->rssi_ant); 57 58 return DEFAULT_RSSI; 59} 60 61static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev) 62{ 63 struct link_ant *ant = &rt2x00dev->link.ant; 64 65 if (ant->rssi_history) 66 return ant->rssi_history; 67 return DEFAULT_RSSI; 68} 69 70static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, 71 int rssi) 72{ 73 struct link_ant *ant = &rt2x00dev->link.ant; 74 ant->rssi_history = rssi; 75} 76 77static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) 78{ 79 ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR, 80 RT2X00_EWMA_WEIGHT); 81} 82 83static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) 84{ 85 struct link_ant *ant = &rt2x00dev->link.ant; 86 struct antenna_setup new_ant; 87 int other_antenna; 88 89 int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev); 90 int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev); 91 92 memcpy(&new_ant, &ant->active, sizeof(new_ant)); 93 94 /* 95 * We are done sampling. Now we should evaluate the results. 96 */ 97 ant->flags &= ~ANTENNA_MODE_SAMPLE; 98 99 /* 100 * During the last period we have sampled the RSSI 101 * from both antennas. It now is time to determine 102 * which antenna demonstrated the best performance. 103 * When we are already on the antenna with the best 104 * performance, just create a good starting point 105 * for the history and we are done. 106 */ 107 if (sample_current >= sample_other) { 108 rt2x00link_antenna_update_rssi_history(rt2x00dev, 109 sample_current); 110 return; 111 } 112 113 other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; 114 115 if (ant->flags & ANTENNA_RX_DIVERSITY) 116 new_ant.rx = other_antenna; 117 118 if (ant->flags & ANTENNA_TX_DIVERSITY) 119 new_ant.tx = other_antenna; 120 121 rt2x00lib_config_antenna(rt2x00dev, new_ant); 122} 123 124static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) 125{ 126 struct link_ant *ant = &rt2x00dev->link.ant; 127 struct antenna_setup new_ant; 128 int rssi_curr; 129 int rssi_old; 130 131 memcpy(&new_ant, &ant->active, sizeof(new_ant)); 132 133 /* 134 * Get current RSSI value along with the historical value, 135 * after that update the history with the current value. 136 */ 137 rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev); 138 rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev); 139 rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr); 140 141 /* 142 * Legacy driver indicates that we should swap antenna's 143 * when the difference in RSSI is greater that 5. This 144 * also should be done when the RSSI was actually better 145 * then the previous sample. 146 * When the difference exceeds the threshold we should 147 * sample the rssi from the other antenna to make a valid 148 * comparison between the 2 antennas. 149 */ 150 if (abs(rssi_curr - rssi_old) < 5) 151 return; 152 153 ant->flags |= ANTENNA_MODE_SAMPLE; 154 155 if (ant->flags & ANTENNA_RX_DIVERSITY) 156 new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; 157 158 if (ant->flags & ANTENNA_TX_DIVERSITY) 159 new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; 160 161 rt2x00lib_config_antenna(rt2x00dev, new_ant); 162} 163 164static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) 165{ 166 struct link_ant *ant = &rt2x00dev->link.ant; 167 168 /* 169 * Determine if software diversity is enabled for 170 * either the TX or RX antenna (or both). 171 */ 172 if (!(ant->flags & ANTENNA_RX_DIVERSITY) && 173 !(ant->flags & ANTENNA_TX_DIVERSITY)) { 174 ant->flags = 0; 175 return true; 176 } 177 178 /* 179 * If we have only sampled the data over the last period 180 * we should now harvest the data. Otherwise just evaluate 181 * the data. The latter should only be performed once 182 * every 2 seconds. 183 */ 184 if (ant->flags & ANTENNA_MODE_SAMPLE) { 185 rt2x00lib_antenna_diversity_sample(rt2x00dev); 186 return true; 187 } else if (rt2x00dev->link.count & 1) { 188 rt2x00lib_antenna_diversity_eval(rt2x00dev); 189 return true; 190 } 191 192 return false; 193} 194 195void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, 196 struct sk_buff *skb, 197 struct rxdone_entry_desc *rxdesc) 198{ 199 struct link *link = &rt2x00dev->link; 200 struct link_qual *qual = &rt2x00dev->link.qual; 201 struct link_ant *ant = &rt2x00dev->link.ant; 202 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 203 204 /* 205 * No need to update the stats for !=STA interfaces 206 */ 207 if (!rt2x00dev->intf_sta_count) 208 return; 209 210 /* 211 * Frame was received successfully since non-succesfull 212 * frames would have been dropped by the hardware. 213 */ 214 qual->rx_success++; 215 216 /* 217 * We are only interested in quality statistics from 218 * beacons which came from the BSS which we are 219 * associated with. 220 */ 221 if (!ieee80211_is_beacon(hdr->frame_control) || 222 !(rxdesc->dev_flags & RXDONE_MY_BSS)) 223 return; 224 225 /* 226 * Update global RSSI 227 */ 228 ewma_add(&link->avg_rssi, -rxdesc->rssi); 229 230 /* 231 * Update antenna RSSI 232 */ 233 ewma_add(&ant->rssi_ant, -rxdesc->rssi); 234} 235 236void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) 237{ 238 struct link *link = &rt2x00dev->link; 239 240 /* 241 * Link tuning should only be performed when 242 * an active sta interface exists. AP interfaces 243 * don't need link tuning and monitor mode interfaces 244 * should never have to work with link tuners. 245 */ 246 if (!rt2x00dev->intf_sta_count) 247 return; 248 249 /** 250 * While scanning, link tuning is disabled. By default 251 * the most sensitive settings will be used to make sure 252 * that all beacons and probe responses will be received 253 * during the scan. 254 */ 255 if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) 256 return; 257 258 rt2x00link_reset_tuner(rt2x00dev, false); 259 260 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 261 ieee80211_queue_delayed_work(rt2x00dev->hw, 262 &link->work, LINK_TUNE_INTERVAL); 263} 264 265void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev) 266{ 267 cancel_delayed_work_sync(&rt2x00dev->link.work); 268} 269 270void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) 271{ 272 struct link_qual *qual = &rt2x00dev->link.qual; 273 u8 vgc_level = qual->vgc_level_reg; 274 275 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 276 return; 277 278 /* 279 * Reset link information. 280 * Both the currently active vgc level as well as 281 * the link tuner counter should be reset. Resetting 282 * the counter is important for devices where the 283 * device should only perform link tuning during the 284 * first minute after being enabled. 285 */ 286 rt2x00dev->link.count = 0; 287 memset(qual, 0, sizeof(*qual)); 288 ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR, 289 RT2X00_EWMA_WEIGHT); 290 291 /* 292 * Restore the VGC level as stored in the registers, 293 * the driver can use this to determine if the register 294 * must be updated during reset or not. 295 */ 296 qual->vgc_level_reg = vgc_level; 297 298 /* 299 * Reset the link tuner. 300 */ 301 rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual); 302 303 if (antenna) 304 rt2x00link_antenna_reset(rt2x00dev); 305} 306 307static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev) 308{ 309 struct link_qual *qual = &rt2x00dev->link.qual; 310 311 qual->rx_success = 0; 312 qual->rx_failed = 0; 313 qual->tx_success = 0; 314 qual->tx_failed = 0; 315} 316 317static void rt2x00link_tuner(struct work_struct *work) 318{ 319 struct rt2x00_dev *rt2x00dev = 320 container_of(work, struct rt2x00_dev, link.work.work); 321 struct link *link = &rt2x00dev->link; 322 struct link_qual *qual = &rt2x00dev->link.qual; 323 324 /* 325 * When the radio is shutting down we should 326 * immediately cease all link tuning. 327 */ 328 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || 329 test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) 330 return; 331 332 /* 333 * Update statistics. 334 */ 335 rt2x00dev->ops->lib->link_stats(rt2x00dev, qual); 336 rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed; 337 338 /* 339 * Update quality RSSI for link tuning, 340 * when we have received some frames and we managed to 341 * collect the RSSI data we could use this. Otherwise we 342 * must fallback to the default RSSI value. 343 */ 344 if (!qual->rx_success) 345 qual->rssi = DEFAULT_RSSI; 346 else 347 qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi); 348 349 /* 350 * Check if link tuning is supported by the hardware, some hardware 351 * do not support link tuning at all, while other devices can disable 352 * the feature from the EEPROM. 353 */ 354 if (rt2x00_has_cap_link_tuning(rt2x00dev)) 355 rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); 356 357 /* 358 * Send a signal to the led to update the led signal strength. 359 */ 360 rt2x00leds_led_quality(rt2x00dev, qual->rssi); 361 362 /* 363 * Evaluate antenna setup, make this the last step when 364 * rt2x00lib_antenna_diversity made changes the quality 365 * statistics will be reset. 366 */ 367 if (rt2x00lib_antenna_diversity(rt2x00dev)) 368 rt2x00link_reset_qual(rt2x00dev); 369 370 /* 371 * Increase tuner counter, and reschedule the next link tuner run. 372 */ 373 link->count++; 374 375 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 376 ieee80211_queue_delayed_work(rt2x00dev->hw, 377 &link->work, LINK_TUNE_INTERVAL); 378} 379 380void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) 381{ 382 struct link *link = &rt2x00dev->link; 383 384 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && 385 rt2x00dev->ops->lib->watchdog) 386 ieee80211_queue_delayed_work(rt2x00dev->hw, 387 &link->watchdog_work, 388 WATCHDOG_INTERVAL); 389} 390 391void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) 392{ 393 cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work); 394} 395 396static void rt2x00link_watchdog(struct work_struct *work) 397{ 398 struct rt2x00_dev *rt2x00dev = 399 container_of(work, struct rt2x00_dev, link.watchdog_work.work); 400 struct link *link = &rt2x00dev->link; 401 402 /* 403 * When the radio is shutting down we should 404 * immediately cease the watchdog monitoring. 405 */ 406 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 407 return; 408 409 rt2x00dev->ops->lib->watchdog(rt2x00dev); 410 411 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 412 ieee80211_queue_delayed_work(rt2x00dev->hw, 413 &link->watchdog_work, 414 WATCHDOG_INTERVAL); 415} 416 417void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) 418{ 419 struct link *link = &rt2x00dev->link; 420 421 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && 422 rt2x00dev->ops->lib->gain_calibration) 423 ieee80211_queue_delayed_work(rt2x00dev->hw, 424 &link->agc_work, 425 AGC_INTERVAL); 426} 427 428void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev) 429{ 430 struct link *link = &rt2x00dev->link; 431 432 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && 433 rt2x00dev->ops->lib->vco_calibration) 434 ieee80211_queue_delayed_work(rt2x00dev->hw, 435 &link->vco_work, 436 VCO_INTERVAL); 437} 438 439void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) 440{ 441 cancel_delayed_work_sync(&rt2x00dev->link.agc_work); 442} 443 444void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev) 445{ 446 cancel_delayed_work_sync(&rt2x00dev->link.vco_work); 447} 448 449static void rt2x00link_agc(struct work_struct *work) 450{ 451 struct rt2x00_dev *rt2x00dev = 452 container_of(work, struct rt2x00_dev, link.agc_work.work); 453 struct link *link = &rt2x00dev->link; 454 455 /* 456 * When the radio is shutting down we should 457 * immediately cease the watchdog monitoring. 458 */ 459 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 460 return; 461 462 rt2x00dev->ops->lib->gain_calibration(rt2x00dev); 463 464 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 465 ieee80211_queue_delayed_work(rt2x00dev->hw, 466 &link->agc_work, 467 AGC_INTERVAL); 468} 469 470static void rt2x00link_vcocal(struct work_struct *work) 471{ 472 struct rt2x00_dev *rt2x00dev = 473 container_of(work, struct rt2x00_dev, link.vco_work.work); 474 struct link *link = &rt2x00dev->link; 475 476 /* 477 * When the radio is shutting down we should 478 * immediately cease the VCO calibration. 479 */ 480 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 481 return; 482 483 rt2x00dev->ops->lib->vco_calibration(rt2x00dev); 484 485 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 486 ieee80211_queue_delayed_work(rt2x00dev->hw, 487 &link->vco_work, 488 VCO_INTERVAL); 489} 490 491void rt2x00link_register(struct rt2x00_dev *rt2x00dev) 492{ 493 INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); 494 if (rt2x00_has_cap_vco_recalibration(rt2x00dev)) 495 INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal); 496 INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); 497 INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); 498}