diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-05-17 05:40:42 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-20 14:46:25 -0400 |
commit | 5bb644a0fd25a5e083ecbfaa92a211db99aa6ef7 (patch) | |
tree | d2a6d5ff2323db0c475be15c63bb8fc55482a1e2 /net/mac80211/mlme.c | |
parent | cc32abd494c0a8f76f2638e3f3a76e01c68bc9ea (diff) |
mac80211: cancel/restart all timers across suspend/resume
We forgot to cancel all timers in mac80211 when suspending.
In particular we forgot to deal with some things that can
cause hardware reconfiguration -- while it is down.
While at it we go ahead and add a warning in ieee80211_sta_work()
if its run while the suspend->resume cycle is in effect. This
should not happen and if it does it would indicate there is
a bug lurking in either mac80211 or mac80211 drivers.
With this now wpa_supplicant doesn't blink when I go to suspend
and resume where as before there where issues with some timers
running during the suspend->resume cycle. This caused a lot of
incorrect assumptions and would at times bring back the device
in an incoherent, but mostly recoverable, state.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 41f3c1f98cc3..b61a7819867e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -37,6 +37,9 @@ | |||
37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) | 37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
39 | 39 | ||
40 | #define TMR_RUNNING_TIMER 0 | ||
41 | #define TMR_RUNNING_CHANSW 1 | ||
42 | |||
40 | /* utils */ | 43 | /* utils */ |
41 | static int ecw2cw(int ecw) | 44 | static int ecw2cw(int ecw) |
42 | { | 45 | { |
@@ -521,6 +524,11 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
521 | (struct ieee80211_sub_if_data *) data; | 524 | (struct ieee80211_sub_if_data *) data; |
522 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 525 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
523 | 526 | ||
527 | if (sdata->local->quiescing) { | ||
528 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
529 | return; | ||
530 | } | ||
531 | |||
524 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | 532 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); |
525 | } | 533 | } |
526 | 534 | ||
@@ -714,6 +722,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
714 | { | 722 | { |
715 | struct ieee80211_local *local = (void *) data; | 723 | struct ieee80211_local *local = (void *) data; |
716 | 724 | ||
725 | if (local->quiescing) | ||
726 | return; | ||
727 | |||
717 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 728 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
718 | } | 729 | } |
719 | 730 | ||
@@ -2108,6 +2119,11 @@ static void ieee80211_sta_timer(unsigned long data) | |||
2108 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2119 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2109 | struct ieee80211_local *local = sdata->local; | 2120 | struct ieee80211_local *local = sdata->local; |
2110 | 2121 | ||
2122 | if (local->quiescing) { | ||
2123 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2124 | return; | ||
2125 | } | ||
2126 | |||
2111 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | 2127 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2112 | queue_work(local->hw.workqueue, &ifmgd->work); | 2128 | queue_work(local->hw.workqueue, &ifmgd->work); |
2113 | } | 2129 | } |
@@ -2240,6 +2256,17 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2240 | 2256 | ||
2241 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2257 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2242 | return; | 2258 | return; |
2259 | |||
2260 | /* | ||
2261 | * Nothing should have been stuffed into the workqueue during | ||
2262 | * the suspend->resume cycle. If this WARN is seen then there | ||
2263 | * is a bug with either the driver suspend or something in | ||
2264 | * mac80211 stuffing into the workqueue which we haven't yet | ||
2265 | * cleared during mac80211's suspend cycle. | ||
2266 | */ | ||
2267 | if (WARN_ON(local->suspended)) | ||
2268 | return; | ||
2269 | |||
2243 | ifmgd = &sdata->u.mgd; | 2270 | ifmgd = &sdata->u.mgd; |
2244 | 2271 | ||
2245 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) | 2272 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
@@ -2307,6 +2334,38 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2307 | } | 2334 | } |
2308 | } | 2335 | } |
2309 | 2336 | ||
2337 | #ifdef CONFIG_PM | ||
2338 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | ||
2339 | { | ||
2340 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2341 | |||
2342 | /* | ||
2343 | * we need to use atomic bitops for the running bits | ||
2344 | * only because both timers might fire at the same | ||
2345 | * time -- the code here is properly synchronised. | ||
2346 | */ | ||
2347 | |||
2348 | cancel_work_sync(&ifmgd->work); | ||
2349 | cancel_work_sync(&ifmgd->beacon_loss_work); | ||
2350 | if (del_timer_sync(&ifmgd->timer)) | ||
2351 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2352 | |||
2353 | cancel_work_sync(&ifmgd->chswitch_work); | ||
2354 | if (del_timer_sync(&ifmgd->chswitch_timer)) | ||
2355 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
2356 | } | ||
2357 | |||
2358 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
2359 | { | ||
2360 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2361 | |||
2362 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | ||
2363 | add_timer(&ifmgd->timer); | ||
2364 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | ||
2365 | add_timer(&ifmgd->chswitch_timer); | ||
2366 | } | ||
2367 | #endif | ||
2368 | |||
2310 | /* interface setup */ | 2369 | /* interface setup */ |
2311 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 2370 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2312 | { | 2371 | { |