ff3f0f728a22eb82e5ae5c0e71238340618092a4
[openwrt/staging/hauke.git] /
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
4 fairness
5
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
10 list modifications.
11
12 Signed-off-by: Felix Fietkau <nbd@nbd.name>
13 ---
14
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.
20 *
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);
28
29 /**
30 - * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
31 - *
32 - * @hw: pointer as obtained from ieee80211_alloc_hw()
33 - * @txq: pointer obtained from station or virtual interface
34 - *
35 - * Should only be called between calls to ieee80211_txq_schedule_start()
36 - * and ieee80211_txq_schedule_end().
37 - */
38 -void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
39 -
40 -/**
41 - * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
42 + * ieee80211_txq_schedule_start - start new scheduling round for TXQs
43 *
44 * @hw: pointer as obtained from ieee80211_alloc_hw()
45 * @ac: AC number to acquire locks for
46 *
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().
50 */
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);
54 +
55 +/* (deprecated) */
56 +static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
57 +{
58 +}
59
60 /**
61 - * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
62 + * ieee80211_schedule_txq - schedule a TXQ for transmission
63 *
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
67 *
68 - * Release locks previously acquired by ieee80211_txq_schedule_end().
69 + * Schedules a TXQ for transmission if it is not already scheduled.
70 */
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);
74
75 /**
76 - * ieee80211_schedule_txq - schedule a TXQ for transmission
77 + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
78 *
79 * @hw: pointer as obtained from ieee80211_alloc_hw()
80 * @txq: pointer obtained from station or virtual interface
81 - *
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()
85 */
86 -void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
87 - __acquires(txq_lock) __releases(txq_lock);
88 +static inline void
89 +ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
90 +{
91 + ieee80211_schedule_txq(hw, txq);
92 +}
93
94 /**
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)
100 {
101 struct ieee80211_local *local = hw_to_local(hw);
102 + struct ieee80211_txq *ret = NULL;
103 struct txq_info *txqi = NULL;
104
105 - lockdep_assert_held(&local->active_txq_lock[ac]);
106 + spin_lock_bh(&local->active_txq_lock[ac]);
107
108 begin:
109 txqi = list_first_entry_or_null(&local->active_txqs[ac],
110 struct txq_info,
111 schedule_order);
112 if (!txqi)
113 - return NULL;
114 + goto out;
115
116 if (txqi->txq.sta) {
117 struct sta_info *sta = container_of(txqi->txq.sta,
118 @@ -3684,21 +3685,25 @@ struct ieee80211_txq *ieee80211_next_txq
119
120
121 if (txqi->schedule_round == local->schedule_round[ac])
122 - return NULL;
123 + goto out;
124
125 list_del_init(&txqi->schedule_order);
126 txqi->schedule_round = local->schedule_round[ac];
127 - return &txqi->txq;
128 + ret = &txqi->txq;
129 +
130 +out:
131 + spin_unlock_bh(&local->active_txq_lock[ac]);
132 + return ret;
133 }
134 EXPORT_SYMBOL(ieee80211_next_txq);
135
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)
140 {
141 struct ieee80211_local *local = hw_to_local(hw);
142 struct txq_info *txqi = to_txq_info(txq);
143
144 - lockdep_assert_held(&local->active_txq_lock[txq->ac]);
145 + spin_lock_bh(&local->active_txq_lock[txq->ac]);
146
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]);
152 }
153 -}
154 -EXPORT_SYMBOL(ieee80211_return_txq);
155 -
156 -void ieee80211_schedule_txq(struct ieee80211_hw *hw,
157 - struct ieee80211_txq *txq)
158 - __acquires(txq_lock) __releases(txq_lock)
159 -{
160 - struct ieee80211_local *local = hw_to_local(hw);
161
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]);
165 }
166 EXPORT_SYMBOL(ieee80211_schedule_txq);
167 @@ -3741,7 +3736,7 @@ bool ieee80211_txq_may_transmit(struct i
168 struct sta_info *sta;
169 u8 ac = txq->ac;
170
171 - lockdep_assert_held(&local->active_txq_lock[ac]);
172 + spin_lock_bh(&local->active_txq_lock[ac]);
173
174 if (!txqi->txq.sta)
175 goto out;
176 @@ -3771,34 +3766,27 @@ bool ieee80211_txq_may_transmit(struct i
177
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]);
181
182 return false;
183 out:
184 if (!list_empty(&txqi->schedule_order))
185 list_del_init(&txqi->schedule_order);
186 + spin_unlock_bh(&local->active_txq_lock[ac]);
187
188 return true;
189 }
190 EXPORT_SYMBOL(ieee80211_txq_may_transmit);
191
192 void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
193 - __acquires(txq_lock)
194 {
195 struct ieee80211_local *local = hw_to_local(hw);
196
197 spin_lock_bh(&local->active_txq_lock[ac]);
198 local->schedule_round[ac]++;
199 -}
200 -EXPORT_SYMBOL(ieee80211_txq_schedule_start);
201 -
202 -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
203 - __releases(txq_lock)
204 -{
205 - struct ieee80211_local *local = hw_to_local(hw);
206 -
207 spin_unlock_bh(&local->active_txq_lock[ac]);
208 }
209 -EXPORT_SYMBOL(ieee80211_txq_schedule_end);
210 +EXPORT_SYMBOL(ieee80211_txq_schedule_start);
211
212 void __ieee80211_subif_start_xmit(struct sk_buff *skb,
213 struct net_device *dev,