ef67dd197701880c29a43831a6fc04eaca09d800
[oweals/openwrt.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 @@ -6069,8 +6069,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 @@ -6078,51 +6076,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 @@ -3619,16 +3619,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 @@ -3645,21 +3646,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 @@ -3679,18 +3684,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 -       struct txq_info *txqi = to_txq_info(txq);
162 -
163 -       spin_lock_bh(&local->active_txq_lock[txq->ac]);
164 -       ieee80211_return_txq(hw, txq);
165         spin_unlock_bh(&local->active_txq_lock[txq->ac]);
166  }
167  EXPORT_SYMBOL(ieee80211_schedule_txq);
168 @@ -3703,7 +3697,7 @@ bool ieee80211_txq_may_transmit(struct i
169         struct sta_info *sta;
170         u8 ac = txq->ac;
171  
172 -       lockdep_assert_held(&local->active_txq_lock[ac]);
173 +       spin_lock_bh(&local->active_txq_lock[ac]);
174  
175         if (!txqi->txq.sta)
176                 goto out;
177 @@ -3733,34 +3727,27 @@ bool ieee80211_txq_may_transmit(struct i
178  
179         sta->airtime[ac].deficit += sta->airtime_weight;
180         list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
181 +       spin_unlock_bh(&local->active_txq_lock[ac]);
182  
183         return false;
184  out:
185         if (!list_empty(&txqi->schedule_order))
186                 list_del_init(&txqi->schedule_order);
187 +       spin_unlock_bh(&local->active_txq_lock[ac]);
188  
189         return true;
190  }
191  EXPORT_SYMBOL(ieee80211_txq_may_transmit);
192  
193  void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
194 -       __acquires(txq_lock)
195  {
196         struct ieee80211_local *local = hw_to_local(hw);
197  
198         spin_lock_bh(&local->active_txq_lock[ac]);
199         local->schedule_round[ac]++;
200 -}
201 -EXPORT_SYMBOL(ieee80211_txq_schedule_start);
202 -
203 -void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
204 -       __releases(txq_lock)
205 -{
206 -       struct ieee80211_local *local = hw_to_local(hw);
207 -
208         spin_unlock_bh(&local->active_txq_lock[ac]);
209  }
210 -EXPORT_SYMBOL(ieee80211_txq_schedule_end);
211 +EXPORT_SYMBOL(ieee80211_txq_schedule_start);
212  
213  void __ieee80211_subif_start_xmit(struct sk_buff *skb,
214                                   struct net_device *dev,