aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToke Høiland-Jørgensen <toke@toke.dk>2018-12-18 20:02:06 -0500
committerJohannes Berg <johannes.berg@intel.com>2019-01-19 03:24:12 -0500
commit1866760096bf40bcf6977a9076b3026598bc12ee (patch)
tree9ccf3723aa2f98fb6fc3acfdaf9ad69112ee3222
parentf04d402f2f00a0f0470b7e636b50170608b425c7 (diff)
mac80211: Add TXQ scheduling API
This adds an API to mac80211 to handle scheduling of TXQs. The interface between driver and mac80211 for TXQ handling is changed by adding two new functions: ieee80211_next_txq(), which will return the next TXQ to schedule in the current round-robin rotation, and ieee80211_return_txq(), which the driver uses to indicate that it has finished scheduling a TXQ (which will then be put back in the scheduling rotation if it isn't empty). The driver must call ieee80211_txq_schedule_start() at the start of each scheduling session, and ieee80211_txq_schedule_end() at the end. The API then guarantees that the same TXQ is not returned twice in the same session (so a driver can loop on ieee80211_next_txq() without worrying about breaking the loop. Usage of the new API is optional, so drivers can be ported one at a time. In this patch, the actual scheduling performed by mac80211 is simple round-robin, but a subsequent commit adds airtime fairness awareness to the scheduler. Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> [minor kernel-doc fix, propagate sparse locking checks out] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h63
-rw-r--r--net/mac80211/agg-tx.c2
-rw-r--r--net/mac80211/driver-ops.h9
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/main.c5
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/tx.c60
7 files changed, 143 insertions, 7 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 88219cc137c3..e8a057f071c4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -108,9 +108,15 @@
108 * The driver is expected to initialize its private per-queue data for stations 108 * The driver is expected to initialize its private per-queue data for stations
109 * and interfaces in the .add_interface and .sta_add ops. 109 * and interfaces in the .add_interface and .sta_add ops.
110 * 110 *
111 * The driver can't access the queue directly. To dequeue a frame, it calls 111 * The driver can't access the queue directly. To dequeue a frame from a
112 * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it 112 * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
113 * calls the .wake_tx_queue driver op. 113 * queue, it calls the .wake_tx_queue driver op.
114 *
115 * Drivers can optionally delegate responsibility for scheduling queues to
116 * mac80211, to take advantage of airtime fairness accounting. In this case, to
117 * obtain the next queue to pull frames from, the driver calls
118 * ieee80211_next_txq(). The driver is then expected to return the txq using
119 * ieee80211_return_txq().
114 * 120 *
115 * For AP powersave TIM handling, the driver only needs to indicate if it has 121 * For AP powersave TIM handling, the driver only needs to indicate if it has
116 * buffered packets in the driver specific data structures by calling 122 * buffered packets in the driver specific data structures by calling
@@ -6103,7 +6109,8 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid);
6103 * ieee80211_tx_dequeue - dequeue a packet from a software tx queue 6109 * ieee80211_tx_dequeue - dequeue a packet from a software tx queue
6104 * 6110 *
6105 * @hw: pointer as obtained from ieee80211_alloc_hw() 6111 * @hw: pointer as obtained from ieee80211_alloc_hw()
6106 * @txq: pointer obtained from station or virtual interface 6112 * @txq: pointer obtained from station or virtual interface, or from
6113 * ieee80211_next_txq()
6107 * 6114 *
6108 * Returns the skb if successful, %NULL if no frame was available. 6115 * Returns the skb if successful, %NULL if no frame was available.
6109 * 6116 *
@@ -6119,6 +6126,54 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
6119 struct ieee80211_txq *txq); 6126 struct ieee80211_txq *txq);
6120 6127
6121/** 6128/**
6129 * ieee80211_next_txq - get next tx queue to pull packets from
6130 *
6131 * @hw: pointer as obtained from ieee80211_alloc_hw()
6132 * @ac: AC number to return packets from.
6133 *
6134 * Should only be called between calls to ieee80211_txq_schedule_start()
6135 * and ieee80211_txq_schedule_end().
6136 * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
6137 * is returned, it should be returned with ieee80211_return_txq() after the
6138 * driver has finished scheduling it.
6139 */
6140struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
6141
6142/**
6143 * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
6144 *
6145 * @hw: pointer as obtained from ieee80211_alloc_hw()
6146 * @txq: pointer obtained from station or virtual interface
6147 *
6148 * Should only be called between calls to ieee80211_txq_schedule_start()
6149 * and ieee80211_txq_schedule_end().
6150 */
6151void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
6152
6153/**
6154 * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
6155 *
6156 * @hw: pointer as obtained from ieee80211_alloc_hw()
6157 * @ac: AC number to acquire locks for
6158 *
6159 * Acquire locks needed to schedule TXQs from the given AC. Should be called
6160 * before ieee80211_next_txq() or ieee80211_return_txq().
6161 */
6162void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
6163 __acquires(txq_lock);
6164
6165/**
6166 * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
6167 *
6168 * @hw: pointer as obtained from ieee80211_alloc_hw()
6169 * @ac: AC number to acquire locks for
6170 *
6171 * Release locks previously acquired by ieee80211_txq_schedule_end().
6172 */
6173void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
6174 __releases(txq_lock);
6175
6176/**
6122 * ieee80211_txq_get_depth - get pending frame/byte count of given txq 6177 * ieee80211_txq_get_depth - get pending frame/byte count of given txq
6123 * 6178 *
6124 * The values are not guaranteed to be coherent with regard to each other, i.e. 6179 * The values are not guaranteed to be coherent with regard to each other, i.e.
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 69e831bc317b..e94b1a0407af 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -229,7 +229,7 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
229 clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); 229 clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
230 local_bh_disable(); 230 local_bh_disable();
231 rcu_read_lock(); 231 rcu_read_lock();
232 drv_wake_tx_queue(sta->sdata->local, txqi); 232 schedule_and_wake_txq(sta->sdata->local, txqi);
233 rcu_read_unlock(); 233 rcu_read_unlock();
234 local_bh_enable(); 234 local_bh_enable();
235} 235}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3e0d5922a440..1aab1734b26f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1173,6 +1173,15 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
1173 local->ops->wake_tx_queue(&local->hw, &txq->txq); 1173 local->ops->wake_tx_queue(&local->hw, &txq->txq);
1174} 1174}
1175 1175
1176static inline void schedule_and_wake_txq(struct ieee80211_local *local,
1177 struct txq_info *txqi)
1178{
1179 spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
1180 ieee80211_return_txq(&local->hw, &txqi->txq);
1181 spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
1182 drv_wake_tx_queue(local, txqi);
1183}
1184
1176static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local, 1185static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local,
1177 struct sk_buff *head, 1186 struct sk_buff *head,
1178 struct sk_buff *skb) 1187 struct sk_buff *skb)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7dfb4e2f98b2..d1db27b1e989 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -831,6 +831,8 @@ enum txq_info_flags {
831 * a fq_flow which is already owned by a different tin 831 * a fq_flow which is already owned by a different tin
832 * @def_cvars: codel vars for @def_flow 832 * @def_cvars: codel vars for @def_flow
833 * @frags: used to keep fragments created after dequeue 833 * @frags: used to keep fragments created after dequeue
834 * @schedule_order: used with ieee80211_local->active_txqs
835 * @schedule_round: counter to prevent infinite loops on TXQ scheduling
834 */ 836 */
835struct txq_info { 837struct txq_info {
836 struct fq_tin tin; 838 struct fq_tin tin;
@@ -838,6 +840,8 @@ struct txq_info {
838 struct codel_vars def_cvars; 840 struct codel_vars def_cvars;
839 struct codel_stats cstats; 841 struct codel_stats cstats;
840 struct sk_buff_head frags; 842 struct sk_buff_head frags;
843 struct list_head schedule_order;
844 u16 schedule_round;
841 unsigned long flags; 845 unsigned long flags;
842 846
843 /* keep last! */ 847 /* keep last! */
@@ -1129,6 +1133,11 @@ struct ieee80211_local {
1129 struct codel_vars *cvars; 1133 struct codel_vars *cvars;
1130 struct codel_params cparams; 1134 struct codel_params cparams;
1131 1135
1136 /* protects active_txqs and txqi->schedule_order */
1137 spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
1138 struct list_head active_txqs[IEEE80211_NUM_ACS];
1139 u16 schedule_round[IEEE80211_NUM_ACS];
1140
1132 const struct ieee80211_ops *ops; 1141 const struct ieee80211_ops *ops;
1133 1142
1134 /* 1143 /*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 87a729926734..9b9d6cadf56e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -663,6 +663,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
663 spin_lock_init(&local->rx_path_lock); 663 spin_lock_init(&local->rx_path_lock);
664 spin_lock_init(&local->queue_stop_reason_lock); 664 spin_lock_init(&local->queue_stop_reason_lock);
665 665
666 for (i = 0; i < IEEE80211_NUM_ACS; i++) {
667 INIT_LIST_HEAD(&local->active_txqs[i]);
668 spin_lock_init(&local->active_txq_lock[i]);
669 }
670
666 INIT_LIST_HEAD(&local->chanctx_list); 671 INIT_LIST_HEAD(&local->chanctx_list);
667 mutex_init(&local->chanctx_mtx); 672 mutex_init(&local->chanctx_mtx);
668 673
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c4a8f115ed33..83e1c316a29e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1249,7 +1249,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1249 if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i])) 1249 if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i]))
1250 continue; 1250 continue;
1251 1251
1252 drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); 1252 schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
1253 } 1253 }
1254 1254
1255 skb_queue_head_init(&pending); 1255 skb_queue_head_init(&pending);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index f170d6c6629a..544da6411620 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1449,6 +1449,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
1449 codel_vars_init(&txqi->def_cvars); 1449 codel_vars_init(&txqi->def_cvars);
1450 codel_stats_init(&txqi->cstats); 1450 codel_stats_init(&txqi->cstats);
1451 __skb_queue_head_init(&txqi->frags); 1451 __skb_queue_head_init(&txqi->frags);
1452 INIT_LIST_HEAD(&txqi->schedule_order);
1452 1453
1453 txqi->txq.vif = &sdata->vif; 1454 txqi->txq.vif = &sdata->vif;
1454 1455
@@ -1489,6 +1490,9 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
1489 1490
1490 fq_tin_reset(fq, tin, fq_skb_free_func); 1491 fq_tin_reset(fq, tin, fq_skb_free_func);
1491 ieee80211_purge_tx_queue(&local->hw, &txqi->frags); 1492 ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
1493 spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
1494 list_del_init(&txqi->schedule_order);
1495 spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
1492} 1496}
1493 1497
1494void ieee80211_txq_set_params(struct ieee80211_local *local) 1498void ieee80211_txq_set_params(struct ieee80211_local *local)
@@ -1605,7 +1609,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
1605 ieee80211_txq_enqueue(local, txqi, skb); 1609 ieee80211_txq_enqueue(local, txqi, skb);
1606 spin_unlock_bh(&fq->lock); 1610 spin_unlock_bh(&fq->lock);
1607 1611
1608 drv_wake_tx_queue(local, txqi); 1612 schedule_and_wake_txq(local, txqi);
1609 1613
1610 return true; 1614 return true;
1611} 1615}
@@ -3630,6 +3634,60 @@ out:
3630} 3634}
3631EXPORT_SYMBOL(ieee80211_tx_dequeue); 3635EXPORT_SYMBOL(ieee80211_tx_dequeue);
3632 3636
3637struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
3638{
3639 struct ieee80211_local *local = hw_to_local(hw);
3640 struct txq_info *txqi = NULL;
3641
3642 lockdep_assert_held(&local->active_txq_lock[ac]);
3643
3644 txqi = list_first_entry_or_null(&local->active_txqs[ac],
3645 struct txq_info,
3646 schedule_order);
3647
3648 if (!txqi || txqi->schedule_round == local->schedule_round[ac])
3649 return NULL;
3650
3651 list_del_init(&txqi->schedule_order);
3652 txqi->schedule_round = local->schedule_round[ac];
3653 return &txqi->txq;
3654}
3655EXPORT_SYMBOL(ieee80211_next_txq);
3656
3657void ieee80211_return_txq(struct ieee80211_hw *hw,
3658 struct ieee80211_txq *txq)
3659{
3660 struct ieee80211_local *local = hw_to_local(hw);
3661 struct txq_info *txqi = to_txq_info(txq);
3662
3663 lockdep_assert_held(&local->active_txq_lock[txq->ac]);
3664
3665 if (list_empty(&txqi->schedule_order) &&
3666 (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets))
3667 list_add_tail(&txqi->schedule_order,
3668 &local->active_txqs[txq->ac]);
3669}
3670EXPORT_SYMBOL(ieee80211_return_txq);
3671
3672void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
3673 __acquires(txq_lock)
3674{
3675 struct ieee80211_local *local = hw_to_local(hw);
3676
3677 spin_lock_bh(&local->active_txq_lock[ac]);
3678 local->schedule_round[ac]++;
3679}
3680EXPORT_SYMBOL(ieee80211_txq_schedule_start);
3681
3682void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
3683 __releases(txq_lock)
3684{
3685 struct ieee80211_local *local = hw_to_local(hw);
3686
3687 spin_unlock_bh(&local->active_txq_lock[ac]);
3688}
3689EXPORT_SYMBOL(ieee80211_txq_schedule_end);
3690
3633void __ieee80211_subif_start_xmit(struct sk_buff *skb, 3691void __ieee80211_subif_start_xmit(struct sk_buff *skb,
3634 struct net_device *dev, 3692 struct net_device *dev,
3635 u32 info_flags) 3693 u32 info_flags)