summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorToke Høiland-Jørgensen <toke@toke.dk>2017-10-31 07:27:46 -0400
committerJohannes Berg <johannes.berg@intel.com>2017-12-11 06:40:24 -0500
commitb0d52ad821843a6c5badebd80feef9f871904fa6 (patch)
tree6962b03bd69935102294e2038ae615309091f3d4 /net/mac80211
parente937b8da5a591f141fe41aa48a2e898df9888c95 (diff)
mac80211: Add airtime account and scheduling to TXQs
This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new hardware flag, AIRTIME_ACCOUNTING, is added that drivers can set if they support reporting airtime usage of transmissions. When this flag is set, mac80211 will expect the actual airtime usage to be reported in the tx_time and rx_time fields of the respective status structs. 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. Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/debugfs.c1
-rw-r--r--net/mac80211/debugfs_sta.c29
-rw-r--r--net/mac80211/ieee80211_i.h8
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/rx.c8
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/sta_info.h7
-rw-r--r--net/mac80211/status.c16
-rw-r--r--net/mac80211/tx.c31
9 files changed, 97 insertions, 8 deletions
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 1f466d12a6bc..d6b87a4ec3e9 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -212,6 +212,7 @@ static const char *hw_flag_names[] = {
212 FLAG(REPORTS_LOW_ACK), 212 FLAG(REPORTS_LOW_ACK),
213 FLAG(SUPPORTS_TX_FRAG), 213 FLAG(SUPPORTS_TX_FRAG),
214 FLAG(SUPPORTS_TDLS_BUFFER_STA), 214 FLAG(SUPPORTS_TDLS_BUFFER_STA),
215 FLAG(AIRTIME_ACCOUNTING),
215#undef FLAG 216#undef FLAG
216}; 217};
217 218
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b15412c21ac9..40dba446836f 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -188,6 +188,32 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
188} 188}
189STA_OPS(aqm); 189STA_OPS(aqm);
190 190
191static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
192 size_t count, loff_t *ppos)
193{
194 struct sta_info *sta = file->private_data;
195 size_t bufsz = 200;
196 char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
197 ssize_t rv;
198
199 if (!buf)
200 return -ENOMEM;
201
202 spin_lock_bh(&sta->lock);
203
204 p += scnprintf(p, bufsz + buf - p,
205 "RX: %llu us\nTX: %llu us\nDeficit: %lld us\n",
206 sta->airtime_stats.rx_airtime,
207 sta->airtime_stats.tx_airtime,
208 sta->airtime_deficit);
209
210 spin_unlock_bh(&sta->lock);
211 rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
212 kfree(buf);
213 return rv;
214}
215STA_OPS(airtime);
216
191static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, 217static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
192 size_t count, loff_t *ppos) 218 size_t count, loff_t *ppos)
193{ 219{
@@ -542,6 +568,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
542 if (local->ops->wake_tx_queue) 568 if (local->ops->wake_tx_queue)
543 DEBUGFS_ADD(aqm); 569 DEBUGFS_ADD(aqm);
544 570
571 if (ieee80211_hw_check(&local->hw, AIRTIME_ACCOUNTING))
572 DEBUGFS_ADD(airtime);
573
545 if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) 574 if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
546 debugfs_create_x32("driver_buffered_tids", 0400, 575 debugfs_create_x32("driver_buffered_tids", 0400,
547 sta->debugfs_dir, 576 sta->debugfs_dir,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4155838c7bef..120c516851cf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -90,6 +90,9 @@ extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS];
90 90
91#define IEEE80211_MAX_NAN_INSTANCE_ID 255 91#define IEEE80211_MAX_NAN_INSTANCE_ID 255
92 92
93/* How much to increase airtime deficit on each scheduling round */
94#define IEEE80211_AIRTIME_QUANTUM 1000 /* usec */
95
93struct ieee80211_fragment_entry { 96struct ieee80211_fragment_entry {
94 struct sk_buff_head skb_list; 97 struct sk_buff_head skb_list;
95 unsigned long first_frag_time; 98 unsigned long first_frag_time;
@@ -1123,9 +1126,10 @@ struct ieee80211_local {
1123 struct codel_vars *cvars; 1126 struct codel_vars *cvars;
1124 struct codel_params cparams; 1127 struct codel_params cparams;
1125 1128
1126 /* protects active_txqs and txqi->schedule_order */ 1129 /* protects active_txqs_{new,old} and txqi->schedule_order */
1127 spinlock_t active_txq_lock; 1130 spinlock_t active_txq_lock;
1128 struct list_head active_txqs; 1131 struct list_head active_txqs_new;
1132 struct list_head active_txqs_old;
1129 1133
1130 const struct ieee80211_ops *ops; 1134 const struct ieee80211_ops *ops;
1131 1135
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 935d6e2491b1..b7142f8491d0 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -619,7 +619,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
619 spin_lock_init(&local->rx_path_lock); 619 spin_lock_init(&local->rx_path_lock);
620 spin_lock_init(&local->queue_stop_reason_lock); 620 spin_lock_init(&local->queue_stop_reason_lock);
621 621
622 INIT_LIST_HEAD(&local->active_txqs); 622 INIT_LIST_HEAD(&local->active_txqs_new);
623 INIT_LIST_HEAD(&local->active_txqs_old);
623 spin_lock_init(&local->active_txq_lock); 624 spin_lock_init(&local->active_txq_lock);
624 625
625 INIT_LIST_HEAD(&local->chanctx_list); 626 INIT_LIST_HEAD(&local->chanctx_list);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b3cff69bfd66..808f41fb536a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1630,6 +1630,14 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
1630 if (ieee80211_vif_is_mesh(&rx->sdata->vif)) 1630 if (ieee80211_vif_is_mesh(&rx->sdata->vif))
1631 ieee80211_mps_rx_h_sta_process(sta, hdr); 1631 ieee80211_mps_rx_h_sta_process(sta, hdr);
1632 1632
1633 /* airtime accounting */
1634 if (status->airtime) {
1635 spin_lock_bh(&sta->lock);
1636 sta->airtime_stats.rx_airtime += status->airtime;
1637 sta->airtime_deficit -= status->airtime;
1638 spin_unlock_bh(&sta->lock);
1639 }
1640
1633 /* 1641 /*
1634 * Drop (qos-)data::nullfunc frames silently, since they 1642 * Drop (qos-)data::nullfunc frames silently, since they
1635 * are used only to control station power saving mode. 1643 * are used only to control station power saving mode.
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index e0bcf16df494..ed5500e8aafb 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -425,6 +425,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
425 sta->cparams.interval = MS2TIME(100); 425 sta->cparams.interval = MS2TIME(100);
426 sta->cparams.ecn = true; 426 sta->cparams.ecn = true;
427 427
428 sta->airtime_deficit = IEEE80211_AIRTIME_QUANTUM;
429
428 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 430 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
429 431
430 return sta; 432 return sta;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index cd53619435b6..e356f2f85e12 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -559,6 +559,13 @@ struct sta_info {
559 } tx_stats; 559 } tx_stats;
560 u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; 560 u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
561 561
562 /* Airtime stats and deficit, protected by lock */
563 struct {
564 u64 rx_airtime;
565 u64 tx_airtime;
566 } airtime_stats;
567 s64 airtime_deficit;
568
562 /* 569 /*
563 * Aggregation information, locked with lock. 570 * Aggregation information, locked with lock.
564 */ 571 */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index da7427a41529..b044dbed2bb1 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -823,6 +823,14 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
823 ieee80211_lost_packet(sta, info); 823 ieee80211_lost_packet(sta, info);
824 } 824 }
825 } 825 }
826
827 if (info->status.tx_time &&
828 ieee80211_hw_check(&local->hw, AIRTIME_ACCOUNTING)) {
829 spin_lock_bh(&sta->lock);
830 sta->airtime_stats.tx_airtime += info->status.tx_time;
831 sta->airtime_deficit -= info->status.tx_time;
832 spin_unlock_bh(&sta->lock);
833 }
826 } 834 }
827 835
828 /* SNMP counters 836 /* SNMP counters
@@ -947,6 +955,14 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
947 sta->status_stats.retry_failed++; 955 sta->status_stats.retry_failed++;
948 sta->status_stats.retry_count += retry_count; 956 sta->status_stats.retry_count += retry_count;
949 957
958 if (info->status.tx_time &&
959 ieee80211_hw_check(&local->hw, AIRTIME_ACCOUNTING)) {
960 spin_lock_bh(&sta->lock);
961 sta->airtime_stats.tx_airtime += info->status.tx_time;
962 sta->airtime_deficit -= info->status.tx_time;
963 spin_unlock_bh(&sta->lock);
964 }
965
950 if (acked) { 966 if (acked) {
951 sta->status_stats.last_ack = jiffies; 967 sta->status_stats.last_ack = jiffies;
952 968
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 842881ca8f20..18381581b5e9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3566,7 +3566,7 @@ bool ieee80211_schedule_txq(struct ieee80211_hw *hw,
3566 spin_lock_bh(&local->active_txq_lock); 3566 spin_lock_bh(&local->active_txq_lock);
3567 3567
3568 if (list_empty(&txqi->schedule_order)) { 3568 if (list_empty(&txqi->schedule_order)) {
3569 list_add_tail(&txqi->schedule_order, &local->active_txqs); 3569 list_add_tail(&txqi->schedule_order, &local->active_txqs_new);
3570 ret = true; 3570 ret = true;
3571 } 3571 }
3572 3572
@@ -3580,14 +3580,35 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw)
3580{ 3580{
3581 struct ieee80211_local *local = hw_to_local(hw); 3581 struct ieee80211_local *local = hw_to_local(hw);
3582 struct txq_info *txqi = NULL; 3582 struct txq_info *txqi = NULL;
3583 struct list_head *head;
3583 3584
3584 spin_lock_bh(&local->active_txq_lock); 3585 spin_lock_bh(&local->active_txq_lock);
3585 3586
3586 if (list_empty(&local->active_txqs)) 3587begin:
3587 goto out; 3588 head = &local->active_txqs_new;
3589 if (list_empty(head)) {
3590 head = &local->active_txqs_old;
3591 if (list_empty(head))
3592 goto out;
3593 }
3594
3595 txqi = list_first_entry(head, struct txq_info, schedule_order);
3596
3597 if (txqi->txq.sta) {
3598 struct sta_info *sta = container_of(txqi->txq.sta,
3599 struct sta_info, sta);
3600
3601 spin_lock_bh(&sta->lock);
3602 if (sta->airtime_deficit < 0) {
3603 sta->airtime_deficit += IEEE80211_AIRTIME_QUANTUM;
3604 list_move_tail(&txqi->schedule_order,
3605 &local->active_txqs_old);
3606 spin_unlock_bh(&sta->lock);
3607 goto begin;
3608 }
3609 spin_unlock_bh(&sta->lock);
3610 }
3588 3611
3589 txqi = list_first_entry(&local->active_txqs,
3590 struct txq_info, schedule_order);
3591 list_del_init(&txqi->schedule_order); 3612 list_del_init(&txqi->schedule_order);
3592 3613
3593out: 3614out: