All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Add support for off-channel powersave state in mac80211
@ 2013-02-06 21:01 Seth Forshee
  2013-02-06 21:01   ` [ath9k-devel] " Seth Forshee
                   ` (4 more replies)
  0 siblings, 5 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
  Cc: Seth Forshee, Arend van Spriel, John W. Linville, brcm80211-dev-list

Hi Johannes,

As promised, here are the patches which add the off-channel powesave
state. At a high level, the changes are:

 * Expand the PS configuration flag to be 2 bits and add helper
   functions for reading and setting the modes
 * Change the terminology around PS states, i.e. disabled -> awake and
   enabled -> doze
 * Add the off-channel PS state and put it to use
 * Minor driver updates based on these changes
 * Update brcmsmac to utilize the off-channel PS state

I've made every attempt to keep things functionally equivalent for every
driver except for brcmsmac. That said, I've only been able to test on
brcmsmac and ath9k, plus a basic sanity check with iwlwifi.

Thanks,
Seth


Seth Forshee (4):
  mac80211: Convert PS configuration from a binary flag to a set of
    modes
  mac80211: Indicate hardware support for doze state rather than
    powersave
  mac80211: Add off-channel PS state
  brcmsmac: Add support for off-channel powersave

 drivers/net/wireless/adm8211.c                     |    3 +-
 drivers/net/wireless/at76c50x-usb.c                |    3 +-
 drivers/net/wireless/ath/ar5523/ar5523.c           |    3 +-
 drivers/net/wireless/ath/ath5k/base.c              |    3 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c      |    2 +-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c      |    2 +-
 drivers/net/wireless/ath/ath9k/init.c              |    2 +-
 drivers/net/wireless/ath/ath9k/main.c              |    2 +-
 drivers/net/wireless/ath/carl9170/fw.c             |    2 +-
 drivers/net/wireless/ath/carl9170/main.c           |    5 +-
 drivers/net/wireless/ath/carl9170/rx.c             |    2 +-
 drivers/net/wireless/b43/main.c                    |    3 +-
 drivers/net/wireless/b43legacy/main.c              |    3 +-
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |   18 ++-
 drivers/net/wireless/brcm80211/brcmsmac/main.c     |    7 +-
 drivers/net/wireless/brcm80211/brcmsmac/main.h     |    1 +
 drivers/net/wireless/iwlegacy/3945-mac.c           |    3 +-
 drivers/net/wireless/iwlegacy/4965-mac.c           |    2 +-
 drivers/net/wireless/iwlwifi/dvm/mac80211.c        |    2 +-
 drivers/net/wireless/iwlwifi/dvm/power.c           |    3 +-
 drivers/net/wireless/iwlwifi/mvm/mac80211.c        |    2 +-
 drivers/net/wireless/libertas_tf/main.c            |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |    5 +-
 drivers/net/wireless/mwl8k.c                       |    3 +-
 drivers/net/wireless/p54/fwio.c                    |    2 +-
 drivers/net/wireless/p54/main.c                    |    2 +-
 drivers/net/wireless/p54/txrx.c                    |    3 +-
 drivers/net/wireless/rt2x00/rt2400pci.c            |    4 +-
 drivers/net/wireless/rt2x00/rt2500pci.c            |    4 +-
 drivers/net/wireless/rt2x00/rt2500usb.c            |    4 +-
 drivers/net/wireless/rt2x00/rt2800lib.c            |    4 +-
 drivers/net/wireless/rt2x00/rt2x00config.c         |    4 +-
 drivers/net/wireless/rt2x00/rt2x00dev.c            |    3 +-
 drivers/net/wireless/rt2x00/rt61pci.c              |    4 +-
 drivers/net/wireless/rt2x00/rt73usb.c              |    4 +-
 drivers/net/wireless/rtl818x/rtl8180/dev.c         |    3 +-
 drivers/net/wireless/rtl818x/rtl8187/dev.c         |    3 +-
 drivers/net/wireless/rtlwifi/base.c                |    2 +-
 drivers/net/wireless/rtlwifi/core.c                |    2 +-
 drivers/net/wireless/rtlwifi/ps.c                  |    4 +-
 drivers/net/wireless/ti/wl1251/main.c              |   10 +-
 drivers/net/wireless/ti/wlcore/main.c              |    5 +-
 drivers/net/wireless/zd1211rw/zd_mac.c             |    3 +-
 include/net/mac80211.h                             |  128 +++++++++++++-------
 net/mac80211/cfg.c                                 |    2 +-
 net/mac80211/debugfs.c                             |    2 +-
 net/mac80211/ieee80211_i.h                         |    7 ++
 net/mac80211/mlme.c                                |   31 ++---
 net/mac80211/offchannel.c                          |   40 +++---
 net/mac80211/tx.c                                  |    4 +-
 net/mac80211/util.c                                |    2 +-
 51 files changed, 227 insertions(+), 143 deletions(-)


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
@ 2013-02-06 21:01   ` Seth Forshee
  2013-02-06 21:01 ` [ath9k-devel] [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave Seth Forshee
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
  Cc: Seth Forshee, Arend van Spriel, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

The powersave configuration in struct ieee80211_conf is currently a
binary state, either enabled or disabled. This is inadequate for
expressing the situation during off-channel operation, when powersave is
set at the AP to request bufferring of frames but the hardware remains
fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
to support this in-between state but lack the information to do so.

To prepare for adding an off-channel powersave mode, expand the current
powersave configuration flag to two bits to support expressing another
state. Add helper functions for setting and retrieving the state, and
convert mac80211 and drivers to use these functions.

In changing from a binary flag to powersave mode, also update the
terminology used to name the states for clarity. The "enabled" state is
changed to "doze" to indicate a low power hardware state, and the
"disabled" state is changed to "awake" to indicate a fully powerd on
hardware state. This is consistent with the terminology defined in IEEE
802.11-2012 section 10.2.1.2.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_main.c      |    2 +-
 drivers/net/wireless/ath/ath9k/main.c              |    2 +-
 drivers/net/wireless/ath/carl9170/main.c           |    3 +-
 drivers/net/wireless/ath/carl9170/rx.c             |    2 +-
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |    3 +-
 drivers/net/wireless/iwlwifi/dvm/power.c           |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |    2 +-
 drivers/net/wireless/p54/fwio.c                    |    2 +-
 drivers/net/wireless/p54/txrx.c                    |    3 +-
 drivers/net/wireless/rt2x00/rt2400pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500usb.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2800lib.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2x00config.c         |    4 +-
 drivers/net/wireless/rt2x00/rt2x00dev.c            |    3 +-
 drivers/net/wireless/rt2x00/rt61pci.c              |    2 +-
 drivers/net/wireless/rt2x00/rt73usb.c              |    2 +-
 drivers/net/wireless/rtlwifi/core.c                |    2 +-
 drivers/net/wireless/rtlwifi/ps.c                  |    4 +-
 drivers/net/wireless/ti/wl1251/main.c              |    8 ++-
 drivers/net/wireless/ti/wlcore/main.c              |    3 +-
 include/net/mac80211.h                             |   64 +++++++++++++-------
 net/mac80211/ieee80211_i.h                         |    7 +++
 net/mac80211/mlme.c                                |   25 ++++----
 net/mac80211/offchannel.c                          |    8 +--
 net/mac80211/tx.c                                  |    2 +-
 net/mac80211/util.c                                |    2 +-
 27 files changed, 101 insertions(+), 65 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index a8016d7..4a508de 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1212,7 +1212,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
-		if (conf->flags & IEEE80211_CONF_PS) {
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 			ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
 			priv->ps_enabled = true;
 		} else {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5432f12..93fb439 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1169,7 +1169,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
 		unsigned long flags;
 		spin_lock_irqsave(&sc->sc_pm_lock, flags);
-		if (conf->flags & IEEE80211_CONF_PS)
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE)
 			ath9k_enable_ps(sc);
 		else
 			ath9k_disable_ps(sc);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ef82751..4af4a66 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -836,7 +836,8 @@ static int carl9170_ps_update(struct ar9170 *ar)
 	int err = 0;
 
 	if (!ar->ps.off_override)
-		ps = (ar->hw->conf.flags & IEEE80211_CONF_PS);
+		ps = ieee80211_conf_ps_mode(&ar->hw->conf) ==
+		     IEEE80211_PS_DOZE;
 
 	if (ps != ar->ps.state) {
 		err = carl9170_powersave(ar, ps);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 4684dd9..ba4563e 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -524,7 +524,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
 	u8 tim_len;
 	bool cam;
 
-	if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
+	if (likely(ieee80211_conf_ps_mode(&ar->hw->conf) != IEEE80211_PS_DOZE))
 		return;
 
 	/* check if this really is a beacon */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c6451c6..5f49326 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -396,7 +396,8 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
 			       "true" : "false");
 	if (changed & IEEE80211_CONF_CHANGE_PS)
 		brcms_err(core, "%s: change power-save mode: %s (implement)\n",
-			  __func__, conf->flags & IEEE80211_CONF_PS ?
+			  __func__,
+			  ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
 			  "true" : "false");
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
index bd69018..5194998 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -286,7 +286,8 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
 static void iwl_power_build_cmd(struct iwl_priv *priv,
 				struct iwl_powertable_cmd *cmd)
 {
-	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
+	bool enabled = ieee80211_conf_ps_mode(&priv->hw->conf) ==
+		       IEEE80211_PS_DOZE;
 	int dtimper;
 
 	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index b73e497..3e4123e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1080,7 +1080,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 		    conf->channel ? conf->channel->center_freq : 0,
 		    hwsim_chantypes[conf->channel_type],
 		    !!(conf->flags & IEEE80211_CONF_IDLE),
-		    !!(conf->flags & IEEE80211_CONF_PS),
+		    ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE,
 		    smps_modes[conf->smps_mode]);
 
 	data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 9ba8510..ed808c8 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -601,7 +601,7 @@ int p54_set_ps(struct p54_common *priv)
 	unsigned int i;
 	u16 mode;
 
-	if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+	if (ieee80211_conf_ps_mode(&priv->hw->conf) == IEEE80211_PS_DOZE &&
 	    !priv->powersave_override)
 		mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
 		       P54_PSM_CHECKSUM | P54_PSM_MCBC;
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 12f0a34..2e166be 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -380,7 +380,8 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
 
 	skb_pull(skb, header_len);
 	skb_trim(skb, le16_to_cpu(hdr->len));
-	if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+	if (unlikely(ieee80211_conf_ps_mode(&priv->hw->conf) ==
+		     IEEE80211_PS_DOZE))
 		p54_pspoll_workaround(priv, skb);
 
 	ieee80211_rx_irqsafe(priv->hw, skb);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index a2d2bc2..203a217 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -521,7 +521,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 9bea10f..e4a7e12 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -570,7 +570,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 6b2e1e43..a411f4e 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -649,7 +649,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u16 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index a658b4b..acfb0a1 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -2862,7 +2862,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev,
 			     struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 49a63e9..8cdf525 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -261,7 +261,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
 	    test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
 	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
-	    (conf->flags & IEEE80211_CONF_PS)) {
+	    ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 		beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
 		beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
 
@@ -274,7 +274,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 				   autowake_timeout - 15);
 	}
 
-	if (conf->flags & IEEE80211_CONF_PS)
+	if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE)
 		set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
 	else
 		clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 1031db6..a837132 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -596,7 +596,8 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
 	 * configured, or if the device is already in powersaving mode
 	 * we can exit now. */
 	if (likely(!ieee80211_is_beacon(hdr->frame_control) ||
-		   !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS)))
+		   ieee80211_conf_ps_mode(&rt2x00dev->hw->conf) !=
+		   IEEE80211_PS_DOZE))
 		return;
 
 	/* min. beacon length + FCS_LEN */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f95792c..c9d3e37 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -942,7 +942,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 24eec66..719e781 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -827,7 +827,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index d3ce9fb..69d6d08 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -289,7 +289,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
 		cancel_delayed_work(&rtlpriv->works.ps_work);
 		cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
-		if (conf->flags & IEEE80211_CONF_PS) {
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 			rtlpriv->psc.sw_ps_enabled = true;
 			/* sleep here is must, or we may recv the beacon and
 			 * cause mac80211 into wrong ps state, this will cause
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 13ad33e..14babaf 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -468,7 +468,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
 	if (rtlpriv->psc.fwctrl_lps)
 		return;
 
-	if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
+	if (likely(ieee80211_conf_ps_mode(&hw->conf) != IEEE80211_PS_DOZE))
 		return;
 
 	/* check if this really is a beacon */
@@ -624,7 +624,7 @@ void rtl_swlps_wq_callback(void *data)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	bool ps = false;
 
-	ps = (hw->conf.flags & IEEE80211_CONF_PS);
+	ps = ieee80211_conf_ps_mode(&hw->conf) == IEEE80211_PS_DOZE;
 
 	/* we can sleep after ps null send ok */
 	if (rtlpriv->psc.state_inap) {
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index f47e8b0..57bea2f 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -576,7 +576,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 
 	wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
 		     channel,
-		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
+		     ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
+		     "on" : "off",
 		     conf->power_level);
 
 	mutex_lock(&wl->mutex);
@@ -594,7 +595,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 			goto out_sleep;
 	}
 
-	if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+	if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE &&
+	    !wl->psm_requested) {
 		wl1251_debug(DEBUG_PSM, "psm enabled");
 
 		wl->psm_requested = true;
@@ -610,7 +612,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 		ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
 		if (ret < 0)
 			goto out_sleep;
-	} else if (!(conf->flags & IEEE80211_CONF_PS) &&
+	} else if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_DOZE &&
 		   wl->psm_requested) {
 		wl1251_debug(DEBUG_PSM, "psm disabled");
 
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index e1dfdf9..c67005f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -2901,7 +2901,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
 		     " changed 0x%x",
-		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
+		     ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
+		     "on" : "off",
 		     conf->power_level,
 		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
 			 changed);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5c98d65..024c495 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -858,13 +858,16 @@ struct ieee80211_rx_status {
  * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this
  *	to determine for example whether to calculate timestamps for packets
  *	or not, do not use instead of filter flags!
- * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only).
- *	This is the power save mode defined by IEEE 802.11-2007 section 11.2,
- *	meaning that the hardware still wakes up for beacons, is able to
- *	transmit frames and receive the possible acknowledgment frames.
- *	Not to be confused with hardware specific wakeup/sleep states,
- *	driver is responsible for that. See the section "Powersave support"
- *	for more.
+ * @IEEE80211_CONF_PS_MASK: This mask defines the bits which identify the
+ *	802.11 power save mode defined by IEEE 802.11-2007 section 11.2.
+ *	Possible values for this field are defined by the subsequent
+ *	IEEE80211_PS_* flags. See the section "Powersave support" for more.
+ * @IEEE80211_PS_AWAKE: The hardware is fully awake and is able to transmit
+ *	and receive frames.
+ * @IEEE80211_PS_DOZE: The hardware is in a low-power state. It still wakes
+ *	up for beacons and is able to transmit and receive the possible
+ *	acknowledgement frames. Not to be confused with hardware specific
+ *	wakeup/sleep states; the driver is responsible for that.
  * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
  *	the driver should be prepared to handle configuration requests but
  *	may turn the device off as much as possible. Typically, this flag will
@@ -875,9 +878,11 @@ struct ieee80211_rx_status {
  */
 enum ieee80211_conf_flags {
 	IEEE80211_CONF_MONITOR		= (1<<0),
-	IEEE80211_CONF_PS		= (1<<1),
-	IEEE80211_CONF_IDLE		= (1<<2),
-	IEEE80211_CONF_OFFCHANNEL	= (1<<3),
+	IEEE80211_CONF_PS_MASK		= (3<<1),
+	IEEE80211_PS_AWAKE		= (0<<1),
+	IEEE80211_PS_DOZE		= (1<<1),
+	IEEE80211_CONF_IDLE		= (1<<3),
+	IEEE80211_CONF_OFFCHANNEL	= (1<<4),
 };
 
 
@@ -980,6 +985,18 @@ struct ieee80211_conf {
 };
 
 /**
+ * ieee80211_conf_ps_mode - get powersave mode
+ *
+ * Returns the current powersave mode from the supplied configuration.
+ *
+ * @conf: device configuration
+ */
+static inline u32 ieee80211_conf_ps_mode(struct ieee80211_conf *conf)
+{
+	return conf->flags & IEEE80211_CONF_PS_MASK;
+}
+
+/**
  * struct ieee80211_channel_switch - holds the channel switch data
  *
  * The information provided in this structure is required for channel switch
@@ -1641,13 +1658,13 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * First, it can support hardware that handles all powersaving by itself,
  * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware
  * flag. In that case, it will be told about the desired powersave mode
- * with the %IEEE80211_CONF_PS flag depending on the association status.
+ * with ieee80211_conf_ps_mode() depending on the association status.
  * The hardware must take care of sending nullfunc frames when necessary,
  * i.e. when entering and leaving powersave mode. The hardware is required
  * to look at the AID in beacons and signal to the AP that it woke up when
  * it finds traffic directed to it.
  *
- * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
+ * The %IEEE80211_PS_DOZE mode means that the powersave mode defined in
  * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
  * with hardware wakeup and sleep states. Driver is responsible for waking
  * up the hardware before issuing commands to the hardware and putting it
@@ -1679,9 +1696,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support
  * dynamic PS mode itself. The driver needs to look at the
  * @dynamic_ps_timeout hardware configuration value and use it that value
- * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable
- * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
- * enabled whenever user has enabled powersave.
+ * whenever the mode is %IEEE80211_PS_DOZE. In this case mac80211 will disable
+ * dynamic PS feature in stack and will just set %IEEE80211_PS_DOZE whenever
+ * the user has enabled powersave.
  *
  * Some hardware need to toggle a single shared antenna between WLAN and
  * Bluetooth to facilitate co-existence. These types of hardware set
@@ -1716,9 +1733,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  *
  * Beacon filter support is advertised with the %IEEE80211_VIF_BEACON_FILTER
  * interface capability. The driver needs to enable beacon filter support
- * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When
- * power save is enabled, the stack will not check for beacon loss and the
- * driver needs to notify about loss of beacons with ieee80211_beacon_loss().
+ * whenever the powersave mode is %IEEE80211_PS_DOZE. When in the doze state,
+ * the stack will not check for beacon loss and the driver needs to notify
+ * about loss of beacons with ieee80211_beacon_loss().
  *
  * The time (or number of beacons missed) until the firmware notifies the
  * driver of a beacon loss event (which in turn causes the driver to call
@@ -3864,8 +3881,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER and
- * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
- * hardware is not receiving beacons with this function.
+ * the powersave mode is %IEEE80211_PS_DOZE, the driver needs to inform
+ * whenever the hardware is not receiving beacons with this function.
  */
 void ieee80211_beacon_loss(struct ieee80211_vif *vif);
 
@@ -3874,9 +3891,10 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and
- * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
- * needs to inform if the connection to the AP has been lost.
+ * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, the
+ * powersave mode is %IEEE80211_PS_DOZE, and %IEEE80211_HW_CONNECTION_MONITOR
+ * is set, the driver needs to inform if the connection to the AP has been
+ * lost.
  *
  * This function will cause immediate change to disassociated state,
  * without connection recovery attempts.
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8adfdfb..0b0662f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1290,6 +1290,13 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 void ieee80211_configure_filter(struct ieee80211_local *local);
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 
+static inline void
+ieee80211_conf_set_ps_mode(struct ieee80211_conf *conf, u32 mode)
+{
+	conf->flags = (conf->flags & ~IEEE80211_CONF_PS_MASK) |
+		      (mode & IEEE80211_CONF_PS_MASK);
+}
+
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0f4e21f..7afcc73 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1004,7 +1004,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
 		    (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
 			return;
 
-		conf->flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 }
@@ -1015,8 +1015,8 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
 
 	if (local->ps_sdata) {
 		ieee80211_enable_ps(local, local->ps_sdata);
-	} else if (conf->flags & IEEE80211_CONF_PS) {
-		conf->flags &= ~IEEE80211_CONF_PS;
+	} else if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 		del_timer_sync(&local->dynamic_ps_timer);
 		cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -1149,9 +1149,10 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local,
 			     dynamic_ps_disable_work);
