summaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2022-06-26 00:24:09 +0300
committerJohannes Berg <johannes.berg@intel.com>2022-07-01 11:51:48 +0300
commit8e4bac0671054ba1ad2e3d41aa568ac55f51affd (patch)
tree3f25767abf196fc9862f9549705959da38acf162 /net/mac80211
parent8ccc07028cb7aaa6ad313f24a9442c7796416e19 (diff)
downloadlinux-8e4bac0671054ba1ad2e3d41aa568ac55f51affd.tar.xz
wifi: 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> Acked-by: Toke Høiland-Jørgensen <toke@toke.dk> Link: https://lore.kernel.org/r/20220625212411.36675-5-nbd@nbd.name Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/main.c1
-rw-r--r--net/mac80211/sta_info.c10
-rw-r--r--net/mac80211/tx.c35
4 files changed, 43 insertions, 4 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c55e1dcba716..f08060a36ef2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1239,6 +1239,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;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e6c1cafbe9e5..929bbdf55213 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -789,6 +789,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
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;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a1a2118b4bf0..28ab55a072c6 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2075,6 +2075,7 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
&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;
}
@@ -2086,14 +2087,17 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
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,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 71c1d2a5eef3..b2430cf8332b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3846,6 +3846,9 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
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,
@@ -3967,6 +3970,25 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
}
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)
{
@@ -3983,6 +4005,9 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
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)
@@ -4022,7 +4047,15 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
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);