aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2015-03-14 02:00:36 +0000
committerFelix Fietkau <nbd@openwrt.org>2015-03-14 02:00:36 +0000
commit25d13b89eeaa9a2df5458ed3d7e5ebe97c3f6560 (patch)
treef5f24a0dd84184c4c5cd439f0a8c155896f26e96 /package/kernel/mac80211
parentba21cbae3eff092d17856c01315ac0e0ce2b3a10 (diff)
downloadupstream-25d13b89eeaa9a2df5458ed3d7e5ebe97c3f6560.tar.gz
upstream-25d13b89eeaa9a2df5458ed3d7e5ebe97c3f6560.tar.bz2
upstream-25d13b89eeaa9a2df5458ed3d7e5ebe97c3f6560.zip
mac80211: improve powersave handling in the tx queue rework patch
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 44748
Diffstat (limited to 'package/kernel/mac80211')
-rw-r--r--package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch161
-rw-r--r--package/kernel/mac80211/patches/301-mac80211-lock-rate-control.patch2
2 files changed, 154 insertions, 9 deletions
diff --git a/package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch b/package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch
index 40aca6dd03..475d32943b 100644
--- a/package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch
+++ b/package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch
@@ -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)
diff --git a/package/kernel/mac80211/patches/301-mac80211-lock-rate-control.patch b/package/kernel/mac80211/patches/301-mac80211-lock-rate-control.patch
index 6b6903215d..3acc529bb9 100644
--- a/package/kernel/mac80211/patches/301-mac80211-lock-rate-control.patch
+++ b/package/kernel/mac80211/patches/301-mac80211-lock-rate-control.patch
@@ -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;