mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 23:12:32 +00:00
132 lines
4.0 KiB
Diff
132 lines
4.0 KiB
Diff
|
From: Felix Fietkau <nbd@nbd.name>
|
||
|
Date: Mon, 20 Jun 2022 21:26:34 +0200
|
||
|
Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness
|
||
|
|
||
|
In order to maintain fairness, the amount of queueing needs to be limited
|
||
|
beyond the simple per-station AQL budget, otherwise the driver can simply
|
||
|
repeatedly do scheduling rounds until all queues that have not used their
|
||
|
AQL budget become eligble.
|
||
|
|
||
|
To be conservative, use the high AQL limit for the first txq and add half
|
||
|
of the low AQL for each subsequent queue.
|
||
|
|
||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||
|
---
|
||
|
|
||
|
--- a/net/mac80211/ieee80211_i.h
|
||
|
+++ b/net/mac80211/ieee80211_i.h
|
||
|
@@ -1211,6 +1211,7 @@ struct ieee80211_local {
|
||
|
u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
|
||
|
u32 aql_threshold;
|
||
|
atomic_t aql_total_pending_airtime;
|
||
|
+ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
|
||
|
|
||
|
const struct ieee80211_ops *ops;
|
||
|
|
||
|
--- a/net/mac80211/main.c
|
||
|
+++ b/net/mac80211/main.c
|
||
|
@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||
|
local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
|
||
|
local->aql_txq_limit_high[i] =
|
||
|
IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
|
||
|
+ atomic_set(&local->aql_ac_pending_airtime[i], 0);
|
||
|
}
|
||
|
|
||
|
local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
|
||
|
--- a/net/mac80211/sta_info.c
|
||
|
+++ b/net/mac80211/sta_info.c
|
||
|
@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim
|
||
|
&sta->airtime[ac].aql_tx_pending);
|
||
|
|
||
|
atomic_add(tx_airtime, &local->aql_total_pending_airtime);
|
||
|
+ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim
|
||
|
tx_pending, 0);
|
||
|
}
|
||
|
|
||
|
+ atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
|
||
|
tx_pending = atomic_sub_return(tx_airtime,
|
||
|
- &local->aql_total_pending_airtime);
|
||
|
+ &local->aql_ac_pending_airtime[ac]);
|
||
|
if (WARN_ONCE(tx_pending < 0,
|
||
|
"Device %s AC %d pending airtime underflow: %u, %u",
|
||
|
wiphy_name(local->hw.wiphy), ac, tx_pending,
|
||
|
- tx_airtime))
|
||
|
- atomic_cmpxchg(&local->aql_total_pending_airtime,
|
||
|
+ tx_airtime)) {
|
||
|
+ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
|
||
|
tx_pending, 0);
|
||
|
+ atomic_sub(tx_pending, &local->aql_total_pending_airtime);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
int sta_info_move_state(struct sta_info *sta,
|
||
|
--- a/net/mac80211/tx.c
|
||
|
+++ b/net/mac80211/tx.c
|
||
|
@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq
|
||
|
|
||
|
spin_lock_bh(&local->active_txq_lock[ac]);
|
||
|
|
||
|
+ if (!local->schedule_round[ac])
|
||
|
+ goto out;
|
||
|
+
|
||
|
begin:
|
||
|
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||
|
struct txq_info,
|
||
|
@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct
|
||
|
}
|
||
|
EXPORT_SYMBOL(ieee80211_txq_airtime_check);
|
||
|
|
||
|
+static bool
|
||
|
+ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
|
||
|
+{
|
||
|
+ unsigned int num_txq = 0;
|
||
|
+ struct txq_info *txq;
|
||
|
+ u32 aql_limit;
|
||
|
+
|
||
|
+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
|
||
|
+ return true;
|
||
|
+
|
||
|
+ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
|
||
|
+ num_txq++;
|
||
|
+
|
||
|
+ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
|
||
|
+ local->aql_txq_limit_high[ac];
|
||
|
+
|
||
|
+ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
|
||
|
+}
|
||
|
+
|
||
|
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||
|
struct ieee80211_txq *txq)
|
||
|
{
|
||
|
@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i
|
||
|
if (list_empty(&txqi->schedule_order))
|
||
|
goto out;
|
||
|
|
||
|
+ if (!ieee80211_txq_schedule_airtime_check(local, ac))
|
||
|
+ goto out;
|
||
|
+
|
||
|
list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
|
||
|
schedule_order) {
|
||
|
if (iter == txqi)
|
||
|
@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct
|
||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||
|
|
||
|
spin_lock_bh(&local->active_txq_lock[ac]);
|
||
|
- local->schedule_round[ac]++;
|
||
|
+
|
||
|
+ if (ieee80211_txq_schedule_airtime_check(local, ac)) {
|
||
|
+ local->schedule_round[ac]++;
|
||
|
+ if (!local->schedule_round[ac])
|
||
|
+ local->schedule_round[ac]++;
|
||
|
+ } else {
|
||
|
+ local->schedule_round[ac] = 0;
|
||
|
+ }
|
||
|
+
|
||
|
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||
|
}
|
||
|
EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|