+	struct ieee80211_conf *conf = &local->hw.conf;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+	if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -1175,7 +1176,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
 
 	ifmgd = &sdata->u.mgd;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS)
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE)
 		return;
 
 	if (!local->disable_dynamic_ps &&
@@ -1226,7 +1227,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
 	      (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) ||
 	    (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
 		ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
-		local->hw.conf.flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -1523,8 +1524,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	 * to do it before sending disassoc, as otherwise the null-packet
 	 * won't be valid.
 	 */
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+	if (ieee80211_conf_ps_mode(&local->hw.conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 	local->ps_sdata = NULL;
@@ -2658,8 +2659,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 							ifmgd->aid);
 		if (directed_tim) {
 			if (local->hw.conf.dynamic_ps_timeout > 0) {
-				if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-					local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+				if (ieee80211_conf_ps_mode(&local->hw.conf) !=
+				    IEEE80211_PS_AWAKE) {
+					ieee80211_conf_set_ps_mode(&local->hw.conf,
+								   IEEE80211_PS_AWAKE);
 					ieee80211_hw_config(local,
 							    IEEE80211_CONF_CHANGE_PS);
 				}
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 28274f9..22bba7a 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -40,9 +40,9 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 
 	cancel_work_sync(&local->dynamic_ps_enable_work);
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
 		local->offchannel_ps_enabled = true;
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -87,11 +87,11 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
 		/* TODO:  Only set hardware if CONF_PS changed?
 		 * TODO:  Should we set offchannel_ps_enabled to false?
 		 */
-		local->hw.conf.flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
 		/*
-		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
+		 * If the powersave mode was awake and the dynamic_ps_timer
 		 * had been running before leaving the operating channel,
 		 * restart the timer now and send a nullfunc frame to inform
 		 * the AP that we are awake.
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2619f4a..2572647 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -231,7 +231,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 	    skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
 		return TX_CONTINUE;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
 		ieee80211_stop_queues_by_reason(&local->hw,
 						IEEE80211_QUEUE_STOP_REASON_PS);
 		ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5259557..0f47a71 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1590,7 +1590,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	 * explicitly send a null packet in order to make sure
 	 * it'll sync against the ap (and get out of psm).
 	 */
-	if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_AWAKE) {
 		list_for_each_entry(sdata, &local->interfaces, list) {
 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
 				continue;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-06 21:01   ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: ath9k-devel

The powersave configuration in struct ieee80211_conf is currently a
binary state, either enabled or disabled. This is inadequate for
expressing the situation during off-channel operation, when powersave is
set at the AP to request bufferring of frames but the hardware remains
fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
to support this in-between state but lack the information to do so.

To prepare for adding an off-channel powersave mode, expand the current
powersave configuration flag to two bits to support expressing another
state. Add helper functions for setting and retrieving the state, and
convert mac80211 and drivers to use these functions.

In changing from a binary flag to powersave mode, also update the
terminology used to name the states for clarity. The "enabled" state is
changed to "doze" to indicate a low power hardware state, and the
"disabled" state is changed to "awake" to indicate a fully powerd on
hardware state. This is consistent with the terminology defined in IEEE
802.11-2012 section 10.2.1.2.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_main.c      |    2 +-
 drivers/net/wireless/ath/ath9k/main.c              |    2 +-
 drivers/net/wireless/ath/carl9170/main.c           |    3 +-
 drivers/net/wireless/ath/carl9170/rx.c             |    2 +-
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |    3 +-
 drivers/net/wireless/iwlwifi/dvm/power.c           |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |    2 +-
 drivers/net/wireless/p54/fwio.c                    |    2 +-
 drivers/net/wireless/p54/txrx.c                    |    3 +-
 drivers/net/wireless/rt2x00/rt2400pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500usb.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2800lib.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2x00config.c         |    4 +-
 drivers/net/wireless/rt2x00/rt2x00dev.c            |    3 +-
 drivers/net/wireless/rt2x00/rt61pci.c              |    2 +-
 drivers/net/wireless/rt2x00/rt73usb.c              |    2 +-
 drivers/net/wireless/rtlwifi/core.c                |    2 +-
 drivers/net/wireless/rtlwifi/ps.c                  |    4 +-
 drivers/net/wireless/ti/wl1251/main.c              |    8 ++-
 drivers/net/wireless/ti/wlcore/main.c              |    3 +-
 include/net/mac80211.h                             |   64 +++++++++++++-------
 net/mac80211/ieee80211_i.h                         |    7 +++
 net/mac80211/mlme.c                                |   25 ++++----
 net/mac80211/offchannel.c                          |    8 +--
 net/mac80211/tx.c                                  |    2 +-
 net/mac80211/util.c                                |    2 +-
 27 files changed, 101 insertions(+), 65 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index a8016d7..4a508de 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1212,7 +1212,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
-		if (conf->flags & IEEE80211_CONF_PS) {
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 			ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
 			priv->ps_enabled = true;
 		} else {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5432f12..93fb439 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1169,7 +1169,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
 		unsigned long flags;
 		spin_lock_irqsave(&sc->sc_pm_lock, flags);
-		if (conf->flags & IEEE80211_CONF_PS)
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE)
 			ath9k_enable_ps(sc);
 		else
 			ath9k_disable_ps(sc);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ef82751..4af4a66 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -836,7 +836,8 @@ static int carl9170_ps_update(struct ar9170 *ar)
 	int err = 0;
 
 	if (!ar->ps.off_override)
-		ps = (ar->hw->conf.flags & IEEE80211_CONF_PS);
+		ps = ieee80211_conf_ps_mode(&ar->hw->conf) ==
+		     IEEE80211_PS_DOZE;
 
 	if (ps != ar->ps.state) {
 		err = carl9170_powersave(ar, ps);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 4684dd9..ba4563e 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -524,7 +524,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
 	u8 tim_len;
 	bool cam;
 
-	if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
+	if (likely(ieee80211_conf_ps_mode(&ar->hw->conf) != IEEE80211_PS_DOZE))
 		return;
 
 	/* check if this really is a beacon */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c6451c6..5f49326 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -396,7 +396,8 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
 			       "true" : "false");
 	if (changed & IEEE80211_CONF_CHANGE_PS)
 		brcms_err(core, "%s: change power-save mode: %s (implement)\n",
-			  __func__, conf->flags & IEEE80211_CONF_PS ?
+			  __func__,
+			  ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
 			  "true" : "false");
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
index bd69018..5194998 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -286,7 +286,8 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
 static void iwl_power_build_cmd(struct iwl_priv *priv,
 				struct iwl_powertable_cmd *cmd)
 {
-	bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
+	bool enabled = ieee80211_conf_ps_mode(&priv->hw->conf) ==
+		       IEEE80211_PS_DOZE;
 	int dtimper;
 
 	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index b73e497..3e4123e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1080,7 +1080,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 		    conf->channel ? conf->channel->center_freq : 0,
 		    hwsim_chantypes[conf->channel_type],
 		    !!(conf->flags & IEEE80211_CONF_IDLE),
-		    !!(conf->flags & IEEE80211_CONF_PS),
+		    ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE,
 		    smps_modes[conf->smps_mode]);
 
 	data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 9ba8510..ed808c8 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -601,7 +601,7 @@ int p54_set_ps(struct p54_common *priv)
 	unsigned int i;
 	u16 mode;
 
-	if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+	if (ieee80211_conf_ps_mode(&priv->hw->conf) == IEEE80211_PS_DOZE &&
 	    !priv->powersave_override)
 		mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
 		       P54_PSM_CHECKSUM | P54_PSM_MCBC;
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 12f0a34..2e166be 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -380,7 +380,8 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
 
 	skb_pull(skb, header_len);
 	skb_trim(skb, le16_to_cpu(hdr->len));
-	if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+	if (unlikely(ieee80211_conf_ps_mode(&priv->hw->conf) ==
+		     IEEE80211_PS_DOZE))
 		p54_pspoll_workaround(priv, skb);
 
 	ieee80211_rx_irqsafe(priv->hw, skb);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index a2d2bc2..203a217 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -521,7 +521,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 9bea10f..e4a7e12 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -570,7 +570,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 6b2e1e43..a411f4e 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -649,7 +649,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u16 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index a658b4b..acfb0a1 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -2862,7 +2862,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev,
 			     struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 49a63e9..8cdf525 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -261,7 +261,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
 	    test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
 	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
-	    (conf->flags & IEEE80211_CONF_PS)) {
+	    ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 		beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
 		beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
 
@@ -274,7 +274,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 				   autowake_timeout - 15);
 	}
 
-	if (conf->flags & IEEE80211_CONF_PS)
+	if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE)
 		set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
 	else
 		clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 1031db6..a837132 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -596,7 +596,8 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
 	 * configured, or if the device is already in powersaving mode
 	 * we can exit now. */
 	if (likely(!ieee80211_is_beacon(hdr->frame_control) ||
-		   !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS)))
+		   ieee80211_conf_ps_mode(&rt2x00dev->hw->conf) !=
+		   IEEE80211_PS_DOZE))
 		return;
 
 	/* min. beacon length + FCS_LEN */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f95792c..c9d3e37 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -942,7 +942,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 24eec66..719e781 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -827,7 +827,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
 	enum dev_state state =
-	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
+	    ieee80211_conf_ps_mode(libconf->conf) == IEEE80211_PS_DOZE ?
 		STATE_SLEEP : STATE_AWAKE;
 	u32 reg;
 
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index d3ce9fb..69d6d08 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -289,7 +289,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
 		cancel_delayed_work(&rtlpriv->works.ps_work);
 		cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
-		if (conf->flags & IEEE80211_CONF_PS) {
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE) {
 			rtlpriv->psc.sw_ps_enabled = true;
 			/* sleep here is must, or we may recv the beacon and
 			 * cause mac80211 into wrong ps state, this will cause
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 13ad33e..14babaf 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -468,7 +468,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
 	if (rtlpriv->psc.fwctrl_lps)
 		return;
 
-	if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
+	if (likely(ieee80211_conf_ps_mode(&hw->conf) != IEEE80211_PS_DOZE))
 		return;
 
 	/* check if this really is a beacon */
@@ -624,7 +624,7 @@ void rtl_swlps_wq_callback(void *data)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	bool ps = false;
 
-	ps = (hw->conf.flags & IEEE80211_CONF_PS);
+	ps = ieee80211_conf_ps_mode(&hw->conf) == IEEE80211_PS_DOZE;
 
 	/* we can sleep after ps null send ok */
 	if (rtlpriv->psc.state_inap) {
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index f47e8b0..57bea2f 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -576,7 +576,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 
 	wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
 		     channel,
-		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
+		     ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
+		     "on" : "off",
 		     conf->power_level);
 
 	mutex_lock(&wl->mutex);
@@ -594,7 +595,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 			goto out_sleep;
 	}
 
-	if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+	if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE &&
+	    !wl->psm_requested) {
 		wl1251_debug(DEBUG_PSM, "psm enabled");
 
 		wl->psm_requested = true;
@@ -610,7 +612,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 		ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
 		if (ret < 0)
 			goto out_sleep;
-	} else if (!(conf->flags & IEEE80211_CONF_PS) &&
+	} else if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_DOZE &&
 		   wl->psm_requested) {
 		wl1251_debug(DEBUG_PSM, "psm disabled");
 
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index e1dfdf9..c67005f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -2901,7 +2901,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
 		     " changed 0x%x",
-		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
+		     ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
+		     "on" : "off",
 		     conf->power_level,
 		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
 			 changed);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5c98d65..024c495 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -858,13 +858,16 @@ struct ieee80211_rx_status {
  * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this
  *	to determine for example whether to calculate timestamps for packets
  *	or not, do not use instead of filter flags!
- * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only).
- *	This is the power save mode defined by IEEE 802.11-2007 section 11.2,
- *	meaning that the hardware still wakes up for beacons, is able to
- *	transmit frames and receive the possible acknowledgment frames.
- *	Not to be confused with hardware specific wakeup/sleep states,
- *	driver is responsible for that. See the section "Powersave support"
- *	for more.
+ * @IEEE80211_CONF_PS_MASK: This mask defines the bits which identify the
+ *	802.11 power save mode defined by IEEE 802.11-2007 section 11.2.
+ *	Possible values for this field are defined by the subsequent
+ *	IEEE80211_PS_* flags. See the section "Powersave support" for more.
+ * @IEEE80211_PS_AWAKE: The hardware is fully awake and is able to transmit
+ *	and receive frames.
+ * @IEEE80211_PS_DOZE: The hardware is in a low-power state. It still wakes
+ *	up for beacons and is able to transmit and receive the possible
+ *	acknowledgement frames. Not to be confused with hardware specific
+ *	wakeup/sleep states; the driver is responsible for that.
  * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
  *	the driver should be prepared to handle configuration requests but
  *	may turn the device off as much as possible. Typically, this flag will
@@ -875,9 +878,11 @@ struct ieee80211_rx_status {
  */
 enum ieee80211_conf_flags {
 	IEEE80211_CONF_MONITOR		= (1<<0),
-	IEEE80211_CONF_PS		= (1<<1),
-	IEEE80211_CONF_IDLE		= (1<<2),
-	IEEE80211_CONF_OFFCHANNEL	= (1<<3),
+	IEEE80211_CONF_PS_MASK		= (3<<1),
+	IEEE80211_PS_AWAKE		= (0<<1),
+	IEEE80211_PS_DOZE		= (1<<1),
+	IEEE80211_CONF_IDLE		= (1<<3),
+	IEEE80211_CONF_OFFCHANNEL	= (1<<4),
 };
 
 
@@ -980,6 +985,18 @@ struct ieee80211_conf {
 };
 
 /**
+ * ieee80211_conf_ps_mode - get powersave mode
+ *
+ * Returns the current powersave mode from the supplied configuration.
+ *
+ * @conf: device configuration
+ */
+static inline u32 ieee80211_conf_ps_mode(struct ieee80211_conf *conf)
+{
+	return conf->flags & IEEE80211_CONF_PS_MASK;
+}
+
+/**
  * struct ieee80211_channel_switch - holds the channel switch data
  *
  * The information provided in this structure is required for channel switch
@@ -1641,13 +1658,13 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * First, it can support hardware that handles all powersaving by itself,
  * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware
  * flag. In that case, it will be told about the desired powersave mode
- * with the %IEEE80211_CONF_PS flag depending on the association status.
+ * with ieee80211_conf_ps_mode() depending on the association status.
  * The hardware must take care of sending nullfunc frames when necessary,
  * i.e. when entering and leaving powersave mode. The hardware is required
  * to look at the AID in beacons and signal to the AP that it woke up when
  * it finds traffic directed to it.
  *
- * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
+ * The %IEEE80211_PS_DOZE mode means that the powersave mode defined in
  * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
  * with hardware wakeup and sleep states. Driver is responsible for waking
  * up the hardware before issuing commands to the hardware and putting it
@@ -1679,9 +1696,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support
  * dynamic PS mode itself. The driver needs to look at the
  * @dynamic_ps_timeout hardware configuration value and use it that value
- * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable
- * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
- * enabled whenever user has enabled powersave.
+ * whenever the mode is %IEEE80211_PS_DOZE. In this case mac80211 will disable
+ * dynamic PS feature in stack and will just set %IEEE80211_PS_DOZE whenever
+ * the user has enabled powersave.
  *
  * Some hardware need to toggle a single shared antenna between WLAN and
  * Bluetooth to facilitate co-existence. These types of hardware set
@@ -1716,9 +1733,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  *
  * Beacon filter support is advertised with the %IEEE80211_VIF_BEACON_FILTER
  * interface capability. The driver needs to enable beacon filter support
- * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When
- * power save is enabled, the stack will not check for beacon loss and the
- * driver needs to notify about loss of beacons with ieee80211_beacon_loss().
+ * whenever the powersave mode is %IEEE80211_PS_DOZE. When in the doze state,
+ * the stack will not check for beacon loss and the driver needs to notify
+ * about loss of beacons with ieee80211_beacon_loss().
  *
  * The time (or number of beacons missed) until the firmware notifies the
  * driver of a beacon loss event (which in turn causes the driver to call
@@ -3864,8 +3881,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER and
- * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
- * hardware is not receiving beacons with this function.
+ * the powersave mode is %IEEE80211_PS_DOZE, the driver needs to inform
+ * whenever the hardware is not receiving beacons with this function.
  */
 void ieee80211_beacon_loss(struct ieee80211_vif *vif);
 
@@ -3874,9 +3891,10 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and
- * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
- * needs to inform if the connection to the AP has been lost.
+ * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, the
+ * powersave mode is %IEEE80211_PS_DOZE, and %IEEE80211_HW_CONNECTION_MONITOR
+ * is set, the driver needs to inform if the connection to the AP has been
+ * lost.
  *
  * This function will cause immediate change to disassociated state,
  * without connection recovery attempts.
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8adfdfb..0b0662f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1290,6 +1290,13 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 void ieee80211_configure_filter(struct ieee80211_local *local);
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 
+static inline void
+ieee80211_conf_set_ps_mode(struct ieee80211_conf *conf, u32 mode)
+{
+	conf->flags = (conf->flags & ~IEEE80211_CONF_PS_MASK) |
+		      (mode & IEEE80211_CONF_PS_MASK);
+}
+
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0f4e21f..7afcc73 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1004,7 +1004,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
 		    (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
 			return;
 
-		conf->flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 }
@@ -1015,8 +1015,8 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
 
 	if (local->ps_sdata) {
 		ieee80211_enable_ps(local, local->ps_sdata);
-	} else if (conf->flags & IEEE80211_CONF_PS) {
-		conf->flags &= ~IEEE80211_CONF_PS;
+	} else if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 		del_timer_sync(&local->dynamic_ps_timer);
 		cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -1149,9 +1149,10 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local,
 			     dynamic_ps_disable_work);
