blob: 89718a8273757a04ccee23e1805d79dd03de651f [file] [log] [blame]
developer1de5e6c2022-06-27 11:23:25 +08001From: Felix Fietkau <nbd@nbd.name>
2Date: Mon, 20 Jun 2022 21:26:34 +0200
3Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness
4
5In order to maintain fairness, the amount of queueing needs to be limited
6beyond the simple per-station AQL budget, otherwise the driver can simply
7repeatedly do scheduling rounds until all queues that have not used their
8AQL budget become eligble.
9
10To be conservative, use the high AQL limit for the first txq and add half
11of the low AQL for each subsequent queue.
12
13Signed-off-by: Felix Fietkau <nbd@nbd.name>
14---
15
16--- a/net/mac80211/ieee80211_i.h
17+++ b/net/mac80211/ieee80211_i.h
18@@ -1211,6 +1211,7 @@ struct ieee80211_local {
19 u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
20 u32 aql_threshold;
21 atomic_t aql_total_pending_airtime;
22+ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
23
24 const struct ieee80211_ops *ops;
25
26--- a/net/mac80211/main.c
27+++ b/net/mac80211/main.c
28@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
29 local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
30 local->aql_txq_limit_high[i] =
31 IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
32+ atomic_set(&local->aql_ac_pending_airtime[i], 0);
33 }
34
35 local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
36--- a/net/mac80211/sta_info.c
37+++ b/net/mac80211/sta_info.c
38@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim
39 &sta->airtime[ac].aql_tx_pending);
40
41 atomic_add(tx_airtime, &local->aql_total_pending_airtime);
42+ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
43 return;
44 }
45
46@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim
47 tx_pending, 0);
48 }
49
50+ atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
51 tx_pending = atomic_sub_return(tx_airtime,
52- &local->aql_total_pending_airtime);
53+ &local->aql_ac_pending_airtime[ac]);
54 if (WARN_ONCE(tx_pending < 0,
55 "Device %s AC %d pending airtime underflow: %u, %u",
56 wiphy_name(local->hw.wiphy), ac, tx_pending,
57- tx_airtime))
58- atomic_cmpxchg(&local->aql_total_pending_airtime,
59+ tx_airtime)) {
60+ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
61 tx_pending, 0);
62+ atomic_sub(tx_pending, &local->aql_total_pending_airtime);
63+ }
64 }
65
66 int sta_info_move_state(struct sta_info *sta,
67--- a/net/mac80211/tx.c
68+++ b/net/mac80211/tx.c
69@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq
70
71 spin_lock_bh(&local->active_txq_lock[ac]);
72
73+ if (!local->schedule_round[ac])
74+ goto out;
75+
76 begin:
77 txqi = list_first_entry_or_null(&local->active_txqs[ac],
78 struct txq_info,
79@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct
80 }
81 EXPORT_SYMBOL(ieee80211_txq_airtime_check);
82
83+static bool
84+ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
85+{
86+ unsigned int num_txq = 0;
87+ struct txq_info *txq;
88+ u32 aql_limit;
89+
90+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
91+ return true;
92+
93+ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
94+ num_txq++;
95+
96+ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
97+ local->aql_txq_limit_high[ac];
98+
99+ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
100+}
101+
102 bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
103 struct ieee80211_txq *txq)
104 {
105@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i
106 if (list_empty(&txqi->schedule_order))
107 goto out;
108
109+ if (!ieee80211_txq_schedule_airtime_check(local, ac))
110+ goto out;
111+
112 list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
113 schedule_order) {
114 if (iter == txqi)
115@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct
116 struct ieee80211_local *local = hw_to_local(hw);
117
118 spin_lock_bh(&local->active_txq_lock[ac]);
119- local->schedule_round[ac]++;
120+
121+ if (ieee80211_txq_schedule_airtime_check(local, ac)) {
122+ local->schedule_round[ac]++;
123+ if (!local->schedule_round[ac])
124+ local->schedule_round[ac]++;
125+ } else {
126+ local->schedule_round[ac] = 0;
127+ }
128+
129 spin_unlock_bh(&local->active_txq_lock[ac]);
130 }
131 EXPORT_SYMBOL(ieee80211_txq_schedule_start);