1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 13 Mar 2019 19:09:22 +0100
3 Subject: [PATCH] mac80211: rework locking for txq scheduling / airtime
6 Holding the lock around the entire duration of tx scheduling can create
7 some nasty lock contention, especially when processing airtime information
8 from the tx status or the rx path.
9 Improve locking by only holding the active_txq_lock for lookups / scheduling
12 Signed-off-by: Felix Fietkau <nbd@nbd.name>
15 --- a/include/net/mac80211.h
16 +++ b/include/net/mac80211.h
17 @@ -6269,8 +6269,6 @@ struct sk_buff *ieee80211_tx_dequeue(str
18 * @hw: pointer as obtained from ieee80211_alloc_hw()
19 * @ac: AC number to return packets from.
21 - * Should only be called between calls to ieee80211_txq_schedule_start()
22 - * and ieee80211_txq_schedule_end().
23 * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
24 * is returned, it should be returned with ieee80211_return_txq() after the
25 * driver has finished scheduling it.
26 @@ -6278,51 +6276,41 @@ struct sk_buff *ieee80211_tx_dequeue(str
27 struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
30 - * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
32 - * @hw: pointer as obtained from ieee80211_alloc_hw()
33 - * @txq: pointer obtained from station or virtual interface
35 - * Should only be called between calls to ieee80211_txq_schedule_start()
36 - * and ieee80211_txq_schedule_end().
38 -void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
41 - * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
42 + * ieee80211_txq_schedule_start - start new scheduling round for TXQs
44 * @hw: pointer as obtained from ieee80211_alloc_hw()
45 * @ac: AC number to acquire locks for
47 - * Acquire locks needed to schedule TXQs from the given AC. Should be called
48 - * before ieee80211_next_txq() or ieee80211_return_txq().
49 + * Should be called before ieee80211_next_txq() or ieee80211_return_txq().
51 -void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
52 - __acquires(txq_lock);
53 +void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac);
56 +static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
61 - * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
62 + * ieee80211_schedule_txq - schedule a TXQ for transmission
64 * @hw: pointer as obtained from ieee80211_alloc_hw()
65 - * @ac: AC number to acquire locks for
66 + * @txq: pointer obtained from station or virtual interface
68 - * Release locks previously acquired by ieee80211_txq_schedule_end().
69 + * Schedules a TXQ for transmission if it is not already scheduled.
71 -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
72 - __releases(txq_lock);
73 +void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
76 - * ieee80211_schedule_txq - schedule a TXQ for transmission
77 + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
79 * @hw: pointer as obtained from ieee80211_alloc_hw()
80 * @txq: pointer obtained from station or virtual interface
82 - * Schedules a TXQ for transmission if it is not already scheduled. Takes a
83 - * lock, which means it must *not* be called between
84 - * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end()
86 -void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
87 - __acquires(txq_lock) __releases(txq_lock);
89 +ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
91 + ieee80211_schedule_txq(hw, txq);
95 * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
96 --- a/net/mac80211/tx.c
97 +++ b/net/mac80211/tx.c
98 @@ -3658,16 +3658,17 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
99 struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
101 struct ieee80211_local *local = hw_to_local(hw);
102 + struct ieee80211_txq *ret = NULL;
103 struct txq_info *txqi = NULL;
105 - lockdep_assert_held(&local->active_txq_lock[ac]);
106 + spin_lock_bh(&local->active_txq_lock[ac]);
109 txqi = list_first_entry_or_null(&local->active_txqs[ac],
117 struct sta_info *sta = container_of(txqi->txq.sta,
118 @@ -3684,21 +3685,25 @@ struct ieee80211_txq *ieee80211_next_txq
121 if (txqi->schedule_round == local->schedule_round[ac])
125 list_del_init(&txqi->schedule_order);
126 txqi->schedule_round = local->schedule_round[ac];
131 + spin_unlock_bh(&local->active_txq_lock[ac]);
134 EXPORT_SYMBOL(ieee80211_next_txq);
136 -void ieee80211_return_txq(struct ieee80211_hw *hw,
137 - struct ieee80211_txq *txq)
138 +void ieee80211_schedule_txq(struct ieee80211_hw *hw,
139 + struct ieee80211_txq *txq)
141 struct ieee80211_local *local = hw_to_local(hw);
142 struct txq_info *txqi = to_txq_info(txq);
144 - lockdep_assert_held(&local->active_txq_lock[txq->ac]);
145 + spin_lock_bh(&local->active_txq_lock[txq->ac]);
147 if (list_empty(&txqi->schedule_order) &&
148 (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
149 @@ -3718,17 +3723,7 @@ void ieee80211_return_txq(struct ieee802
150 list_add_tail(&txqi->schedule_order,
151 &local->active_txqs[txq->ac]);
154 -EXPORT_SYMBOL(ieee80211_return_txq);
156 -void ieee80211_schedule_txq(struct ieee80211_hw *hw,
157 - struct ieee80211_txq *txq)
158 - __acquires(txq_lock) __releases(txq_lock)
160 - struct ieee80211_local *local = hw_to_local(hw);
162 - spin_lock_bh(&local->active_txq_lock[txq->ac]);
163 - ieee80211_return_txq(hw, txq);
164 spin_unlock_bh(&local->active_txq_lock[txq->ac]);
166 EXPORT_SYMBOL(ieee80211_schedule_txq);
167 @@ -3741,7 +3736,7 @@ bool ieee80211_txq_may_transmit(struct i
168 struct sta_info *sta;
171 - lockdep_assert_held(&local->active_txq_lock[ac]);
172 + spin_lock_bh(&local->active_txq_lock[ac]);
176 @@ -3771,34 +3766,27 @@ bool ieee80211_txq_may_transmit(struct i
178 sta->airtime[ac].deficit += sta->airtime_weight;
179 list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
180 + spin_unlock_bh(&local->active_txq_lock[ac]);
184 if (!list_empty(&txqi->schedule_order))
185 list_del_init(&txqi->schedule_order);
186 + spin_unlock_bh(&local->active_txq_lock[ac]);
190 EXPORT_SYMBOL(ieee80211_txq_may_transmit);
192 void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
193 - __acquires(txq_lock)
195 struct ieee80211_local *local = hw_to_local(hw);
197 spin_lock_bh(&local->active_txq_lock[ac]);
198 local->schedule_round[ac]++;
200 -EXPORT_SYMBOL(ieee80211_txq_schedule_start);
202 -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
203 - __releases(txq_lock)
205 - struct ieee80211_local *local = hw_to_local(hw);
207 spin_unlock_bh(&local->active_txq_lock[ac]);
209 -EXPORT_SYMBOL(ieee80211_txq_schedule_end);
210 +EXPORT_SYMBOL(ieee80211_txq_schedule_start);
212 void __ieee80211_subif_start_xmit(struct sk_buff *skb,
213 struct net_device *dev,