2009-01-06 17:52:58

by Johannes Berg

[permalink] [raw]
Subject: [RFC] mac80211: extend/document powersave API

This modifies hardware flags for powersave to support three different
flags:
* IEEE80211_HW_SUPPORTS_PS - indicates general PS support
* IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc/... handling in software
* IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device

It also adds documentation for all this which explains how to set the
various flags.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-core.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/rt61pci.c | 4 ++
drivers/net/wireless/rt2x00/rt73usb.c | 4 ++
include/net/mac80211.h | 47 ++++++++++++++++++++++++++++----
net/mac80211/mlme.c | 4 +-
net/mac80211/tx.c | 2 -
net/mac80211/wext.c | 31 +++++++++++++++++++--
10 files changed, 90 insertions(+), 17 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/include/net/mac80211.h 2009-01-06 18:50:45.000000000 +0100
@@ -858,10 +858,15 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_AMPDU_AGGREGATION:
* Hardware supports 11n A-MPDU aggregation.
*
- * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
- * Hardware which has dynamic power save support, meaning
- * that power save is enabled in idle periods, and don't need support
- * from stack.
+ * @IEEE80211_HW_SUPPORTS_PS:
+ * Hardware has power save support (i.e. can go to sleep).
+ *
+ * @IEEE80211_HW_PS_NULLFUNC_STACK:
+ * Hardware requires nullfunc frame handling in stack, implies
+ * stack support for dynamic PS.
+ *
+ * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS:
+ * Hardware has support for dynamic PS.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -874,7 +879,9 @@ enum ieee80211_hw_flags {
IEEE80211_HW_NOISE_DBM = 1<<8,
IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
- IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
+ IEEE80211_HW_SUPPORTS_PS = 1<<11,
+ IEEE80211_HW_PS_NULLFUNC_STACK = 1<<12,
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<13,
};

/**
@@ -1061,6 +1068,36 @@ ieee80211_get_alt_retry_rate(const struc
*/

/**
+ * DOC: Powersave support
+ *
+ * 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 regardless of association status, and the driver or
+ * hardware must take care of enabling/disabling powersave depending on
+ * the association status and TIM bit and send nullfunc frames by itself.
+ *
+ * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
+ * flag to indicate that it can support dynamic PS mode (see below).
+ *
+ * Other hardware designs cannot send nullfunc frames by themselves and
+ * need to be told explicitly about powersave transitions depending on
+ * association status, need software support for parsing the TIM bitmap
+ * and can implement dynamic PS mode in software. This is also supported
+ * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
+ * %IEEE80211_HW_PS_NULLFUNC_STACK flags.
+ *
+ * Dynamic powersave mode is an extension to normal powersave mode in which
+ * the hardware stays awake for a user-specified period of time after sending
+ * a frame so that reply frames need not be buffered and therefore delayed
+ * to the next wakeup. This can either be supported by hardware, in which case
+ * the driver needs to look at the @dynamic_ps_timeout hardware configuration
+ * value, or by the stack if all nullfunc handling is in the stack.
+ */
+
+/**
* DOC: Frame filtering
*
* mac80211 requires to see many management frames for proper
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-06 18:34:21.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-01-06 18:50:59.000000000 +0100
@@ -836,6 +836,9 @@ static int ieee80211_ioctl_siwpower(stru
int ret = 0, timeout = 0;
bool ps;

+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+ return -EOPNOTSUPP;
+
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;

@@ -858,8 +861,17 @@ static int ieee80211_ioctl_siwpower(stru
if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
return -EINVAL;

- if (wrq->flags & IW_POWER_TIMEOUT)
+ if (wrq->flags & IW_POWER_TIMEOUT) {
+ /*
+ * dynamic PS only supported if nullfunc handling in stack
+ * or hardware supports dynamic PS itself
+ */
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
+ !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+ return -EOPNOTSUPP;
+
timeout = wrq->value / 1000;
+ }

set:
if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
@@ -868,10 +880,12 @@ set:
local->powersave = ps;
conf->dynamic_ps_timeout = timeout;

