This allows a driver to buffer frames for a PS station and tell mac80211
to wake it up even though mac80211 does not have any buffered frames for
it.
This is necessary for properly handling aggregation related buffering,
in ath9k, because the driver needs to keep its frames in order to keep
track of the Block-ACK window.
Signed-off-by: Felix Fietkau <[email protected]>
---
include/net/mac80211.h | 12 ++++++++++++
net/mac80211/sta_info.c | 13 ++++++++++++-
net/mac80211/sta_info.h | 3 +++
3 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6c9c4e9..d23dd6c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2227,6 +2227,18 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
#define IEEE80211_TX_STATUS_HEADROOM 13
/**
+ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
+ *
+ * If a driver buffers frames for a powersave station instead of passing
+ * them back to mac80211 for retransmission, the station needs to be told
+ * to wake up using the TIM bitmap in the beacon.
+ *
+ * This function sets the station's TIM bit - it will be cleared when the
+ * station wakes up.
+ */
+void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
+
+/**
* ieee80211_tx_status - transmit status callback
*
* Call this function for all transmitted frames after they have been
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 9421760..a03d8a3 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -612,7 +612,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
#endif
dev_kfree_skb(skb);
- if (skb_queue_empty(&sta->ps_tx_buf))
+ if (skb_queue_empty(&sta->ps_tx_buf) &&
+ !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
sta_info_clear_tim_bit(sta);
}
@@ -896,6 +897,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
int sent, buffered;
+ clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
@@ -988,3 +990,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &sta->drv_unblock_wk);
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
+
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+{
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+ set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+ sta_info_set_tim_bit(sta);
+}
+EXPORT_SYMBOL(ieee80211_sta_set_tim);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 3415136..aa0adcb 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -43,6 +43,8 @@
* be in the queues
* @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
* station in power-save mode, reply when the driver unblocks.
+ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
+ * buffers. Automatically cleared on station wake-up.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
@@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_BLOCK_BA = 1<<11,
WLAN_STA_PS_DRIVER = 1<<12,
WLAN_STA_PSPOLL = 1<<13,
+ WLAN_STA_PS_DRIVER_BUF = 1<<14,
};
#define STA_TID_NUM 16
--
1.7.3.2
On 2011-04-18 10:15 AM, Johannes Berg wrote:
> On Sun, 2011-04-17 at 17:45 +0200, Felix Fietkau wrote:
>> This allows a driver to buffer frames for a PS station and tell mac80211
>> to wake it up even though mac80211 does not have any buffered frames for
>> it.
>> This is necessary for properly handling aggregation related buffering,
>> in ath9k, because the driver needs to keep its frames in order to keep
>> track of the Block-ACK window.
>
> Indeed, I thought I'd solved these cases with the WLAN_STA_PS_DRIVER
> thing but that's not true of course because it blocks wakeup until all
> frames have been filtered, which will never happen here. I think I'll
> probably need to implement using this in iwlwifi as well.
>
> The only question I have is how will PS-Poll be handled while an
> aggregation session is active?? Is it even allowed to poll a-MPDUs?
Not sure - polling A-MPDUs may not be allowed, the standard only
mentions polling MSDU and A-MSDU. We could add a driver callback later
that mac80211 calls upon receiving a PS-Poll when WLAN_STA_PS_DRIVER_BUF
is set, which will trigger the release of a single packet and indicate
in the return status whether it was the last one (from the driver's
point of view).
- Felix
On Mon, 2011-04-18 at 11:11 +0200, Felix Fietkau wrote:
> > The only question I have is how will PS-Poll be handled while an
> > aggregation session is active?? Is it even allowed to poll a-MPDUs?
> Not sure - polling A-MPDUs may not be allowed, the standard only
> mentions polling MSDU and A-MSDU. We could add a driver callback later
> that mac80211 calls upon receiving a PS-Poll when WLAN_STA_PS_DRIVER_BUF
> is set, which will trigger the release of a single packet and indicate
> in the return status whether it was the last one (from the driver's
> point of view).
Yeah I just looked at it too -- seems not allowed, and I don't even see
a way to implement it. I suppose for any long-term sleep (rather than
for things like scanning) the aggregation sessions should just be torn
down.
johannes
On Sun, 2011-04-17 at 17:45 +0200, Felix Fietkau wrote:
> This allows a driver to buffer frames for a PS station and tell mac80211
> to wake it up even though mac80211 does not have any buffered frames for
> it.
> This is necessary for properly handling aggregation related buffering,
> in ath9k, because the driver needs to keep its frames in order to keep
> track of the Block-ACK window.
Indeed, I thought I'd solved these cases with the WLAN_STA_PS_DRIVER
thing but that's not true of course because it blocks wakeup until all
frames have been filtered, which will never happen here. I think I'll
probably need to implement using this in iwlwifi as well.
The only question I have is how will PS-Poll be handled while an
aggregation session is active?? Is it even allowed to poll a-MPDUs?
johannes
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> include/net/mac80211.h | 12 ++++++++++++
> net/mac80211/sta_info.c | 13 ++++++++++++-
> net/mac80211/sta_info.h | 3 +++
> 3 files changed, 27 insertions(+), 1 deletions(-)
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 6c9c4e9..d23dd6c 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -2227,6 +2227,18 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
> #define IEEE80211_TX_STATUS_HEADROOM 13
>
> /**
> + * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
> + *
> + * If a driver buffers frames for a powersave station instead of passing
> + * them back to mac80211 for retransmission, the station needs to be told
> + * to wake up using the TIM bitmap in the beacon.
> + *
> + * This function sets the station's TIM bit - it will be cleared when the
> + * station wakes up.
> + */
> +void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
> +
> +/**
> * ieee80211_tx_status - transmit status callback
> *
> * Call this function for all transmitted frames after they have been
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index 9421760..a03d8a3 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -612,7 +612,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
> #endif
> dev_kfree_skb(skb);
>
> - if (skb_queue_empty(&sta->ps_tx_buf))
> + if (skb_queue_empty(&sta->ps_tx_buf) &&
> + !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
> sta_info_clear_tim_bit(sta);
> }
>
> @@ -896,6 +897,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
> struct ieee80211_local *local = sdata->local;
> int sent, buffered;
>
> + clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
> if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
> drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
>
> @@ -988,3 +990,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
> ieee80211_queue_work(hw, &sta->drv_unblock_wk);
> }
> EXPORT_SYMBOL(ieee80211_sta_block_awake);
> +
> +void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
> +{
> + struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
> +
> + set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
> + sta_info_set_tim_bit(sta);
> +}
> +EXPORT_SYMBOL(ieee80211_sta_set_tim);
> diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
> index 3415136..aa0adcb 100644
> --- a/net/mac80211/sta_info.h
> +++ b/net/mac80211/sta_info.h
> @@ -43,6 +43,8 @@
> * be in the queues
> * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
> * station in power-save mode, reply when the driver unblocks.
> + * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
> + * buffers. Automatically cleared on station wake-up.
> */
> enum ieee80211_sta_info_flags {
> WLAN_STA_AUTH = 1<<0,
> @@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags {
> WLAN_STA_BLOCK_BA = 1<<11,
> WLAN_STA_PS_DRIVER = 1<<12,
> WLAN_STA_PSPOLL = 1<<13,
> + WLAN_STA_PS_DRIVER_BUF = 1<<14,
> };
>
> #define STA_TID_NUM 16