+	struct ieee80211_conf *conf = &local->hw.conf;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+	if (ieee80211_conf_ps_mode(conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -1175,7 +1176,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
 
 	ifmgd = &sdata->u.mgd;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS)
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE)
 		return;
 
 	if (!local->disable_dynamic_ps &&
@@ -1226,7 +1227,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
 	      (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) ||
 	    (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
 		ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
-		local->hw.conf.flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -1523,8 +1524,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	 * to do it before sending disassoc, as otherwise the null-packet
 	 * won't be valid.
 	 */
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+	if (ieee80211_conf_ps_mode(&local->hw.conf) != IEEE80211_PS_AWAKE) {
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 	local->ps_sdata = NULL;
@@ -2658,8 +2659,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 							ifmgd->aid);
 		if (directed_tim) {
 			if (local->hw.conf.dynamic_ps_timeout > 0) {
-				if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-					local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+				if (ieee80211_conf_ps_mode(&local->hw.conf) !=
+				    IEEE80211_PS_AWAKE) {
+					ieee80211_conf_set_ps_mode(&local->hw.conf,
+								   IEEE80211_PS_AWAKE);
 					ieee80211_hw_config(local,
 							    IEEE80211_CONF_CHANGE_PS);
 				}
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 28274f9..22bba7a 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -40,9 +40,9 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 
 	cancel_work_sync(&local->dynamic_ps_enable_work);
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
 		local->offchannel_ps_enabled = true;
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
 
@@ -87,11 +87,11 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
 		/* TODO:  Only set hardware if CONF_PS changed?
 		 * TODO:  Should we set offchannel_ps_enabled to false?
 		 */
-		local->hw.conf.flags |= IEEE80211_CONF_PS;
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
 		/*
-		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
+		 * If the powersave mode was awake and the dynamic_ps_timer
 		 * had been running before leaving the operating channel,
 		 * restart the timer now and send a nullfunc frame to inform
 		 * the AP that we are awake.
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2619f4a..2572647 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -231,7 +231,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 	    skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
 		return TX_CONTINUE;
 
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
 		ieee80211_stop_queues_by_reason(&local->hw,
 						IEEE80211_QUEUE_STOP_REASON_PS);
 		ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5259557..0f47a71 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1590,7 +1590,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	 * explicitly send a null packet in order to make sure
 	 * it'll sync against the ap (and get out of psm).
 	 */
-	if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_AWAKE) {
 		list_for_each_entry(sdata, &local->interfaces, list) {
 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
 				continue;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave
  2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
  2013-02-06 21:01   ` [ath9k-devel] " Seth Forshee
@ 2013-02-06 21:01 ` Seth Forshee
  2013-02-15 23:45   ` Hin-Tak Leung
  2013-02-06 21:01 ` [PATCH 3/4] mac80211: Add off-channel PS state Seth Forshee
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: ath9k-devel

When the off-channel powersave mode is added to mac80211, even drivers
which do not support a doze powersave state will be informed of changes
in the powersave state. To prepare for this, change the hardware
powersave support flag to IEEE80211_HW_SUPPORTS_PS_DOZE to indicate only
support for the doze state rather than powersave support in general.
Most drivers which do not support the doze state can continue to ignore
powersave state changes.

It will also become necessary for all drivers to accurately set the
IEEE80211_HW_PS_NULLFUNC_STACK flag. Set this flag for all drivers which
do not support the doze state.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 drivers/net/wireless/adm8211.c                     |    3 +-
 drivers/net/wireless/at76c50x-usb.c                |    3 +-
 drivers/net/wireless/ath/ar5523/ar5523.c           |    3 +-
 drivers/net/wireless/ath/ath5k/base.c              |    3 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c      |    2 +-
 drivers/net/wireless/ath/ath9k/init.c              |    2 +-
 drivers/net/wireless/ath/carl9170/fw.c             |    2 +-
 drivers/net/wireless/ath/carl9170/main.c           |    2 +-
 drivers/net/wireless/b43/main.c                    |    3 +-
 drivers/net/wireless/b43legacy/main.c              |    3 +-
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |    3 +-
 drivers/net/wireless/iwlegacy/3945-mac.c           |    3 +-
 drivers/net/wireless/iwlegacy/4965-mac.c           |    2 +-
 drivers/net/wireless/iwlwifi/dvm/mac80211.c        |    2 +-
 drivers/net/wireless/iwlwifi/mvm/mac80211.c        |    2 +-
 drivers/net/wireless/libertas_tf/main.c            |    3 +-
 drivers/net/wireless/mac80211_hwsim.c              |    3 +-
 drivers/net/wireless/mwl8k.c                       |    3 +-
 drivers/net/wireless/p54/main.c                    |    2 +-
 drivers/net/wireless/rt2x00/rt2400pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500pci.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2500usb.c            |    2 +-
 drivers/net/wireless/rt2x00/rt2800lib.c            |    2 +-
 drivers/net/wireless/rt2x00/rt61pci.c              |    2 +-
 drivers/net/wireless/rt2x00/rt73usb.c              |    2 +-
 drivers/net/wireless/rtl818x/rtl8180/dev.c         |    3 +-
 drivers/net/wireless/rtl818x/rtl8187/dev.c         |    3 +-
 drivers/net/wireless/rtlwifi/base.c                |    2 +-
 drivers/net/wireless/ti/wl1251/main.c              |    2 +-
 drivers/net/wireless/ti/wlcore/main.c              |    2 +-
 drivers/net/wireless/zd1211rw/zd_mac.c             |    3 +-
 include/net/mac80211.h                             |   61 +++++++++++---------
 net/mac80211/cfg.c                                 |    2 +-
 net/mac80211/debugfs.c                             |    2 +-
 net/mac80211/mlme.c                                |    6 +-
 net/mac80211/tx.c                                  |    2 +-
 36 files changed, 86 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 3d339e0..802b70c 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1862,7 +1862,8 @@ static int adm8211_probe(struct pci_dev *pdev,
 
 	dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
 	/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
-	dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+	dev->flags = IEEE80211_HW_SIGNAL_UNSPEC |
+		IEEE80211_HW_PS_NULLFUNC_STACK;
 	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
 	dev->channel_change_time = 1000;
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 77fa428..3d79d5b 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2253,7 +2253,8 @@ static int at76_init_new_device(struct at76_priv *priv,
 	priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 	priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
 	priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-			  IEEE80211_HW_SIGNAL_UNSPEC;
+			  IEEE80211_HW_SIGNAL_UNSPEC |
+			  IEEE80211_HW_PS_NULLFUNC_STACK;
 	priv->hw->max_signal = 100;
 
 	SET_IEEE80211_DEV(priv->hw, &interface->dev);
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 7157f7d..6b2b5c1 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1684,7 +1684,8 @@ static int ar5523_probe(struct usb_interface *intf,
 	ar->vif = NULL;
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		    IEEE80211_HW_SIGNAL_DBM |
-		    IEEE80211_HW_HAS_RATE_CONTROL;
+		    IEEE80211_HW_HAS_RATE_CONTROL |
+		    IEEE80211_HW_PS_NULLFUNC_STACK;
 	hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) +
 				sizeof(struct ar5523_chunk);
 	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 1d264c0..4122a15 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2439,7 +2439,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
 			IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 			IEEE80211_HW_SIGNAL_DBM |
 			IEEE80211_HW_MFP_CAPABLE |
-			IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+			IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+			IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index e5d7958..847cf6d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -718,7 +718,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 		IEEE80211_HW_SPECTRUM_MGMT |
 		IEEE80211_HW_HAS_RATE_CONTROL |
 		IEEE80211_HW_RX_INCLUDES_FCS |
-		IEEE80211_HW_SUPPORTS_PS |
+		IEEE80211_HW_SUPPORTS_PS_DOZE |
 		IEEE80211_HW_PS_NULLFUNC_STACK |
 		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index af932c9..9880af8 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -743,7 +743,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 		IEEE80211_HW_SIGNAL_DBM |
-		IEEE80211_HW_SUPPORTS_PS |
+		IEEE80211_HW_SUPPORTS_PS_DOZE |
 		IEEE80211_HW_PS_NULLFUNC_STACK |
 		IEEE80211_HW_SPECTRUM_MGMT |
 		IEEE80211_HW_REPORTS_TX_ACK_STATUS;
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 47d5c2e..bfd6c8e 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -286,7 +286,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 	}
 
 	if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
-		ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+		ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS_DOZE;
 
 	if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
 		dev_err(&ar->udev->dev, "firmware does not provide "
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 4af4a66..edab945 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1852,7 +1852,7 @@ void *carl9170_alloc(size_t priv_size)
 	hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
 		     IEEE80211_HW_MFP_CAPABLE |
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-		     IEEE80211_HW_SUPPORTS_PS |
+		     IEEE80211_HW_SUPPORTS_PS_DOZE |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_NEED_DTIM_PERIOD |
 		     IEEE80211_HW_SIGNAL_DBM;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 806e34c..0f4ddc7 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -5352,7 +5352,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
 
 	/* fill hw info */
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-		    IEEE80211_HW_SIGNAL_DBM;
+		    IEEE80211_HW_SIGNAL_DBM |
+		    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 8c3f70e..3b0b7e8 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3836,7 +3836,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 
 	/* fill hw info */
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-		    IEEE80211_HW_SIGNAL_DBM;
+		    IEEE80211_HW_SIGNAL_DBM |
+		    IEEE80211_HW_PS_NULLFUNC_STACK;
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_AP) |
 		BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 5f49326..e36df33 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -987,7 +987,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
 	hw->flags = IEEE80211_HW_SIGNAL_DBM
 	    /* | IEEE80211_HW_CONNECTION_MONITOR  What is this? */
 	    | IEEE80211_HW_REPORTS_TX_ACK_STATUS
-	    | IEEE80211_HW_AMPDU_AGGREGATION;
+	    | IEEE80211_HW_AMPDU_AGGREGATION
+	    | IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	hw->extra_tx_headroom = brcms_c_get_header_len();
 	hw->queues = N_TX_QUEUES;
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 83856d1..b6b2f30 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3565,7 +3565,8 @@ il3945_setup_mac(struct il_priv *il)
 
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
-		    IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+		    IEEE80211_HW_SUPPORTS_PS_DOZE |
+		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
 	hw->wiphy->interface_modes =
 	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 9741ac1..7b63ace 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5734,7 +5734,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
 	hw->flags =
 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
 	    IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
-	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS_DOZE |
 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 	if (il->cfg->sku & IL_SKU_N)
 		hw->flags |=
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index c2f03ec..c235216 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -149,7 +149,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
 		    IEEE80211_HW_SPECTRUM_MGMT |
 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		    IEEE80211_HW_QUEUE_CONTROL |
-		    IEEE80211_HW_SUPPORTS_PS |
+		    IEEE80211_HW_SUPPORTS_PS_DOZE |
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		    IEEE80211_HW_WANT_MONITOR_VIF |
 		    IEEE80211_HW_SCAN_WHILE_IDLE;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index a6b05a0..ac2f788 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -115,7 +115,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 		    IEEE80211_HW_WANT_MONITOR_VIF |
 		    IEEE80211_HW_SCAN_WHILE_IDLE |
 		    IEEE80211_HW_NEED_DTIM_PERIOD |
-		    IEEE80211_HW_SUPPORTS_PS |
+		    IEEE80211_HW_SUPPORTS_PS_DOZE |
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		    IEEE80211_HW_AMPDU_AGGREGATION;
 
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 7001856..c3e8fc6 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -637,7 +637,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
 	priv->tx_skb = NULL;
 
 	hw->queues = 1;
-	hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		    IEEE80211_HW_PS_NULLFUNC_STACK;
 	hw->extra_tx_headroom = sizeof(struct txpd);
 	memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels));
 	memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates));
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 3e4123e..f45c8ef 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2239,7 +2239,8 @@ static int __init init_mac80211_hwsim(void)
 			    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
 			    IEEE80211_HW_AMPDU_AGGREGATION |
 			    IEEE80211_HW_WANT_MONITOR_VIF |
-			    IEEE80211_HW_QUEUE_CONTROL;
+			    IEEE80211_HW_QUEUE_CONTROL |
+			    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 		hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
 				    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 2031130..89a0bff 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -5864,7 +5864,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
 	hw->queues = MWL8K_TX_WMM_QUEUES;
 
 	/* Set rssi values to dBm */
-	hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
+	hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL |
+		     IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	/*
 	 * Ask mac80211 to not to trigger PS mode
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index aadda99..88b8d09 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -747,7 +747,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 	skb_queue_head_init(&priv->tx_pending);
 	dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		     IEEE80211_HW_SIGNAL_DBM |
-		     IEEE80211_HW_SUPPORTS_PS |
+		     IEEE80211_HW_SUPPORTS_PS_DOZE |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_MFP_CAPABLE |
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 203a217..2c501cc 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1573,7 +1573,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 			       IEEE80211_HW_SIGNAL_DBM |
-			       IEEE80211_HW_SUPPORTS_PS |
+			       IEEE80211_HW_SUPPORTS_PS_DOZE |
 			       IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index e4a7e12..71546a8 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1866,7 +1866,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 			       IEEE80211_HW_SIGNAL_DBM |
-			       IEEE80211_HW_SUPPORTS_PS |
+			       IEEE80211_HW_SUPPORTS_PS_DOZE |
 			       IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a411f4e..a68593d 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1705,7 +1705,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	rt2x00dev->hw->flags =
 	    IEEE80211_HW_RX_INCLUDES_FCS |
 	    IEEE80211_HW_SIGNAL_DBM |
-	    IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_SUPPORTS_PS_DOZE |
 	    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index acfb0a1..a60756c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5142,7 +5142,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00dev->hw->flags =
 	    IEEE80211_HW_SIGNAL_DBM |
-	    IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_SUPPORTS_PS_DOZE |
 	    IEEE80211_HW_PS_NULLFUNC_STACK |
 	    IEEE80211_HW_AMPDU_AGGREGATION |
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index c9d3e37..ca84cc5 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2763,7 +2763,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	rt2x00dev->hw->flags =
 	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 	    IEEE80211_HW_SIGNAL_DBM |
-	    IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_SUPPORTS_PS_DOZE |
 	    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 719e781..70aa736 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2118,7 +2118,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00dev->hw->flags =
 	    IEEE80211_HW_SIGNAL_DBM |
-	    IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_SUPPORTS_PS_DOZE |
 	    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 1b3c284..4f7a737 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -991,7 +991,8 @@ static int rtl8180_probe(struct pci_dev *pdev,
 
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 		     IEEE80211_HW_RX_INCLUDES_FCS |
-		     IEEE80211_HW_SIGNAL_UNSPEC;
+		     IEEE80211_HW_SIGNAL_UNSPEC |
+		     IEEE80211_HW_PS_NULLFUNC_STACK;
 	dev->vif_data_size = sizeof(struct rtl8180_vif);
 	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 					BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 4574bd2..4a4e917 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1467,7 +1467,8 @@ static int rtl8187_probe(struct usb_interface *intf,
 
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 		     IEEE80211_HW_SIGNAL_DBM |
-		     IEEE80211_HW_RX_INCLUDES_FCS;
+		     IEEE80211_HW_RX_INCLUDES_FCS |
+		     IEEE80211_HW_PS_NULLFUNC_STACK;
 	/* Initialize rate-control variables */
 	dev->max_rates = 1;
 	dev->max_rate_tries = RETRY_COUNT;
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 0f8b051..195424c 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -315,7 +315,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
 
 	/* swlps or hwlps has been set in diff chip in init_sw_vars */
 	if (rtlpriv->psc.swctrl_lps)
-		hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+		hw->flags |= IEEE80211_HW_SUPPORTS_PS_DOZE |
 			IEEE80211_HW_PS_NULLFUNC_STACK |
 			/* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
 			0;
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 57bea2f..83b0789 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1337,7 +1337,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
 	wl->hw->channel_change_time = 10000;
 
 	wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-		IEEE80211_HW_SUPPORTS_PS |
+		IEEE80211_HW_SUPPORTS_PS_DOZE |
 		IEEE80211_HW_SUPPORTS_UAPSD;
 
 	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index c67005f..9a33877 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5630,7 +5630,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 	wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
 
 	wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-		IEEE80211_HW_SUPPORTS_PS |
+		IEEE80211_HW_SUPPORTS_PS_DOZE |
 		IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		IEEE80211_HW_SUPPORTS_UAPSD |
 		IEEE80211_HW_HAS_RATE_CONTROL |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 114364b..0c39718 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1402,7 +1402,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		    IEEE80211_HW_SIGNAL_UNSPEC |
 		    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-		    IEEE80211_HW_MFP_CAPABLE;
+		    IEEE80211_HW_MFP_CAPABLE |
+		    IEEE80211_HW_PS_NULLFUNC_STACK;
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_MESH_POINT) |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 024c495..c5ca5ab 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1307,7 +1307,7 @@ struct ieee80211_tx_control {
  * @IEEE80211_HW_AMPDU_AGGREGATION:
  *	Hardware supports 11n A-MPDU aggregation.
  *
- * @IEEE80211_HW_SUPPORTS_PS:
+ * @IEEE80211_HW_SUPPORTS_PS_DOZE:
  *	Hardware has power save support (i.e. can go to sleep).
  *
  * @IEEE80211_HW_PS_NULLFUNC_STACK:
@@ -1399,7 +1399,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_NEED_DTIM_PERIOD			= 1<<7,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<8,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<9,
-	IEEE80211_HW_SUPPORTS_PS			= 1<<10,
+	IEEE80211_HW_SUPPORTS_PS_DOZE			= 1<<10,
 	IEEE80211_HW_PS_NULLFUNC_STACK			= 1<<11,
 	IEEE80211_HW_SUPPORTS_DYNAMIC_PS		= 1<<12,
 	IEEE80211_HW_MFP_CAPABLE			= 1<<13,
@@ -1655,28 +1655,37 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  *
  * mac80211 has support for various powersave implementations.
  *
- * First, it can support hardware that handles all powersaving by itself,
- * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware
- * flag. In that case, it will be told about the desired powersave mode
- * with ieee80211_conf_ps_mode() depending on the association status.
- * The hardware must take care of sending nullfunc frames when necessary,
- * i.e. when entering and leaving powersave mode. The hardware is required
- * to look at the AID in beacons and signal to the AP that it woke up when
- * it finds traffic directed to it.
- *
- * The %IEEE80211_PS_DOZE mode means that the powersave mode defined in
- * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
- * with hardware wakeup and sleep states. Driver is responsible for waking
- * up the hardware before issuing commands to the hardware and putting it
- * back to sleep at appropriate times.
- *
- * When PS is enabled, hardware needs to wakeup for beacons and receive the
- * buffered multicast/broadcast frames after the beacon. Also it must be
- * possible to send frames and receive the acknowledment frame.
+ * Drivers are informed about changes to the powersave state with the
+ * %IEEE80211_CONF_PS_MASK bits in the configuration flags. The current
+ * mode can be read by calling ieee80211_conf_ps_mode(). Hardware which
+ * does not support a low-power state should leave
+ * %IEEE80211_HW_SUPPORTS_PS_DOZE clear to avoid being placed into a low-
+ * power state. %IEEE80211_HW_PS_NULLFUNC_STACK should be set if the
+ * hardware requires that mac80211 generate nullfunc frames when
+ * transitioning between powersave modes.
+ *
+ * Hardware which supports a low-power "doze" state should set the
+ * %IEEE80211_HW_SUPPORTS_PS_DOZE hardware flag. This will make it possible
+ * to put the hardware into the %IEEE80211_PS_DOZE mode. When in the doze
+ * state the powersave mode defined in IEEE 802.11-2007 section 11.2 is
+ * enabled. This is not to be confused with hardware wakeup and sleep
+ * states. While in the doze state, the driver is responsible for waking up
+ * the hardware before issuing commands to the hardware and putting it back
+ * to sleep at appropriate times. The hardware needs to wakeup for beacons
+ * and receive the buffered multicast/broadcast frames after the beacon.
+ * Also it must be possible to send frames and receive the acknowledment
+ * frame.
+ *
+ * For hardware that handles all powersaving by itself, setting
+ * %IEEE80211_HW_SUPPORTS_PS_DOZE is all that is needed. The hardware must
+ * take care of sending nullfunc frames when necessary, i.e. when entering
+ * and leaving powersave mode. The hardware is required to look at the AID
+ * in beacons and signal to the AP that it woke up when it finds traffic
+ * directed to it.
  *
  * Other hardware designs cannot send nullfunc frames by themselves and also
  * need software support for parsing the TIM bitmap. This is also supported
- * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
+ * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS_DOZE and
  * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still
  * required to pass up beacons. The hardware is still required to handle
  * waking up for multicast traffic; if it cannot the driver must handle that
@@ -1690,11 +1699,11 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * periods.
  *
  * Dynamic powersave is simply supported by mac80211 enabling and disabling
- * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS
- * flag and mac80211 will handle everything automatically. Additionally,
- * hardware having support for the dynamic PS feature may set the
- * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support
- * dynamic PS mode itself. The driver needs to look at the
+ * PS based on traffic. Driver needs to only set
+ * %IEEE80211_HW_SUPPORTS_PS_DOZE flag and mac80211 will handle everything
+ * automatically. Additionally, hardware having support for the dynamic PS
+ * feature may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate
+ * that it can support dynamic PS mode itself. The driver needs to look@the
  * @dynamic_ps_timeout hardware configuration value and use it that value
  * whenever the mode is %IEEE80211_PS_DOZE. In this case mac80211 will disable
  * dynamic PS feature in stack and will just set %IEEE80211_PS_DOZE whenever
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fd38c37..fac5ef8 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2265,7 +2265,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
 	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -EOPNOTSUPP;
 
-	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE))
 		return -EOPNOTSUPP;
 
 	if (enabled == sdata->u.mgd.powersave &&
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 466f4b4..21ad1f5 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -127,7 +127,7 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
 		sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
 	if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
 		sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
-	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE)
 		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
 	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
 		sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7afcc73..d13d885 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -953,7 +953,7 @@ void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
 	struct ieee80211_conf *conf = &local->hw.conf;
 
 	WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
-		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE) ||
 		(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
 
 	local->disable_dynamic_ps = false;
@@ -968,7 +968,7 @@ void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
 	struct ieee80211_conf *conf = &local->hw.conf;
 
 	WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
-		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE) ||
 		(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
 
 	local->disable_dynamic_ps = true;
@@ -1058,7 +1058,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 	int count = 0;
 	int timeout;
 
-	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE)) {
 		local->ps_sdata = NULL;
 		return;
 	}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2572647..e96994e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -185,7 +185,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 	struct ieee80211_if_managed *ifmgd;
 
 	/* driver doesn't support power save */
-	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS_DOZE))
 		return TX_CONTINUE;
 
 	/* hardware does dynamic power save */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 3/4] mac80211: Add off-channel PS state
  2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
  2013-02-06 21:01   ` [ath9k-devel] " Seth Forshee
  2013-02-06 21:01 ` [ath9k-devel] [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave Seth Forshee
@ 2013-02-06 21:01 ` Seth Forshee
  2013-02-06 21:01 ` [PATCH 4/4] brcmsmac: Add support for off-channel powersave Seth Forshee
  2013-02-06 21:32 ` [PATCH 0/4] Add support for off-channel powersave state in mac80211 Johannes Berg
  4 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
  Cc: Seth Forshee, Arend van Spriel, John W. Linville, brcm80211-dev-list

Add a new powersave state for off-channel operation and transition to
the off-channel code to using this state.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 include/net/mac80211.h    |    9 ++++++++-
 net/mac80211/offchannel.c |   36 +++++++++++++++++++++---------------
 2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c5ca5ab..014dcec 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -868,6 +868,10 @@ struct ieee80211_rx_status {
  *	up for beacons and is able to transmit and receive the possible
  *	acknowledgement frames. Not to be confused with hardware specific
  *	wakeup/sleep states; the driver is responsible for that.
+ * @IEEE80211_PS_OFFCHANNEL: The hardware is fully awake and is able to
+ *	transmit and receive frames, but the AP is asked to buffer frames
+ *	as during powersave. This is used for temporarily leaving the
+ *	operating channel.
  * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
  *	the driver should be prepared to handle configuration requests but
  *	may turn the device off as much as possible. Typically, this flag will
@@ -881,6 +885,7 @@ enum ieee80211_conf_flags {
 	IEEE80211_CONF_PS_MASK		= (3<<1),
 	IEEE80211_PS_AWAKE		= (0<<1),
 	IEEE80211_PS_DOZE		= (1<<1),
+	IEEE80211_PS_OFFCHANNEL		= (2<<1),
 	IEEE80211_CONF_IDLE		= (1<<3),
 	IEEE80211_CONF_OFFCHANNEL	= (1<<4),
 };
@@ -1662,7 +1667,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * %IEEE80211_HW_SUPPORTS_PS_DOZE clear to avoid being placed into a low-
  * power state. %IEEE80211_HW_PS_NULLFUNC_STACK should be set if the
  * hardware requires that mac80211 generate nullfunc frames when
- * transitioning between powersave modes.
+ * transitioning between powersave modes. The %IEEE80211_PS_DOZE and
+ * %IEEE80211_PS_OFFCHANNEL modes must be supported by all drivers, but for
+ * most hardware these states are equivalent.
  *
  * Hardware which supports a low-power "doze" state should set the
  * %IEEE80211_HW_SUPPORTS_PS_DOZE hardware flag. This will make it possible
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 22bba7a..6912339 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -40,11 +40,11 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 
 	cancel_work_sync(&local->dynamic_ps_enable_work);
 
-	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
+	if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE)
 		local->offchannel_ps_enabled = true;
-		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
-		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-	}
+
+	ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_OFFCHANNEL);
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 
 	if (!local->offchannel_ps_enabled ||
 	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
@@ -57,6 +57,12 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 		 * sent a null frame with power save disabled. So we need
 		 * to send a new nullfunc frame to inform the AP that we
 		 * are again sleeping.
+		 *
+		 * XXX: This should no longer be necessary with the off-
+		 * channel PS state when the hw is creating the nullfunc
+		 * frame, as hardware should have enough information to
+		 * send the correct nullfunc frames. It remains to be seen
+		 * whether or not this holds in practice.
 		 */
 		ret = ieee80211_send_nullfunc(local, sdata, 1);
 
@@ -68,9 +74,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
 
-	if (!local->ps_sdata)
-		ieee80211_send_nullfunc(local, sdata, 0);
-	else if (local->offchannel_ps_enabled) {
+	if (local->offchannel_ps_enabled) {
 		/*
 		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
 		 * will send a nullfunc frame with the powersave bit set
@@ -84,21 +88,23 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
 		 * we are sleeping, let's just enable power save mode in
 		 * hardware.
 		 */
-		/* TODO:  Only set hardware if CONF_PS changed?
-		 * TODO:  Should we set offchannel_ps_enabled to false?
+		/* TODO:  Should we set offchannel_ps_enabled to false?
 		 */
 		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
+	} else {
+		ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+		ieee80211_send_nullfunc(local, sdata, 0);
+
 		/*
 		 * If the powersave mode was awake and the dynamic_ps_timer
 		 * had been running before leaving the operating channel,
-		 * restart the timer now and send a nullfunc frame to inform
-		 * the AP that we are awake.
+		 * restart the timer now.
 		 */
-		ieee80211_send_nullfunc(local, sdata, 0);
-		mod_timer(&local->dynamic_ps_timer, jiffies +
-			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+		if (local->hw.conf.dynamic_ps_timeout > 0)
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 	}
 
 	ieee80211_sta_reset_beacon_monitor(sdata);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 4/4] brcmsmac: Add support for off-channel powersave
  2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
                   ` (2 preceding siblings ...)
  2013-02-06 21:01 ` [PATCH 3/4] mac80211: Add off-channel PS state Seth Forshee
@ 2013-02-06 21:01 ` Seth Forshee
  2013-02-06 21:32 ` [PATCH 0/4] Add support for off-channel powersave state in mac80211 Johannes Berg
  4 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-06 21:01 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
  Cc: Seth Forshee, Arend van Spriel, John W. Linville, brcm80211-dev-list

Broadcom hardware sets the value of the PM flag in frame control based
on the value of MCTL_HPS, which seems to include actively clearing PM
if MCTL_HPS is not set. brcmsmac needs to suppor the off-channel
powersave state in order to enable powersave at the AP at all.

Add limited support for powersave to brcmsmac to prevent frame loss
during background scans. Full powersave supoprt remains unimplemented,
but switching between the off-channel and disabled states is possible.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |   16 +++++++++++-----
 drivers/net/wireless/brcm80211/brcmsmac/main.c     |    7 ++++++-
 drivers/net/wireless/brcm80211/brcmsmac/main.h     |    1 +
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index e36df33..4fff8fc 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -394,11 +394,17 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
 		brcms_dbg_info(core, "%s: change monitor mode: %s\n",
 			       __func__, conf->flags & IEEE80211_CONF_MONITOR ?
 			       "true" : "false");
-	if (changed & IEEE80211_CONF_CHANGE_PS)
-		brcms_err(core, "%s: change power-save mode: %s (implement)\n",
-			  __func__,
-			  ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE ?
-			  "true" : "false");
+	if (changed & IEEE80211_CONF_CHANGE_PS) {
+		/*
+		 * brcmsmac doesn't support powersave, but it does support
+		 * setting the PM bit in frame control for off-channel PS
+		 */
+		if (ieee80211_conf_ps_mode(conf) == IEEE80211_PS_DOZE)
+			brcms_err(core, "%s: cannot enable power-save mode (implement)\n",
+				  __func__);
+		else
+			brcms_c_set_ps_ctrl(wl->wlc);
+	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
 		err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 62be550..8b259ca 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -3051,6 +3051,11 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
 	if (!wlc->pub->associated)
 		return false;
 
+	/* allow PS when off-channel PS is enabled */
+	if (ieee80211_conf_ps_mode(&wlc->pub->ieee_hw->conf) ==
+	    IEEE80211_PS_OFFCHANNEL)
+		return true;
+
 	/* disallow PS when one of these meets when not scanning */
 	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
 		return false;
@@ -3740,7 +3745,7 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
 }
 
 /* push sw hps and wake state through hardware */
-static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
+void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
 {
 	u32 v1, v2;
 	bool hps;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h
index fb44774..35a93ef 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -638,6 +638,7 @@ extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
 					  u32 bcn_rate);
 extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
 				     u8 antsel_type);
+extern void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc);
 extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw,
 				  u16 chanspec,
 				  bool mute, struct txpwr_limits *txpwr);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 0/4] Add support for off-channel powersave state in mac80211
  2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
                   ` (3 preceding siblings ...)
  2013-02-06 21:01 ` [PATCH 4/4] brcmsmac: Add support for off-channel powersave Seth Forshee
@ 2013-02-06 21:32 ` Johannes Berg
  2013-02-07 18:15   ` Seth Forshee
  4 siblings, 1 reply; 29+ messages in thread
From: Johannes Berg @ 2013-02-06 21:32 UTC (permalink / raw)
  To: Seth Forshee
  Cc: linux-wireless, Arend van Spriel, John W. Linville, brcm80211-dev-list

On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> Hi Johannes,
> 
> As promised, here are the patches which add the off-channel powesave
> state. At a high level, the changes are:
> 
>  * Expand the PS configuration flag to be 2 bits and add helper
>    functions for reading and setting the modes
>  * Change the terminology around PS states, i.e. disabled -> awake and
>    enabled -> doze
>  * Add the off-channel PS state and put it to use
>  * Minor driver updates based on these changes
>  * Update brcmsmac to utilize the off-channel PS state

That's a lot of driver changes ... :)

I've been trying to disentangle the mess a bit. It looks like I was
completely wrong about wl1251, it has HW scan so we don't care about its
weird PS behaviour (1).

That leaves us with a few different drivers:
 * iwlegacy -- has PS support but not NULLFUNC_STACK, so generates a
   wakeup to the AP when we want to go scan ...
 * drivers like iwlwifi/wl12xx have HW scan and don't set NULLFUNC_STACK
 * drivers like ath5k/9k/... have all SW but set NULLFUNC_STACK
 * drivers that just don't have powersave

So I guess iwlegacy is kinda the weird case and not wl1251 ... Oh well.

So for those that have HW scan we just don't have to worry about all of
this, since they never run the scan code :-)

Ok now I forgot where I was going with this ... oops. I'll look at the
code and patches some more.

johannes

(1) let's leave aside remain-on-channel for now, I think we should
probably go and require that drivers set a "I support this" flag, since
it is otherwise almost certain to not work ... it also only matters for
P2P and 11u, so no big deal for old drivers



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 0/4] Add support for off-channel powersave state in mac80211
  2013-02-06 21:32 ` [PATCH 0/4] Add support for off-channel powersave state in mac80211 Johannes Berg
@ 2013-02-07 18:15   ` Seth Forshee
  2013-02-07 20:01     ` Arend van Spriel
  0 siblings, 1 reply; 29+ messages in thread
From: Seth Forshee @ 2013-02-07 18:15 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Arend van Spriel, John W. Linville, brcm80211-dev-list

On Wed, Feb 06, 2013 at 10:32:02PM +0100, Johannes Berg wrote:
> On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> > Hi Johannes,
> > 
> > As promised, here are the patches which add the off-channel powesave
> > state. At a high level, the changes are:
> > 
> >  * Expand the PS configuration flag to be 2 bits and add helper
> >    functions for reading and setting the modes
> >  * Change the terminology around PS states, i.e. disabled -> awake and
> >    enabled -> doze
> >  * Add the off-channel PS state and put it to use
> >  * Minor driver updates based on these changes
> >  * Update brcmsmac to utilize the off-channel PS state

Hmm, I guess I should have mentioned that these patches were written on
top of the version 2 patches I sent for adding the off-channel queue
stop reason, etc. I'll need to resend them before they're likely to
apply cleanly anywhere.

> That's a lot of driver changes ... :)

A large number of those changes were made by sed ;-)

