diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dac8bd37dcf..5ba721b6a39 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -745,8 +745,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, bss_info_changed); if (local->powersave) { - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + if (local->dynamic_ps_timeout > 0) + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->dynamic_ps_timeout)); + else { + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_PS); + } } netif_tx_start_all_queues(sdata->dev); @@ -866,6 +872,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, local->oper_channel_type = NL80211_CHAN_NO_HT; config_changed |= IEEE80211_CONF_CHANGE_HT; + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + if (local->hw.conf.flags & IEEE80211_CONF_PS) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; config_changed |= IEEE80211_CONF_CHANGE_PS; @@ -2593,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) ieee80211_restart_sta_timer(sdata); rcu_read_unlock(); } + +void ieee80211_dynamic_ps_disable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_disable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + ieee80211_wake_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); +} + +void ieee80211_dynamic_ps_enable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_enable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) + return; + + local->hw.conf.flags |= IEEE80211_CONF_PS; + + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); +} + +void ieee80211_dynamic_ps_timer(unsigned long data) +{ + struct ieee80211_local *local = (void *) data; + + queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); +} |