aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/wext.c
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2008-12-18 16:35:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-19 15:24:00 -0500
commit520eb82076993b7f55ef9b80771d264272e5127b (patch)
treef98b74dbe404d4c3a55b5f649c25ca24958e62ba /net/mac80211/wext.c
parentce7c9111a97492d04c504f40736a669c235d664a (diff)
mac80211: implement dynamic power save
This patch implements dynamic power save for mac80211. Basically it means enabling power save mode after an idle period. Implementing it dynamically gives a good compromise of low power consumption and low latency. Some hardware have support for this in firmware, but some require the host to do it. The dynamic power save is implemented by adding an timeout to ieee80211_subif_start_xmit(). The timeout can be enabled from userspace with Wireless Extensions. For example, the command below enables the dynamic power save and sets the time timeout to 500 ms: iwconfig wlan0 power timeout 500m Power save now only works with devices which handle power save in firmware. It's also disabled by default and the heuristics when and how to enable is considered as a policy decision and will be left for the userspace to handle. In case the firmware has support for this, drivers can disable this feature with IEEE80211_HW_NO_STACK_DYNAMIC_PS. Big thanks to Johannes Berg for the help with the design and code. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/wext.c')
-rw-r--r--net/mac80211/wext.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index f6640d047157..7162d5816f39 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -833,7 +833,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
833 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 833 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
834 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 834 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
835 struct ieee80211_conf *conf = &local->hw.conf; 835 struct ieee80211_conf *conf = &local->hw.conf;
836 int ret = 0; 836 int ret = 0, timeout = 0;
837 bool ps; 837 bool ps;
838 838
839 if (sdata->vif.type != NL80211_IFTYPE_STATION) 839 if (sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -841,6 +841,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
841 841
842 if (wrq->disabled) { 842 if (wrq->disabled) {
843 ps = false; 843 ps = false;
844 timeout = 0;
844 goto set; 845 goto set;
845 } 846 }
846 847
@@ -850,22 +851,31 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
850 case IW_POWER_ALL_R: /* If explicitely state all */ 851 case IW_POWER_ALL_R: /* If explicitely state all */
851 ps = true; 852 ps = true;
852 break; 853 break;
853 default: /* Otherwise we don't support it */ 854 default: /* Otherwise we ignore */
854 return -EINVAL; 855 break;
855 } 856 }
856 857
857 if (ps == local->powersave) 858 if (wrq->flags & IW_POWER_TIMEOUT)
858 return ret; 859 timeout = wrq->value / 1000;
859 860
860set: 861set:
862 if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
863 return ret;
864
861 local->powersave = ps; 865 local->powersave = ps;
866 local->dynamic_ps_timeout = timeout;
862 867
863 if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { 868 if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
864 if (local->powersave) 869 if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
865 conf->flags |= IEEE80211_CONF_PS; 870 local->dynamic_ps_timeout > 0)
866 else 871 mod_timer(&local->dynamic_ps_timer, jiffies +
867 conf->flags &= ~IEEE80211_CONF_PS; 872 msecs_to_jiffies(local->dynamic_ps_timeout));
868 873 else {
874 if (local->powersave)
875 conf->flags |= IEEE80211_CONF_PS;
876 else
877 conf->flags &= ~IEEE80211_CONF_PS;
878 }
869 ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 879 ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
870 } 880 }
871 881