> I've been trying to disentangle the mess a bit. It looks like I was
> completely wrong about wl1251, it has HW scan so we don't care about its
> weird PS behaviour (1).
> 
> That leaves us with a few different drivers:
>  * iwlegacy -- has PS support but not NULLFUNC_STACK, so generates a
>    wakeup to the AP when we want to go scan ...
>  * drivers like iwlwifi/wl12xx have HW scan and don't set NULLFUNC_STACK
>  * drivers like ath5k/9k/... have all SW but set NULLFUNC_STACK
>  * drivers that just don't have powersave

I tried to ensure that the patches would result in equivalent behavior
for all drivers except brcmsmac (which will behave better). But I
obviously wan't able to test every driver to verify this.

I suspect b43 should also be updated similarly to brcmsmac. The only
hardware I have that uses b43 is a macbook whose wireless functions too
poorly to be a good test case.

Seth


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 0/4] Add support for off-channel powersave state in mac80211
  2013-02-07 18:15   ` Seth Forshee
@ 2013-02-07 20:01     ` Arend van Spriel
  2013-02-07 20:10       ` Seth Forshee
  0 siblings, 1 reply; 29+ messages in thread
From: Arend van Spriel @ 2013-02-07 20:01 UTC (permalink / raw)
  To: Seth Forshee
  Cc: Johannes Berg, linux-wireless, John W. Linville, brcm80211-dev-list

On 02/07/2013 07:15 PM, Seth Forshee wrote:
> On Wed, Feb 06, 2013 at 10:32:02PM +0100, Johannes Berg wrote:
>> On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
>>> Hi Johannes,
>>>
>>> As promised, here are the patches which add the off-channel powesave
>>> state. At a high level, the changes are:
>>>
>>>  * Expand the PS configuration flag to be 2 bits and add helper
>>>    functions for reading and setting the modes
>>>  * Change the terminology around PS states, i.e. disabled -> awake and
>>>    enabled -> doze
>>>  * Add the off-channel PS state and put it to use
>>>  * Minor driver updates based on these changes
>>>  * Update brcmsmac to utilize the off-channel PS state
> 
> Hmm, I guess I should have mentioned that these patches were written on
> top of the version 2 patches I sent for adding the off-channel queue
> stop reason, etc. I'll need to resend them before they're likely to
> apply cleanly anywhere.
> 
>> That's a lot of driver changes ... :)
> 
> A large number of those changes were made by sed ;-)
> 
>> I've been trying to disentangle the mess a bit. It looks like I was
>> completely wrong about wl1251, it has HW scan so we don't care about its
>> weird PS behaviour (1).
>>
>> That leaves us with a few different drivers:
>>  * iwlegacy -- has PS support but not NULLFUNC_STACK, so generates a
>>    wakeup to the AP when we want to go scan ...
>>  * drivers like iwlwifi/wl12xx have HW scan and don't set NULLFUNC_STACK
>>  * drivers like ath5k/9k/... have all SW but set NULLFUNC_STACK
>>  * drivers that just don't have powersave
> 
> I tried to ensure that the patches would result in equivalent behavior
> for all drivers except brcmsmac (which will behave better). But I
> obviously wan't able to test every driver to verify this.
> 
> I suspect b43 should also be updated similarly to brcmsmac. The only
> hardware I have that uses b43 is a macbook whose wireless functions too
> poorly to be a good test case.

If I recall correctly b43 has a Kconfig option to allow it to support
the same devices brcmsmac supports.

Gr. AvS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 0/4] Add support for off-channel powersave state in mac80211
  2013-02-07 20:01     ` Arend van Spriel
@ 2013-02-07 20:10       ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-07 20:10 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Johannes Berg, linux-wireless, John W. Linville, brcm80211-dev-list

On Thu, Feb 07, 2013 at 09:01:21PM +0100, Arend van Spriel wrote:
> On 02/07/2013 07:15 PM, Seth Forshee wrote:
> > On Wed, Feb 06, 2013 at 10:32:02PM +0100, Johannes Berg wrote:
> >> On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> >>> Hi Johannes,
> >>>
> >>> As promised, here are the patches which add the off-channel powesave
> >>> state. At a high level, the changes are:
> >>>
> >>>  * Expand the PS configuration flag to be 2 bits and add helper
> >>>    functions for reading and setting the modes
> >>>  * Change the terminology around PS states, i.e. disabled -> awake and
> >>>    enabled -> doze
> >>>  * Add the off-channel PS state and put it to use
> >>>  * Minor driver updates based on these changes
> >>>  * Update brcmsmac to utilize the off-channel PS state
> > 
> > Hmm, I guess I should have mentioned that these patches were written on
> > top of the version 2 patches I sent for adding the off-channel queue
> > stop reason, etc. I'll need to resend them before they're likely to
> > apply cleanly anywhere.
> > 
> >> That's a lot of driver changes ... :)
> > 
> > A large number of those changes were made by sed ;-)
> > 
> >> I've been trying to disentangle the mess a bit. It looks like I was
> >> completely wrong about wl1251, it has HW scan so we don't care about its
> >> weird PS behaviour (1).
> >>
> >> That leaves us with a few different drivers:
> >>  * iwlegacy -- has PS support but not NULLFUNC_STACK, so generates a
> >>    wakeup to the AP when we want to go scan ...
> >>  * drivers like iwlwifi/wl12xx have HW scan and don't set NULLFUNC_STACK
> >>  * drivers like ath5k/9k/... have all SW but set NULLFUNC_STACK
> >>  * drivers that just don't have powersave
> > 
> > I tried to ensure that the patches would result in equivalent behavior
> > for all drivers except brcmsmac (which will behave better). But I
> > obviously wan't able to test every driver to verify this.
> > 
> > I suspect b43 should also be updated similarly to brcmsmac. The only
> > hardware I have that uses b43 is a macbook whose wireless functions too
> > poorly to be a good test case.
> 
> If I recall correctly b43 has a Kconfig option to allow it to support
> the same devices brcmsmac supports.

You're right; I forgot about that. It looks like that will make it at
least claim to support my BCM43224. I'll have to give that a try.

Thanks for the suggestion.

Seth


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-06 21:01   ` [ath9k-devel] " Seth Forshee
@ 2013-02-13 15:06     ` Johannes Berg
  -1 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-13 15:06 UTC (permalink / raw)
  To: Seth Forshee
  Cc: linux-wireless, Arend van Spriel, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> The powersave configuration in struct ieee80211_conf is currently a
> binary state, either enabled or disabled. This is inadequate for
> expressing the situation during off-channel operation, when powersave is
> set at the AP to request bufferring of frames but the hardware remains
> fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
> to support this in-between state but lack the information to do so.
> 
> To prepare for adding an off-channel powersave mode, expand the current
> powersave configuration flag to two bits to support expressing another
> state. Add helper functions for setting and retrieving the state, and
> convert mac80211 and drivers to use these functions.
> 
> In changing from a binary flag to powersave mode, also update the
> terminology used to name the states for clarity. The "enabled" state is
> changed to "doze" to indicate a low power hardware state, and the
> "disabled" state is changed to "awake" to indicate a fully powerd on
> hardware state. This is consistent with the terminology defined in IEEE
> 802.11-2012 section 10.2.1.2.

Ok so I'm reviewing this again.

I'm not really convinced this is the right thing to do. Sooner or later,
multi-virtual interface support will become more relevant, and then all
of this is completely moot because then powersave is entirely disabled
and not handled right now.

Is all this really worth it? It seems a quick fix for brcmsmac might be
to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
enabled in the config, and then go implement a real solution like I
described earlier with powersave being separated out of the core
mac80211 routines, and actually made possible for multiple interfaces?

