aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2009-11-30 06:20:53 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-07 16:51:18 -0500
commit7c3f4bbedc241ddcd3abe1f419c356e625231da1 (patch)
tree98b1141a86d4ac65ae930e1c0cb15cd6a17d2a01
parentbc83b6819289c031c439a5aa18ba0fd539d14f3e (diff)
mac80211: Fix dynamic power save for scanning.
Not only ps_sdata but also IEEE80211_CONF_PS is to be considered before restoring PS in scan_ps_disable(). For instance, when ps_sdata is set but CONF_PS is not set just because the dynamic timer is still running, a sw scan leads to setting of CONF_PS in scan_ps_disable instead of restarting the dynamic PS timer. Also for the above case, a null data frame is to be sent after returning to operating channel which was not happening with the current implementation. This patch fixes this too. Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> Reviewed-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/scan.c20
2 files changed, 17 insertions, 4 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 419f186cfcf0..91dc8636d644 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -746,6 +746,7 @@ struct ieee80211_local {
746 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ 746 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
747 747
748 bool pspolling; 748 bool pspolling;
749 bool scan_ps_enabled;
749 /* 750 /*
750 * PS can only be enabled when we have exactly one managed 751 * PS can only be enabled when we have exactly one managed
751 * interface (and monitors) in PS, this then points there. 752 * interface (and monitors) in PS, this then points there.
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4cf387c944bf..f1a4c7160300 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -227,7 +227,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
227static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) 227static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
228{ 228{
229 struct ieee80211_local *local = sdata->local; 229 struct ieee80211_local *local = sdata->local;
230 bool ps = false; 230
231 local->scan_ps_enabled = false;
231 232
232 /* FIXME: what to do when local->pspolling is true? */ 233 /* FIXME: what to do when local->pspolling is true? */
233 234
@@ -235,12 +236,13 @@ static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
235 cancel_work_sync(&local->dynamic_ps_enable_work); 236 cancel_work_sync(&local->dynamic_ps_enable_work);
236 237
237 if (local->hw.conf.flags & IEEE80211_CONF_PS) { 238 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
238 ps = true; 239 local->scan_ps_enabled = true;
239 local->hw.conf.flags &= ~IEEE80211_CONF_PS; 240 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
240 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 241 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
241 } 242 }
242 243
243 if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) 244 if (!(local->scan_ps_enabled) ||
245 !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
244 /* 246 /*
245 * If power save was enabled, no need to send a nullfunc 247 * If power save was enabled, no need to send a nullfunc
246 * frame because AP knows that we are sleeping. But if the 248 * frame because AP knows that we are sleeping. But if the
@@ -261,7 +263,7 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
261 263
262 if (!local->ps_sdata) 264 if (!local->ps_sdata)
263 ieee80211_send_nullfunc(local, sdata, 0); 265 ieee80211_send_nullfunc(local, sdata, 0);
264 else { 266 else if (local->scan_ps_enabled) {
265 /* 267 /*
266 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware 268 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
267 * will send a nullfunc frame with the powersave bit set 269 * will send a nullfunc frame with the powersave bit set
@@ -277,6 +279,16 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
277 */ 279 */
278 local->hw.conf.flags |= IEEE80211_CONF_PS; 280 local->hw.conf.flags |= IEEE80211_CONF_PS;
279 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 281 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
282 } else if (local->hw.conf.dynamic_ps_timeout > 0) {
283 /*
284 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
285 * had been running before leaving the operating channel,
286 * restart the timer now and send a nullfunc frame to inform
287 * the AP that we are awake.
288 */
289 ieee80211_send_nullfunc(local, sdata, 0);
290 mod_timer(&local->dynamic_ps_timer, jiffies +
291 msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
280 } 292 }
281} 293}
282 294