summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rt2x00/rt2x00link.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00link.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c168
1 files changed, 88 insertions, 80 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index eb9b981b9139..c64db0ba7f40 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -46,7 +46,15 @@
#define DEFAULT_PERCENTAGE 50
/*
- * Small helper macro to work with moving/walking averages.
+ * Small helper macro for percentage calculation
+ * This is a very simple macro with the only catch that it will
+ * produce a default value in case no total value was provided.
+ */
+#define PERCENTAGE(__value, __total) \
+ ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
+
+/*
+ * Helper struct and macro to work with moving/walking averages.
* When adding a value to the average value the following calculation
* is needed:
*
@@ -60,18 +68,28 @@
* for a few minutes but when the device is moved away from the AP
* the average will not decrease fast enough to compensate.
* The walking average compensates this and will move towards
- * the new values correctly allowing a effective link tuning.
- */
-#define MOVING_AVERAGE(__avg, __val, __samples) \
- ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
-
-/*
- * Small helper macro for percentage calculation
- * This is a very simple macro with the only catch that it will
- * produce a default value in case no total value was provided.
+ * the new values correctly allowing a effective link tuning,
+ * the speed of the average moving towards other values depends
+ * on the value for the number of samples. The higher the number
+ * of samples, the slower the average will move.
+ * We use two variables to keep track of the average value to
+ * compensate for the rounding errors. This can be a significant
+ * error (>5dBm) if the factor is too low.
*/
-#define PERCENTAGE(__value, __total) \
- ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
+#define AVG_SAMPLES 8
+#define AVG_FACTOR 1000
+#define MOVING_AVERAGE(__avg, __val) \
+({ \
+ struct avg_val __new; \
+ __new.avg_weight = \
+ (__avg).avg_weight ? \
+ ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
+ ((__val) * (AVG_FACTOR))) / \
+ (AVG_SAMPLES) ) : \
+ ((__val) * (AVG_FACTOR)); \
+ __new.avg = __new.avg_weight / (AVG_FACTOR); \
+ __new; \
+})
/*
* For calculating the Signal quality we have determined
@@ -98,56 +116,41 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- if (ant->rssi_ant && rt2x00dev->link.qual.rx_success)
- return ant->rssi_ant;
+ if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success)
+ return ant->rssi_ant.avg;
return DEFAULT_RSSI;
}
-static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev,
- enum antenna antenna)
+static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- if (ant->rssi_history[antenna - ANTENNA_A])
- return ant->rssi_history[antenna - ANTENNA_A];
+ if (ant->rssi_history)
+ return ant->rssi_history;
return DEFAULT_RSSI;
}
-/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
-#define rt2x00link_antenna_get_rssi_rx_history(__dev) \
- rt2x00link_antenna_get_rssi_history((__dev), \
- (__dev)->link.ant.active.rx)
-#define rt2x00link_antenna_get_rssi_tx_history(__dev) \
- rt2x00link_antenna_get_rssi_history((__dev), \
- (__dev)->link.ant.active.tx)
static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
- enum antenna antenna,
int rssi)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi;
+ ant->rssi_history = rssi;
}
-/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
-#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \
- rt2x00link_antenna_update_rssi_history((__dev), \
- (__dev)->link.ant.active.rx, \
- (__rssi))
-#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \
- rt2x00link_antenna_update_rssi_history((__dev), \
- (__dev)->link.ant.active.tx, \
- (__rssi))
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
{
- rt2x00dev->link.ant.rssi_ant = 0;
+ rt2x00dev->link.ant.rssi_ant.avg = 0;
+ rt2x00dev->link.ant.rssi_ant.avg_weight = 0;
}
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
- int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A);
- int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B);
+ int other_antenna;
+
+ int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
+ int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
memcpy(&new_ant, &ant->active, sizeof(new_ant));
@@ -158,22 +161,27 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/*
* During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
+ * from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
- * performance, then there really is nothing for us
- * left to do.
+ * performance, just create a good starting point
+ * for the history and we are done.
*/
- if (sample_a == sample_b)
+ if (sample_current >= sample_other) {
+ rt2x00link_antenna_update_rssi_history(rt2x00dev,
+ sample_current);
return;
+ }
+
+ other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_RX_DIVERSITY)
- new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ new_ant.rx = other_antenna;
if (ant->flags & ANTENNA_TX_DIVERSITY)
- new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ new_ant.tx = other_antenna;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
@@ -190,8 +198,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
* after that update the history with the current value.
*/
rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
- rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev);
- rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr);
+ rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
+ rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
/*
* Legacy driver indicates that we should swap antenna's
@@ -213,12 +221,13 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
-static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
+static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
+ unsigned int flags = ant->flags;
/*
* Determine if software diversity is enabled for
@@ -226,30 +235,38 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
* Always perform this check since within the link
* tuner interval the configuration might have changed.
*/
- ant->flags &= ~ANTENNA_RX_DIVERSITY;
- ant->flags &= ~ANTENNA_TX_DIVERSITY;
+ flags &= ~ANTENNA_RX_DIVERSITY;
+ flags &= ~ANTENNA_TX_DIVERSITY;
if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_RX_DIVERSITY;
+ flags |= ANTENNA_RX_DIVERSITY;
if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_TX_DIVERSITY;
+ flags |= ANTENNA_TX_DIVERSITY;
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
ant->flags = 0;
- return;
+ return true;
}
+ /* Update flags */
+ ant->flags = flags;
+
/*
* If we have only sampled the data over the last period
* we should now harvest the data. Otherwise just evaluate
* the data. The latter should only be performed once
* every 2 seconds.
*/
- if (ant->flags & ANTENNA_MODE_SAMPLE)
+ if (ant->flags & ANTENNA_MODE_SAMPLE) {
rt2x00lib_antenna_diversity_sample(rt2x00dev);
- else if (rt2x00dev->link.count & 1)
+ return true;
+ } else if (rt2x00dev->link.count & 1) {
rt2x00lib_antenna_diversity_eval(rt2x00dev);
+ return true;
+ }
+
+ return false;
}
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
@@ -260,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual = &rt2x00dev->link.qual;
struct link_ant *ant = &rt2x00dev->link.ant;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- int avg_rssi = rxdesc->rssi;
- int ant_rssi = rxdesc->rssi;
/*
* Frame was received successfully since non-succesfull
@@ -281,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update global RSSI
*/
- if (link->avg_rssi)
- avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
- link->avg_rssi = avg_rssi;
+ link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi);
/*
* Update antenna RSSI
*/
- if (ant->rssi_ant)
- ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8);
- ant->rssi_ant = ant_rssi;
+ ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
}
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
@@ -351,8 +362,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00link_reset_tuner(rt2x00dev, false);
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -423,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work)
* collect the RSSI data we could use this. Otherwise we
* must fallback to the default RSSI value.
*/
- if (!link->avg_rssi || !qual->rx_success)
+ if (!link->avg_rssi.avg || !qual->rx_success)
qual->rssi = DEFAULT_RSSI;
else
- qual->rssi = link->avg_rssi;
+ qual->rssi = link->avg_rssi.avg;
/*
* Only perform the link tuning when Link tuning
@@ -444,25 +455,22 @@ static void rt2x00link_tuner(struct work_struct *work)
/*
* Send a signal to the led to update the led signal strength.
*/
- rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
-
- /*
- * Evaluate antenna setup, make this the last step since this could
- * possibly reset some statistics.
- */
- rt2x00lib_antenna_diversity(rt2x00dev);
+ rt2x00leds_led_quality(rt2x00dev, qual->rssi);
/*
- * Reset the quality counters which recounted during each period.
+ * Evaluate antenna setup, make this the last step when
+ * rt2x00lib_antenna_diversity made changes the quality
+ * statistics will be reset.
*/
- rt2x00link_reset_qual(rt2x00dev);
+ if (rt2x00lib_antenna_diversity(rt2x00dev))
+ rt2x00link_reset_qual(rt2x00dev);
/*
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)