johannes


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 15:06     ` Johannes Berg
  0 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-13 15:06 UTC (permalink / raw)
  To: ath9k-devel

On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> The powersave configuration in struct ieee80211_conf is currently a
> binary state, either enabled or disabled. This is inadequate for
> expressing the situation during off-channel operation, when powersave is
> set at the AP to request bufferring of frames but the hardware remains
> fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
> to support this in-between state but lack the information to do so.
> 
> To prepare for adding an off-channel powersave mode, expand the current
> powersave configuration flag to two bits to support expressing another
> state. Add helper functions for setting and retrieving the state, and
> convert mac80211 and drivers to use these functions.
> 
> In changing from a binary flag to powersave mode, also update the
> terminology used to name the states for clarity. The "enabled" state is
> changed to "doze" to indicate a low power hardware state, and the
> "disabled" state is changed to "awake" to indicate a fully powerd on
> hardware state. This is consistent with the terminology defined in IEEE
> 802.11-2012 section 10.2.1.2.

Ok so I'm reviewing this again.

I'm not really convinced this is the right thing to do. Sooner or later,
multi-virtual interface support will become more relevant, and then all
of this is completely moot because then powersave is entirely disabled
and not handled right now.

Is all this really worth it? It seems a quick fix for brcmsmac might be
to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
enabled in the config, and then go implement a real solution like I
described earlier with powersave being separated out of the core
mac80211 routines, and actually made possible for multiple interfaces?

johannes

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 15:06     ` [ath9k-devel] " Johannes Berg
@ 2013-02-13 17:04       ` Seth Forshee
  -1 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 17:04 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Arend van Spriel, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, Feb 13, 2013 at 04:06:10PM +0100, Johannes Berg wrote:
> On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> > The powersave configuration in struct ieee80211_conf is currently a
> > binary state, either enabled or disabled. This is inadequate for
> > expressing the situation during off-channel operation, when powersave is
> > set at the AP to request bufferring of frames but the hardware remains
> > fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
> > to support this in-between state but lack the information to do so.
> > 
> > To prepare for adding an off-channel powersave mode, expand the current
> > powersave configuration flag to two bits to support expressing another
> > state. Add helper functions for setting and retrieving the state, and
> > convert mac80211 and drivers to use these functions.
> > 
> > In changing from a binary flag to powersave mode, also update the
> > terminology used to name the states for clarity. The "enabled" state is
> > changed to "doze" to indicate a low power hardware state, and the
> > "disabled" state is changed to "awake" to indicate a fully powerd on
> > hardware state. This is consistent with the terminology defined in IEEE
> > 802.11-2012 section 10.2.1.2.
> 
> Ok so I'm reviewing this again.
> 
> I'm not really convinced this is the right thing to do. Sooner or later,
> multi-virtual interface support will become more relevant, and then all
> of this is completely moot because then powersave is entirely disabled
> and not handled right now.

Hmm, I don't recall you really going into any detail regarding
powersave, only managing the queues for off-channel. Though I can see
that multi-vif throws a wrench into things, even if I don't understand
all the details.

> Is all this really worth it? It seems a quick fix for brcmsmac might be
> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> enabled in the config, and then go implement a real solution like I
> described earlier with powersave being separated out of the core
> mac80211 routines, and actually made possible for multiple interfaces?

Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
PS is sent the flag won't be set, as we're still on the operating
channel. When we're actually off-channel the value of PM doesn't matter
for the types of frames which are being sent. The only quick fix I've
found is to watch out for frames with PM set and set the powersave bit
while they're being transmitted.

I'm going to have to spend some time trying to grok how powersave would
work out with multiple interfaces. Honestly though I don't know that
multiple interfaces is something that we have any interest in at the
moment, and if not then it may be difficult for me to justify spending
much time on it.

Seth


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 17:04       ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 17:04 UTC (permalink / raw)
  To: ath9k-devel

On Wed, Feb 13, 2013 at 04:06:10PM +0100, Johannes Berg wrote:
> On Wed, 2013-02-06 at 15:01 -0600, Seth Forshee wrote:
> > The powersave configuration in struct ieee80211_conf is currently a
> > binary state, either enabled or disabled. This is inadequate for
> > expressing the situation during off-channel operation, when powersave is
> > set at the AP to request bufferring of frames but the hardware remains
> > fully awake. Some drivers (e.g. brcmsmac) need to perform configuration
> > to support this in-between state but lack the information to do so.
> > 
> > To prepare for adding an off-channel powersave mode, expand the current
> > powersave configuration flag to two bits to support expressing another
> > state. Add helper functions for setting and retrieving the state, and
> > convert mac80211 and drivers to use these functions.
> > 
> > In changing from a binary flag to powersave mode, also update the
> > terminology used to name the states for clarity. The "enabled" state is
> > changed to "doze" to indicate a low power hardware state, and the
> > "disabled" state is changed to "awake" to indicate a fully powerd on
> > hardware state. This is consistent with the terminology defined in IEEE
> > 802.11-2012 section 10.2.1.2.
> 
> Ok so I'm reviewing this again.
> 
> I'm not really convinced this is the right thing to do. Sooner or later,
> multi-virtual interface support will become more relevant, and then all
> of this is completely moot because then powersave is entirely disabled
> and not handled right now.

Hmm, I don't recall you really going into any detail regarding
powersave, only managing the queues for off-channel. Though I can see
that multi-vif throws a wrench into things, even if I don't understand
all the details.

> Is all this really worth it? It seems a quick fix for brcmsmac might be
> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> enabled in the config, and then go implement a real solution like I
> described earlier with powersave being separated out of the core
> mac80211 routines, and actually made possible for multiple interfaces?

Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
PS is sent the flag won't be set, as we're still on the operating
channel. When we're actually off-channel the value of PM doesn't matter
for the types of frames which are being sent. The only quick fix I've
found is to watch out for frames with PM set and set the powersave bit
while they're being transmitted.

I'm going to have to spend some time trying to grok how powersave would
work out with multiple interfaces. Honestly though I don't know that
multiple interfaces is something that we have any interest in at the
moment, and if not then it may be difficult for me to justify spending
much time on it.

Seth

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 17:04       ` [ath9k-devel] " Seth Forshee
@ 2013-02-13 18:54         ` Arend van Spriel
  -1 siblings, 0 replies; 29+ messages in thread
From: Arend van Spriel @ 2013-02-13 18:54 UTC (permalink / raw)
  To: Seth Forshee
  Cc: Johannes Berg, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On 02/13/2013 06:04 PM, Seth Forshee wrote:
>> Is all this really worth it? It seems a quick fix for brcmsmac might be
>> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
>> > enabled in the config, and then go implement a real solution like I
>> > described earlier with powersave being separated out of the core
>> > mac80211 routines, and actually made possible for multiple interfaces?
> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> PS is sent the flag won't be set, as we're still on the operating
> channel. When we're actually off-channel the value of PM doesn't matter
> for the types of frames which are being sent. The only quick fix I've
> found is to watch out for frames with PM set and set the powersave bit
> while they're being transmitted.

I actually don't see that one fly. The frames are posted on a DMA fifo
towards the hardware so in the driver we have no clue when that frame is
being processes/transmitted hence no way of knowing when to write the
register(s).

Gr. AvS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 18:54         ` Arend van Spriel
  0 siblings, 0 replies; 29+ messages in thread
From: Arend van Spriel @ 2013-02-13 18:54 UTC (permalink / raw)
  To: ath9k-devel

On 02/13/2013 06:04 PM, Seth Forshee wrote:
>> Is all this really worth it? It seems a quick fix for brcmsmac might be
>> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
>> > enabled in the config, and then go implement a real solution like I
>> > described earlier with powersave being separated out of the core
>> > mac80211 routines, and actually made possible for multiple interfaces?
> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> PS is sent the flag won't be set, as we're still on the operating
> channel. When we're actually off-channel the value of PM doesn't matter
> for the types of frames which are being sent. The only quick fix I've
> found is to watch out for frames with PM set and set the powersave bit
> while they're being transmitted.

I actually don't see that one fly. The frames are posted on a DMA fifo
towards the hardware so in the driver we have no clue when that frame is
being processes/transmitted hence no way of knowing when to write the
register(s).

Gr. AvS

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 18:54         ` [ath9k-devel] " Arend van Spriel
@ 2013-02-13 19:09           ` Johannes Berg
  -1 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-13 19:09 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Seth Forshee, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, 2013-02-13 at 19:54 +0100, Arend van Spriel wrote:
> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >> > enabled in the config, and then go implement a real solution like I
> >> > described earlier with powersave being separated out of the core
> >> > mac80211 routines, and actually made possible for multiple interfaces?
> > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > PS is sent the flag won't be set, as we're still on the operating
> > channel. When we're actually off-channel the value of PM doesn't matter
> > for the types of frames which are being sent. The only quick fix I've
> > found is to watch out for frames with PM set and set the powersave bit
> > while they're being transmitted.
> 
> I actually don't see that one fly. The frames are posted on a DMA fifo
> towards the hardware so in the driver we have no clue when that frame is
> being processes/transmitted hence no way of knowing when to write the
> register(s).

I think the various flushing would prevent issues there, no?

johannes


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 19:09           ` Johannes Berg
  0 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-13 19:09 UTC (permalink / raw)
  To: ath9k-devel

On Wed, 2013-02-13 at 19:54 +0100, Arend van Spriel wrote:
> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >> > enabled in the config, and then go implement a real solution like I
> >> > described earlier with powersave being separated out of the core
> >> > mac80211 routines, and actually made possible for multiple interfaces?
> > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > PS is sent the flag won't be set, as we're still on the operating
> > channel. When we're actually off-channel the value of PM doesn't matter
> > for the types of frames which are being sent. The only quick fix I've
> > found is to watch out for frames with PM set and set the powersave bit
> > while they're being transmitted.
> 
> I actually don't see that one fly. The frames are posted on a DMA fifo
> towards the hardware so in the driver we have no clue when that frame is
> being processes/transmitted hence no way of knowing when to write the
> register(s).

I think the various flushing would prevent issues there, no?

johannes

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 18:54         ` [ath9k-devel] " Arend van Spriel
@ 2013-02-13 19:25           ` Seth Forshee
  -1 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 19:25 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Johannes Berg, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >> > enabled in the config, and then go implement a real solution like I
> >> > described earlier with powersave being separated out of the core
> >> > mac80211 routines, and actually made possible for multiple interfaces?
> > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > PS is sent the flag won't be set, as we're still on the operating
> > channel. When we're actually off-channel the value of PM doesn't matter
> > for the types of frames which are being sent. The only quick fix I've
> > found is to watch out for frames with PM set and set the powersave bit
> > while they're being transmitted.
> 
> I actually don't see that one fly. The frames are posted on a DMA fifo
> towards the hardware so in the driver we have no clue when that frame is
> being processes/transmitted hence no way of knowing when to write the
> register(s).

There's a couple of ways of doing it. I had a working patch at one point
but can't seem to find it now, so I'm not sure which way I used. You're
right though that we can't tell when the hardware is actually processing
or transmitting the frame, so in either case MCTL_HPS has to be set
before you put the frame in the tx fifo.

The first option is that for any frame with PM set, set MCTL_HPS when
mac80211 hands off the frame and clear it once it has finished
transmitting.

The second option is to look specifically for nullfunc frames and set or
clear MCTL_HPS based on the value of PM.

Either of these should work fine with the current mac80211 code, but
overall the second one is probably a little safer.

Seth


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 19:25           ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 19:25 UTC (permalink / raw)
  To: ath9k-devel

On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >> > enabled in the config, and then go implement a real solution like I
> >> > described earlier with powersave being separated out of the core
> >> > mac80211 routines, and actually made possible for multiple interfaces?
> > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > PS is sent the flag won't be set, as we're still on the operating
> > channel. When we're actually off-channel the value of PM doesn't matter
> > for the types of frames which are being sent. The only quick fix I've
> > found is to watch out for frames with PM set and set the powersave bit
> > while they're being transmitted.
> 
> I actually don't see that one fly. The frames are posted on a DMA fifo
> towards the hardware so in the driver we have no clue when that frame is
> being processes/transmitted hence no way of knowing when to write the
> register(s).

There's a couple of ways of doing it. I had a working patch at one point
but can't seem to find it now, so I'm not sure which way I used. You're
right though that we can't tell when the hardware is actually processing
or transmitting the frame, so in either case MCTL_HPS has to be set
before you put the frame in the tx fifo.

The first option is that for any frame with PM set, set MCTL_HPS when
mac80211 hands off the frame and clear it once it has finished
transmitting.

The second option is to look specifically for nullfunc frames and set or
clear MCTL_HPS based on the value of PM.

Either of these should work fine with the current mac80211 code, but
overall the second one is probably a little safer.

Seth

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 19:25           ` [ath9k-devel] " Seth Forshee
@ 2013-02-13 21:36             ` Seth Forshee
  -1 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 21:36 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Johannes Berg, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, Feb 13, 2013 at 01:25:19PM -0600, Seth Forshee wrote:
> On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> > On 02/13/2013 06:04 PM, Seth Forshee wrote:
> > >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> > >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> > >> > enabled in the config, and then go implement a real solution like I
> > >> > described earlier with powersave being separated out of the core
> > >> > mac80211 routines, and actually made possible for multiple interfaces?
> > > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > > PS is sent the flag won't be set, as we're still on the operating
> > > channel. When we're actually off-channel the value of PM doesn't matter
> > > for the types of frames which are being sent. The only quick fix I've
> > > found is to watch out for frames with PM set and set the powersave bit
> > > while they're being transmitted.
> > 
> > I actually don't see that one fly. The frames are posted on a DMA fifo
> > towards the hardware so in the driver we have no clue when that frame is
> > being processes/transmitted hence no way of knowing when to write the
> > register(s).
> 
> There's a couple of ways of doing it. I had a working patch at one point
> but can't seem to find it now, so I'm not sure which way I used. You're
> right though that we can't tell when the hardware is actually processing
> or transmitting the frame, so in either case MCTL_HPS has to be set
> before you put the frame in the tx fifo.
> 
> The first option is that for any frame with PM set, set MCTL_HPS when
> mac80211 hands off the frame and clear it once it has finished
> transmitting.
> 
> The second option is to look specifically for nullfunc frames and set or
> clear MCTL_HPS based on the value of PM.
> 
> Either of these should work fine with the current mac80211 code, but
> overall the second one is probably a little safer.

Aha, found the patch. It looks like it's the first option. I've pasted
it below. The changes look rather larger than they are in reality due to
shuffling some code around.


diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 8d560b6..d1c6db6 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -825,6 +825,72 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
 	return macintmask;
 }
 
+static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
+{
+	/* delay before first read of ucode state */
+	udelay(40);
+
+	/* wait until ucode is no longer asleep */
+	SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
+		  DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
+}
+
+/*
+ * conditions under which the PM bit should be set in outgoing frames
+ * and STAY_AWAKE is meaningful
+ */
+static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+{
+	struct brcms_bss_cfg *cfg = wlc->bsscfg;
+
+	/* disallow PS when one of the following global conditions meets */
+	if (!wlc->pub->associated)
+		return false;
+
+	/* disallow PS when one of these meets when not scanning */
+	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
+		return false;
+
+	if (cfg->associated) {
+		/*
+		 * disallow PS when one of the following
+		 * bsscfg specific conditions meets
+		 */
+		if (!cfg->BSS)
+			return false;
+
+		return false;
+	}
+
+	return true;
+}
+
+/* push sw hps and wake state through hardware */
+static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc, bool force_hps)
+{
+	u32 v1, v2;
+	bool hps = true;
+	bool awake_before;
+
+	if (!force_hps)
+		hps = brcms_c_ps_allowed(wlc);
+
+	brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
+			   hps);
+
+	v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+	v2 = MCTL_WAKE;
+	if (hps)
+		v2 |= MCTL_HPS;
+
+	brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
+
+	awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
+
+	if (!awake_before)
+		brcms_b_wait_for_wake(wlc->hw);
+}
+
 /* process an individual struct tx_status */
 static bool
 brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
@@ -983,6 +1049,9 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 
 		if (txs->status & TX_STATUS_ACK_RCV)
 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+		if (h->frame_control & cpu_to_le16(IEEE80211_FCTL_PM))
+			brcms_c_set_ps_ctrl(wlc, false);
 	}
 
 	totlen = p->len;
@@ -1226,16 +1295,6 @@ static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
 	wlc_hw->chanspec = ch20mhz_chspec(1);
 }
 
-static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
-{
-	/* delay before first read of ucode state */
-	udelay(40);
-
-	/* wait until ucode is no longer asleep */
-	SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
-		  DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
-}
-
 /* control chip clock to save power, enable dynamic clock or force fast clock */
 static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
 {
@@ -3039,36 +3098,6 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
 	wlc_hw->antsel_avail = antsel_avail;
 }
 
-/*
- * conditions under which the PM bit should be set in outgoing frames
- * and STAY_AWAKE is meaningful
- */
-static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
-{
-	struct brcms_bss_cfg *cfg = wlc->bsscfg;
-
-	/* disallow PS when one of the following global conditions meets */
-	if (!wlc->pub->associated)
-		return false;
-
-	/* disallow PS when one of these meets when not scanning */
-	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
-		return false;
-
-	if (cfg->associated) {
-		/*
-		 * disallow PS when one of the following
-		 * bsscfg specific conditions meets
-		 */
-		if (!cfg->BSS)
-			return false;
-
-		return false;
-	}
-
-	return true;
-}
-
 static void brcms_c_statsupd(struct brcms_c_info *wlc)
 {
 	int i;
@@ -3739,31 +3768,6 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
 	return 0;
 }
 
-/* push sw hps and wake state through hardware */
-static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
-{
-	u32 v1, v2;
-	bool hps;
-	bool awake_before;
-
-	hps = brcms_c_ps_allowed(wlc);
-
-	brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
-			   hps);
-
-	v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
-	v2 = MCTL_WAKE;
-	if (hps)
-		v2 |= MCTL_HPS;
-
-	brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
-
-	awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
-
-	if (!awake_before)
-		brcms_b_wait_for_wake(wlc->hw);
-}
-
 /*
  * Write this BSS config's MAC address to core.
  * Updates RXE match engine.
@@ -3884,7 +3888,7 @@ static void brcms_c_setband(struct brcms_c_info *wlc,
 		return;
 
 	/* wait for at least one beacon before entering sleeping state */
-	brcms_c_set_ps_ctrl(wlc);
+	brcms_c_set_ps_ctrl(wlc, false);
 
 	/* band-specific initializations */
 	brcms_c_bsinit(wlc);
@@ -6868,6 +6872,7 @@ static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
 	int fifo, ret = -ENOSPC;
 	struct d11txh *txh;
 	u16 frameid = INVALIDFID;
+	struct ieee80211_hdr *hdr;
 
 	fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb));
 	dma = wlc->hw->di[fifo];
@@ -6905,6 +6910,14 @@ static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
 		brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
 	}
 
+	/*
+	 * When PM is set in frame_control, force MCTL_HPS to be set so
+	 * that PM isn't cleared by the hardware.
+	 */
+	hdr = (struct ieee80211_hdr *)skb->data;
+	if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_PM))
+		brcms_c_set_ps_ctrl(wlc, true);
+
 	ret = brcms_c_txfifo(wlc, fifo, skb);
 	/*
 	 * The only reason for brcms_c_txfifo to fail is because
@@ -7790,7 +7803,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 			     bi << CFPREP_CBI_SHIFT);
 
 		/* Update maccontrol PM related bits */
-		brcms_c_set_ps_ctrl(wlc);
+		brcms_c_set_ps_ctrl(wlc, false);
 	}
 
 	brcms_c_bandinit_ordered(wlc, chanspec);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 21:36             ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 21:36 UTC (permalink / raw)
  To: ath9k-devel

On Wed, Feb 13, 2013 at 01:25:19PM -0600, Seth Forshee wrote:
> On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> > On 02/13/2013 06:04 PM, Seth Forshee wrote:
> > >> Is all this really worth it? It seems a quick fix for brcmsmac might be
> > >> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> > >> > enabled in the config, and then go implement a real solution like I
> > >> > described earlier with powersave being separated out of the core
> > >> > mac80211 routines, and actually made possible for multiple interfaces?
> > > Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> > > PS is sent the flag won't be set, as we're still on the operating
> > > channel. When we're actually off-channel the value of PM doesn't matter
> > > for the types of frames which are being sent. The only quick fix I've
> > > found is to watch out for frames with PM set and set the powersave bit
> > > while they're being transmitted.
> > 
> > I actually don't see that one fly. The frames are posted on a DMA fifo
> > towards the hardware so in the driver we have no clue when that frame is
> > being processes/transmitted hence no way of knowing when to write the
> > register(s).
> 
> There's a couple of ways of doing it. I had a working patch at one point
> but can't seem to find it now, so I'm not sure which way I used. You're
> right though that we can't tell when the hardware is actually processing
> or transmitting the frame, so in either case MCTL_HPS has to be set
> before you put the frame in the tx fifo.
> 
> The first option is that for any frame with PM set, set MCTL_HPS when
> mac80211 hands off the frame and clear it once it has finished
> transmitting.
> 
> The second option is to look specifically for nullfunc frames and set or
> clear MCTL_HPS based on the value of PM.
> 
> Either of these should work fine with the current mac80211 code, but
> overall the second one is probably a little safer.

Aha, found the patch. It looks like it's the first option. I've pasted
it below. The changes look rather larger than they are in reality due to
shuffling some code around.


diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 8d560b6..d1c6db6 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -825,6 +825,72 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
 	return macintmask;
 }
 
+static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
+{
+	/* delay before first read of ucode state */
+	udelay(40);
+
+	/* wait until ucode is no longer asleep */
+	SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
+		  DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
+}
+
+/*
+ * conditions under which the PM bit should be set in outgoing frames
+ * and STAY_AWAKE is meaningful
+ */
+static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+{
+	struct brcms_bss_cfg *cfg = wlc->bsscfg;
+
+	/* disallow PS when one of the following global conditions meets */
+	if (!wlc->pub->associated)
+		return false;
+
+	/* disallow PS when one of these meets when not scanning */
+	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
+		return false;
+
+	if (cfg->associated) {
+		/*
+		 * disallow PS when one of the following
+		 * bsscfg specific conditions meets
+		 */
+		if (!cfg->BSS)
+			return false;
+
+		return false;
+	}
+
+	return true;
+}
+
+/* push sw hps and wake state through hardware */
+static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc, bool force_hps)
+{
+	u32 v1, v2;
+	bool hps = true;
+	bool awake_before;
+
+	if (!force_hps)
+		hps = brcms_c_ps_allowed(wlc);
+
+	brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
+			   hps);
+
+	v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+	v2 = MCTL_WAKE;
+	if (hps)
+		v2 |= MCTL_HPS;
+
+	brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
+
+	awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
+
+	if (!awake_before)
+		brcms_b_wait_for_wake(wlc->hw);
+}
+
 /* process an individual struct tx_status */
 static bool
 brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
@@ -983,6 +1049,9 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 
 		if (txs->status & TX_STATUS_ACK_RCV)
 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+		if (h->frame_control & cpu_to_le16(IEEE80211_FCTL_PM))
+			brcms_c_set_ps_ctrl(wlc, false);
 	}
 
 	totlen = p->len;
@@ -1226,16 +1295,6 @@ static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
 	wlc_hw->chanspec = ch20mhz_chspec(1);
 }
 
-static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
-{
-	/* delay before first read of ucode state */
-	udelay(40);
-
-	/* wait until ucode is no longer asleep */
-	SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
-		  DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
-}
-
 /* control chip clock to save power, enable dynamic clock or force fast clock */
 static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
 {
@@ -3039,36 +3098,6 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
 	wlc_hw->antsel_avail = antsel_avail;
 }
 
-/*
- * conditions under which the PM bit should be set in outgoing frames
- * and STAY_AWAKE is meaningful
- */
-static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
-{
-	struct brcms_bss_cfg *cfg = wlc->bsscfg;
-
-	/* disallow PS when one of the following global conditions meets */
-	if (!wlc->pub->associated)
-		return false;
-
-	/* disallow PS when one of these meets when not scanning */
-	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
-		return false;
-
-	if (cfg->associated) {
-		/*
-		 * disallow PS when one of the following
-		 * bsscfg specific conditions meets
-		 */
-		if (!cfg->BSS)
-			return false;
-
-		return false;
-	}
-
-	return true;
-}
-
 static void brcms_c_statsupd(struct brcms_c_info *wlc)
 {
 	int i;
@@ -3739,31 +3768,6 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
 	return 0;
 }
 
-/* push sw hps and wake state through hardware */
-static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
-{
-	u32 v1, v2;
-	bool hps;
-	bool awake_before;
-
-	hps = brcms_c_ps_allowed(wlc);
-
-	brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
-			   hps);
-
-	v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
-	v2 = MCTL_WAKE;
-	if (hps)
-		v2 |= MCTL_HPS;
-
-	brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
-
-	awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
-
-	if (!awake_before)
-		brcms_b_wait_for_wake(wlc->hw);
-}
-
 /*
  * Write this BSS config's MAC address to core.
  * Updates RXE match engine.
@@ -3884,7 +3888,7 @@ static void brcms_c_setband(struct brcms_c_info *wlc,
 		return;
 
 	/* wait for at least one beacon before entering sleeping state */
-	brcms_c_set_ps_ctrl(wlc);
+	brcms_c_set_ps_ctrl(wlc, false);
 
 	/* band-specific initializations */
 	brcms_c_bsinit(wlc);
@@ -6868,6 +6872,7 @@ static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
 	int fifo, ret = -ENOSPC;
 	struct d11txh *txh;
 	u16 frameid = INVALIDFID;
+	struct ieee80211_hdr *hdr;
 
 	fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb));
 	dma = wlc->hw->di[fifo];
@@ -6905,6 +6910,14 @@ static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
 		brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
 	}
 
+	/*
+	 * When PM is set in frame_control, force MCTL_HPS to be set so
+	 * that PM isn't cleared by the hardware.
+	 */
+	hdr = (struct ieee80211_hdr *)skb->data;
+	if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_PM))
+		brcms_c_set_ps_ctrl(wlc, true);
+
 	ret = brcms_c_txfifo(wlc, fifo, skb);
 	/*
 	 * The only reason for brcms_c_txfifo to fail is because
@@ -7790,7 +7803,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 			     bi << CFPREP_CBI_SHIFT);
 
 		/* Update maccontrol PM related bits */
-		brcms_c_set_ps_ctrl(wlc);
+		brcms_c_set_ps_ctrl(wlc, false);
 	}
 
 	brcms_c_bandinit_ordered(wlc, chanspec);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 19:25           ` [ath9k-devel] " Seth Forshee
