mac80211: improve powersave handling in the tx queue rework patch

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 44748
This commit is contained in:
Felix Fietkau 2015-03-14 02:00:36 +00:00
parent ba21cbae3e
commit 25d13b89ee
2 changed files with 154 additions and 9 deletions

View file

@ -293,7 +293,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
atomic_dec(&ps->num_sta_ps);
}
+ if (sta->txq) {
+ if (sta->txqi) {
+ for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+ ieee80211_flush_tx_queue(local, sta->sta.txq[i]);
+ }
@ -305,7 +305,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
+ kfree(sta->txq);
+ kfree(sta->txqi);
kfree(rcu_dereference_raw(sta->sta.rates));
kfree(sta);
}
@ -339,7 +339,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+ if (!txq_data)
+ goto free;
+
+ sta->txq = txq_data;
+ sta->txqi = txq_data;
+ for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+ struct txq_info *txq = txq_data + i * size;
+ ieee80211_init_tx_queue(sdata, sta, txq, i);
@ -367,20 +367,130 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
return sta;
+
+free_txq:
+ kfree(sta->txq);
+ kfree(sta->txqi);
+free:
+ kfree(sta);
+ return NULL;
}
static int sta_info_insert_check(struct sta_info *sta)
@@ -640,6 +667,8 @@ static void __sta_info_recalc_tim(struct
indicate_tim |=
sta->driver_buffered_tids & tids;
+ indicate_tim |=
+ sta->txq_buffered_tids & tids;
}
done:
@@ -1071,7 +1100,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
- int filtered = 0, buffered = 0, ac;
+ int filtered = 0, buffered = 0, ac, i;
unsigned long flags;
struct ps_data *ps;
@@ -1090,10 +1119,25 @@ void ieee80211_sta_ps_deliver_wakeup(str
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
sta->driver_buffered_tids = 0;
+ sta->txq_buffered_tids = 0;
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
+ if (sta->txqi) {
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+ struct txq_info *txqi;
+
+ txqi = container_of(sta->sta.txq[i], struct txq_info,
+ txq);
+
+ if (!skb_queue_len(&txqi->queue))
+ continue;
+
+ drv_wake_tx_queue(local, txqi);
+ }
+ }
+
skb_queue_head_init(&pending);
/* sync with ieee80211_tx_h_unicast_ps_buf */
@@ -1254,7 +1298,7 @@ ieee80211_sta_ps_deliver_response(struct
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
bool more_data = false;
- int ac;
+ int ac, tid;
unsigned long driver_release_tids = 0;
struct sk_buff_head frames;
@@ -1275,8 +1319,10 @@ ieee80211_sta_ps_deliver_response(struct
/* if we already have frames from software, then we can't also
* release from hardware queues
*/
- if (skb_queue_empty(&frames))
+ if (skb_queue_empty(&frames)) {
driver_release_tids |= sta->driver_buffered_tids & tids;
+ driver_release_tids |= sta->txq_buffered_tids & tids;
+ }
if (driver_release_tids) {
/* If the driver has data on more than one TID then
@@ -1447,6 +1493,8 @@ ieee80211_sta_ps_deliver_response(struct
sta_info_recalc_tim(sta);
} else {
+ unsigned long tids = sta->txq_buffered_tids & driver_release_tids;
+
/*
* We need to release a frame that is buffered somewhere in the
* driver ... it'll have to handle that.
@@ -1466,8 +1514,25 @@ ieee80211_sta_ps_deliver_response(struct
* that the TID(s) became empty before returning here from the
* release function.
* Either way, however, when the driver tells us that the TID(s)
- * became empty we'll do the TIM recalculation.
+ * became empty or we find that a txq became empty, we'll do the
+ * TIM recalculation.
*/
+
+ if (!sta->txqi)
+ return;
+
+ for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
+ struct txq_info *txqi;
+
+ txqi = container_of(sta->sta.txq[tid], struct txq_info,
+ txq);
+
+ if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
+ continue;
+
+ sta_info_recalc_tim(sta);
+ break;
+ }
}
}
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -368,6 +368,7 @@ struct sta_info {
@@ -274,6 +274,7 @@ struct sta_ampdu_mlme {
* entered power saving state, these are also delivered to
* the station when it leaves powersave or polls for frames
* @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
+ * @txq_buffered_tids: bitmap of TIDs that mac80211 has txq data buffered on
* @rx_packets: Number of MSDUs received from this STA
* @rx_bytes: Number of bytes received from this STA
* @last_rx: time (in jiffies) when last frame was received from this STA
@@ -368,6 +369,8 @@ struct sta_info {
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids;
+ struct txq_info *txq;
+ unsigned long txq_buffered_tids;
+ struct txq_info *txqi;
/* Updated from RX path only, no locking requirements */
unsigned long rx_packets;
@ -429,7 +539,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
#define TRACE_SYSTEM mac80211_msg
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1201,13 +1201,76 @@ ieee80211_tx_prepare(struct ieee80211_su
@@ -1201,13 +1201,80 @@ ieee80211_tx_prepare(struct ieee80211_su
return TX_CONTINUE;
}
@ -440,6 +550,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_control control = {
+ .sta = pubsta
+ };
@ -447,6 +558,9 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+ struct txq_info *txqi;
+ u8 ac;
+
+ if (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)
+ goto tx_normal;
+
+ if (ieee80211_is_mgmt(hdr->frame_control) ||
+ ieee80211_is_ctl(hdr->frame_control))
+ goto tx_normal;
@ -507,7 +621,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
struct sk_buff *skb, *tmp;
unsigned long flags;
@@ -1265,10 +1328,9 @@ static bool ieee80211_tx_frags(struct ie
@@ -1265,10 +1332,9 @@ static bool ieee80211_tx_frags(struct ie
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
info->control.vif = vif;
@ -570,3 +684,34 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+ atomic_sub(n, &sdata->txqs_len[txq->ac]);
+}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1176,6 +1176,7 @@ static void sta_ps_start(struct sta_info
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;
+ int tid;
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -1189,6 +1190,20 @@ static void sta_ps_start(struct sta_info
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
sta->sta.addr, sta->sta.aid);
+
+ if (!sta->txqi)
+ return;
+
+ for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
+ struct txq_info *txqi;
+
+ txqi = container_of(sta->sta.txq[tid], struct txq_info, txq);
+
+ if (!skb_queue_len(&txqi->queue))
+ set_bit(tid, &sta->txq_buffered_tids);
+ else
+ clear_bit(tid, &sta->txq_buffered_tids);
+ }
}
static void sta_ps_end(struct sta_info *sta)

View file

@ -115,7 +115,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -348,6 +348,7 @@ struct sta_info {
@@ -349,6 +349,7 @@ struct sta_info {
u8 ptk_idx;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;