|
@@ -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);
|
|
|
+}
|