diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2013-10-09 05:00:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-10-10 13:49:29 -0400 |
commit | 1dc254ac9f04f23d332ed8eea79055f067c90627 (patch) | |
tree | cbadcc1ab4c37dae2d5856f98fa3245346bbca31 | |
parent | 8f78b0bb8791d8164aed86970905cdc12f3b8496 (diff) |
rt2x00: use generic EWMA functions for average RSSI calculations
Remove the local MOVING_AVERAGE implementation, and use
the generic EWMA functions instead.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rt2x00/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00link.c | 70 |
3 files changed, 29 insertions, 58 deletions
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 68dbbb9c6d12..a18b0051a745 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig | |||
@@ -219,6 +219,7 @@ config RT2X00_LIB_USB | |||
219 | 219 | ||
220 | config RT2X00_LIB | 220 | config RT2X00_LIB |
221 | tristate | 221 | tristate |
222 | select AVERAGE | ||
222 | 223 | ||
223 | config RT2X00_LIB_FIRMWARE | 224 | config RT2X00_LIB_FIRMWARE |
224 | boolean | 225 | boolean |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index fe4c572db52c..30ed92a6121e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/input-polldev.h> | 39 | #include <linux/input-polldev.h> |
40 | #include <linux/kfifo.h> | 40 | #include <linux/kfifo.h> |
41 | #include <linux/hrtimer.h> | 41 | #include <linux/hrtimer.h> |
42 | #include <linux/average.h> | ||
42 | 43 | ||
43 | #include <net/mac80211.h> | 44 | #include <net/mac80211.h> |
44 | 45 | ||
@@ -138,17 +139,6 @@ | |||
138 | #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ | 139 | #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ |
139 | GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) | 140 | GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) |
140 | 141 | ||
141 | /* | ||
142 | * Structure for average calculation | ||
143 | * The avg field contains the actual average value, | ||
144 | * but avg_weight is internally used during calculations | ||
145 | * to prevent rounding errors. | ||
146 | */ | ||
147 | struct avg_val { | ||
148 | int avg; | ||
149 | int avg_weight; | ||
150 | }; | ||
151 | |||
152 | enum rt2x00_chip_intf { | 142 | enum rt2x00_chip_intf { |
153 | RT2X00_CHIP_INTF_PCI, | 143 | RT2X00_CHIP_INTF_PCI, |
154 | RT2X00_CHIP_INTF_PCIE, | 144 | RT2X00_CHIP_INTF_PCIE, |
@@ -297,7 +287,7 @@ struct link_ant { | |||
297 | * Similar to the avg_rssi in the link_qual structure | 287 | * Similar to the avg_rssi in the link_qual structure |
298 | * this value is updated by using the walking average. | 288 | * this value is updated by using the walking average. |
299 | */ | 289 | */ |
300 | struct avg_val rssi_ant; | 290 | struct ewma rssi_ant; |
301 | }; | 291 | }; |
302 | 292 | ||
303 | /* | 293 | /* |
@@ -326,7 +316,7 @@ struct link { | |||
326 | /* | 316 | /* |
327 | * Currently active average RSSI value | 317 | * Currently active average RSSI value |
328 | */ | 318 | */ |
329 | struct avg_val avg_rssi; | 319 | struct ewma avg_rssi; |
330 | 320 | ||
331 | /* | 321 | /* |
332 | * Work structure for scheduling periodic link tuning. | 322 | * Work structure for scheduling periodic link tuning. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 8368aab86f28..a0e3c021c128 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,10 +343,10 @@ 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 |