@ 2013-02-13 21:43             ` Arend van Spriel
  -1 siblings, 0 replies; 29+ messages in thread
From: Arend van Spriel @ 2013-02-13 21:43 UTC (permalink / raw)
  To: Seth Forshee
  Cc: Johannes Berg, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On 02/13/2013 08:25 PM, Seth Forshee wrote:
> On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
>> On 02/13/2013 06:04 PM, Seth Forshee wrote:
>>>> Is all this really worth it? It seems a quick fix for brcmsmac might be
>>>>> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
>>>>> enabled in the config, and then go implement a real solution like I
>>>>> described earlier with powersave being separated out of the core
>>>>> mac80211 routines, and actually made possible for multiple interfaces?
>>> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
>>> PS is sent the flag won't be set, as we're still on the operating
>>> channel. When we're actually off-channel the value of PM doesn't matter
>>> for the types of frames which are being sent. The only quick fix I've
>>> found is to watch out for frames with PM set and set the powersave bit
>>> while they're being transmitted.
>>
>> I actually don't see that one fly. The frames are posted on a DMA fifo
>> towards the hardware so in the driver we have no clue when that frame is
>> being processes/transmitted hence no way of knowing when to write the
>> register(s).
> 
> There's a couple of ways of doing it. I had a working patch at one point
> but can't seem to find it now, so I'm not sure which way I used. You're
> right though that we can't tell when the hardware is actually processing
> or transmitting the frame, so in either case MCTL_HPS has to be set
> before you put the frame in the tx fifo.
> 
> The first option is that for any frame with PM set, set MCTL_HPS when
> mac80211 hands off the frame and clear it once it has finished
> transmitting.
> 
> The second option is to look specifically for nullfunc frames and set or
> clear MCTL_HPS based on the value of PM.
> 
> Either of these should work fine with the current mac80211 code, but
> overall the second one is probably a little safer.

So you have verified that the last packet mac80211 sends before going
off-channel is the nullfunc frame with PM bit set. I have seen packets
coming in our driver during the .flush() callback, but never checked
whether the last of those packets is indeed the nullfunc.

Gr. AvS



^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 21:43             ` Arend van Spriel
  0 siblings, 0 replies; 29+ messages in thread
From: Arend van Spriel @ 2013-02-13 21:43 UTC (permalink / raw)
  To: ath9k-devel

On 02/13/2013 08:25 PM, Seth Forshee wrote:
> On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
>> On 02/13/2013 06:04 PM, Seth Forshee wrote:
>>>> Is all this really worth it? It seems a quick fix for brcmsmac might be
>>>>> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
>>>>> enabled in the config, and then go implement a real solution like I
>>>>> described earlier with powersave being separated out of the core
>>>>> mac80211 routines, and actually made possible for multiple interfaces?
>>> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
>>> PS is sent the flag won't be set, as we're still on the operating
>>> channel. When we're actually off-channel the value of PM doesn't matter
>>> for the types of frames which are being sent. The only quick fix I've
>>> found is to watch out for frames with PM set and set the powersave bit
>>> while they're being transmitted.
>>
>> I actually don't see that one fly. The frames are posted on a DMA fifo
>> towards the hardware so in the driver we have no clue when that frame is
>> being processes/transmitted hence no way of knowing when to write the
>> register(s).
> 
> There's a couple of ways of doing it. I had a working patch at one point
> but can't seem to find it now, so I'm not sure which way I used. You're
> right though that we can't tell when the hardware is actually processing
> or transmitting the frame, so in either case MCTL_HPS has to be set
> before you put the frame in the tx fifo.
> 
> The first option is that for any frame with PM set, set MCTL_HPS when
> mac80211 hands off the frame and clear it once it has finished
> transmitting.
> 
> The second option is to look specifically for nullfunc frames and set or
> clear MCTL_HPS based on the value of PM.
> 
> Either of these should work fine with the current mac80211 code, but
> overall the second one is probably a little safer.

So you have verified that the last packet mac80211 sends before going
off-channel is the nullfunc frame with PM bit set. I have seen packets
coming in our driver during the .flush() callback, but never checked
whether the last of those packets is indeed the nullfunc.

Gr. AvS

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 21:43             ` [ath9k-devel] " Arend van Spriel
@ 2013-02-13 22:00               ` Seth Forshee
  -1 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 22:00 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Johannes Berg, linux-wireless, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Intel Linux Wireless, Luciano Coelho, ath9k-devel,
	brcm80211-dev-list, users

On Wed, Feb 13, 2013 at 10:43:14PM +0100, Arend van Spriel wrote:
> On 02/13/2013 08:25 PM, Seth Forshee wrote:
> > On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> >> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >>>> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >>>>> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >>>>> enabled in the config, and then go implement a real solution like I
> >>>>> described earlier with powersave being separated out of the core
> >>>>> mac80211 routines, and actually made possible for multiple interfaces?
> >>> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> >>> PS is sent the flag won't be set, as we're still on the operating
> >>> channel. When we're actually off-channel the value of PM doesn't matter
> >>> for the types of frames which are being sent. The only quick fix I've
> >>> found is to watch out for frames with PM set and set the powersave bit
> >>> while they're being transmitted.
> >>
> >> I actually don't see that one fly. The frames are posted on a DMA fifo
> >> towards the hardware so in the driver we have no clue when that frame is
> >> being processes/transmitted hence no way of knowing when to write the
> >> register(s).
> > 
> > There's a couple of ways of doing it. I had a working patch at one point
> > but can't seem to find it now, so I'm not sure which way I used. You're
> > right though that we can't tell when the hardware is actually processing
> > or transmitting the frame, so in either case MCTL_HPS has to be set
> > before you put the frame in the tx fifo.
> > 
> > The first option is that for any frame with PM set, set MCTL_HPS when
> > mac80211 hands off the frame and clear it once it has finished
> > transmitting.
> > 
> > The second option is to look specifically for nullfunc frames and set or
> > clear MCTL_HPS based on the value of PM.
> > 
> > Either of these should work fine with the current mac80211 code, but
> > overall the second one is probably a little safer.
> 
> So you have verified that the last packet mac80211 sends before going
> off-channel is the nullfunc frame with PM bit set. I have seen packets
> coming in our driver during the .flush() callback, but never checked
> whether the last of those packets is indeed the nullfunc.

The other set of patches I was working on ensures that the last frame
before going off-channel is a nullfunc with PM set. The order of events
is now:

  * stop the mac80211 queues with the offchannel stop reason
  * flush
  * send a nullfunc with PM set
  * flush again

Without the first flush ath9k was often transmitting data frames with PM
clear after the nullfunc. The second flush ensures the nullfunc gets
sent before we go off-channel. Since the mac80211 queues are stopped
during the flushes you shouldn't see any frames coming in (at least not
during these flushes).

I've done numerous wireshark traces with both brcmsmac and ath9k with
these changes, and the nullfunc is the last thing on the air before
going off-channel. Of course things still aren't working quite right
with brcmsmac since the hardware is clearing the PM bit.

Seth


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-13 22:00               ` Seth Forshee
  0 siblings, 0 replies; 29+ messages in thread
From: Seth Forshee @ 2013-02-13 22:00 UTC (permalink / raw)
  To: ath9k-devel

On Wed, Feb 13, 2013 at 10:43:14PM +0100, Arend van Spriel wrote:
> On 02/13/2013 08:25 PM, Seth Forshee wrote:
> > On Wed, Feb 13, 2013 at 07:54:19PM +0100, Arend van Spriel wrote:
> >> On 02/13/2013 06:04 PM, Seth Forshee wrote:
> >>>> Is all this really worth it? It seems a quick fix for brcmsmac might be
> >>>>> to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> >>>>> enabled in the config, and then go implement a real solution like I
> >>>>> described earlier with powersave being separated out of the core
> >>>>> mac80211 routines, and actually made possible for multiple interfaces?
> >>> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> >>> PS is sent the flag won't be set, as we're still on the operating
> >>> channel. When we're actually off-channel the value of PM doesn't matter
> >>> for the types of frames which are being sent. The only quick fix I've
> >>> found is to watch out for frames with PM set and set the powersave bit
> >>> while they're being transmitted.
> >>
> >> I actually don't see that one fly. The frames are posted on a DMA fifo
> >> towards the hardware so in the driver we have no clue when that frame is
> >> being processes/transmitted hence no way of knowing when to write the
> >> register(s).
> > 
> > There's a couple of ways of doing it. I had a working patch at one point
> > but can't seem to find it now, so I'm not sure which way I used. You're
> > right though that we can't tell when the hardware is actually processing
> > or transmitting the frame, so in either case MCTL_HPS has to be set
> > before you put the frame in the tx fifo.
> > 
> > The first option is that for any frame with PM set, set MCTL_HPS when
> > mac80211 hands off the frame and clear it once it has finished
> > transmitting.
> > 
> > The second option is to look specifically for nullfunc frames and set or
> > clear MCTL_HPS based on the value of PM.
> > 
> > Either of these should work fine with the current mac80211 code, but
> > overall the second one is probably a little safer.
> 
> So you have verified that the last packet mac80211 sends before going
> off-channel is the nullfunc frame with PM bit set. I have seen packets
> coming in our driver during the .flush() callback, but never checked
> whether the last of those packets is indeed the nullfunc.

The other set of patches I was working on ensures that the last frame
before going off-channel is a nullfunc with PM set. The order of events
is now:

  * stop the mac80211 queues with the offchannel stop reason
  * flush
  * send a nullfunc with PM set
  * flush again

Without the first flush ath9k was often transmitting data frames with PM
clear after the nullfunc. The second flush ensures the nullfunc gets
sent before we go off-channel. Since the mac80211 queues are stopped
during the flushes you shouldn't see any frames coming in (at least not
during these flushes).

I've done numerous wireshark traces with both brcmsmac and ath9k with
these changes, and the nullfunc is the last thing on the air before
going off-channel. Of course things still aren't working quite right
with brcmsmac since the hardware is clearing the PM bit.

Seth

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
  2013-02-13 17:04       ` [ath9k-devel] " Seth Forshee
@ 2013-02-15 12:20         ` Johannes Berg
  -1 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-15 12:20 UTC (permalink / raw)
  To: Seth Forshee
  Cc: linux-wireless, Arend van Spriel, John W. Linville,
	Luis R. Rodriguez, Jouni Malinen, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian, Christian Lamparter, Ivo van Doorn,
	Gertjan van Wingerde, Helmut Schaa, Larry Finger, Chaoming Li,
	Wey-Yi Guy, Luciano Coelho, ath9k-devel, brcm80211-dev-list,
	users

[-ilw list, it just bothers me about putting emails into quarantine]

> > I'm not really convinced this is the right thing to do. Sooner or later,
> > multi-virtual interface support will become more relevant, and then all
> > of this is completely moot because then powersave is entirely disabled
> > and not handled right now.
> 
> Hmm, I don't recall you really going into any detail regarding
> powersave, only managing the queues for off-channel. Though I can see
> that multi-vif throws a wrench into things, even if I don't understand
> all the details.

Yeah, that must've been another time. I've evidently been kicking around
these ideas in my head for long enough to not be able to tell apart
reality and dream any more ;-)

> > Is all this really worth it? It seems a quick fix for brcmsmac might be
> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> > enabled in the config, and then go implement a real solution like I
> > described earlier with powersave being separated out of the core
> > mac80211 routines, and actually made possible for multiple interfaces?
> 
> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> PS is sent the flag won't be set, as we're still on the operating
> channel. When we're actually off-channel the value of PM doesn't matter
> for the types of frames which are being sent. 

Oh, right.

> The only quick fix I've
> found is to watch out for frames with PM set and set the powersave bit
> while they're being transmitted.

That's ugly.

> I'm going to have to spend some time trying to grok how powersave would
> work out with multiple interfaces. Honestly though I don't know that
> multiple interfaces is something that we have any interest in at the
> moment, and if not then it may be difficult for me to justify spending
> much time on it.

Yeah, I know, nobody really seems to care, but the current code is so
crappy ... do I have to _make_ people care by just removing all
powersave code? Hard to justify too ... :)

johannes


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [ath9k-devel] [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes
@ 2013-02-15 12:20         ` Johannes Berg
  0 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2013-02-15 12:20 UTC (permalink / raw)
  To: ath9k-devel

[-ilw list, it just bothers me about putting emails into quarantine]

> > I'm not really convinced this is the right thing to do. Sooner or later,
> > multi-virtual interface support will become more relevant, and then all
> > of this is completely moot because then powersave is entirely disabled
> > and not handled right now.
> 
> Hmm, I don't recall you really going into any detail regarding
> powersave, only managing the queues for off-channel. Though I can see
> that multi-vif throws a wrench into things, even if I don't understand
> all the details.

Yeah, that must've been another time. I've evidently been kicking around
these ideas in my head for long enough to not be able to tell apart
reality and dream any more ;-)

> > Is all this really worth it? It seems a quick fix for brcmsmac might be
> > to always set the powersave bit when IEEE80211_CONF_OFFCHANNEL is
> > enabled in the config, and then go implement a real solution like I
> > described earlier with powersave being separated out of the core
> > mac80211 routines, and actually made possible for multiple interfaces?
> 
> Using IEEE80211_CONF_OFFCHANNEL won't work. When the nullfunc to enable
> PS is sent the flag won't be set, as we're still on the operating
> channel. When we're actually off-channel the value of PM doesn't matter
> for the types of frames which are being sent. 

