mac80211: Optimize scans on current operating channel.

This should decrease un-necessary flushes, on/off channel work,
and channel changes in cases where the only scanned channel is
the current operating channel.

* Removes SCAN_OFF_CHANNEL flag, uses SDATA_STATE_OFFCHANNEL
  and is-scanning flags instead.

* Add helper method to determine if we are currently configured
  for the operating channel.

* Do no blindly go off/on channel in work.c  Instead, only call
  appropriate on/off code when we really need to change channels.
  Always enable offchannel-ps mode when starting work,
  and disable it when we are done.

* Consolidate ieee80211_offchannel_stop_station and
  ieee80211_offchannel_stop_beaconing, call it
  ieee80211_offchannel_stop_vifs instead.

* Accept non-beacon frames when scanning on operating channel.

* Scan state machine optimized to minimize on/off channel
  transitions.  Also, when going on-channel, go ahead and
  re-enable beaconing.  We're going to be there for 200ms,
  so seems like some useful beaconing could happen.
  Always enable offchannel-ps mode when starting software
  scan, and disable it when we are done.

* Grab local->mtx earlier in __ieee80211_scan_completed_finish
  so that we are protected when calling hw_config(), etc.

* Pass probe-responses up the stack if scanning on local
  channel, so that mlme can take a look.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Ben Greear
2011-02-04 11:54:17 -08:00
committed by John W. Linville
parent cb8d61de2d
commit b23b025fe2
7 changed files with 233 additions and 108 deletions

View File

@@ -924,18 +924,44 @@ static void ieee80211_work_work(struct work_struct *work)
}
if (!started && !local->tmp_channel) {
/*
* TODO: could optimize this by leaving the
* station vifs in awake mode if they
* happen to be on the same channel as
* the requested channel
*/
ieee80211_offchannel_stop_beaconing(local);
ieee80211_offchannel_stop_station(local);
bool on_oper_chan;
bool tmp_chan_changed = false;
bool on_oper_chan2;
on_oper_chan = ieee80211_cfg_on_oper_channel(local);
if (local->tmp_channel)
if ((local->tmp_channel != wk->chan) ||
(local->tmp_channel_type != wk->chan_type))
tmp_chan_changed = true;
local->tmp_channel = wk->chan;
local->tmp_channel_type = wk->chan_type;
ieee80211_hw_config(local, 0);
/*
* Leave the station vifs in awake mode if they
* happen to be on the same channel as
* the requested channel.
*/
on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
if (on_oper_chan != on_oper_chan2) {
if (on_oper_chan2) {
/* going off oper channel, PS too */
ieee80211_offchannel_stop_vifs(local,
true);
ieee80211_hw_config(local, 0);
} else {
/* going on channel, but leave PS
* off-channel. */
ieee80211_hw_config(local, 0);
ieee80211_offchannel_return(local,
true,
false);
}
} else if (tmp_chan_changed)
/* Still off-channel, but on some other
* channel, so update hardware.
* PS should already be off-channel.
*/
ieee80211_hw_config(local, 0);
started = true;
wk->timeout = jiffies;
}
@@ -1011,9 +1037,27 @@ static void ieee80211_work_work(struct work_struct *work)
}
if (!remain_off_channel && local->tmp_channel) {
bool on_oper_chan = ieee80211_cfg_on_oper_channel(local);
local->tmp_channel = NULL;
ieee80211_hw_config(local, 0);
ieee80211_offchannel_return(local, true);
/* If tmp_channel wasn't operating channel, then
* we need to go back on-channel.
* NOTE: If we can ever be here while scannning,
* or if the hw_config() channel config logic changes,
* then we may need to do a more thorough check to see if
* we still need to do a hardware config. Currently,
* we cannot be here while scanning, however.
*/
if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan)
ieee80211_hw_config(local, 0);
/* At the least, we need to disable offchannel_ps,
* so just go ahead and run the entire offchannel
* return logic here. We *could* skip enabling
* beaconing if we were already on-oper-channel
* as a future optimization.
*/
ieee80211_offchannel_return(local, true, true);
/* give connection some time to breathe */
run_again(local, jiffies + HZ/2);
}