summaryrefslogtreecommitdiff
path: root/net/mac80211/work.c
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2011-02-04 22:54:17 +0300
committerJohn W. Linville <linville@tuxdriver.com>2011-02-05 00:30:32 +0300
commitb23b025fe246f3acc2988eb6d400df34c27cb8ae (patch)
treee1c8cd163dc4dc7c603652a9e101f8381cf66fdc /net/mac80211/work.c
parentcb8d61de2d7f074654057b2b924da1efbf625ad4 (diff)
downloadlinux-b23b025fe246f3acc2988eb6d400df34c27cb8ae.tar.xz
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>
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r--net/mac80211/work.c66
1 files changed, 55 insertions, 11 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 36305e0d06ef..6bf787a5b38a 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -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);
}