diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-01-07 12:28:20 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:59:58 -0500 |
commit | 4be8c3873e0b88397866d3ede578503e188f9ad2 (patch) | |
tree | 1ccf8a0c204bb01aca08d90c2d8c37b5e0439bd3 | |
parent | acbaf32e94cb70218792cac68e5149e482e77441 (diff) |
mac80211: extend/document powersave API
This modifies hardware flags for powersave to support three different
flags:
* IEEE80211_HW_SUPPORTS_PS - indicates general PS support
* IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc sending in software
* IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device
It also adds documentation for all this which explains how to set the
various flags.
Additionally, it fixes a few things:
* a spot where && was used to test flags
* enable CONF_PS only when associated again
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | Documentation/DocBook/mac80211.tmpl | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 4 | ||||
-rw-r--r-- | include/net/mac80211.h | 53 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 31 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 | ||||
-rw-r--r-- | net/mac80211/wext.c | 40 |
11 files changed, 111 insertions, 46 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index bdf908a6e545..8af6d9626878 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -17,8 +17,7 @@ | |||
17 | </authorgroup> | 17 | </authorgroup> |
18 | 18 | ||
19 | <copyright> | 19 | <copyright> |
20 | <year>2007</year> | 20 | <year>2007-2009</year> |
21 | <year>2008</year> | ||
22 | <holder>Johannes Berg</holder> | 21 | <holder>Johannes Berg</holder> |
23 | </copyright> | 22 | </copyright> |
24 | 23 | ||
@@ -223,6 +222,11 @@ usage should require reading the full document. | |||
223 | !Finclude/net/mac80211.h ieee80211_key_flags | 222 | !Finclude/net/mac80211.h ieee80211_key_flags |
224 | </chapter> | 223 | </chapter> |
225 | 224 | ||
225 | <chapter id="powersave"> | ||
226 | <title>Powersave support</title> | ||
227 | !Pinclude/net/mac80211.h Powersave support | ||
228 | </chapter> | ||
229 | |||
226 | <chapter id="qos"> | 230 | <chapter id="qos"> |
227 | <title>Multiple queues and QoS support</title> | 231 | <title>Multiple queues and QoS support</title> |
228 | <para>TBD</para> | 232 | <para>TBD</para> |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 76315c30e6fc..07c3870365be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -805,7 +805,8 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
805 | /* Tell mac80211 our characteristics */ | 805 | /* Tell mac80211 our characteristics */ |
806 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 806 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
807 | IEEE80211_HW_NOISE_DBM | | 807 | IEEE80211_HW_NOISE_DBM | |
808 | IEEE80211_HW_AMPDU_AGGREGATION; | 808 | IEEE80211_HW_AMPDU_AGGREGATION | |
809 | IEEE80211_HW_SUPPORTS_PS; | ||
809 | hw->wiphy->interface_modes = | 810 | hw->wiphy->interface_modes = |
810 | BIT(NL80211_IFTYPE_STATION) | | 811 | BIT(NL80211_IFTYPE_STATION) | |
811 | BIT(NL80211_IFTYPE_ADHOC); | 812 | BIT(NL80211_IFTYPE_ADHOC); |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 9104113270d0..ae8bfd6b59df 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1449,7 +1449,9 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
1449 | * Initialize all hw fields. | 1449 | * Initialize all hw fields. |
1450 | */ | 1450 | */ |
1451 | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1451 | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1452 | IEEE80211_HW_SIGNAL_DBM; | 1452 | IEEE80211_HW_SIGNAL_DBM | |
1453 | IEEE80211_HW_SUPPORTS_PS | | ||
1454 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
1453 | rt2x00dev->hw->extra_tx_headroom = 0; | 1455 | rt2x00dev->hw->extra_tx_headroom = 0; |
1454 | 1456 | ||
1455 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | 1457 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index ebcc49770922..bca6798be153 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1749,7 +1749,9 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
1749 | * Initialize all hw fields. | 1749 | * Initialize all hw fields. |
1750 | */ | 1750 | */ |
1751 | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1751 | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1752 | IEEE80211_HW_SIGNAL_DBM; | 1752 | IEEE80211_HW_SIGNAL_DBM | |
1753 | IEEE80211_HW_SUPPORTS_PS | | ||
1754 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
1753 | 1755 | ||
1754 | rt2x00dev->hw->extra_tx_headroom = 0; | 1756 | rt2x00dev->hw->extra_tx_headroom = 0; |
1755 | 1757 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index e992bad64644..27a6971df579 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1801,7 +1801,9 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
1801 | rt2x00dev->hw->flags = | 1801 | rt2x00dev->hw->flags = |
1802 | IEEE80211_HW_RX_INCLUDES_FCS | | 1802 | IEEE80211_HW_RX_INCLUDES_FCS | |
1803 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1803 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1804 | IEEE80211_HW_SIGNAL_DBM; | 1804 | IEEE80211_HW_SIGNAL_DBM | |
1805 | IEEE80211_HW_SUPPORTS_PS | | ||
1806 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
1805 | 1807 | ||
1806 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; | 1808 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; |
1807 | 1809 | ||
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 82d35a5a4aa7..549480a963e9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2556,7 +2556,9 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2556 | */ | 2556 | */ |
2557 | rt2x00dev->hw->flags = | 2557 | rt2x00dev->hw->flags = |
2558 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 2558 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
2559 | IEEE80211_HW_SIGNAL_DBM; | 2559 | IEEE80211_HW_SIGNAL_DBM | |
2560 | IEEE80211_HW_SUPPORTS_PS | | ||
2561 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
2560 | rt2x00dev->hw->extra_tx_headroom = 0; | 2562 | rt2x00dev->hw->extra_tx_headroom = 0; |
2561 | 2563 | ||
2562 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | 2564 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 2b70c01b55e9..849220236c7d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2077,7 +2077,9 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2077 | */ | 2077 | */ |
2078 | rt2x00dev->hw->flags = | 2078 | rt2x00dev->hw->flags = |
2079 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 2079 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
2080 | IEEE80211_HW_SIGNAL_DBM; | 2080 | IEEE80211_HW_SIGNAL_DBM | |
2081 | IEEE80211_HW_SUPPORTS_PS | | ||
2082 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
2081 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; | 2083 | rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; |
2082 | 2084 | ||
2083 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | 2085 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 83ee8a212296..8a305bfdb87b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -850,10 +850,15 @@ enum ieee80211_tkip_key_type { | |||
850 | * @IEEE80211_HW_AMPDU_AGGREGATION: | 850 | * @IEEE80211_HW_AMPDU_AGGREGATION: |
851 | * Hardware supports 11n A-MPDU aggregation. | 851 | * Hardware supports 11n A-MPDU aggregation. |
852 | * | 852 | * |
853 | * @IEEE80211_HW_NO_STACK_DYNAMIC_PS: | 853 | * @IEEE80211_HW_SUPPORTS_PS: |
854 | * Hardware which has dynamic power save support, meaning | 854 | * Hardware has power save support (i.e. can go to sleep). |
855 | * that power save is enabled in idle periods, and don't need support | 855 | * |
856 | * from stack. | 856 | * @IEEE80211_HW_PS_NULLFUNC_STACK: |
857 | * Hardware requires nullfunc frame handling in stack, implies | ||
858 | * stack support for dynamic PS. | ||
859 | * | ||
860 | * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS: | ||
861 | * Hardware has support for dynamic PS. | ||
857 | */ | 862 | */ |
858 | enum ieee80211_hw_flags { | 863 | enum ieee80211_hw_flags { |
859 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, | 864 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, |
@@ -866,7 +871,9 @@ enum ieee80211_hw_flags { | |||
866 | IEEE80211_HW_NOISE_DBM = 1<<8, | 871 | IEEE80211_HW_NOISE_DBM = 1<<8, |
867 | IEEE80211_HW_SPECTRUM_MGMT = 1<<9, | 872 | IEEE80211_HW_SPECTRUM_MGMT = 1<<9, |
868 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, | 873 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, |
869 | IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11, | 874 | IEEE80211_HW_SUPPORTS_PS = 1<<11, |
875 | IEEE80211_HW_PS_NULLFUNC_STACK = 1<<12, | ||
876 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<13, | ||
870 | }; | 877 | }; |
871 | 878 | ||
872 | /** | 879 | /** |
@@ -1053,6 +1060,42 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
1053 | */ | 1060 | */ |
1054 | 1061 | ||
1055 | /** | 1062 | /** |
1063 | * DOC: Powersave support | ||
1064 | * | ||
1065 | * mac80211 has support for various powersave implementations. | ||
1066 | * | ||
1067 | * First, it can support hardware that handles all powersaving by | ||
1068 | * itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS | ||
1069 | * hardware flag. In that case, it will be told about the desired | ||
1070 | * powersave mode depending on the association status, and the driver | ||
1071 | * must take care of sending nullfunc frames when necessary, i.e. when | ||
1072 | * entering and leaving powersave mode. The driver is required to look at | ||
1073 | * the AID in beacons and signal to the AP that it woke up when it finds | ||
1074 | * traffic directed to it. This mode supports dynamic PS by simply | ||
1075 | * enabling/disabling PS. | ||
1076 | * | ||
1077 | * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS | ||
1078 | * flag to indicate that it can support dynamic PS mode itself (see below). | ||
1079 | * | ||
1080 | * Other hardware designs cannot send nullfunc frames by themselves and also | ||
1081 | * need software support for parsing the TIM bitmap. This is also supported | ||
1082 | * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and | ||
1083 | * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still | ||
1084 | * required to pass up beacons. Additionally, in this case, mac80211 will | ||
1085 | * wake up the hardware when multicast traffic is announced in the beacon. | ||
1086 | * | ||
1087 | * FIXME: I don't think we can be fast enough in software when we want to | ||
1088 | * receive multicast traffic? | ||
1089 | * | ||
1090 | * Dynamic powersave mode is an extension to normal powersave mode in which | ||
1091 | * the hardware stays awake for a user-specified period of time after sending | ||
1092 | * a frame so that reply frames need not be buffered and therefore delayed | ||
1093 | * to the next wakeup. This can either be supported by hardware, in which case | ||
1094 | * the driver needs to look at the @dynamic_ps_timeout hardware configuration | ||
1095 | * value, or by the stack if all nullfunc handling is in the stack. | ||
1096 | */ | ||
1097 | |||
1098 | /** | ||
1056 | * DOC: Frame filtering | 1099 | * DOC: Frame filtering |
1057 | * | 1100 | * |
1058 | * mac80211 requires to see many management frames for proper | 1101 | * mac80211 requires to see many management frames for proper |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7709e7645671..a1e683e305f0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -775,17 +775,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
775 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; | 775 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; |
776 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 776 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
777 | 777 | ||
778 | if (local->powersave && | 778 | if (local->powersave) { |
779 | !(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) { | 779 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && |
780 | if (local->hw.conf.dynamic_ps_timeout > 0) | 780 | local->hw.conf.dynamic_ps_timeout > 0) { |
781 | mod_timer(&local->dynamic_ps_timer, jiffies + | 781 | mod_timer(&local->dynamic_ps_timer, jiffies + |
782 | msecs_to_jiffies( | 782 | msecs_to_jiffies( |
783 | local->hw.conf.dynamic_ps_timeout)); | 783 | local->hw.conf.dynamic_ps_timeout)); |
784 | else { | 784 | } else { |
785 | ieee80211_send_nullfunc(local, sdata, 1); | 785 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
786 | ieee80211_send_nullfunc(local, sdata, 1); | ||
786 | conf->flags |= IEEE80211_CONF_PS; | 787 | conf->flags |= IEEE80211_CONF_PS; |
787 | ieee80211_hw_config(local, | 788 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
788 | IEEE80211_CONF_CHANGE_PS); | ||
789 | } | 789 | } |
790 | } | 790 | } |
791 | 791 | ||
@@ -1779,16 +1779,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1779 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1779 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
1780 | elems.wmm_param_len); | 1780 | elems.wmm_param_len); |
1781 | 1781 | ||
1782 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) { | 1782 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && |
1783 | local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1783 | directed_tim = check_tim(&elems, ifsta->aid, &is_mc); | 1784 | directed_tim = check_tim(&elems, ifsta->aid, &is_mc); |
1784 | 1785 | ||
1785 | if (directed_tim || is_mc) { | 1786 | if (directed_tim || is_mc) { |
1786 | if (local->hw.conf.flags && IEEE80211_CONF_PS) { | 1787 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
1787 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | 1788 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
1788 | ieee80211_hw_config(local, | 1789 | ieee80211_send_nullfunc(local, sdata, 0); |
1789 | IEEE80211_CONF_CHANGE_PS); | ||
1790 | ieee80211_send_nullfunc(local, sdata, 0); | ||
1791 | } | ||
1792 | } | 1790 | } |
1793 | } | 1791 | } |
1794 | 1792 | ||
@@ -2694,9 +2692,10 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
2694 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 2692 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
2695 | return; | 2693 | return; |
2696 | 2694 | ||
2697 | ieee80211_send_nullfunc(local, sdata, 1); | 2695 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
2698 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 2696 | ieee80211_send_nullfunc(local, sdata, 1); |
2699 | 2697 | ||
2698 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
2700 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 2699 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
2701 | } | 2700 | } |
2702 | 2701 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b18a72690119..cd6bc87eec73 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1295,7 +1295,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1295 | return 0; | 1295 | return 0; |
1296 | } | 1296 | } |
1297 | 1297 | ||
1298 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && | 1298 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
1299 | local->hw.conf.dynamic_ps_timeout > 0) { | 1299 | local->hw.conf.dynamic_ps_timeout > 0) { |
1300 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 1300 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
1301 | ieee80211_stop_queues_by_reason(&local->hw, | 1301 | ieee80211_stop_queues_by_reason(&local->hw, |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 3f2db0bda46c..1e5b29bdb3a7 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -837,6 +837,9 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
837 | int ret = 0, timeout = 0; | 837 | int ret = 0, timeout = 0; |
838 | bool ps; | 838 | bool ps; |
839 | 839 | ||
840 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
841 | return -EOPNOTSUPP; | ||
842 | |||
840 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 843 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
841 | return -EINVAL; | 844 | return -EINVAL; |
842 | 845 | ||
@@ -862,32 +865,37 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
862 | if (wrq->flags & IW_POWER_TIMEOUT) | 865 | if (wrq->flags & IW_POWER_TIMEOUT) |
863 | timeout = wrq->value / 1000; | 866 | timeout = wrq->value / 1000; |
864 | 867 | ||
865 | set: | 868 | set: |
866 | if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) | 869 | if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) |
867 | return ret; | 870 | return ret; |
868 | 871 | ||
869 | local->powersave = ps; | 872 | local->powersave = ps; |
870 | conf->dynamic_ps_timeout = timeout; | 873 | conf->dynamic_ps_timeout = timeout; |
871 | 874 | ||
872 | if (local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) { | 875 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
873 | ret = ieee80211_hw_config(local, | 876 | ret = ieee80211_hw_config(local, |
874 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); | 877 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); |
875 | } else if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 878 | |
876 | if (conf->dynamic_ps_timeout > 0) | 879 | if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) |
877 | mod_timer(&local->dynamic_ps_timer, jiffies + | 880 | return ret; |
878 | msecs_to_jiffies(conf->dynamic_ps_timeout)); | 881 | |
879 | else { | 882 | if (conf->dynamic_ps_timeout > 0 && |
880 | if (local->powersave) { | 883 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { |
884 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
885 | msecs_to_jiffies(conf->dynamic_ps_timeout)); | ||
886 | } else { | ||
887 | if (local->powersave) { | ||
888 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
881 | ieee80211_send_nullfunc(local, sdata, 1); | 889 | ieee80211_send_nullfunc(local, sdata, 1); |
882 | conf->flags |= IEEE80211_CONF_PS; | 890 | conf->flags |= IEEE80211_CONF_PS; |
883 | ret = ieee80211_hw_config(local, | 891 | ret = ieee80211_hw_config(local, |
884 | IEEE80211_CONF_CHANGE_PS); | 892 | IEEE80211_CONF_CHANGE_PS); |
885 | } else { | 893 | } else { |
886 | conf->flags &= ~IEEE80211_CONF_PS; | 894 | conf->flags &= ~IEEE80211_CONF_PS; |
887 | ret = ieee80211_hw_config(local, | 895 | ret = ieee80211_hw_config(local, |
888 | IEEE80211_CONF_CHANGE_PS); | 896 | IEEE80211_CONF_CHANGE_PS); |
897 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
889 | ieee80211_send_nullfunc(local, sdata, 0); | 898 | ieee80211_send_nullfunc(local, sdata, 0); |
890 | } | ||
891 | } | 899 | } |
892 | } | 900 | } |
893 | 901 | ||