summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/mac80211.h24
-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
10 files changed, 121 insertions, 8 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 45155803c875..531b526a10db 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1188,6 +1188,8 @@ enum mac80211_rx_encoding {
1188 * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) 1188 * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
1189 * @nss: number of streams (VHT and HE only) 1189 * @nss: number of streams (VHT and HE only)
1190 * @flag: %RX_FLAG_\* 1190 * @flag: %RX_FLAG_\*
1191 * @airtime: Duration of frame in usec. See @IEEE80211_HW_AIRTIME_ACCOUNTING for
1192 * how to use this.
1191 * @encoding: &enum mac80211_rx_encoding 1193 * @encoding: &enum mac80211_rx_encoding
1192 * @bw: &enum rate_info_bw 1194 * @bw: &enum rate_info_bw
1193 * @enc_flags: uses bits from &enum mac80211_rx_encoding_flags 1195 * @enc_flags: uses bits from &enum mac80211_rx_encoding_flags
@@ -1202,6 +1204,7 @@ struct ieee80211_rx_status {
1202 u32 device_timestamp; 1204 u32 device_timestamp;
1203 u32 ampdu_reference; 1205 u32 ampdu_reference;
1204 u32 flag; 1206 u32 flag;
1207 u16 airtime;
1205 u16 freq; 1208 u16 freq;
1206 u8 enc_flags; 1209 u8 enc_flags;
1207 u8 encoding:2, bw:3; 1210 u8 encoding:2, bw:3;
@@ -2066,6 +2069,26 @@ struct ieee80211_txq {
2066 * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on 2069 * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on
2067 * TDLS links. 2070 * TDLS links.
2068 * 2071 *
2072 * @IEEE80211_HW_AIRTIME_ACCOUNTING: Hardware supports accounting the airtime
2073 * usage of other stations and reports it in the @tx_time and/or @airtime
2074 * fields of the TX/RX status structs.
2075 * When setting this flag, the driver should ensure that the respective
2076 * fields in the TX and RX status structs are always either zero or
2077 * contains a valid duration for the frame in usec. The driver can choose
2078 * to report either or both of TX and RX airtime, but it is recommended to
2079 * report both.
2080 * The reported airtime should as a minimum include all time that is spent
2081 * transmitting to the remote station, including overhead and padding, but
2082 * not including time spent waiting for a TXOP. If the time is not reported
2083 * by the hardware it can in some cases be calculated from the rate and
2084 * known frame composition. When possible, the time should include any
2085 * failed transmission attempts.
2086 * For aggregated frames, there are two possible strategies to report the
2087 * airtime: Either include the airtime of the entire aggregate in the first
2088 * (or last) frame and leave the others at zero. Alternatively, include the
2089 * overhead of the full aggregate in the first or last frame and report the
2090 * time of each frame + padding not including the full aggregate overhead.
2091 *
2069 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays 2092 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
2070 */ 2093 */
2071enum ieee80211_hw_flags { 2094enum ieee80211_hw_flags {
@@ -2109,6 +2132,7 @@ enum ieee80211_hw_flags {
2109 IEEE80211_HW_REPORTS_LOW_ACK, 2132 IEEE80211_HW_REPORTS_LOW_ACK,
2110 IEEE80211_HW_SUPPORTS_TX_FRAG, 2133 IEEE80211_HW_SUPPORTS_TX_FRAG,
2111 IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, 2134 IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
2135 IEEE80211_HW_AIRTIME_ACCOUNTING,
2112 2136
2113 /* keep last, obviously */ 2137 /* keep last, obviously */
2114 NUM_IEEE80211_HW_FLAGS 2138 NUM_IEEE80211_HW_FLAGS
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: