89718a8273757a04ccee23e1805d79dd03de651f
[openwrt/staging/linusw.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Mon, 20 Jun 2022 21:26:34 +0200
3 Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness
4
5 In order to maintain fairness, the amount of queueing needs to be limited
6 beyond the simple per-station AQL budget, otherwise the driver can simply
7 repeatedly do scheduling rounds until all queues that have not used their
8 AQL budget become eligble.
9
10 To be conservative, use the high AQL limit for the first txq and add half
11 of the low AQL for each subsequent queue.
12
13 Signed-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);