Skip to content

Commit b4809e9

Browse files
tohojojmberg-intel
authored andcommitted
mac80211: Add airtime accounting and scheduling to TXQs
This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan <[email protected]> Signed-off-by: Louie Lu <[email protected]> [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen <[email protected]> Signed-off-by: Rajkumar Manoharan <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 3664705 commit b4809e9

10 files changed

Lines changed: 282 additions & 10 deletions

File tree

include/net/mac80211.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,9 @@ enum ieee80211_hw_flags {
23602360
* @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from
23612361
* them are encountered. The default should typically not be changed,
23622362
* unless the driver has good reasons for needing more buffers.
2363+
*
2364+
* @weight_multipler: Driver specific airtime weight multiplier used while
2365+
* refilling deficit of each TXQ.
23632366
*/
23642367
struct ieee80211_hw {
23652368
struct ieee80211_conf conf;
@@ -2396,6 +2399,7 @@ struct ieee80211_hw {
23962399
const struct ieee80211_cipher_scheme *cipher_schemes;
23972400
u8 max_nan_de_entries;
23982401
u8 tx_sk_pacing_shift;
2402+
u8 weight_multiplier;
23992403
};
24002404

24012405
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
@@ -5407,6 +5411,34 @@ void ieee80211_sta_eosp(struct ieee80211_sta *pubsta);
54075411
*/
54085412
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
54095413

5414+
/**
5415+
* ieee80211_sta_register_airtime - register airtime usage for a sta/tid
5416+
*
5417+
* Register airtime usage for a given sta on a given tid. The driver can call
5418+
* this function to notify mac80211 that a station used a certain amount of
5419+
* airtime. This information will be used by the TXQ scheduler to schedule
5420+
* stations in a way that ensures airtime fairness.
5421+
*
5422+
* The reported airtime should as a minimum include all time that is spent
5423+
* transmitting to the remote station, including overhead and padding, but not
5424+
* including time spent waiting for a TXOP. If the time is not reported by the
5425+
* hardware it can in some cases be calculated from the rate and known frame
5426+
* composition. When possible, the time should include any failed transmission
5427+
* attempts.
5428+
*
5429+
* The driver can either call this function synchronously for every packet or
5430+
* aggregate, or asynchronously as airtime usage information becomes available.
5431+
* TX and RX airtime can be reported together, or separately by setting one of
5432+
* them to 0.
5433+
*
5434+
* @pubsta: the station
5435+
* @tid: the TID to register airtime for
5436+
* @tx_airtime: airtime used during TX (in usec)
5437+
* @rx_airtime: airtime used during RX (in usec)
5438+
*/
5439+
void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
5440+
u32 tx_airtime, u32 rx_airtime);
5441+
54105442
/**
54115443
* ieee80211_iter_keys - iterate keys programmed into the device
54125444
* @hw: pointer obtained from ieee80211_alloc_hw()
@@ -6173,6 +6205,33 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
61736205
void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
61746206
__releases(txq_lock);
61756207

6208+
/**
6209+
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
6210+
*
6211+
* This function is used to check whether given txq is allowed to transmit by
6212+
* the airtime scheduler, and can be used by drivers to access the airtime
6213+
* fairness accounting without going using the scheduling order enfored by
6214+
* next_txq().
6215+
*
6216+
* Returns %true if the airtime scheduler thinks the TXQ should be allowed to
6217+
* transmit, and %false if it should be throttled. This function can also have
6218+
* the side effect of rotating the TXQ in the scheduler rotation, which will
6219+
* eventually bring the deficit to positive and allow the station to transmit
6220+
* again.
6221+
*
6222+
* The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
6223+
* aligned aginst driver's own round-robin scheduler list. i.e it rotates
6224+
* the TXQ list till it makes the requested node becomes the first entry
6225+
* in TXQ list. Thus both the TXQ list and driver's list are in sync. If this
6226+
* function returns %true, the driver is expected to schedule packets
6227+
* for transmission, and then return the TXQ through ieee80211_return_txq().
6228+
*
6229+
* @hw: pointer as obtained from ieee80211_alloc_hw()
6230+
* @txq: pointer obtained from station or virtual interface
6231+
*/
6232+
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
6233+
struct ieee80211_txq *txq);
6234+
61766235
/**
61776236
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
61786237
*

net/mac80211/cfg.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
14471447
if (ieee80211_vif_is_mesh(&sdata->vif))
14481448
sta_apply_mesh_params(local, sta, params);
14491449

1450+
if (params->airtime_weight)
1451+
sta->airtime_weight = params->airtime_weight;
1452+
14501453
/* set the STA state after all sta info from usermode has been set */
14511454
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
14521455
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {

net/mac80211/debugfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,9 @@ void debugfs_hw_add(struct ieee80211_local *local)
383383
if (local->ops->wake_tx_queue)
384384
DEBUGFS_ADD_MODE(aqm, 0600);
385385

386+
debugfs_create_u16("airtime_flags", 0600,
387+
phyd, &local->airtime_flags);
388+
386389
statsd = debugfs_create_dir("statistics", phyd);
387390

388391
/* if the dir failed, don't put all the other things into the root! */

net/mac80211/debugfs_sta.c

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
181181
txqi->tin.tx_bytes,
182182
txqi->tin.tx_packets,
183183
txqi->flags,
184-
txqi->flags & (1<<IEEE80211_TXQ_STOP) ? "STOP" : "RUN",
185-
txqi->flags & (1<<IEEE80211_TXQ_AMPDU) ? " AMPDU" : "",
186-
txqi->flags & (1<<IEEE80211_TXQ_NO_AMSDU) ? " NO-AMSDU" : "");
184+
test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
185+
test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
186+
test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
187187
}
188188

189189
rcu_read_unlock();
@@ -195,6 +195,64 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
195195
}
196196
STA_OPS(aqm);
197197

198+
static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
199+
size_t count, loff_t *ppos)
200+
{
201+
struct sta_info *sta = file->private_data;
202+
struct ieee80211_local *local = sta->sdata->local;
203+
size_t bufsz = 200;
204+
char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
205+
u64 rx_airtime = 0, tx_airtime = 0;
206+
s64 deficit[IEEE80211_NUM_ACS];
207+
ssize_t rv;
208+
int ac;
209+
210+
if (!buf)
211+
return -ENOMEM;
212+
213+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
214+
spin_lock_bh(&local->active_txq_lock[ac]);
215+
rx_airtime += sta->airtime[ac].rx_airtime;
216+
tx_airtime += sta->airtime[ac].tx_airtime;
217+
deficit[ac] = sta->airtime[ac].deficit;
218+
spin_unlock_bh(&local->active_txq_lock[ac]);
219+
}
220+
221+
p += scnprintf(p, bufsz + buf - p,
222+
"RX: %llu us\nTX: %llu us\nWeight: %u\n"
223+
"Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
224+
rx_airtime,
225+
tx_airtime,
226+
sta->airtime_weight,
227+
deficit[0],
228+
deficit[1],
229+
deficit[2],
230+
deficit[3]);
231+
232+
rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
233+
kfree(buf);
234+
return rv;
235+
}
236+
237+
static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
238+
size_t count, loff_t *ppos)
239+
{
240+
struct sta_info *sta = file->private_data;
241+
struct ieee80211_local *local = sta->sdata->local;
242+
int ac;
243+
244+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
245+
spin_lock_bh(&local->active_txq_lock[ac]);
246+
sta->airtime[ac].rx_airtime = 0;
247+
sta->airtime[ac].tx_airtime = 0;
248+
sta->airtime[ac].deficit = sta->airtime_weight;
249+
spin_unlock_bh(&local->active_txq_lock[ac]);
250+
}
251+
252+
return count;
253+
}
254+
STA_OPS_RW(airtime);
255+
198256
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
199257
size_t count, loff_t *ppos)
200258
{
@@ -906,6 +964,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
906964
if (local->ops->wake_tx_queue)
907965
DEBUGFS_ADD(aqm);
908966

967+
if (wiphy_ext_feature_isset(local->hw.wiphy,
968+
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
969+
DEBUGFS_ADD(airtime);
970+
909971
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
910972
debugfs_create_x32("driver_buffered_tids", 0400,
911973
sta->debugfs_dir,

net/mac80211/ieee80211_i.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,8 @@ struct ieee80211_local {
11381138
struct list_head active_txqs[IEEE80211_NUM_ACS];
11391139
u16 schedule_round[IEEE80211_NUM_ACS];
11401140

1141+
u16 airtime_flags;
1142+
11411143
const struct ieee80211_ops *ops;
11421144

11431145
/*

net/mac80211/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
667667
INIT_LIST_HEAD(&local->active_txqs[i]);
668668
spin_lock_init(&local->active_txq_lock[i]);
669669
}
670+
local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
670671

671672
INIT_LIST_HEAD(&local->chanctx_list);
672673
mutex_init(&local->chanctx_mtx);
@@ -1153,6 +1154,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
11531154
if (!local->hw.max_nan_de_entries)
11541155
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
11551156

1157+
if (!local->hw.weight_multiplier)
1158+
local->hw.weight_multiplier = 1;
1159+
11561160
result = ieee80211_wep_init(local);
11571161
if (result < 0)
11581162
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",

net/mac80211/sta_info.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
9090
struct tid_ampdu_tx *tid_tx;
9191
struct ieee80211_sub_if_data *sdata = sta->sdata;
9292
struct ieee80211_local *local = sdata->local;
93-
struct fq *fq = &local->fq;
9493
struct ps_data *ps;
9594

9695
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
@@ -120,9 +119,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
120119

121120
txqi = to_txq_info(sta->sta.txq[i]);
122121

123-
spin_lock_bh(&fq->lock);
124122
ieee80211_txq_purge(local, txqi);
125-
spin_unlock_bh(&fq->lock);
126123
}
127124
}
128125

@@ -387,9 +384,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
387384
if (sta_prepare_rate_control(local, sta, gfp))
388385
goto free_txq;
389386

387+
sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
388+
390389
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
391390
skb_queue_head_init(&sta->ps_tx_buf[i]);
392391
skb_queue_head_init(&sta->tx_filtered[i]);
392+
sta->airtime[i].deficit = sta->airtime_weight;
393393
}
394394

395395
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
@@ -1826,6 +1826,27 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
18261826
}
18271827
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
18281828

1829+
void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
1830+
u32 tx_airtime, u32 rx_airtime)
1831+
{
1832+
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1833+
struct ieee80211_local *local = sta->sdata->local;
1834+
u8 ac = ieee80211_ac_from_tid(tid);
1835+
u32 airtime = 0;
1836+
1837+
if (sta->local->airtime_flags & AIRTIME_USE_TX)
1838+
airtime += tx_airtime;
1839+
if (sta->local->airtime_flags & AIRTIME_USE_RX)
1840+
airtime += rx_airtime;
1841+
1842+
spin_lock_bh(&local->active_txq_lock[ac]);
1843+
sta->airtime[ac].tx_airtime += tx_airtime;
1844+
sta->airtime[ac].rx_airtime += rx_airtime;
1845+
sta->airtime[ac].deficit -= airtime;
1846+
spin_unlock_bh(&local->active_txq_lock[ac]);
1847+
}
1848+
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
1849+
18291850
int sta_info_move_state(struct sta_info *sta,
18301851
enum ieee80211_sta_state new_state)
18311852
{
@@ -2188,6 +2209,23 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
21882209
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
21892210
}
21902211

2212+
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
2213+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
2214+
sinfo->rx_duration += sta->airtime[ac].rx_airtime;
2215+
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
2216+
}
2217+
2218+
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
2219+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
2220+
sinfo->tx_duration += sta->airtime[ac].tx_airtime;
2221+
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
2222+
}
2223+
2224+
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
2225+
sinfo->airtime_weight = sta->airtime_weight;
2226+
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
2227+
}
2228+
21912229
sinfo->rx_dropped_misc = sta->rx_stats.dropped;
21922230
if (sta->pcpu_rx_stats) {
21932231
for_each_possible_cpu(cpu) {

net/mac80211/sta_info.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ enum ieee80211_agg_stop_reason {
127127
AGG_STOP_DESTROY_STA,
128128
};
129129

130+
/* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
131+
#define AIRTIME_USE_TX BIT(0)
132+
#define AIRTIME_USE_RX BIT(1)
133+
134+
struct airtime_info {
135+
u64 rx_airtime;
136+
u64 tx_airtime;
137+
s64 deficit;
138+
};
139+
130140
struct sta_info;
131141

132142
/**
@@ -565,6 +575,9 @@ struct sta_info {
565575
} tx_stats;
566576
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
567577

578+
struct airtime_info airtime[IEEE80211_NUM_ACS];
579+
u16 airtime_weight;
580+
568581
/*
569582
* Aggregation information, locked with lock.
570583
*/

net/mac80211/status.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
823823
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
824824
acked, info->status.tx_time);
825825

826+
if (info->status.tx_time &&
827+
wiphy_ext_feature_isset(local->hw.wiphy,
828+
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
829+
ieee80211_sta_register_airtime(&sta->sta, tid,
830+
info->status.tx_time, 0);
831+
826832
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
827833
if (info->flags & IEEE80211_TX_STAT_ACK) {
828834
if (sta->status_stats.lost_packets)

0 commit comments

Comments
 (0)