carl9170: improve site survey

The firmware keeps track of channel usage. This data can
be used by the automatic channel selection to find the
*best* channel.

Survey data from wlan22
	frequency:                      2412 MHz [in use]
	noise:                          -86 dBm
	channel active time:            3339608 ms
	channel busy time:              270982 ms
	channel transmit time:          121515 ms
Survey data from wlan22
	frequency:                      2417 MHz
	noise:                          -86 dBm
	channel active time:            70 ms
	channel busy time:              2 ms
	channel transmit time:          1 ms

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Christian Lamparter
2011-08-15 19:50:48 +02:00
committed by John W. Linville
parent f5e2289a14
commit acf1771221
5 changed files with 153 additions and 15 deletions

View File

@@ -413,6 +413,9 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED);
ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
ieee80211_wake_queues(ar->hw);
err = 0;
@@ -423,6 +426,7 @@ out:
static void carl9170_cancel_worker(struct ar9170 *ar)
{
cancel_delayed_work_sync(&ar->stat_work);
cancel_delayed_work_sync(&ar->tx_janitor);
#ifdef CONFIG_CARL9170_LEDS
cancel_delayed_work_sync(&ar->led_work);
@@ -794,6 +798,43 @@ static void carl9170_ps_work(struct work_struct *work)
mutex_unlock(&ar->mutex);
}
static int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise)
{
int err;
if (noise) {
err = carl9170_get_noisefloor(ar);
if (err)
return err;
}
if (ar->fw.hw_counters) {
err = carl9170_collect_tally(ar);
if (err)
return err;
}
if (flush)
memset(&ar->tally, 0, sizeof(ar->tally));
return 0;
}
static void carl9170_stat_work(struct work_struct *work)
{
struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work);
int err;
mutex_lock(&ar->mutex);
err = carl9170_update_survey(ar, false, true);
mutex_unlock(&ar->mutex);
if (err)
return;
ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
}
static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
{
@@ -828,11 +869,19 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
if (err)
goto out;
err = carl9170_update_survey(ar, true, false);
if (err)
goto out;
err = carl9170_set_channel(ar, hw->conf.channel,
hw->conf.channel_type, CARL9170_RFI_NONE);
if (err)
goto out;
err = carl9170_update_survey(ar, false, true);
if (err)
goto out;
err = carl9170_set_dyn_sifs_ack(ar);
if (err)
goto out;
@@ -1423,20 +1472,52 @@ static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
struct ar9170 *ar = hw->priv;
int err;
struct ieee80211_channel *chan;
struct ieee80211_supported_band *band;
int err, b, i;
if (idx != 0)
return -ENOENT;
chan = ar->channel;
if (!chan)
return -ENODEV;
mutex_lock(&ar->mutex);
err = carl9170_get_noisefloor(ar);
mutex_unlock(&ar->mutex);
if (err)
return err;
if (idx == chan->hw_value) {
mutex_lock(&ar->mutex);
err = carl9170_update_survey(ar, false, true);
mutex_unlock(&ar->mutex);
if (err)
return err;
}
survey->channel = ar->channel;
for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
band = ar->hw->wiphy->bands[b];
if (!band)
continue;
for (i = 0; i < band->n_channels; i++) {
if (band->channels[i].hw_value == idx) {
chan = &band->channels[i];
goto found;
}
}
}
return -ENOENT;
found:
memcpy(survey, &ar->survey[idx], sizeof(*survey));
survey->channel = chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = ar->noise[0];
if (ar->channel == chan)
survey->filled |= SURVEY_INFO_IN_USE;
if (ar->fw.hw_counters) {
survey->filled |= SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX;
}
return 0;
}
@@ -1569,6 +1650,7 @@ void *carl9170_alloc(size_t priv_size)
INIT_WORK(&ar->ping_work, carl9170_ping_work);
INIT_WORK(&ar->restart_work, carl9170_restart_work);
INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work);
INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
INIT_LIST_HEAD(&ar->tx_ampdu_list);
rcu_assign_pointer(ar->tx_ampdu_iter,
@@ -1652,6 +1734,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
struct ath_regulatory *regulatory = &ar->common.regulatory;
unsigned int rx_streams, tx_streams, tx_params = 0;
int bands = 0;
int chans = 0;
if (ar->eeprom.length == cpu_to_le16(0xffff))
return -ENODATA;
@@ -1675,14 +1758,24 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&carl9170_band_2GHz;
chans += carl9170_band_2GHz.n_channels;
bands++;
}
if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&carl9170_band_5GHz;
chans += carl9170_band_5GHz.n_channels;
bands++;
}
if (!bands)
return -EINVAL;
ar->survey = kzalloc(sizeof(struct survey_info) * chans, GFP_KERNEL);
if (!ar->survey)
return -ENOMEM;
ar->num_channels = chans;
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
@@ -1701,7 +1794,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
/* second part of wiphy init */
SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address);
return bands ? 0 : -EINVAL;
return 0;
}
static int carl9170_reg_notifier(struct wiphy *wiphy,
@@ -1834,6 +1927,9 @@ void carl9170_free(struct ar9170 *ar)
kfree(ar->mem_bitmap);
ar->mem_bitmap = NULL;
kfree(ar->survey);
ar->survey = NULL;
mutex_destroy(&ar->mutex);
ieee80211_free_hw(ar->hw);