diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00link.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00link.c | 168 |
1 files changed, 88 insertions, 80 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index eb9b981b913..c64db0ba7f4 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) |