Oh, right.

> The only quick fix I've
> found is to watch out for frames with PM set and set the powersave bit
> while they're being transmitted.

That's ugly.

> I'm going to have to spend some time trying to grok how powersave would
> work out with multiple interfaces. Honestly though I don't know that
> multiple interfaces is something that we have any interest in at the
> moment, and if not then it may be difficult for me to justify spending
> much time on it.

Yeah, I know, nobody really seems to care, but the current code is so
crappy ... do I have to _make_ people care by just removing all
powersave code? Hard to justify too ... :)

johannes

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave
  2013-02-06 21:01 ` [ath9k-devel] [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave Seth Forshee
@ 2013-02-15 23:45   ` Hin-Tak Leung
  0 siblings, 0 replies; 29+ messages in thread
From: Hin-Tak Leung @ 2013-02-15 23:45 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless, Seth Forshee
  Cc: John W. Linville, Larry Finger, Herton Ronaldo Krzesinski

--- On Wed, 6/2/13, Seth Forshee <seth.forshee@canonical.com> wrote:

> When the off-channel powersave mode
> is added to mac80211, even drivers
> which do not support a doze powersave state will be informed
> of changes
> in the powersave state. To prepare for this, change the
> hardware
> powersave support flag to IEEE80211_HW_SUPPORTS_PS_DOZE to
> indicate only
> support for the doze state rather than powersave support in
> general.
> Most drivers which do not support the doze state can
> continue to ignore
> powersave state changes.
> 
> It will also become necessary for all drivers to accurately
> set the
> IEEE80211_HW_PS_NULLFUNC_STACK flag. Set this flag for all
> drivers which
> do not support the doze state.
> 
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>

Acked-by: Hin-Tak Leung <htl10@users.sourceforge.net>

The rtl8187 part & some of the revisions of comments in the mac80211 header.

Hin-Tak  

