diff options
author | Felix Fietkau <nbd@openwrt.org> | 2015-03-14 02:00:36 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2015-03-14 02:00:36 +0000 |
commit | 25d13b89eeaa9a2df5458ed3d7e5ebe97c3f6560 (patch) | |
tree | f5f24a0dd84184c4c5cd439f0a8c155896f26e96 /package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch | |
parent | ba21cbae3eff092d17856c01315ac0e0ce2b3a10 (diff) | |
download | upstream-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/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch')
-rw-r--r-- | package/kernel/mac80211/patches/300-mac80211-add-an-intermediate-software-queue-implemen.patch | 161 |
1 files changed, 153 insertions, 8 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) |