]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/mlme.c
mac80211: implement dynamic power save
[linux-2.6-omap-h63xx.git] / net / mac80211 / mlme.c
index dac8bd37dcf5ebe745781222846249bb98a2d01e..5ba721b6a399ddadefc0924ec50ab5531efd1e5c 100644 (file)
@@ -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);
+}