aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-01-07 12:28:20 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 15:59:58 -0500
commit4be8c3873e0b88397866d3ede578503e188f9ad2 (patch)
tree1ccf8a0c204bb01aca08d90c2d8c37b5e0439bd3
parentacbaf32e94cb70218792cac68e5149e482e77441 (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.tmpl8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c4
-rw-r--r--include/net/mac80211.h53
-rw-r--r--net/mac80211/mlme.c31
-rw-r--r--net/mac80211/tx.c2
-rw-r--r--net/mac80211/wext.c40
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 */
858enum ieee80211_hw_flags { 863enum 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
865set: 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