- if (local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) {
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
ret = ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
- } else if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+
+ if ((sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) &&
+ (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
if (conf->dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(conf->dynamic_ps_timeout));
@@ -888,6 +902,17 @@ set:
ieee80211_send_nullfunc(local, sdata, 0);
}
}
+ } else if (!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
+ /*
+ * hardware-based PS has to handle it all in hw/driver,
+ * including turning off PS when not associated.
+ */
+ if (local->powersave)
+ conf->flags |= IEEE80211_CONF_PS;
+ else
+ conf->flags &= ~IEEE80211_CONF_PS;
+
+ ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}

return ret;
--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-01-06 18:39:51.000000000 +0100
@@ -778,7 +778,7 @@ static void ieee80211_set_associated(str
ieee80211_bss_info_change_notify(sdata, bss_info_changed);

if (local->powersave &&
- !(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
+ (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
if (local->hw.conf.dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
@@ -1785,7 +1785,7 @@ static void ieee80211_rx_mgmt_beacon(str
ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
elems.wmm_param_len);

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
directed_tim = check_tim(&elems, ifsta->aid, &is_mc);

if (directed_tim || is_mc) {
--- wireless-testing.orig/net/mac80211/tx.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c 2009-01-06 18:34:23.000000000 +0100
@@ -1298,7 +1298,7 @@ int ieee80211_master_start_xmit(struct s
return 0;
}

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+ if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-06 18:34:23.000000000 +0100
@@ -806,7 +806,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION;
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -1451,7 +1451,9 @@ static int rt2400pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -1752,7 +1752,9 @@ static int rt2500pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = 0;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-06 18:34:23.000000000 +0100
@@ -1803,7 +1803,9 @@ static int rt2500usb_probe_hw_mode(struc
rt2x00dev->hw->flags =
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -2558,7 +2558,9 @@ static int rt61pci_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-06 18:34:23.000000000 +0100
@@ -2079,7 +2079,9 @@ static int rt73usb_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);




2009-01-07 15:50:27

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC v2] mac80211: extend/document powersave API

Johannes Berg <[email protected]> writes:

> This modifies hardware flags for powersave to support three different
> flags:
> * IEEE80211_HW_SUPPORTS_PS - indicates general PS support
> * IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc/... handling in software
> * IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device
>
> It also adds documentation for all this which explains how to set the
> various flags.

Very good, this is just what was needed. I was planning to add similar
flags myself. Few comments though:

> + * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS:
> + * Hardware has support for dynamic PS.

The "dynamic power save" was a very bad term, it seems that people
misunderstand it all the time. Maybe we should rename it to something
else? We can do it later, though.

> + * DOC: Powersave support
> + *
> + * 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 regardless of association status, and the driver or
> + * hardware must take care of enabling/disabling powersave depending on
> + * the association status and TIM bit and send nullfunc frames by
> + itself.

Actually I'm not aware of any hardware designs which enables and
disables power save according to association status (modulo fullmac
design, of course). Even iwlwifi, which I think has the most
sophisticated power save support, requires the host to enable power
save according to the association status. Hence I would like to have
the power save enable/disable logic based on association status in
mac80211.

We already have this support in ieee80211_set_associated()

[Reads the function again]

Or, actually we had it. I think Vivek's patch changed the
functionality. But anyway, it's very easy to add the support back.

The reason why I would like to have this in mac80211 is to avoid
having duplicate bugs in different drivers and make the driver
implementation easier.

> + * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
> + * flag to indicate that it can support dynamic PS mode (see below).
> + *
> + * Other hardware designs cannot send nullfunc frames by themselves and
> + * need to be told explicitly about powersave transitions depending on
> + * association status, need software support for parsing the TIM bitmap
> + * and can implement dynamic PS mode in software. This is also supported
> + * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
> + * %IEEE80211_HW_PS_NULLFUNC_STACK flags.

stlc45xx (and p54spi) wakeup for multicast frames automatically, but
ath5/9k need the host to do it. I think we will need a separate flag
for that, but I can add it later.

> + * Dynamic powersave mode is an extension to normal powersave mode in which
> + * the hardware stays awake for a user-specified period of time after sending
> + * a frame so that reply frames need not be buffered and therefore delayed
> + * to the next wakeup. This can either be supported by hardware, in which case
> + * the driver needs to look at the @dynamic_ps_timeout hardware configuration
> + * value, or by the stack if all nullfunc handling is in the stack.
> + */

Good description of the feature. Hopefully people now better
understand what I meant with dynamic power save.

> @@ -858,8 +861,17 @@ static int ieee80211_ioctl_siwpower(stru
> if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
> return -EINVAL;
>
> - if (wrq->flags & IW_POWER_TIMEOUT)
> + if (wrq->flags & IW_POWER_TIMEOUT) {
> + /*
> + * dynamic PS only supported if nullfunc handling in stack
> + * or hardware supports dynamic PS itself
> + */
> + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
> + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
> + return -EOPNOTSUPP;
> +
> timeout = wrq->value / 1000;
> + }

Actually there are hardware designs which don't have dynamic power
save but have null frame creation in firmware (and hence don't need
IEEE80211_HW_PS_NULLFUNC_STACK). So IEEE80211_HW_SUPPORTS_DYNAMIC_PS
and IEEE80211_HW_PS_NULLFUNC_STACK are not related to each other in
any way. I suspect at76_usb is such design, but I need to recheck
that.

So I would like to implement this so that if
IEEE80211_HW_SUPPORTS_DYNAMIC_PS is not set mac80211 will always use
it's own timer, independent of IEEE80211_HW_PS_NULLFUNC_STACK. If you
agree, I can create a separate patch for this.

--
Kalle Valo

2009-01-07 17:30:38

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v3] mac80211: extend/document powersave API

On Wed, 2009-01-07 at 19:25 +0200, Kalle Valo wrote:

> > -set:
> > + set:
>
> Really? My emacs always indents it without space, should I fix my
> settings?

I like it better for two reasons:
(1) my editor uses a heuristic to display the function you're in, and
the heuristic will display the label if it's in the first column
(2) diff -p does the same, so you'll end up with the label in the @@
row which isn't very useful.

The "right" way never got added to CodingStyle, despite discussions.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2009-01-07 17:25:36

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC v3] mac80211: extend/document powersave API

Johannes Berg <[email protected]> writes:

> This modifies hardware flags for powersave to support three different
> flags:
> * IEEE80211_HW_SUPPORTS_PS - indicates general PS support
> * IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc sending in software
> * IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device
>
> It also adds documentation for all this which explains how to set the
> various flags.
>
> Additionally, it fixes a few things:
> * a spot where && was used to test flags
> * enable CONF_PS only when associated again
>
> Signed-off-by: Johannes Berg <[email protected]>

Looks good to me.

Reviewed-by: Kalle Valo <[email protected]>

> -set:
> + set:

Really? My emacs always indents it without space, should I fix my
settings?

--
Kalle Valo

2009-01-07 17:49:40

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC v3] mac80211: extend/document powersave API

Johannes Berg <[email protected]> writes:

> On Wed, 2009-01-07 at 19:25 +0200, Kalle Valo wrote:
>
>> > -set:
>> > + set:
>>
>> Really? My emacs always indents it without space, should I fix my
>> settings?
>
> I like it better for two reasons:
> (1) my editor uses a heuristic to display the function you're in, and
> the heuristic will display the label if it's in the first column
> (2) diff -p does the same, so you'll end up with the label in the @@
> row which isn't very useful.
>
> The "right" way never got added to CodingStyle, despite discussions.

Ok, I'm now convinced :) I'll fix emacs to indent like this.

--
Kalle Valo

2009-01-07 16:43:26

by Johannes Berg

[permalink] [raw]
Subject: [RFC v3] mac80211: extend/document powersave API

This modifies hardware flags for powersave to support three different
flags:
* IEEE80211_HW_SUPPORTS_PS - indicates general PS support
* IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc sending in software
* IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device

It also adds documentation for all this which explains how to set the
various flags.

Additionally, it fixes a few things:
* a spot where && was used to test flags
* enable CONF_PS only when associated again

Signed-off-by: Johannes Berg <[email protected]>
---
Documentation/DocBook/mac80211.tmpl | 8 +++-
drivers/net/wireless/iwlwifi/iwl-core.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/rt61pci.c | 4 +-
drivers/net/wireless/rt2x00/rt73usb.c | 4 +-
include/net/mac80211.h | 53 ++++++++++++++++++++++++++++----
net/mac80211/mlme.c | 31 +++++++++---------
net/mac80211/tx.c | 2 -
net/mac80211/wext.c | 40 ++++++++++++++----------
11 files changed, 111 insertions(+), 46 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h 2009-01-07 17:03:34.000000000 +0100
+++ wireless-testing/include/net/mac80211.h 2009-01-07 17:34:50.000000000 +0100
@@ -851,10 +851,15 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_AMPDU_AGGREGATION:
* Hardware supports 11n A-MPDU aggregation.
*
- * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
- * Hardware which has dynamic power save support, meaning
- * that power save is enabled in idle periods, and don't need support
- * from stack.
+ * @IEEE80211_HW_SUPPORTS_PS:
+ * Hardware has power save support (i.e. can go to sleep).
+ *
+ * @IEEE80211_HW_PS_NULLFUNC_STACK:
+ * Hardware requires nullfunc frame handling in stack, implies
+ * stack support for dynamic PS.
+ *
+ * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS:
+ * Hardware has support for dynamic PS.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -867,7 +872,9 @@ enum ieee80211_hw_flags {
IEEE80211_HW_NOISE_DBM = 1<<8,
IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
- IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
+ IEEE80211_HW_SUPPORTS_PS = 1<<11,
+ IEEE80211_HW_PS_NULLFUNC_STACK = 1<<12,
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<13,
};

/**
@@ -1054,6 +1061,42 @@ ieee80211_get_alt_retry_rate(const struc
*/

/**
+ * DOC: Powersave support
+ *
+ * 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 depending on the association status, and the driver
+ * must take care of sending nullfunc frames when necessary, i.e. when
+ * entering and leaving powersave mode. The driver 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. This mode supports dynamic PS by simply
+ * enabling/disabling PS.
+ *
+ * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
+ * flag to indicate that it can support dynamic PS mode itself (see below).
+ *
+ * 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
+ * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still
+ * required to pass up beacons. Additionally, in this case, mac80211 will
+ * wake up the hardware when multicast traffic is announced in the beacon.
+ *
+ * FIXME: I don't think we can be fast enough in software when we want to
+ * receive multicast traffic?
+ *
+ * Dynamic powersave mode is an extension to normal powersave mode in which
+ * the hardware stays awake for a user-specified period of time after sending
+ * a frame so that reply frames need not be buffered and therefore delayed
+ * to the next wakeup. This can either be supported by hardware, in which case
+ * the driver needs to look at the @dynamic_ps_timeout hardware configuration
+ * value, or by the stack if all nullfunc handling is in the stack.
+ */
+
+/**
* DOC: Frame filtering
*
* mac80211 requires to see many management frames for proper
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-07 17:03:34.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-01-07 17:27:58.000000000 +0100
@@ -835,6 +835,9 @@ static int ieee80211_ioctl_siwpower(stru
int ret = 0, timeout = 0;
bool ps;

+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+ return -EOPNOTSUPP;
+
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;

@@ -860,32 +863,37 @@ static int ieee80211_ioctl_siwpower(stru
if (wrq->flags & IW_POWER_TIMEOUT)
timeout = wrq->value / 1000;

-set:
+ set:
if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
return ret;

local->powersave = ps;
conf->dynamic_ps_timeout = timeout;

- if (local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) {
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
ret = ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
- } else if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
- if (conf->dynamic_ps_timeout > 0)
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(conf->dynamic_ps_timeout));
- else {
- if (local->powersave) {
+
+ if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
+ return ret;
+
+ if (conf->dynamic_ps_timeout > 0 &&
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(conf->dynamic_ps_timeout));
+ } else {
+ if (local->powersave) {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
ieee80211_send_nullfunc(local, sdata, 1);
- conf->flags |= IEEE80211_CONF_PS;
- ret = ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
- } else {
- conf->flags &= ~IEEE80211_CONF_PS;
- ret = ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
+ conf->flags |= IEEE80211_CONF_PS;
+ ret = ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ } else {
+ conf->flags &= ~IEEE80211_CONF_PS;
+ ret = ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
ieee80211_send_nullfunc(local, sdata, 0);
- }
}
}

--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-07 17:03:34.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-01-07 17:38:15.000000000 +0100
@@ -777,17 +777,17 @@ static void ieee80211_set_associated(str
bss_info_changed |= BSS_CHANGED_BASIC_RATES;
ieee80211_bss_info_change_notify(sdata, bss_info_changed);

- if (local->powersave &&
- !(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
- if (local->hw.conf.dynamic_ps_timeout > 0)
+ if (local->powersave) {
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
+ local->hw.conf.dynamic_ps_timeout > 0) {
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
- else {
- ieee80211_send_nullfunc(local, sdata, 1);
+ } else {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 1);
conf->flags |= IEEE80211_CONF_PS;
- ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
}

@@ -1784,16 +1784,14 @@ static void ieee80211_rx_mgmt_beacon(str
ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
elems.wmm_param_len);

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK &&
+ local->hw.conf.flags & IEEE80211_CONF_PS) {
directed_tim = check_tim(&elems, ifsta->aid, &is_mc);

if (directed_tim || is_mc) {
- if (local->hw.conf.flags && IEEE80211_CONF_PS) {
- local->hw.conf.flags &= ~IEEE80211_CONF_PS;
- ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
- ieee80211_send_nullfunc(local, sdata, 0);
- }
+ local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ ieee80211_send_nullfunc(local, sdata, 0);
}
}

@@ -2700,9 +2698,10 @@ void ieee80211_dynamic_ps_enable_work(st
if (local->hw.conf.flags & IEEE80211_CONF_PS)
return;

- ieee80211_send_nullfunc(local, sdata, 1);
- local->hw.conf.flags |= IEEE80211_CONF_PS;
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 1);

+ local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}

--- wireless-testing.orig/net/mac80211/tx.c 2009-01-07 17:03:34.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c 2009-01-07 17:03:40.000000000 +0100
@@ -1298,7 +1298,7 @@ int ieee80211_master_start_xmit(struct s
return 0;
}

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+ if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-07 17:02:53.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-07 17:03:40.000000000 +0100
@@ -806,7 +806,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION;
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-07 17:02:54.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-07 17:03:40.000000000 +0100
@@ -1451,7 +1451,9 @@ static int rt2400pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-07 17:02:53.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-07 17:03:40.000000000 +0100
@@ -1752,7 +1752,9 @@ static int rt2500pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = 0;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-07 17:02:54.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-07 17:03:40.000000000 +0100
@@ -1803,7 +1803,9 @@ static int rt2500usb_probe_hw_mode(struc
rt2x00dev->hw->flags =
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-07 17:02:53.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-07 17:03:40.000000000 +0100
@@ -2558,7 +2558,9 @@ static int rt61pci_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-07 17:02:53.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-07 17:03:40.000000000 +0100
@@ -2079,7 +2079,9 @@ static int rt73usb_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/Documentation/DocBook/mac80211.tmpl 2009-01-07 17:02:53.000000000 +0100
+++ wireless-testing/Documentation/DocBook/mac80211.tmpl 2009-01-07 17:03:40.000000000 +0100
@@ -17,8 +17,7 @@
</authorgroup>

<copyright>
- <year>2007</year>
- <year>2008</year>
+ <year>2007-2009</year>
<holder>Johannes Berg</holder>
</copyright>

@@ -223,6 +222,11 @@ usage should require reading the full do
!Finclude/net/mac80211.h ieee80211_key_flags
</chapter>

+ <chapter id="powersave">
+ <title>Powersave support</title>
+!Pinclude/net/mac80211.h Powersave support
+ </chapter>
+
<chapter id="qos">
<title>Multiple queues and QoS support</title>
<para>TBD</para>



2009-01-06 20:24:44

by Johannes Berg

[permalink] [raw]
Subject: [RFC v2] mac80211: extend/document powersave API

This modifies hardware flags for powersave to support three different
flags:
* IEEE80211_HW_SUPPORTS_PS - indicates general PS support
* IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc/... handling in software
* IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device

It also adds documentation for all this which explains how to set the
various flags.

Signed-off-by: Johannes Berg <[email protected]>
---
v2: update docbook

Documentation/DocBook/mac80211.tmpl | 8 ++++-
drivers/net/wireless/iwlwifi/iwl-core.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/rt61pci.c | 4 ++
drivers/net/wireless/rt2x00/rt73usb.c | 4 ++
include/net/mac80211.h | 47 ++++++++++++++++++++++++++++----
net/mac80211/mlme.c | 4 +-
net/mac80211/tx.c | 2 -
net/mac80211/wext.c | 31 +++++++++++++++++++--
11 files changed, 96 insertions(+), 19 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/include/net/mac80211.h 2009-01-06 18:50:45.000000000 +0100
@@ -858,10 +858,15 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_AMPDU_AGGREGATION:
* Hardware supports 11n A-MPDU aggregation.
*
- * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
- * Hardware which has dynamic power save support, meaning
- * that power save is enabled in idle periods, and don't need support
- * from stack.
+ * @IEEE80211_HW_SUPPORTS_PS:
+ * Hardware has power save support (i.e. can go to sleep).
+ *
+ * @IEEE80211_HW_PS_NULLFUNC_STACK:
+ * Hardware requires nullfunc frame handling in stack, implies
+ * stack support for dynamic PS.
+ *
+ * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS:
+ * Hardware has support for dynamic PS.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -874,7 +879,9 @@ enum ieee80211_hw_flags {
IEEE80211_HW_NOISE_DBM = 1<<8,
IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
- IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
+ IEEE80211_HW_SUPPORTS_PS = 1<<11,
+ IEEE80211_HW_PS_NULLFUNC_STACK = 1<<12,
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<13,
};

/**
@@ -1061,6 +1068,36 @@ ieee80211_get_alt_retry_rate(const struc
*/

/**
+ * DOC: Powersave support
+ *
+ * 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 regardless of association status, and the driver or
+ * hardware must take care of enabling/disabling powersave depending on
+ * the association status and TIM bit and send nullfunc frames by itself.
+ *
+ * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
+ * flag to indicate that it can support dynamic PS mode (see below).
+ *
+ * Other hardware designs cannot send nullfunc frames by themselves and
+ * need to be told explicitly about powersave transitions depending on
+ * association status, need software support for parsing the TIM bitmap
+ * and can implement dynamic PS mode in software. This is also supported
+ * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
+ * %IEEE80211_HW_PS_NULLFUNC_STACK flags.
+ *
+ * Dynamic powersave mode is an extension to normal powersave mode in which
+ * the hardware stays awake for a user-specified period of time after sending
+ * a frame so that reply frames need not be buffered and therefore delayed
+ * to the next wakeup. This can either be supported by hardware, in which case
+ * the driver needs to look at the @dynamic_ps_timeout hardware configuration
+ * value, or by the stack if all nullfunc handling is in the stack.
+ */
+
+/**
* DOC: Frame filtering
*
* mac80211 requires to see many management frames for proper
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-06 18:34:21.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-01-06 18:50:59.000000000 +0100
@@ -836,6 +836,9 @@ static int ieee80211_ioctl_siwpower(stru
int ret = 0, timeout = 0;
bool ps;

+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+ return -EOPNOTSUPP;
+
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;

@@ -858,8 +861,17 @@ static int ieee80211_ioctl_siwpower(stru
if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
return -EINVAL;

- if (wrq->flags & IW_POWER_TIMEOUT)
+ if (wrq->flags & IW_POWER_TIMEOUT) {
+ /*
+ * dynamic PS only supported if nullfunc handling in stack
+ * or hardware supports dynamic PS itself
+ */
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
+ !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+ return -EOPNOTSUPP;
+
timeout = wrq->value / 1000;
+ }

set:
if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
@@ -868,10 +880,12 @@ set:
local->powersave = ps;
conf->dynamic_ps_timeout = timeout;

- if (local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) {
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
ret = ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
- } else if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+
+ if ((sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) &&
+ (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
if (conf->dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(conf->dynamic_ps_timeout));
@@ -888,6 +902,17 @@ set:
ieee80211_send_nullfunc(local, sdata, 0);
}
}
+ } else if (!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
+ /*
+ * hardware-based PS has to handle it all in hw/driver,
+ * including turning off PS when not associated.
+ */
+ if (local->powersave)
+ conf->flags |= IEEE80211_CONF_PS;
+ else
+ conf->flags &= ~IEEE80211_CONF_PS;
+
+ ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}

return ret;
--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-01-06 18:39:51.000000000 +0100
@@ -778,7 +778,7 @@ static void ieee80211_set_associated(str
ieee80211_bss_info_change_notify(sdata, bss_info_changed);

if (local->powersave &&
- !(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
+ (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) {
if (local->hw.conf.dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
@@ -1785,7 +1785,7 @@ static void ieee80211_rx_mgmt_beacon(str
ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
elems.wmm_param_len);

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
directed_tim = check_tim(&elems, ifsta->aid, &is_mc);

if (directed_tim || is_mc) {
--- wireless-testing.orig/net/mac80211/tx.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c 2009-01-06 18:34:23.000000000 +0100
@@ -1298,7 +1298,7 @@ int ieee80211_master_start_xmit(struct s
return 0;
}

- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+ if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c 2009-01-06 21:23:52.000000000 +0100
@@ -806,7 +806,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION;
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2400pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -1451,7 +1451,9 @@ static int rt2400pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -1752,7 +1752,9 @@ static int rt2500pci_probe_hw_mode(struc
* Initialize all hw fields.
*/
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = 0;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt2500usb.c 2009-01-06 18:34:23.000000000 +0100
@@ -1803,7 +1803,9 @@ static int rt2500usb_probe_hw_mode(struc
rt2x00dev->hw->flags =
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;

rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-06 18:33:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt61pci.c 2009-01-06 18:34:23.000000000 +0100
@@ -2558,7 +2558,9 @@ static int rt61pci_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = 0;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-06 18:33:49.000000000 +0100
+++ wireless-testing/drivers/net/wireless/rt2x00/rt73usb.c 2009-01-06 18:34:23.000000000 +0100
@@ -2079,7 +2079,9 @@ static int rt73usb_probe_hw_mode(struct
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;

SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
--- wireless-testing.orig/Documentation/DocBook/mac80211.tmpl 2009-01-06 21:23:49.000000000 +0100
+++ wireless-testing/Documentation/DocBook/mac80211.tmpl 2009-01-06 21:24:01.000000000 +0100
@@ -17,8 +17,7 @@
</authorgroup>

<copyright>
- <year>2007</year>
- <year>2008</year>
+ <year>2007-2009</year>
<holder>Johannes Berg</holder>
</copyright>

@@ -223,6 +222,11 @@ usage should require reading the full do
!Finclude/net/mac80211.h ieee80211_key_flags
</chapter>

+ <chapter id="powersave">
+ <title>Powersave support</title>
+!Pinclude/net/mac80211.h Powersave support
+ </chapter>
+
<chapter id="qos">
<title>Multiple queues and QoS support</title>
<para>TBD</para>



2009-01-07 16:22:46

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC v2] mac80211: extend/document powersave API

Johannes Berg <[email protected]> writes:

> On Wed, 2009-01-07 at 17:49 +0200, Kalle Valo wrote:
>
>> > + * 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 regardless of association status, and the driver or
>> > + * hardware must take care of enabling/disabling powersave depending on
>> > + * the association status and TIM bit and send nullfunc frames by
>> > + itself.
>>
>> Actually I'm not aware of any hardware designs which enables and
>> disables power save according to association status (modulo fullmac
>> design, of course). Even iwlwifi, which I think has the most
>> sophisticated power save support, requires the host to enable power
>> save according to the association status. Hence I would like to have
>> the power save enable/disable logic based on association status in
>> mac80211.
>
> Yeah, good point. But iwlwifi is confusing me ;) Since iwlwifi is the
> only user, I'll clean that up along with cleaning up iwlwifi, would you
> mind leaving it as-is, and I'll fix it in the short term?

I'm perfectly fine with this. Most important is that we have a
consensus about long term goals, the current solution is just fine.
Power save is always tricky, and it's even trickier when we have to
deal with all these different hardware designs. Let's do this in small
pieces, it makes life a lot easier.

>> We already have this support in ieee80211_set_associated()
>>
>> [Reads the function again]
>>
>> Or, actually we had it. I think Vivek's patch changed the
>> functionality. But anyway, it's very easy to add the support back.
>>
>> The reason why I would like to have this in mac80211 is to avoid
>> having duplicate bugs in different drivers and make the driver
>> implementation easier.
>
> Makes sense.

Good, we have an agreement :)

>> Actually there are hardware designs which don't have dynamic power
>> save but have null frame creation in firmware (and hence don't need
>> IEEE80211_HW_PS_NULLFUNC_STACK). So IEEE80211_HW_SUPPORTS_DYNAMIC_PS
>> and IEEE80211_HW_PS_NULLFUNC_STACK are not related to each other in
>> any way. I suspect at76_usb is such design, but I need to recheck
>> that.
>
> But if they don't have dynps but nullfunc in firmware then we can't
> support dynamic ps at all, can we?
>
>> So I would like to implement this so that if
>> IEEE80211_HW_SUPPORTS_DYNAMIC_PS is not set mac80211 will always use
>> it's own timer, independent of IEEE80211_HW_PS_NULLFUNC_STACK. If you
>> agree, I can create a separate patch for this.
>
> Oh, I see now, so the firmware just creates the nullfunc whenever you
> tell it to?

Exactly. In that case we command the null frame creation in firmware
with the CONF_PS flag.

> bit strange, I guess.

It's strange, but I think it's because the hardware designers haven't
properly thought about power save. 802.11 power save wasn't important
few years ago, but fortunately times are changing.

--
Kalle Valo

2009-01-07 15:56:21

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2] mac80211: extend/document powersave API

On Wed, 2009-01-07 at 17:49 +0200, Kalle Valo wrote:

> > + * 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 regardless of association status, and the driver or
> > + * hardware must take care of enabling/disabling powersave depending on
> > + * the association status and TIM bit and send nullfunc frames by
> > + itself.
>
> Actually I'm not aware of any hardware designs which enables and
> disables power save according to association status (modulo fullmac
> design, of course). Even iwlwifi, which I think has the most
> sophisticated power save support, requires the host to enable power
> save according to the association status. Hence I would like to have
> the power save enable/disable logic based on association status in
> mac80211.

Yeah, good point. But iwlwifi is confusing me ;) Since iwlwifi is the
only user, I'll clean that up along with cleaning up iwlwifi, would you
mind leaving it as-is, and I'll fix it in the short term?

> We already have this support in ieee80211_set_associated()
>
> [Reads the function again]
>
> Or, actually we had it. I think Vivek's patch changed the
> functionality. But anyway, it's very easy to add the support back.
>
> The reason why I would like to have this in mac80211 is to avoid
> having duplicate bugs in different drivers and make the driver
> implementation easier.

Makes sense.

> > + * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
> > + * flag to indicate that it can support dynamic PS mode (see below).
> > + *
> > + * Other hardware designs cannot send nullfunc frames by themselves and
> > + * need to be told explicitly about powersave transitions depending on
> > + * association status, need software support for parsing the TIM bitmap
> > + * and can implement dynamic PS mode in software. This is also supported
> > + * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
> > + * %IEEE80211_HW_PS_NULLFUNC_STACK flags.
>
> stlc45xx (and p54spi) wakeup for multicast frames automatically, but
> ath5/9k need the host to do it. I think we will need a separate flag
> for that, but I can add it later.

Good point, we need to add that later.

> > @@ -858,8 +861,17 @@ static int ieee80211_ioctl_siwpower(stru
> > if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
> > return -EINVAL;
> >
> > - if (wrq->flags & IW_POWER_TIMEOUT)
> > + if (wrq->flags & IW_POWER_TIMEOUT) {
> > + /*
> > + * dynamic PS only supported if nullfunc handling in stack
> > + * or hardware supports dynamic PS itself
> > + */
> > + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
> > + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
> > + return -EOPNOTSUPP;
> > +
> > timeout = wrq->value / 1000;
> > + }
>
> Actually there are hardware designs which don't have dynamic power
> save but have null frame creation in firmware (and hence don't need
> IEEE80211_HW_PS_NULLFUNC_STACK). So IEEE80211_HW_SUPPORTS_DYNAMIC_PS
> and IEEE80211_HW_PS_NULLFUNC_STACK are not related to each other in
> any way. I suspect at76_usb is such design, but I need to recheck
> that.

But if they don't have dynps but nullfunc in firmware then we can't
support dynamic ps at all, can we?

> So I would like to implement this so that if
> IEEE80211_HW_SUPPORTS_DYNAMIC_PS is not set mac80211 will always use
> it's own timer, independent of IEEE80211_HW_PS_NULLFUNC_STACK. If you
> agree, I can create a separate patch for this.

Oh, I see now, so the firmware just creates the nullfunc whenever you
tell it to? bit strange, I guess.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part