[PATCH] wifi: mac80211: scale the airtime queue limit by the station's weight
Julius Bairaktaris <[email protected]>
| Newsgroups | org.kernel.vger.linux-wireless |
|---|---|
| Message-ID | <[email protected]> |
The airtime queue limit is the same for every station, so on a driver that pushes a whole scheduling selection into the hardware, every station is allowed the same airtime in flight and the deficit round robin can only decide the order in which they reach that ceiling, not how much of the medium each one gets. Setting NL80211_ATTR_AIRTIME_WEIGHT then has no effect on the airtime a station receives. Measured on an IPQ8074 access point with two stations on one radio, a 1x1 VHT80 client and a 2x2 HE160 client, both saturated from the access point at once, BE aql_txq_limit at 500/1000 us, three interleaved runs per weight with the association verified unchanged across every run. Without this change the slow station takes 44.4, 43.9 and 44.0 per cent of the medium at equal weights, 44.0, 43.5 and 44.4 at 1024:256, and 43.1, 43.4 and 42.8 at 256:1024. The weight moves the split by less than the spread within one setting. Scale the per-station limit by the station's weight. A station weighted above the default is allowed proportionally more airtime in flight and therefore takes proportionally more of the medium. A network that never sets a weight is unaffected, since every station keeps the default. The same pair then reads 42.1, 43.3 and 42.8 per cent at equal weights, 78.0, 78.9 and 77.2 at 1024:256, and 19.6, 18.3 and 20.0 at 256:1024: a 4:1 weight produces a 3.6:1 airtime ratio and 1:4 produces 4.2:1. It is not free, and over the pair the aggregate is 557 Mbit/s at equal weights, 925 when the faster station is favoured and 337 when the slower one is. The low limit is consulted without reference to the radio total, so the scaled value is bounded by aql_threshold. Without that bound a weight of 65535 grants one station 1.3 seconds of standing airtime on the default low limit, which no total accounts for. The bound reaches the high limit as well, where it changes nothing: that check already requires the radio total to sit below the same threshold. The bound never reduces a limit below the value configured for it, so an access point that raises aql_txq_limit above aql_threshold keeps what it asked for at every weight, and scaling a weight up cannot scale a limit down. That bound is also the ceiling on what a weight can express. At the default low limit of 5000 us it takes effect near a weight of 1229, so ratios beyond roughly five to one do not resolve: a weight of 65535 against 256 asks for 256 to 1 and delivers 4.9 to 1. This changes nothing where the limit does not bind. A station whose pending airtime never approaches the limit is not held back by it at either weight, mac80211 holds no backlog to arbitrate, and the share each station gets is decided by the hardware's own scheduling. Assisted-by: Claude:claude-opus-5 Signed-off-by: Julius Bairaktaris <[email protected]> --- The measurements were taken on ath11k with the series "wifi: ath11k: airtime queue limits, fairness and a driver TXQ scheduler", posted separately to linux-wireless. net/mac80211/tx.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3a1e2c9e1565..11350133d637 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4223,6 +4223,25 @@ EXPORT_SYMBOL(__ieee80211_schedule_txq); DEFINE_STATIC_KEY_FALSE(aql_disable); +/* The airtime a station may keep in flight scales with its weight. The low + * limit is consulted unconditionally, so the scaled value is bounded by the + * radio-wide threshold rather than by the weight alone, and never below the + * limit that was configured. + */ +static u32 ieee80211_aql_sta_limit(struct ieee80211_local *local, + struct sta_info *sta, u32 limit) +{ + u32 scaled; + + if (sta->airtime_weight == IEEE80211_DEFAULT_AIRTIME_WEIGHT) + return limit; + + scaled = mult_frac(limit, sta->airtime_weight, + IEEE80211_DEFAULT_AIRTIME_WEIGHT); + + return min(scaled, max(limit, local->aql_threshold)); +} + bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { @@ -4244,13 +4263,15 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, sta = container_of(txq->sta, struct sta_info, sta); if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < - sta->airtime[txq->ac].aql_limit_low) + ieee80211_aql_sta_limit(local, sta, + sta->airtime[txq->ac].aql_limit_low)) return true; if (atomic_read(&local->aql_total_pending_airtime) < local->aql_threshold && atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < - sta->airtime[txq->ac].aql_limit_high) + ieee80211_aql_sta_limit(local, sta, + sta->airtime[txq->ac].aql_limit_high)) return true; return false; -- 2.53.0