mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
ea5078014d
Signed-off-by: Felix Fietkau <nbd@nbd.name>
147 lines
4.5 KiB
Diff
147 lines
4.5 KiB
Diff
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
|
|
Date: Mon, 18 Nov 2019 22:06:10 -0800
|
|
Subject: [PATCH] mac80211: Use Airtime-based Queue Limits (AQL) on packet
|
|
dequeue
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
The previous commit added the ability to throttle stations when they queue
|
|
too much airtime in the hardware. This commit enables the functionality by
|
|
calculating the expected airtime usage of each packet that is dequeued from
|
|
the TXQs in mac80211, and accounting that as pending airtime.
|
|
|
|
The estimated airtime for each skb is stored in the tx_info, so we can
|
|
subtract the same amount from the running total when the skb is freed or
|
|
recycled. The throttling mechanism relies on this accounting to be
|
|
accurate (i.e., that we are not freeing skbs without subtracting any
|
|
airtime they were accounted for), so we put the subtraction into
|
|
ieee80211_report_used_skb(). As an optimisation, we also subtract the
|
|
airtime on regular TX completion, zeroing out the value stored in the
|
|
packet afterwards, to avoid having to do an expensive lookup of the station
|
|
from the packet data on every packet.
|
|
|
|
This patch does *not* include any mechanism to wake a throttled TXQ again,
|
|
on the assumption that this will happen anyway as a side effect of whatever
|
|
freed the skb (most commonly a TX completion).
|
|
|
|
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
|
Link: https://lore.kernel.org/r/20191119060610.76681-5-kyan@google.com
|
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
---
|
|
|
|
--- a/include/net/mac80211.h
|
|
+++ b/include/net/mac80211.h
|
|
@@ -1060,6 +1060,22 @@ struct ieee80211_tx_info {
|
|
};
|
|
};
|
|
|
|
+static inline u16
|
|
+ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est)
|
|
+{
|
|
+ /* We only have 10 bits in tx_time_est, so store airtime
|
|
+ * in increments of 4us and clamp the maximum to 2**12-1
|
|
+ */
|
|
+ info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2;
|
|
+ return info->tx_time_est << 2;
|
|
+}
|
|
+
|
|
+static inline u16
|
|
+ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
|
|
+{
|
|
+ return info->tx_time_est << 2;
|
|
+}
|
|
+
|
|
/**
|
|
* struct ieee80211_tx_status - extended tx staus info for rate control
|
|
*
|
|
--- a/net/mac80211/status.c
|
|
+++ b/net/mac80211/status.c
|
|
@@ -670,12 +670,26 @@ static void ieee80211_report_used_skb(st
|
|
struct sk_buff *skb, bool dropped)
|
|
{
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
+ u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
|
|
struct ieee80211_hdr *hdr = (void *)skb->data;
|
|
bool acked = info->flags & IEEE80211_TX_STAT_ACK;
|
|
|
|
if (dropped)
|
|
acked = false;
|
|
|
|
+ if (tx_time_est) {
|
|
+ struct sta_info *sta;
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
|
|
+ ieee80211_sta_update_pending_airtime(local, sta,
|
|
+ skb_get_queue_mapping(skb),
|
|
+ tx_time_est,
|
|
+ true);
|
|
+ rcu_read_unlock();
|
|
+ }
|
|
+
|
|
if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
|
|
struct ieee80211_sub_if_data *sdata;
|
|
|
|
@@ -885,6 +899,7 @@ static void __ieee80211_tx_status(struct
|
|
struct ieee80211_bar *bar;
|
|
int shift = 0;
|
|
int tid = IEEE80211_NUM_TIDS;
|
|
+ u16 tx_time_est;
|
|
|
|
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
|
|
|
@@ -996,6 +1011,17 @@ static void __ieee80211_tx_status(struct
|
|
ieee80211_sta_register_airtime(&sta->sta, tid,
|
|
info->status.tx_time, 0);
|
|
|
|
+ if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
|
|
+ /* Do this here to avoid the expensive lookup of the sta
|
|
+ * in ieee80211_report_used_skb().
|
|
+ */
|
|
+ ieee80211_sta_update_pending_airtime(local, sta,
|
|
+ skb_get_queue_mapping(skb),
|
|
+ tx_time_est,
|
|
+ true);
|
|
+ ieee80211_info_set_tx_time_est(info, 0);
|
|
+ }
|
|
+
|
|
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
|
|
if (acked) {
|
|
if (sta->status_stats.lost_packets)
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -3544,6 +3544,9 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
|
|
|
WARN_ON_ONCE(softirq_count() == 0);
|
|
|
|
+ if (!ieee80211_txq_airtime_check(hw, txq))
|
|
+ return NULL;
|
|
+
|
|
begin:
|
|
spin_lock_bh(&fq->lock);
|
|
|
|
@@ -3654,6 +3657,21 @@ begin:
|
|
}
|
|
|
|
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
|
+
|
|
+ if (local->airtime_flags & AIRTIME_USE_AQL) {
|
|
+ u32 airtime;
|
|
+
|
|
+ airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
|
|
+ skb->len);
|
|
+ if (airtime) {
|
|
+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
|
|
+ ieee80211_sta_update_pending_airtime(local, tx.sta,
|
|
+ txq->ac,
|
|
+ airtime,
|
|
+ false);
|
|
+ }
|
|
+ }
|
|
+
|
|
return skb;
|
|
|
|
out:
|