aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGabor Juhos <juhosg@openwrt.org>2013-10-09 05:00:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-10-10 13:49:29 -0400
commit1dc254ac9f04f23d332ed8eea79055f067c90627 (patch)
treecbadcc1ab4c37dae2d5856f98fa3245346bbca31
parent8f78b0bb8791d8164aed86970905cdc12f3b8496 (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/Kconfig1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h16
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c70
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
220config RT2X00_LIB 220config RT2X00_LIB
221 tristate 221 tristate
222 select AVERAGE
222 223
223config RT2X00_LIB_FIRMWARE 224config 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 */
147struct avg_val {
148 int avg;
149 int avg_weight;
150};
151
152enum rt2x00_chip_intf { 142enum 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 * 42static 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
76static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) 53static 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
101static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) 79static 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
107static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) 85static 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
260void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) 238void 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