|
@@ -29,60 +29,6 @@
|
|
#include "rt2x00.h"
|
|
#include "rt2x00.h"
|
|
#include "rt2x00lib.h"
|
|
#include "rt2x00lib.h"
|
|
|
|
|
|
-/*
|
|
|
|
- * Link tuning handlers
|
|
|
|
- */
|
|
|
|
-void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Reset link information.
|
|
|
|
- * Both the currently active vgc level as well as
|
|
|
|
- * the link tuner counter should be reset. Resetting
|
|
|
|
- * the counter is important for devices where the
|
|
|
|
- * device should only perform link tuning during the
|
|
|
|
- * first minute after being enabled.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->link.count = 0;
|
|
|
|
- rt2x00dev->link.vgc_level = 0;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Reset the link tuner.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- /*
|
|
|
|
- * Clear all (possibly) pre-existing quality statistics.
|
|
|
|
- */
|
|
|
|
- memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * The RX and TX percentage should start at 50%
|
|
|
|
- * this will assure we will get at least get some
|
|
|
|
- * decent value when the link tuner starts.
|
|
|
|
- * The value will be dropped and overwritten with
|
|
|
|
- * the correct (measured )value anyway during the
|
|
|
|
- * first run of the link tuner.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->link.qual.rx_percentage = 50;
|
|
|
|
- rt2x00dev->link.qual.tx_percentage = 50;
|
|
|
|
-
|
|
|
|
- rt2x00lib_reset_link_tuner(rt2x00dev);
|
|
|
|
-
|
|
|
|
- queue_delayed_work(rt2x00dev->hw->workqueue,
|
|
|
|
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- cancel_delayed_work_sync(&rt2x00dev->link.work);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Radio control handlers.
|
|
* Radio control handlers.
|
|
*/
|
|
*/
|
|
@@ -161,238 +107,15 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
|
|
* When we are disabling the RX, we should also stop the link tuner.
|
|
* When we are disabling the RX, we should also stop the link tuner.
|
|
*/
|
|
*/
|
|
if (state == STATE_RADIO_RX_OFF)
|
|
if (state == STATE_RADIO_RX_OFF)
|
|
- rt2x00lib_stop_link_tuner(rt2x00dev);
|
|
|
|
|
|
+ rt2x00link_stop_tuner(rt2x00dev);
|
|
|
|
|
|
rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
|
|
rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
|
|
|
|
|
|
/*
|
|
/*
|
|
* When we are enabling the RX, we should also start the link tuner.
|
|
* When we are enabling the RX, we should also start the link tuner.
|
|
*/
|
|
*/
|
|
- if (state == STATE_RADIO_RX_ON &&
|
|
|
|
- (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count))
|
|
|
|
- rt2x00lib_start_link_tuner(rt2x00dev);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- struct antenna_setup ant;
|
|
|
|
- int sample_a =
|
|
|
|
- rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
|
|
|
|
- int sample_b =
|
|
|
|
- rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
|
|
|
|
-
|
|
|
|
- memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * We are done sampling. Now we should evaluate the results.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * During the last period we have sampled the RSSI
|
|
|
|
- * from both antenna's. 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.
|
|
|
|
- */
|
|
|
|
- if (sample_a == sample_b)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
|
|
|
|
- ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
|
|
|
|
-
|
|
|
|
- if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
|
|
|
|
- ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
|
|
|
|
-
|
|
|
|
- rt2x00lib_config_antenna(rt2x00dev, &ant);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- struct antenna_setup ant;
|
|
|
|
- int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
|
|
|
|
- int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
|
|
|
|
-
|
|
|
|
- memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Legacy driver indicates that we should swap antenna's
|
|
|
|
- * when the difference in RSSI is greater that 5. This
|
|
|
|
- * also should be done when the RSSI was actually better
|
|
|
|
- * then the previous sample.
|
|
|
|
- * When the difference exceeds the threshold we should
|
|
|
|
- * sample the rssi from the other antenna to make a valid
|
|
|
|
- * comparison between the 2 antennas.
|
|
|
|
- */
|
|
|
|
- if (abs(rssi_curr - rssi_old) < 5)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
|
|
|
|
-
|
|
|
|
- if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
|
|
|
|
- ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
|
|
|
|
-
|
|
|
|
- if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
|
|
|
|
- ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
|
|
|
|
-
|
|
|
|
- rt2x00lib_config_antenna(rt2x00dev, &ant);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
|
|
|
|
-{
|
|
|
|
- /*
|
|
|
|
- * Determine if software diversity is enabled for
|
|
|
|
- * either the TX or RX antenna (or both).
|
|
|
|
- * Always perform this check since within the link
|
|
|
|
- * tuner interval the configuration might have changed.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
|
|
|
|
- rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
|
|
|
|
-
|
|
|
|
- if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
|
|
|
|
- rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
|
|
|
|
- if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
|
|
|
|
- rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
|
|
|
|
-
|
|
|
|
- if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
|
|
|
|
- !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) {
|
|
|
|
- rt2x00dev->link.ant.flags = 0;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * 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 (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE)
|
|
|
|
- rt2x00lib_evaluate_antenna_sample(rt2x00dev);
|
|
|
|
- else if (rt2x00dev->link.count & 1)
|
|
|
|
- rt2x00lib_evaluate_antenna_eval(rt2x00dev);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_update_link_stats(struct link *link, int rssi)
|
|
|
|
-{
|
|
|
|
- int avg_rssi = rssi;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Update global RSSI
|
|
|
|
- */
|
|
|
|
- if (link->qual.avg_rssi)
|
|
|
|
- avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8);
|
|
|
|
- link->qual.avg_rssi = avg_rssi;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Update antenna RSSI
|
|
|
|
- */
|
|
|
|
- if (link->ant.rssi_ant)
|
|
|
|
- rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8);
|
|
|
|
- link->ant.rssi_ant = rssi;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_precalculate_link_signal(struct link_qual *qual)
|
|
|
|
-{
|
|
|
|
- if (qual->rx_failed || qual->rx_success)
|
|
|
|
- qual->rx_percentage =
|
|
|
|
- (qual->rx_success * 100) /
|
|
|
|
- (qual->rx_failed + qual->rx_success);
|
|
|
|
- else
|
|
|
|
- qual->rx_percentage = 50;
|
|
|
|
-
|
|
|
|
- if (qual->tx_failed || qual->tx_success)
|
|
|
|
- qual->tx_percentage =
|
|
|
|
- (qual->tx_success * 100) /
|
|
|
|
- (qual->tx_failed + qual->tx_success);
|
|
|
|
- else
|
|
|
|
- qual->tx_percentage = 50;
|
|
|
|
-
|
|
|
|
- qual->rx_success = 0;
|
|
|
|
- qual->rx_failed = 0;
|
|
|
|
- qual->tx_success = 0;
|
|
|
|
- qual->tx_failed = 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
|
|
|
|
- int rssi)
|
|
|
|
-{
|
|
|
|
- int rssi_percentage = 0;
|
|
|
|
- int signal;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * We need a positive value for the RSSI.
|
|
|
|
- */
|
|
|
|
- if (rssi < 0)
|
|
|
|
- rssi += rt2x00dev->rssi_offset;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Calculate the different percentages,
|
|
|
|
- * which will be used for the signal.
|
|
|
|
- */
|
|
|
|
- if (rt2x00dev->rssi_offset)
|
|
|
|
- rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Add the individual percentages and use the WEIGHT
|
|
|
|
- * defines to calculate the current link signal.
|
|
|
|
- */
|
|
|
|
- signal = ((WEIGHT_RSSI * rssi_percentage) +
|
|
|
|
- (WEIGHT_TX * rt2x00dev->link.qual.tx_percentage) +
|
|
|
|
- (WEIGHT_RX * rt2x00dev->link.qual.rx_percentage)) / 100;
|
|
|
|
-
|
|
|
|
- return (signal > 100) ? 100 : signal;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void rt2x00lib_link_tuner(struct work_struct *work)
|
|
|
|
-{
|
|
|
|
- struct rt2x00_dev *rt2x00dev =
|
|
|
|
- container_of(work, struct rt2x00_dev, link.work.work);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * When the radio is shutting down we should
|
|
|
|
- * immediately cease all link tuning.
|
|
|
|
- */
|
|
|
|
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Update statistics.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual);
|
|
|
|
- rt2x00dev->low_level_stats.dot11FCSErrorCount +=
|
|
|
|
- rt2x00dev->link.qual.rx_failed;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Only perform the link tuning when Link tuning
|
|
|
|
- * has been enabled (This could have been disabled from the EEPROM).
|
|
|
|
- */
|
|
|
|
- if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
|
|
|
|
- rt2x00dev->ops->lib->link_tuner(rt2x00dev);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Precalculate a portion of the link signal which is
|
|
|
|
- * in based on the tx/rx success/failure counters.
|
|
|
|
- */
|
|
|
|
- rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Send a signal to the led to update the led signal strength.
|
|
|
|
- */
|
|
|
|
- rt2x00leds_led_quality(rt2x00dev, rt2x00dev->link.qual.avg_rssi);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Evaluate antenna setup, make this the last step since this could
|
|
|
|
- * possibly reset some statistics.
|
|
|
|
- */
|
|
|
|
- rt2x00lib_evaluate_antenna(rt2x00dev);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Increase tuner counter, and reschedule the next link tuner run.
|
|
|
|
- */
|
|
|
|
- rt2x00dev->link.count++;
|
|
|
|
- queue_delayed_work(rt2x00dev->hw->workqueue,
|
|
|
|
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
|
|
|
|
|
|
+ if (state == STATE_RADIO_RX_ON)
|
|
|
|
+ rt2x00link_start_tuner(rt2x00dev);
|
|
}
|
|
}
|
|
|
|
|
|
static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
|
|
static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
|
|
@@ -597,7 +320,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
|
struct sk_buff *skb;
|
|
struct sk_buff *skb;
|
|
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
|
|
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_supported_band *sband;
|
|
- struct ieee80211_hdr *hdr;
|
|
|
|
const struct rt2x00_rate *rate;
|
|
const struct rt2x00_rate *rate;
|
|
unsigned int header_length;
|
|
unsigned int header_length;
|
|
unsigned int align;
|
|
unsigned int align;
|
|
@@ -674,23 +396,14 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Only update link status if this is a beacon frame carrying our bssid.
|
|
|
|
|
|
+ * Update extra components
|
|
*/
|
|
*/
|
|
- hdr = (struct ieee80211_hdr *)entry->skb->data;
|
|
|
|
- if (ieee80211_is_beacon(hdr->frame_control) &&
|
|
|
|
- (rxdesc.dev_flags & RXDONE_MY_BSS))
|
|
|
|
- rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
|
|
|
|
-
|
|
|
|
- rt2x00debug_update_crypto(rt2x00dev,
|
|
|
|
- rxdesc.cipher,
|
|
|
|
- rxdesc.cipher_status);
|
|
|
|
-
|
|
|
|
- rt2x00dev->link.qual.rx_success++;
|
|
|
|
|
|
+ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
|
|
|
|
+ rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
|
|
|
|
|
|
rx_status->mactime = rxdesc.timestamp;
|
|
rx_status->mactime = rxdesc.timestamp;
|
|
rx_status->rate_idx = idx;
|
|
rx_status->rate_idx = idx;
|
|
- rx_status->qual =
|
|
|
|
- rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
|
|
|
|
|
|
+ rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi);
|
|
rx_status->signal = rxdesc.rssi;
|
|
rx_status->signal = rxdesc.rssi;
|
|
rx_status->flag = rxdesc.flags;
|
|
rx_status->flag = rxdesc.flags;
|
|
rx_status->antenna = rt2x00dev->link.ant.active.rx;
|
|
rx_status->antenna = rt2x00dev->link.ant.active.rx;
|
|
@@ -1083,7 +796,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|
*/
|
|
*/
|
|
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
|
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
|
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
|
|
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
|
|
- INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Allocate queue array.
|
|
* Allocate queue array.
|
|
@@ -1104,6 +816,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|
/*
|
|
/*
|
|
* Register extra components.
|
|
* Register extra components.
|
|
*/
|
|
*/
|
|
|
|
+ rt2x00link_register(rt2x00dev);
|
|
rt2x00leds_register(rt2x00dev);
|
|
rt2x00leds_register(rt2x00dev);
|
|
rt2x00rfkill_allocate(rt2x00dev);
|
|
rt2x00rfkill_allocate(rt2x00dev);
|
|
rt2x00debug_register(rt2x00dev);
|
|
rt2x00debug_register(rt2x00dev);
|