> ---
>  drivers/net/wireless/adm8211.c       
>              | 
>   3 +-
>  drivers/net/wireless/at76c50x-usb.c     
>           |    3 +-
>  drivers/net/wireless/ath/ar5523/ar5523.c   
>        |    3 +-
>  drivers/net/wireless/ath/ath5k/base.c     
>         |    3 +-
>  drivers/net/wireless/ath/ath9k/htc_drv_init.c   
>   |    2 +-
>  drivers/net/wireless/ath/ath9k/init.c     
>         |    2 +-
>  drivers/net/wireless/ath/carl9170/fw.c     
>        |    2 +-
>  drivers/net/wireless/ath/carl9170/main.c   
>        |    2 +-
>  drivers/net/wireless/b43/main.c       
>             |    3
> +-
>  drivers/net/wireless/b43legacy/main.c     
>         |    3 +-
>  .../net/wireless/brcm80211/brcmsmac/mac80211_if.c 
> |    3 +-
>  drivers/net/wireless/iwlegacy/3945-mac.c   
>        |    3 +-
>  drivers/net/wireless/iwlegacy/4965-mac.c   
>        |    2 +-
>  drivers/net/wireless/iwlwifi/dvm/mac80211.c   
>     |    2 +-
>  drivers/net/wireless/iwlwifi/mvm/mac80211.c   
>     |    2 +-
>  drivers/net/wireless/libertas_tf/main.c     
>       |    3 +-
>  drivers/net/wireless/mac80211_hwsim.c     
>         |    3 +-
>  drivers/net/wireless/mwl8k.c       
>            
>    |    3 +-
>  drivers/net/wireless/p54/main.c       
>             |    2
> +-
>  drivers/net/wireless/rt2x00/rt2400pci.c     
>       |    2 +-
>  drivers/net/wireless/rt2x00/rt2500pci.c     
>       |    2 +-
>  drivers/net/wireless/rt2x00/rt2500usb.c     
>       |    2 +-
>  drivers/net/wireless/rt2x00/rt2800lib.c     
>       |    2 +-
>  drivers/net/wireless/rt2x00/rt61pci.c     
>         |    2 +-
>  drivers/net/wireless/rt2x00/rt73usb.c     
>         |    2 +-
>  drivers/net/wireless/rtl818x/rtl8180/dev.c   
>      |    3 +-
>  drivers/net/wireless/rtl818x/rtl8187/dev.c   
>      |    3 +-
>  drivers/net/wireless/rtlwifi/base.c     
>           |    2 +-
>  drivers/net/wireless/ti/wl1251/main.c     
>         |    2 +-
>  drivers/net/wireless/ti/wlcore/main.c     
>         |    2 +-
>  drivers/net/wireless/zd1211rw/zd_mac.c     
>        |    3 +-
>  include/net/mac80211.h         
>                
>    |   61
> +++++++++++---------
>  net/mac80211/cfg.c           
>                
>      |    2 +-
>  net/mac80211/debugfs.c         
>                
>    |    2 +-
>  net/mac80211/mlme.c         
>                
>       |    6 +-
>  net/mac80211/tx.c           
>                
>       |    2 +-
>  36 files changed, 86 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/net/wireless/adm8211.c
> b/drivers/net/wireless/adm8211.c
> index 3d339e0..802b70c 100644
> --- a/drivers/net/wireless/adm8211.c
> +++ b/drivers/net/wireless/adm8211.c
> @@ -1862,7 +1862,8 @@ static int adm8211_probe(struct
> pci_dev *pdev,
>  
>      dev->extra_tx_headroom =
> sizeof(struct adm8211_tx_hdr);
>      /* dev->flags =
> IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
> -    dev->flags =
> IEEE80211_HW_SIGNAL_UNSPEC;
> +    dev->flags =
> IEEE80211_HW_SIGNAL_UNSPEC |
> +       
> IEEE80211_HW_PS_NULLFUNC_STACK;
>      dev->wiphy->interface_modes =
> BIT(NL80211_IFTYPE_STATION);
>  
>      dev->channel_change_time = 1000;
> diff --git a/drivers/net/wireless/at76c50x-usb.c
> b/drivers/net/wireless/at76c50x-usb.c
> index 77fa428..3d79d5b 100644
> --- a/drivers/net/wireless/at76c50x-usb.c
> +++ b/drivers/net/wireless/at76c50x-usb.c
> @@ -2253,7 +2253,8 @@ static int at76_init_new_device(struct
> at76_priv *priv,
>     
> priv->hw->wiphy->interface_modes =
> BIT(NL80211_IFTYPE_STATION);
>     
> priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
> &at76_supported_band;
>      priv->hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
> -           
>   IEEE80211_HW_SIGNAL_UNSPEC;
> +           
>   IEEE80211_HW_SIGNAL_UNSPEC |
> +           
>   IEEE80211_HW_PS_NULLFUNC_STACK;
>      priv->hw->max_signal = 100;
>  
>      SET_IEEE80211_DEV(priv->hw,
> &interface->dev);
> diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c
> b/drivers/net/wireless/ath/ar5523/ar5523.c
> index 7157f7d..6b2b5c1 100644
> --- a/drivers/net/wireless/ath/ar5523/ar5523.c
> +++ b/drivers/net/wireless/ath/ar5523/ar5523.c
> @@ -1684,7 +1684,8 @@ static int ar5523_probe(struct
> usb_interface *intf,
>      ar->vif = NULL;
>      hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
>             
> IEEE80211_HW_SIGNAL_DBM |
> -           
> IEEE80211_HW_HAS_RATE_CONTROL;
> +           
> IEEE80211_HW_HAS_RATE_CONTROL |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>      hw->extra_tx_headroom = sizeof(struct
> ar5523_tx_desc) +
>             
>     sizeof(struct ar5523_chunk);
>      hw->wiphy->interface_modes =
> BIT(NL80211_IFTYPE_STATION);
> diff --git a/drivers/net/wireless/ath/ath5k/base.c
> b/drivers/net/wireless/ath/ath5k/base.c
> index 1d264c0..4122a15 100644
> --- a/drivers/net/wireless/ath/ath5k/base.c
> +++ b/drivers/net/wireless/ath/ath5k/base.c
> @@ -2439,7 +2439,8 @@ ath5k_init_ah(struct ath5k_hw *ah,
> const struct ath_bus_ops *bus_ops)
>             
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>             
> IEEE80211_HW_SIGNAL_DBM |
>             
> IEEE80211_HW_MFP_CAPABLE |
> -           
> IEEE80211_HW_REPORTS_TX_ACK_STATUS;
> +           
> IEEE80211_HW_REPORTS_TX_ACK_STATUS |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      hw->wiphy->interface_modes =
>         
> BIT(NL80211_IFTYPE_AP) |
> diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
> b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
> index e5d7958..847cf6d 100644
> --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
> +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
> @@ -718,7 +718,7 @@ static void ath9k_set_hw_capab(struct
> ath9k_htc_priv *priv,
>         
> IEEE80211_HW_SPECTRUM_MGMT |
>         
> IEEE80211_HW_HAS_RATE_CONTROL |
>         
> IEEE80211_HW_RX_INCLUDES_FCS |
> -       
> IEEE80211_HW_SUPPORTS_PS |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK |
>         
> IEEE80211_HW_REPORTS_TX_ACK_STATUS |
>         
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
> diff --git a/drivers/net/wireless/ath/ath9k/init.c
> b/drivers/net/wireless/ath/ath9k/init.c
> index af932c9..9880af8 100644
> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -743,7 +743,7 @@ void ath9k_set_hw_capab(struct ath_softc
> *sc, struct ieee80211_hw *hw)
>      hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
>         
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>         
> IEEE80211_HW_SIGNAL_DBM |
> -       
> IEEE80211_HW_SUPPORTS_PS |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK |
>         
> IEEE80211_HW_SPECTRUM_MGMT |
>         
> IEEE80211_HW_REPORTS_TX_ACK_STATUS;
> diff --git a/drivers/net/wireless/ath/carl9170/fw.c
> b/drivers/net/wireless/ath/carl9170/fw.c
> index 47d5c2e..bfd6c8e 100644
> --- a/drivers/net/wireless/ath/carl9170/fw.c
> +++ b/drivers/net/wireless/ath/carl9170/fw.c
> @@ -286,7 +286,7 @@ static int carl9170_fw(struct ar9170
> *ar, const __u8 *data, size_t len)
>      }
>  
>      if (SUPP(CARL9170FW_PSM) &&
> SUPP(CARL9170FW_FIXED_5GHZ_PSM))
> -        ar->hw->flags
> |= IEEE80211_HW_SUPPORTS_PS;
> +        ar->hw->flags
> |= IEEE80211_HW_SUPPORTS_PS_DOZE;
>  
>      if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE))
> {
>         
> dev_err(&ar->udev->dev, "firmware does not provide
> "
> diff --git a/drivers/net/wireless/ath/carl9170/main.c
> b/drivers/net/wireless/ath/carl9170/main.c
> index 4af4a66..edab945 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -1852,7 +1852,7 @@ void *carl9170_alloc(size_t
> priv_size)
>      hw->flags |=
> IEEE80211_HW_RX_INCLUDES_FCS |
>           
>    IEEE80211_HW_MFP_CAPABLE |
>           
>    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
> -         
>    IEEE80211_HW_SUPPORTS_PS |
> +         
>    IEEE80211_HW_SUPPORTS_PS_DOZE |
>           
>    IEEE80211_HW_PS_NULLFUNC_STACK |
>           
>    IEEE80211_HW_NEED_DTIM_PERIOD |
>           
>    IEEE80211_HW_SIGNAL_DBM;
> diff --git a/drivers/net/wireless/b43/main.c
> b/drivers/net/wireless/b43/main.c
> index 806e34c..0f4ddc7 100644
> --- a/drivers/net/wireless/b43/main.c
> +++ b/drivers/net/wireless/b43/main.c
> @@ -5352,7 +5352,8 @@ static struct b43_wl
> *b43_wireless_init(struct b43_bus_dev *dev)
>  
>      /* fill hw info */
>      hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
> -           
> IEEE80211_HW_SIGNAL_DBM;
> +           
> IEEE80211_HW_SIGNAL_DBM |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      hw->wiphy->interface_modes =
>         
> BIT(NL80211_IFTYPE_AP) |
> diff --git a/drivers/net/wireless/b43legacy/main.c
> b/drivers/net/wireless/b43legacy/main.c
> index 8c3f70e..3b0b7e8 100644
> --- a/drivers/net/wireless/b43legacy/main.c
> +++ b/drivers/net/wireless/b43legacy/main.c
> @@ -3836,7 +3836,8 @@ static int
> b43legacy_wireless_init(struct ssb_device *dev)
>  
>      /* fill hw info */
>      hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
> -           
> IEEE80211_HW_SIGNAL_DBM;
> +           
> IEEE80211_HW_SIGNAL_DBM |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>      hw->wiphy->interface_modes =
>         
> BIT(NL80211_IFTYPE_AP) |
>         
> BIT(NL80211_IFTYPE_STATION) |
> diff --git
> a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
> b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
> index 5f49326..e36df33 100644
> --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
> +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
> @@ -987,7 +987,8 @@ static int ieee_hw_init(struct
> ieee80211_hw *hw)
>      hw->flags = IEEE80211_HW_SIGNAL_DBM
>          /* |
> IEEE80211_HW_CONNECTION_MONITOR  What is this? */
>          |
> IEEE80211_HW_REPORTS_TX_ACK_STATUS
> -        |
> IEEE80211_HW_AMPDU_AGGREGATION;
> +        |
> IEEE80211_HW_AMPDU_AGGREGATION
> +        |
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      hw->extra_tx_headroom =
> brcms_c_get_header_len();
>      hw->queues = N_TX_QUEUES;
> diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c
> b/drivers/net/wireless/iwlegacy/3945-mac.c
> index 83856d1..b6b2f30 100644
> --- a/drivers/net/wireless/iwlegacy/3945-mac.c
> +++ b/drivers/net/wireless/iwlegacy/3945-mac.c
> @@ -3565,7 +3565,8 @@ il3945_setup_mac(struct il_priv *il)
>  
>      /* Tell mac80211 our characteristics */
>      hw->flags = IEEE80211_HW_SIGNAL_DBM |
> IEEE80211_HW_SPECTRUM_MGMT |
> -           
> IEEE80211_HW_SUPPORTS_PS |
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
> +           
> IEEE80211_HW_SUPPORTS_PS_DOZE |
> +           
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
>  
>      hw->wiphy->interface_modes =
>         
> BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
> diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c
> b/drivers/net/wireless/iwlegacy/4965-mac.c
> index 9741ac1..7b63ace 100644
> --- a/drivers/net/wireless/iwlegacy/4965-mac.c
> +++ b/drivers/net/wireless/iwlegacy/4965-mac.c
> @@ -5734,7 +5734,7 @@ il4965_mac_setup_register(struct
> il_priv *il, u32 max_probe_length)
>      hw->flags =
>          IEEE80211_HW_SIGNAL_DBM |
> IEEE80211_HW_AMPDU_AGGREGATION |
>         
> IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT
> |
> -       
> IEEE80211_HW_REPORTS_TX_ACK_STATUS |
> IEEE80211_HW_SUPPORTS_PS |
> +       
> IEEE80211_HW_REPORTS_TX_ACK_STATUS |
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
>      if (il->cfg->sku & IL_SKU_N)
>          hw->flags |=
> diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
> b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
> index c2f03ec..c235216 100644
> --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
> +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
> @@ -149,7 +149,7 @@ int iwlagn_mac_setup_register(struct
> iwl_priv *priv,
>             
> IEEE80211_HW_SPECTRUM_MGMT |
>             
> IEEE80211_HW_REPORTS_TX_ACK_STATUS |
>             
> IEEE80211_HW_QUEUE_CONTROL |
> -           
> IEEE80211_HW_SUPPORTS_PS |
> +           
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>             
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
>             
> IEEE80211_HW_WANT_MONITOR_VIF |
>             
> IEEE80211_HW_SCAN_WHILE_IDLE;
> diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> index a6b05a0..ac2f788 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> @@ -115,7 +115,7 @@ int iwl_mvm_mac_setup_register(struct
> iwl_mvm *mvm)
>             
> IEEE80211_HW_WANT_MONITOR_VIF |
>             
> IEEE80211_HW_SCAN_WHILE_IDLE |
>             
> IEEE80211_HW_NEED_DTIM_PERIOD |
> -           
> IEEE80211_HW_SUPPORTS_PS |
> +           
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>             
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
>             
> IEEE80211_HW_AMPDU_AGGREGATION;
>  
> diff --git a/drivers/net/wireless/libertas_tf/main.c
> b/drivers/net/wireless/libertas_tf/main.c
> index 7001856..c3e8fc6 100644
> --- a/drivers/net/wireless/libertas_tf/main.c
> +++ b/drivers/net/wireless/libertas_tf/main.c
> @@ -637,7 +637,8 @@ struct lbtf_private *lbtf_add_card(void
> *card, struct device *dmdev)
>      priv->tx_skb = NULL;
>  
>      hw->queues = 1;
> -    hw->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
> +    hw->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>      hw->extra_tx_headroom = sizeof(struct
> txpd);
>      memcpy(priv->channels, lbtf_channels,
> sizeof(lbtf_channels));
>      memcpy(priv->rates, lbtf_rates,
> sizeof(lbtf_rates));
> diff --git a/drivers/net/wireless/mac80211_hwsim.c
> b/drivers/net/wireless/mac80211_hwsim.c
> index 3e4123e..f45c8ef 100644
> --- a/drivers/net/wireless/mac80211_hwsim.c
> +++ b/drivers/net/wireless/mac80211_hwsim.c
> @@ -2239,7 +2239,8 @@ static int __init
> init_mac80211_hwsim(void)
>             
>     IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
>             
>     IEEE80211_HW_AMPDU_AGGREGATION |
>             
>     IEEE80211_HW_WANT_MONITOR_VIF |
> -           
>     IEEE80211_HW_QUEUE_CONTROL;
> +           
>     IEEE80211_HW_QUEUE_CONTROL |
> +           
>     IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>         
> hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
>             
>        
> WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
> diff --git a/drivers/net/wireless/mwl8k.c
> b/drivers/net/wireless/mwl8k.c
> index 2031130..89a0bff 100644
> --- a/drivers/net/wireless/mwl8k.c
> +++ b/drivers/net/wireless/mwl8k.c
> @@ -5864,7 +5864,8 @@ static int
> mwl8k_firmware_load_success(struct mwl8k_priv *priv)
>      hw->queues = MWL8K_TX_WMM_QUEUES;
>  
>      /* Set rssi values to dBm */
> -    hw->flags |= IEEE80211_HW_SIGNAL_DBM
> | IEEE80211_HW_HAS_RATE_CONTROL;
> +    hw->flags |= IEEE80211_HW_SIGNAL_DBM
> | IEEE80211_HW_HAS_RATE_CONTROL |
> +         
>    IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      /*
>       * Ask mac80211 to not to
> trigger PS mode
> diff --git a/drivers/net/wireless/p54/main.c
> b/drivers/net/wireless/p54/main.c
> index aadda99..88b8d09 100644
> --- a/drivers/net/wireless/p54/main.c
> +++ b/drivers/net/wireless/p54/main.c
> @@ -747,7 +747,7 @@ struct ieee80211_hw
> *p54_init_common(size_t priv_data_len)
>     
> skb_queue_head_init(&priv->tx_pending);
>      dev->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
>           
>    IEEE80211_HW_SIGNAL_DBM |
> -         
>    IEEE80211_HW_SUPPORTS_PS |
> +         
>    IEEE80211_HW_SUPPORTS_PS_DOZE |
>           
>    IEEE80211_HW_PS_NULLFUNC_STACK |
>           
>    IEEE80211_HW_MFP_CAPABLE |
>           
>    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c
> b/drivers/net/wireless/rt2x00/rt2400pci.c
> index 203a217..2c501cc 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -1573,7 +1573,7 @@ static int
> rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
>       */
>      rt2x00dev->hw->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>             
>        IEEE80211_HW_SIGNAL_DBM |
> -           
>        IEEE80211_HW_SUPPORTS_PS |
> +           
>    
>    IEEE80211_HW_SUPPORTS_PS_DOZE |
>             
>    
>    IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      SET_IEEE80211_DEV(rt2x00dev->hw,
> rt2x00dev->dev);
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c
> b/drivers/net/wireless/rt2x00/rt2500pci.c
> index e4a7e12..71546a8 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -1866,7 +1866,7 @@ static int
> rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
>       */
>      rt2x00dev->hw->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>             
>        IEEE80211_HW_SIGNAL_DBM |
> -           
>        IEEE80211_HW_SUPPORTS_PS |
> +           
>    
>    IEEE80211_HW_SUPPORTS_PS_DOZE |
>             
>    
>    IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      SET_IEEE80211_DEV(rt2x00dev->hw,
> rt2x00dev->dev);
> diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c
> b/drivers/net/wireless/rt2x00/rt2500usb.c
> index a411f4e..a68593d 100644
> --- a/drivers/net/wireless/rt2x00/rt2500usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2500usb.c
> @@ -1705,7 +1705,7 @@ static int
> rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
>      rt2x00dev->hw->flags =
>         
> IEEE80211_HW_RX_INCLUDES_FCS |
>          IEEE80211_HW_SIGNAL_DBM |
> -        IEEE80211_HW_SUPPORTS_PS
> |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      SET_IEEE80211_DEV(rt2x00dev->hw,
> rt2x00dev->dev);
> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c
> b/drivers/net/wireless/rt2x00/rt2800lib.c
> index acfb0a1..a60756c 100644
> --- a/drivers/net/wireless/rt2x00/rt2800lib.c
> +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
> @@ -5142,7 +5142,7 @@ static int rt2800_probe_hw_mode(struct
> rt2x00_dev *rt2x00dev)
>       */
>      rt2x00dev->hw->flags =
>          IEEE80211_HW_SIGNAL_DBM |
> -        IEEE80211_HW_SUPPORTS_PS
> |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK |
>         
> IEEE80211_HW_AMPDU_AGGREGATION |
>         
> IEEE80211_HW_REPORTS_TX_ACK_STATUS;
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c
> b/drivers/net/wireless/rt2x00/rt61pci.c
> index c9d3e37..ca84cc5 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -2763,7 +2763,7 @@ static int
> rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
>      rt2x00dev->hw->flags =
>         
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>          IEEE80211_HW_SIGNAL_DBM |
> -        IEEE80211_HW_SUPPORTS_PS
> |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      SET_IEEE80211_DEV(rt2x00dev->hw,
> rt2x00dev->dev);
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c
> b/drivers/net/wireless/rt2x00/rt73usb.c
> index 719e781..70aa736 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.c
> +++ b/drivers/net/wireless/rt2x00/rt73usb.c
> @@ -2118,7 +2118,7 @@ static int
> rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
>       */
>      rt2x00dev->hw->flags =
>          IEEE80211_HW_SIGNAL_DBM |
> -        IEEE80211_HW_SUPPORTS_PS
> |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      SET_IEEE80211_DEV(rt2x00dev->hw,
> rt2x00dev->dev);
> diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c
> b/drivers/net/wireless/rtl818x/rtl8180/dev.c
> index 1b3c284..4f7a737 100644
> --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
> +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
> @@ -991,7 +991,8 @@ static int rtl8180_probe(struct pci_dev
> *pdev,
>  
>      dev->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>           
>    IEEE80211_HW_RX_INCLUDES_FCS |
> -         
>    IEEE80211_HW_SIGNAL_UNSPEC;
> +         
>    IEEE80211_HW_SIGNAL_UNSPEC |
> +         
>    IEEE80211_HW_PS_NULLFUNC_STACK;
>      dev->vif_data_size = sizeof(struct
> rtl8180_vif);
>      dev->wiphy->interface_modes =
> BIT(NL80211_IFTYPE_STATION) |
>             
>        
> BIT(NL80211_IFTYPE_ADHOC);
> diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c
> b/drivers/net/wireless/rtl818x/rtl8187/dev.c
> index 4574bd2..4a4e917 100644
> --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
> +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
> @@ -1467,7 +1467,8 @@ static int rtl8187_probe(struct
> usb_interface *intf,
>  
>      dev->flags =
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
>           
>    IEEE80211_HW_SIGNAL_DBM |
> -         
>    IEEE80211_HW_RX_INCLUDES_FCS;
> +         
>    IEEE80211_HW_RX_INCLUDES_FCS |
> +         
>    IEEE80211_HW_PS_NULLFUNC_STACK;
>      /* Initialize rate-control variables */
>      dev->max_rates = 1;
>      dev->max_rate_tries = RETRY_COUNT;
> diff --git a/drivers/net/wireless/rtlwifi/base.c
> b/drivers/net/wireless/rtlwifi/base.c
> index 0f8b051..195424c 100644
> --- a/drivers/net/wireless/rtlwifi/base.c
> +++ b/drivers/net/wireless/rtlwifi/base.c
> @@ -315,7 +315,7 @@ static void _rtl_init_mac80211(struct
> ieee80211_hw *hw)
>  
>      /* swlps or hwlps has been set in diff
> chip in init_sw_vars */
>      if (rtlpriv->psc.swctrl_lps)
> -        hw->flags |=
> IEEE80211_HW_SUPPORTS_PS |
> +        hw->flags |=
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>             
> IEEE80211_HW_PS_NULLFUNC_STACK |
>              /*
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
>             
> 0;
> diff --git a/drivers/net/wireless/ti/wl1251/main.c
> b/drivers/net/wireless/ti/wl1251/main.c
> index 57bea2f..83b0789 100644
> --- a/drivers/net/wireless/ti/wl1251/main.c
> +++ b/drivers/net/wireless/ti/wl1251/main.c
> @@ -1337,7 +1337,7 @@ int wl1251_init_ieee80211(struct
> wl1251 *wl)
>      wl->hw->channel_change_time =
> 10000;
>  
>      wl->hw->flags =
> IEEE80211_HW_SIGNAL_DBM |
> -       
> IEEE80211_HW_SUPPORTS_PS |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_SUPPORTS_UAPSD;
>  
>      wl->hw->wiphy->interface_modes
> = BIT(NL80211_IFTYPE_STATION) |
> diff --git a/drivers/net/wireless/ti/wlcore/main.c
> b/drivers/net/wireless/ti/wlcore/main.c
> index c67005f..9a33877 100644
> --- a/drivers/net/wireless/ti/wlcore/main.c
> +++ b/drivers/net/wireless/ti/wlcore/main.c
> @@ -5630,7 +5630,7 @@ static int
> wl1271_init_ieee80211(struct wl1271 *wl)
>      wl->hw->max_listen_interval =
> wl->conf.conn.max_listen_interval;
>  
>      wl->hw->flags =
> IEEE80211_HW_SIGNAL_DBM |
> -       
> IEEE80211_HW_SUPPORTS_PS |
> +       
> IEEE80211_HW_SUPPORTS_PS_DOZE |
>         
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
>         
> IEEE80211_HW_SUPPORTS_UAPSD |
>         
> IEEE80211_HW_HAS_RATE_CONTROL |
> diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c
> b/drivers/net/wireless/zd1211rw/zd_mac.c
> index 114364b..0c39718 100644
> --- a/drivers/net/wireless/zd1211rw/zd_mac.c
> +++ b/drivers/net/wireless/zd1211rw/zd_mac.c
> @@ -1402,7 +1402,8 @@ struct ieee80211_hw
> *zd_mac_alloc_hw(struct usb_interface *intf)
>      hw->flags =
> IEEE80211_HW_RX_INCLUDES_FCS |
>             
> IEEE80211_HW_SIGNAL_UNSPEC |
>             
> IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
> -           
> IEEE80211_HW_MFP_CAPABLE;
> +           
> IEEE80211_HW_MFP_CAPABLE |
> +           
> IEEE80211_HW_PS_NULLFUNC_STACK;
>  
>      hw->wiphy->interface_modes =
>         
> BIT(NL80211_IFTYPE_MESH_POINT) |
> diff --git a/include/net/mac80211.h
> b/include/net/mac80211.h
> index 024c495..c5ca5ab 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -1307,7 +1307,7 @@ struct ieee80211_tx_control {
>   * @IEEE80211_HW_AMPDU_AGGREGATION:
>   *    Hardware supports 11n A-MPDU
> aggregation.
>   *
> - * @IEEE80211_HW_SUPPORTS_PS:
> + * @IEEE80211_HW_SUPPORTS_PS_DOZE:
>   *    Hardware has power save support
> (i.e. can go to sleep).
>   *
>   * @IEEE80211_HW_PS_NULLFUNC_STACK:
> @@ -1399,7 +1399,7 @@ enum ieee80211_hw_flags {
>     
> IEEE80211_HW_NEED_DTIM_PERIOD   
>         = 1<<7,
>     
> IEEE80211_HW_SPECTRUM_MGMT   
>         = 1<<8,
>     
> IEEE80211_HW_AMPDU_AGGREGATION   
>         = 1<<9,
> -   
> IEEE80211_HW_SUPPORTS_PS   
>         = 1<<10,
> +   
> IEEE80211_HW_SUPPORTS_PS_DOZE   
>         = 1<<10,
>     
> IEEE80211_HW_PS_NULLFUNC_STACK   
>         = 1<<11,
>     
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS   
>     = 1<<12,
>     
> IEEE80211_HW_MFP_CAPABLE   
>         = 1<<13,
> @@ -1655,28 +1655,37 @@ void ieee80211_free_txskb(struct
> ieee80211_hw *hw, struct sk_buff *skb);
>   *
>   * mac80211 has support for various powersave
> implementations.
>   *
> - * First, it can support hardware that handles all
> powersaving by itself,
> - * such hardware should simply set the
> %IEEE80211_HW_SUPPORTS_PS hardware
> - * flag. In that case, it will be told about the desired
> powersave mode
> - * with ieee80211_conf_ps_mode() depending on the
> association status.
> - * The hardware must take care of sending nullfunc frames
> when necessary,
> - * i.e. when entering and leaving powersave mode. The
> hardware is required
> - * to look at the AID in beacons and signal to the AP that
> it woke up when
> - * it finds traffic directed to it.
> - *
> - * The %IEEE80211_PS_DOZE mode means that the powersave
> mode defined in
> - * IEEE 802.11-2007 section 11.2 is enabled. This is not to
> be confused
> - * with hardware wakeup and sleep states. Driver is
> responsible for waking
> - * up the hardware before issuing commands to the hardware
> and putting it
> - * back to sleep at appropriate times.
> - *
> - * When PS is enabled, hardware needs to wakeup for beacons
> and receive the
> - * buffered multicast/broadcast frames after the beacon.
> Also it must be
> - * possible to send frames and receive the acknowledment
> frame.
> + * Drivers are informed about changes to the powersave
> state with the
> + * %IEEE80211_CONF_PS_MASK bits in the configuration flags.
> The current
> + * mode can be read by calling ieee80211_conf_ps_mode().
> Hardware which
> + * does not support a low-power state should leave
> + * %IEEE80211_HW_SUPPORTS_PS_DOZE clear to avoid being
> placed into a low-
> + * power state. %IEEE80211_HW_PS_NULLFUNC_STACK should be
> set if the
> + * hardware requires that mac80211 generate nullfunc frames
> when
> + * transitioning between powersave modes.
> + *
> + * Hardware which supports a low-power "doze" state should
> set the
> + * %IEEE80211_HW_SUPPORTS_PS_DOZE hardware flag. This will
> make it possible
> + * to put the hardware into the %IEEE80211_PS_DOZE mode.
> When in the doze
> + * state the powersave mode defined in IEEE 802.11-2007
> section 11.2 is
> + * enabled. This is not to be confused with hardware wakeup
> and sleep
> + * states. While in the doze state, the driver is
> responsible for waking up
> + * the hardware before issuing commands to the hardware and
> putting it back
> + * to sleep at appropriate times. The hardware needs to
> wakeup for beacons
> + * and receive the buffered multicast/broadcast frames
> after the beacon.
> + * Also it must be possible to send frames and receive the
> acknowledment
> + * frame.
> + *
> + * For hardware that handles all powersaving by itself,
> setting
> + * %IEEE80211_HW_SUPPORTS_PS_DOZE is all that is needed.
> The hardware must
> + * take care of sending nullfunc frames when necessary,
> i.e. when entering
> + * and leaving powersave mode. The hardware is required to
> look at the AID
> + * in beacons and signal to the AP that it woke up when it
> finds traffic
> + * directed to it.
>   *
>   * Other hardware designs cannot send nullfunc frames
> by themselves and also
>   * need software support for parsing the TIM bitmap.
> This is also supported
> - * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS
> and
> + * by mac80211 by combining the
> %IEEE80211_HW_SUPPORTS_PS_DOZE and
>   * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware
> is of course still
>   * required to pass up beacons. The hardware is still
> required to handle
>   * waking up for multicast traffic; if it cannot the
> driver must handle that
> @@ -1690,11 +1699,11 @@ void ieee80211_free_txskb(struct
> ieee80211_hw *hw, struct sk_buff *skb);
>   * periods.
>   *
>   * Dynamic powersave is simply supported by mac80211
> enabling and disabling
> - * PS based on traffic. Driver needs to only set
> %IEEE80211_HW_SUPPORTS_PS
> - * flag and mac80211 will handle everything automatically.
> Additionally,
> - * hardware having support for the dynamic PS feature may
> set the
> - * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that
> it can support
> - * dynamic PS mode itself. The driver needs to look at the
> + * PS based on traffic. Driver needs to only set
> + * %IEEE80211_HW_SUPPORTS_PS_DOZE flag and mac80211 will
> handle everything
> + * automatically. Additionally, hardware having support for
> the dynamic PS
> + * feature may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
> flag to indicate
> + * that it can support dynamic PS mode itself. The driver
> needs to look at the
>   * @dynamic_ps_timeout hardware configuration value
> and use it that value
>   * whenever the mode is %IEEE80211_PS_DOZE. In this
> case mac80211 will disable
>   * dynamic PS feature in stack and will just set
> %IEEE80211_PS_DOZE whenever
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index fd38c37..fac5ef8 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -2265,7 +2265,7 @@ static int
> ieee80211_set_power_mgmt(struct wiphy *wiphy, struct
> net_device *dev,
>          sdata->vif.type !=
> NL80211_IFTYPE_MESH_POINT)
>          return -EOPNOTSUPP;
>  
> -    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS))
> +    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS_DOZE))
>          return -EOPNOTSUPP;
>  
>      if (enabled == sdata->u.mgd.powersave
> &&
> diff --git a/net/mac80211/debugfs.c
> b/net/mac80211/debugfs.c
> index 466f4b4..21ad1f5 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -127,7 +127,7 @@ static ssize_t hwflags_read(struct file
> *file, char __user *user_buf,
>          sf += snprintf(buf +
> sf, mxln - sf, "SPECTRUM_MGMT\n");
>      if (local->hw.flags &
> IEEE80211_HW_AMPDU_AGGREGATION)
>          sf += snprintf(buf +
> sf, mxln - sf, "AMPDU_AGGREGATION\n");
> -    if (local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS)
> +    if (local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS_DOZE)
>          sf += snprintf(buf +
> sf, mxln - sf, "SUPPORTS_PS\n");
>      if (local->hw.flags &
> IEEE80211_HW_PS_NULLFUNC_STACK)
>          sf += snprintf(buf +
> sf, mxln - sf, "PS_NULLFUNC_STACK\n");
> diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
> index 7afcc73..d13d885 100644
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -953,7 +953,7 @@ void ieee80211_enable_dyn_ps(struct
> ieee80211_vif *vif)
>      struct ieee80211_conf *conf =
> &local->hw.conf;
>  
>      WARN_ON(sdata->vif.type !=
> NL80211_IFTYPE_STATION ||
> -        !(local->hw.flags
> & IEEE80211_HW_SUPPORTS_PS) ||
> +        !(local->hw.flags
> & IEEE80211_HW_SUPPORTS_PS_DOZE) ||
>          (local->hw.flags
> & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
>  
>      local->disable_dynamic_ps = false;
> @@ -968,7 +968,7 @@ void ieee80211_disable_dyn_ps(struct
> ieee80211_vif *vif)
>      struct ieee80211_conf *conf =
> &local->hw.conf;
>  
>      WARN_ON(sdata->vif.type !=
> NL80211_IFTYPE_STATION ||
> -        !(local->hw.flags
> & IEEE80211_HW_SUPPORTS_PS) ||
> +        !(local->hw.flags
> & IEEE80211_HW_SUPPORTS_PS_DOZE) ||
>          (local->hw.flags
> & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
>  
>      local->disable_dynamic_ps = true;
> @@ -1058,7 +1058,7 @@ void ieee80211_recalc_ps(struct
> ieee80211_local *local, s32 latency)
>      int count = 0;
>      int timeout;
>  
> -    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS)) {
> +    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS_DOZE)) {
>          local->ps_sdata =
> NULL;
>          return;
>      }
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 2572647..e96994e 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -185,7 +185,7 @@ ieee80211_tx_h_dynamic_ps(struct
> ieee80211_tx_data *tx)
>      struct ieee80211_if_managed *ifmgd;
>  
>      /* driver doesn't support power save */
> -    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS))
> +    if (!(local->hw.flags &
> IEEE80211_HW_SUPPORTS_PS_DOZE))
>          return TX_CONTINUE;
>  
>      /* hardware does dynamic power save */
> -- 
> 1.7.9.5
> 
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2013-02-15 23:45 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-06 21:01 [PATCH 0/4] Add support for off-channel powersave state in mac80211 Seth Forshee
2013-02-06 21:01 ` [PATCH 1/4] mac80211: Convert PS configuration from a binary flag to a set of modes Seth Forshee
2013-02-06 21:01   ` [ath9k-devel] " Seth Forshee
2013-02-13 15:06   ` Johannes Berg
2013-02-13 15:06     ` [ath9k-devel] " Johannes Berg
2013-02-13 17:04     ` Seth Forshee
2013-02-13 17:04       ` [ath9k-devel] " Seth Forshee
2013-02-13 18:54       ` Arend van Spriel
2013-02-13 18:54         ` [ath9k-devel] " Arend van Spriel
2013-02-13 19:09         ` Johannes Berg
2013-02-13 19:09           ` [ath9k-devel] " Johannes Berg
2013-02-13 19:25         ` Seth Forshee
2013-02-13 19:25           ` [ath9k-devel] " Seth Forshee
2013-02-13 21:36           ` Seth Forshee
2013-02-13 21:36             ` [ath9k-devel] " Seth Forshee
2013-02-13 21:43           ` Arend van Spriel
2013-02-13 21:43             ` [ath9k-devel] " Arend van Spriel
2013-02-13 22:00             ` Seth Forshee
2013-02-13 22:00               ` [ath9k-devel] " Seth Forshee
2013-02-15 12:20       ` Johannes Berg
2013-02-15 12:20         ` [ath9k-devel] " Johannes Berg
2013-02-06 21:01 ` [ath9k-devel] [PATCH 2/4] mac80211: Indicate hardware support for doze state rather than powersave Seth Forshee
2013-02-15 23:45   ` Hin-Tak Leung
2013-02-06 21:01 ` [PATCH 3/4] mac80211: Add off-channel PS state Seth Forshee
2013-02-06 21:01 ` [PATCH 4/4] brcmsmac: Add support for off-channel powersave Seth Forshee
2013-02-06 21:32 ` [PATCH 0/4] Add support for off-channel powersave state in mac80211 Johannes Berg
2013-02-07 18:15   ` Seth Forshee
2013-02-07 20:01     ` Arend van Spriel
2013-02-07 20:10       ` Seth Forshee

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.