diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00link.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00link.c | 74 |
1 files changed, 27 insertions, 47 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 8368aab86f28..c2b3b6629188 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -35,50 +35,28 @@ | |||
35 | */ | 35 | */ |
36 | #define DEFAULT_RSSI -128 | 36 | #define DEFAULT_RSSI -128 |
37 | 37 | ||
38 | /* | 38 | /* Constants for EWMA calculations. */ |
39 | * Helper struct and macro to work with moving/walking averages. | 39 | #define RT2X00_EWMA_FACTOR 1024 |
40 | * When adding a value to the average value the following calculation | 40 | #define RT2X00_EWMA_WEIGHT 8 |
41 | * is needed: | 41 | |
42 | * | 42 | static inline int rt2x00link_get_avg_rssi(struct ewma *ewma) |
43 | * avg_rssi = ((avg_rssi * 7) + rssi) / 8; | 43 | { |
44 | * | 44 | unsigned long avg; |
45 | * The advantage of this approach is that we only need 1 variable | 45 | |
46 | * to store the average in (No need for a count and a total). | 46 | avg = ewma_read(ewma); |
47 | * But more importantly, normal average values will over time | 47 | if (avg) |
48 | * move less and less towards newly added values this results | 48 | return -avg; |
49 | * that with link tuning, the device can have a very good RSSI | 49 | |
50 | * for a few minutes but when the device is moved away from the AP | 50 | return DEFAULT_RSSI; |
51 | * the average will not decrease fast enough to compensate. | 51 | } |
52 | * The walking average compensates this and will move towards | ||
53 | * the new values correctly allowing a effective link tuning, | ||
54 | * the speed of the average moving towards other values depends | ||
55 | * on the value for the number of samples. The higher the number | ||
56 | * of samples, the slower the average will move. | ||
57 | * We use two variables to keep track of the average value to | ||
58 | * compensate for the rounding errors. This can be a significant | ||
59 | * error (>5dBm) if the factor is too low. | ||
60 | */ | ||
61 | #define AVG_SAMPLES 8 | ||
62 | #define AVG_FACTOR 1000 | ||
63 | #define MOVING_AVERAGE(__avg, __val) \ | ||
64 | ({ \ | ||
65 | struct avg_val __new; \ | ||
66 | __new.avg_weight = \ | ||
67 | (__avg).avg_weight ? \ | ||
68 | ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \ | ||
69 | ((__val) * (AVG_FACTOR))) / \ | ||
70 | (AVG_SAMPLES)) : \ | ||
71 | ((__val) * (AVG_FACTOR)); \ | ||
72 | __new.avg = __new.avg_weight / (AVG_FACTOR); \ | ||
73 | __new; \ | ||
74 | }) | ||
75 | 52 | ||
76 | static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) | 53 | static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) |
77 | { | 54 | { |
78 | struct link_ant *ant = &rt2x00dev->link.ant; | 55 | struct link_ant *ant = &rt2x00dev->link.ant; |
79 | 56 | ||
80 | if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success) | 57 | if (rt2x00dev->link.qual.rx_success) |
81 | return ant->rssi_ant.avg; | 58 | return rt2x00link_get_avg_rssi(&ant->rssi_ant); |
59 | |||
82 | return DEFAULT_RSSI; | 60 | return DEFAULT_RSSI; |
83 | } | 61 | } |
84 | 62 | ||
@@ -100,8 +78,8 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, | |||
100 | 78 | ||
101 | static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) | 79 | static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) |
102 | { | 80 | { |
103 | rt2x00dev->link.ant.rssi_ant.avg = 0; | 81 | ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR, |
104 | rt2x00dev->link.ant.rssi_ant.avg_weight = 0; | 82 | RT2X00_EWMA_WEIGHT); |
105 | } | 83 | } |
106 | 84 | ||
107 | static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) | 85 | static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) |
@@ -249,12 +227,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | |||
249 | /* | 227 | /* |
250 | * Update global RSSI | 228 | * Update global RSSI |
251 | */ | 229 | */ |
252 | link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi); | 230 | ewma_add(&link->avg_rssi, -rxdesc->rssi); |
253 | 231 | ||
254 | /* | 232 | /* |
255 | * Update antenna RSSI | 233 | * Update antenna RSSI |
256 | */ | 234 | */ |
257 | ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); | 235 | ewma_add(&ant->rssi_ant, -rxdesc->rssi); |
258 | } | 236 | } |
259 | 237 | ||
260 | void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) | 238 | void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) |
@@ -309,6 +287,8 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) | |||
309 | */ | 287 | */ |
310 | rt2x00dev->link.count = 0; | 288 | rt2x00dev->link.count = 0; |
311 | memset(qual, 0, sizeof(*qual)); | 289 | memset(qual, 0, sizeof(*qual)); |
290 | ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR, | ||
291 | RT2X00_EWMA_WEIGHT); | ||
312 | 292 | ||
313 | /* | 293 | /* |
314 | * Restore the VGC level as stored in the registers, | 294 | * Restore the VGC level as stored in the registers, |
@@ -363,17 +343,17 @@ static void rt2x00link_tuner(struct work_struct *work) | |||
363 | * collect the RSSI data we could use this. Otherwise we | 343 | * collect the RSSI data we could use this. Otherwise we |
364 | * must fallback to the default RSSI value. | 344 | * must fallback to the default RSSI value. |
365 | */ | 345 | */ |
366 | if (!link->avg_rssi.avg || !qual->rx_success) | 346 | if (!qual->rx_success) |
367 | qual->rssi = DEFAULT_RSSI; | 347 | qual->rssi = DEFAULT_RSSI; |
368 | else | 348 | else |
369 | qual->rssi = link->avg_rssi.avg; | 349 | qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi); |
370 | 350 | ||
371 | /* | 351 | /* |
372 | * Check if link tuning is supported by the hardware, some hardware | 352 | * Check if link tuning is supported by the hardware, some hardware |
373 | * do not support link tuning at all, while other devices can disable | 353 | * do not support link tuning at all, while other devices can disable |
374 | * the feature from the EEPROM. | 354 | * the feature from the EEPROM. |
375 | */ | 355 | */ |
376 | if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags)) | 356 | if (rt2x00_has_cap_link_tuning(rt2x00dev)) |
377 | rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); | 357 | rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); |
378 | 358 | ||
379 | /* | 359 | /* |
@@ -513,7 +493,7 @@ static void rt2x00link_vcocal(struct work_struct *work) | |||
513 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) | 493 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) |
514 | { | 494 | { |
515 | INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); | 495 | INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); |
516 | if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags)) | 496 | if (rt2x00_has_cap_vco_recalibration(rt2x00dev)) |
517 | INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal); | 497 | INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal); |
518 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); | 498 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); |
519 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); | 499 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); |