diff options
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 55 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 210 | ||||
-rw-r--r-- | include/net/mac80211.h | 37 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 6 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 12 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 7 | ||||
-rw-r--r-- | net/mac80211/trace.h | 32 | ||||
-rw-r--r-- | net/mac80211/tx.c | 49 |
15 files changed, 173 insertions, 262 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b29fdbd21ead..90d16a38475f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c | |||
@@ -2574,9 +2574,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, | |||
2574 | 2574 | ||
2575 | mutex_init(&ar->conf_mutex); | 2575 | mutex_init(&ar->conf_mutex); |
2576 | spin_lock_init(&ar->data_lock); | 2576 | spin_lock_init(&ar->data_lock); |
2577 | spin_lock_init(&ar->txqs_lock); | ||
2578 | 2577 | ||
2579 | INIT_LIST_HEAD(&ar->txqs); | ||
2580 | INIT_LIST_HEAD(&ar->peers); | 2578 | INIT_LIST_HEAD(&ar->peers); |
2581 | init_waitqueue_head(&ar->peer_mapping_wq); | 2579 | init_waitqueue_head(&ar->peer_mapping_wq); |
2582 | init_waitqueue_head(&ar->htt.empty_tx_wq); | 2580 | init_waitqueue_head(&ar->htt.empty_tx_wq); |
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 643041ef3271..4a79fdce9a08 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -347,7 +347,6 @@ struct ath10k_peer { | |||
347 | }; | 347 | }; |
348 | 348 | ||
349 | struct ath10k_txq { | 349 | struct ath10k_txq { |
350 | struct list_head list; | ||
351 | unsigned long num_fw_queued; | 350 | unsigned long num_fw_queued; |
352 | unsigned long num_push_allowed; | 351 | unsigned long num_push_allowed; |
353 | }; | 352 | }; |
@@ -895,10 +894,7 @@ struct ath10k { | |||
895 | 894 | ||
896 | /* protects shared structure data */ | 895 | /* protects shared structure data */ |
897 | spinlock_t data_lock; | 896 | spinlock_t data_lock; |
898 | /* protects: ar->txqs, artxq->list */ | ||
899 | spinlock_t txqs_lock; | ||
900 | 897 | ||
901 | struct list_head txqs; | ||
902 | struct list_head arvifs; | 898 | struct list_head arvifs; |
903 | struct list_head peers; | 899 | struct list_head peers; |
904 | struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS]; | 900 | struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS]; |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0a947eef348d..cca4cd82853b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -3830,12 +3830,10 @@ static void ath10k_mac_txq_init(struct ieee80211_txq *txq) | |||
3830 | return; | 3830 | return; |
3831 | 3831 | ||
3832 | artxq = (void *)txq->drv_priv; | 3832 | artxq = (void *)txq->drv_priv; |
3833 | INIT_LIST_HEAD(&artxq->list); | ||
3834 | } | 3833 | } |
3835 | 3834 | ||
3836 | static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) | 3835 | static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) |
3837 | { | 3836 | { |
3838 | struct ath10k_txq *artxq; | ||
3839 | struct ath10k_skb_cb *cb; | 3837 | struct ath10k_skb_cb *cb; |
3840 | struct sk_buff *msdu; | 3838 | struct sk_buff *msdu; |
3841 | int msdu_id; | 3839 | int msdu_id; |
@@ -3843,12 +3841,6 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) | |||
3843 | if (!txq) | 3841 | if (!txq) |
3844 | return; | 3842 | return; |
3845 | 3843 | ||
3846 | artxq = (void *)txq->drv_priv; | ||
3847 | spin_lock_bh(&ar->txqs_lock); | ||
3848 | if (!list_empty(&artxq->list)) | ||
3849 | list_del_init(&artxq->list); | ||
3850 | spin_unlock_bh(&ar->txqs_lock); | ||
3851 | |||
3852 | spin_lock_bh(&ar->htt.tx_lock); | 3844 | spin_lock_bh(&ar->htt.tx_lock); |
3853 | idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) { | 3845 | idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) { |
3854 | cb = ATH10K_SKB_CB(msdu); | 3846 | cb = ATH10K_SKB_CB(msdu); |
@@ -3978,23 +3970,17 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, | |||
3978 | void ath10k_mac_tx_push_pending(struct ath10k *ar) | 3970 | void ath10k_mac_tx_push_pending(struct ath10k *ar) |
3979 | { | 3971 | { |
3980 | struct ieee80211_hw *hw = ar->hw; | 3972 | struct ieee80211_hw *hw = ar->hw; |
3981 | struct ieee80211_txq *txq; | 3973 | struct ieee80211_txq *txq, *first = NULL; |
3982 | struct ath10k_txq *artxq; | ||
3983 | struct ath10k_txq *last; | ||
3984 | int ret; | 3974 | int ret; |
3985 | int max; | 3975 | int max; |
3986 | 3976 | ||
3987 | if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) | 3977 | if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) |
3988 | return; | 3978 | return; |
3989 | 3979 | ||
3990 | spin_lock_bh(&ar->txqs_lock); | ||
3991 | rcu_read_lock(); | 3980 | rcu_read_lock(); |
3992 | 3981 | ||
3993 | last = list_last_entry(&ar->txqs, struct ath10k_txq, list); | 3982 | txq = ieee80211_next_txq(hw); |
3994 | while (!list_empty(&ar->txqs)) { | 3983 | while (txq) { |
3995 | artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list); | ||
3996 | txq = container_of((void *)artxq, struct ieee80211_txq, | ||
3997 | drv_priv); | ||
3998 | 3984 | ||
3999 | /* Prevent aggressive sta/tid taking over tx queue */ | 3985 | /* Prevent aggressive sta/tid taking over tx queue */ |
4000 | max = 16; | 3986 | max = 16; |
@@ -4005,18 +3991,21 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar) | |||
4005 | break; | 3991 | break; |
4006 | } | 3992 | } |
4007 | 3993 | ||
4008 | list_del_init(&artxq->list); | ||
4009 | if (ret != -ENOENT) | 3994 | if (ret != -ENOENT) |
4010 | list_add_tail(&artxq->list, &ar->txqs); | 3995 | ieee80211_schedule_txq(hw, txq); |
4011 | 3996 | ||
4012 | ath10k_htt_tx_txq_update(hw, txq); | 3997 | ath10k_htt_tx_txq_update(hw, txq); |
4013 | 3998 | ||
4014 | if (artxq == last || (ret < 0 && ret != -ENOENT)) | 3999 | if (first == txq || (ret < 0 && ret != -ENOENT)) |
4015 | break; | 4000 | break; |
4001 | |||
4002 | if (!first) | ||
4003 | first = txq; | ||
4004 | |||
4005 | txq = ieee80211_next_txq(hw); | ||
4016 | } | 4006 | } |
4017 | 4007 | ||
4018 | rcu_read_unlock(); | 4008 | rcu_read_unlock(); |
4019 | spin_unlock_bh(&ar->txqs_lock); | ||
4020 | } | 4009 | } |
4021 | 4010 | ||
4022 | /************/ | 4011 | /************/ |
@@ -4250,34 +4239,22 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, | |||
4250 | } | 4239 | } |
4251 | } | 4240 | } |
4252 | 4241 | ||
4253 | static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, | 4242 | static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw) |
4254 | struct ieee80211_txq *txq) | ||
4255 | { | 4243 | { |
4256 | struct ath10k *ar = hw->priv; | 4244 | struct ieee80211_txq *txq; |
4257 | struct ath10k_txq *artxq = (void *)txq->drv_priv; | ||
4258 | struct ieee80211_txq *f_txq; | ||
4259 | struct ath10k_txq *f_artxq; | ||
4260 | int ret = 0; | 4245 | int ret = 0; |
4261 | int max = 16; | 4246 | int max = 16; |
4262 | 4247 | ||
4263 | spin_lock_bh(&ar->txqs_lock); | 4248 | txq = ieee80211_next_txq(hw); |
4264 | if (list_empty(&artxq->list)) | ||
4265 | list_add_tail(&artxq->list, &ar->txqs); | ||
4266 | |||
4267 | f_artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list); | ||
4268 | f_txq = container_of((void *)f_artxq, struct ieee80211_txq, drv_priv); | ||
4269 | list_del_init(&f_artxq->list); | ||
4270 | 4249 | ||
4271 | while (ath10k_mac_tx_can_push(hw, f_txq) && max--) { | 4250 | while (ath10k_mac_tx_can_push(hw, txq) && max--) { |
4272 | ret = ath10k_mac_tx_push_txq(hw, f_txq); | 4251 | ret = ath10k_mac_tx_push_txq(hw, txq); |
4273 | if (ret) | 4252 | if (ret) |
4274 | break; | 4253 | break; |
4275 | } | 4254 | } |
4276 | if (ret != -ENOENT) | 4255 | if (ret != -ENOENT) |
4277 | list_add_tail(&f_artxq->list, &ar->txqs); | 4256 | ieee80211_schedule_txq(hw, txq); |
4278 | spin_unlock_bh(&ar->txqs_lock); | ||
4279 | 4257 | ||
4280 | ath10k_htt_tx_txq_update(hw, f_txq); | ||
4281 | ath10k_htt_tx_txq_update(hw, txq); | 4258 | ath10k_htt_tx_txq_update(hw, txq); |
4282 | } | 4259 | } |
4283 | 4260 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ef0de4f1312c..face2bb7f357 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -246,12 +246,8 @@ struct ath_atx_tid { | |||
246 | s8 bar_index; | 246 | s8 bar_index; |
247 | bool active; | 247 | bool active; |
248 | bool clear_ps_filter; | 248 | bool clear_ps_filter; |
249 | bool has_queued; | ||
250 | }; | 249 | }; |
251 | 250 | ||
252 | void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid); | ||
253 | void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid); | ||
254 | |||
255 | struct ath_node { | 251 | struct ath_node { |
256 | struct ath_softc *sc; | 252 | struct ath_softc *sc; |
257 | struct ieee80211_sta *sta; /* station struct we're part of */ | 253 | struct ieee80211_sta *sta; /* station struct we're part of */ |
@@ -591,8 +587,7 @@ bool ath_drain_all_txq(struct ath_softc *sc); | |||
591 | void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); | 587 | void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); |
592 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); | 588 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); |
593 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); | 589 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); |
594 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); | 590 | void ath_txq_schedule(struct ath_softc *sc); |
595 | void ath_txq_schedule_all(struct ath_softc *sc); | ||
596 | int ath_tx_init(struct ath_softc *sc, int nbufs); | 591 | int ath_tx_init(struct ath_softc *sc, int nbufs); |
597 | int ath_txq_update(struct ath_softc *sc, int qnum, | 592 | int ath_txq_update(struct ath_softc *sc, int qnum, |
598 | struct ath9k_tx_queue_info *q); | 593 | struct ath9k_tx_queue_info *q); |
@@ -618,7 +613,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, | |||
618 | u16 tids, int nframes, | 613 | u16 tids, int nframes, |
619 | enum ieee80211_frame_release_type reason, | 614 | enum ieee80211_frame_release_type reason, |
620 | bool more_data); | 615 | bool more_data); |
621 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); | 616 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw); |
622 | 617 | ||
623 | /********/ | 618 | /********/ |
624 | /* VIFs */ | 619 | /* VIFs */ |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a3be8add56e1..f7dfcdf508ce 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -266,7 +266,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
266 | } | 266 | } |
267 | work: | 267 | work: |
268 | ath_restart_work(sc); | 268 | ath_restart_work(sc); |
269 | ath_txq_schedule_all(sc); | 269 | ath_txq_schedule(sc); |
270 | } | 270 | } |
271 | 271 | ||
272 | sc->gtt_cnt = 0; | 272 | sc->gtt_cnt = 0; |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2197aee2bb72..a768e841524d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -1057,8 +1057,6 @@ static void ath_rx_count_airtime(struct ath_softc *sc, | |||
1057 | if (!!(sc->airtime_flags & AIRTIME_USE_RX)) { | 1057 | if (!!(sc->airtime_flags & AIRTIME_USE_RX)) { |
1058 | spin_lock_bh(&acq->lock); | 1058 | spin_lock_bh(&acq->lock); |
1059 | an->airtime_deficit[acno] -= airtime; | 1059 | an->airtime_deficit[acno] -= airtime; |
1060 | if (an->airtime_deficit[acno] <= 0) | ||
1061 | __ath_tx_queue_tid(sc, ATH_AN_2_TID(an, tidno)); | ||
1062 | spin_unlock_bh(&acq->lock); | 1060 | spin_unlock_bh(&acq->lock); |
1063 | } | 1061 | } |
1064 | ath_debug_airtime(sc, an, airtime, 0); | 1062 | ath_debug_airtime(sc, an, airtime, 0); |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 396bf05c6bf6..bd438062a6db 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -112,62 +112,11 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) | |||
112 | ath_tx_status(hw, skb); | 112 | ath_tx_status(hw, skb); |
113 | } | 113 | } |
114 | 114 | ||
115 | void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | 115 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw) |
116 | { | ||
117 | struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; | ||
118 | struct ath_chanctx *ctx = avp->chanctx; | ||
119 | struct ath_acq *acq; | ||
120 | struct list_head *tid_list; | ||
121 | u8 acno = TID_TO_WME_AC(tid->tidno); | ||
122 | |||
123 | if (!ctx || !list_empty(&tid->list)) | ||
124 | return; | ||
125 | |||
126 | |||
127 | acq = &ctx->acq[acno]; | ||
128 | if ((sc->airtime_flags & AIRTIME_USE_NEW_QUEUES) && | ||
129 | tid->an->airtime_deficit[acno] > 0) | ||
130 | tid_list = &acq->acq_new; | ||
131 | else | ||
132 | tid_list = &acq->acq_old; | ||
133 | |||
134 | list_add_tail(&tid->list, tid_list); | ||
135 | } | ||
136 | |||
137 | void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | ||
138 | { | ||
139 | struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; | ||
140 | struct ath_chanctx *ctx = avp->chanctx; | ||
141 | struct ath_acq *acq; | ||
142 | |||
143 | if (!ctx || !list_empty(&tid->list)) | ||
144 | return; | ||
145 | |||
146 | acq = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; | ||
147 | spin_lock_bh(&acq->lock); | ||
148 | __ath_tx_queue_tid(sc, tid); | ||
149 | spin_unlock_bh(&acq->lock); | ||
150 | } | ||
151 | |||
152 | |||
153 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) | ||
154 | { | 116 | { |
155 | struct ath_softc *sc = hw->priv; | 117 | struct ath_softc *sc = hw->priv; |
156 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
157 | struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; | ||
158 | struct ath_txq *txq = tid->txq; | ||
159 | |||
160 | ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", | ||
161 | queue->sta ? queue->sta->addr : queue->vif->addr, | ||
162 | tid->tidno); | ||
163 | |||
164 | ath_txq_lock(sc, txq); | ||
165 | 118 | ||
166 | tid->has_queued = true; | 119 | ath_txq_schedule(sc); |
167 | ath_tx_queue_tid(sc, tid); | ||
168 | ath_txq_schedule(sc, txq); | ||
169 | |||
170 | ath_txq_unlock(sc, txq); | ||
171 | } | 120 | } |
172 | 121 | ||
173 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) | 122 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) |
@@ -230,14 +179,9 @@ ath_tid_pull(struct ath_atx_tid *tid) | |||
230 | struct ath_frame_info *fi; | 179 | struct ath_frame_info *fi; |
231 | int q; | 180 | int q; |
232 | 181 | ||
233 | if (!tid->has_queued) | ||
234 | return NULL; | ||
235 | |||
236 | skb = ieee80211_tx_dequeue(hw, txq); | 182 | skb = ieee80211_tx_dequeue(hw, txq); |
237 | if (!skb) { | 183 | if (!skb) |
238 | tid->has_queued = false; | ||
239 | return NULL; | 184 | return NULL; |
240 | } | ||
241 | 185 | ||
242 | if (ath_tx_prepare(hw, skb, &txctl)) { | 186 | if (ath_tx_prepare(hw, skb, &txctl)) { |
243 | ieee80211_free_txskb(hw, skb); | 187 | ieee80211_free_txskb(hw, skb); |
@@ -254,12 +198,6 @@ ath_tid_pull(struct ath_atx_tid *tid) | |||
254 | return skb; | 198 | return skb; |
255 | } | 199 | } |
256 | 200 | ||
257 | |||
258 | static bool ath_tid_has_buffered(struct ath_atx_tid *tid) | ||
259 | { | ||
260 | return !skb_queue_empty(&tid->retry_q) || tid->has_queued; | ||
261 | } | ||
262 | |||
263 | static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) | 201 | static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) |
264 | { | 202 | { |
265 | struct sk_buff *skb; | 203 | struct sk_buff *skb; |
@@ -671,7 +609,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
671 | 609 | ||
672 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); | 610 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); |
673 | if (!an->sleeping) { | 611 | if (!an->sleeping) { |
674 | ath_tx_queue_tid(sc, tid); | 612 | struct ieee80211_txq *queue = container_of( |
613 | (void *)tid, struct ieee80211_txq, drv_priv); | ||
614 | |||
615 | ieee80211_schedule_txq(sc->hw, queue); | ||
675 | 616 | ||
676 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) | 617 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) |
677 | tid->clear_ps_filter = true; | 618 | tid->clear_ps_filter = true; |
@@ -719,8 +660,6 @@ static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an, | |||
719 | 660 | ||
720 | spin_lock_bh(&acq->lock); | 661 | spin_lock_bh(&acq->lock); |
721 | an->airtime_deficit[q] -= airtime; | 662 | an->airtime_deficit[q] -= airtime; |
722 | if (an->airtime_deficit[q] <= 0) | ||
723 | __ath_tx_queue_tid(sc, tid); | ||
724 | spin_unlock_bh(&acq->lock); | 663 | spin_unlock_bh(&acq->lock); |
725 | } | 664 | } |
726 | ath_debug_airtime(sc, an, 0, airtime); | 665 | ath_debug_airtime(sc, an, 0, airtime); |
@@ -770,8 +709,6 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, | |||
770 | } else | 709 | } else |
771 | ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); | 710 | ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); |
772 | 711 | ||
773 | if (!flush) | ||
774 | ath_txq_schedule(sc, txq); | ||
775 | } | 712 | } |
776 | 713 | ||
777 | static bool ath_lookup_legacy(struct ath_buf *bf) | 714 | static bool ath_lookup_legacy(struct ath_buf *bf) |
@@ -1506,8 +1443,8 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, | |||
1506 | } while (1); | 1443 | } while (1); |
1507 | } | 1444 | } |
1508 | 1445 | ||
1509 | static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | 1446 | static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, |
1510 | struct ath_atx_tid *tid) | 1447 | struct ath_atx_tid *tid) |
1511 | { | 1448 | { |
1512 | struct ath_buf *bf; | 1449 | struct ath_buf *bf; |
1513 | struct ieee80211_tx_info *tx_info; | 1450 | struct ieee80211_tx_info *tx_info; |
@@ -1515,21 +1452,18 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
1515 | int aggr_len = 0; | 1452 | int aggr_len = 0; |
1516 | bool aggr; | 1453 | bool aggr; |
1517 | 1454 | ||
1518 | if (!ath_tid_has_buffered(tid)) | ||
1519 | return false; | ||
1520 | |||
1521 | INIT_LIST_HEAD(&bf_q); | 1455 | INIT_LIST_HEAD(&bf_q); |
1522 | 1456 | ||
1523 | bf = ath_tx_get_tid_subframe(sc, txq, tid); | 1457 | bf = ath_tx_get_tid_subframe(sc, txq, tid); |
1524 | if (!bf) | 1458 | if (!bf) |
1525 | return false; | 1459 | return -ENOENT; |
1526 | 1460 | ||
1527 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | 1461 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); |
1528 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); | 1462 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); |
1529 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || | 1463 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || |
1530 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { | 1464 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { |
1531 | __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); | 1465 | __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); |
1532 | return false; | 1466 | return -ENOBUFS; |
1533 | } | 1467 | } |
1534 | 1468 | ||
1535 | ath_set_rates(tid->an->vif, tid->an->sta, bf); | 1469 | ath_set_rates(tid->an->vif, tid->an->sta, bf); |
@@ -1539,7 +1473,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
1539 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf); | 1473 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf); |
1540 | 1474 | ||
1541 | if (list_empty(&bf_q)) | 1475 | if (list_empty(&bf_q)) |
1542 | return false; | 1476 | return -ENOENT; |
1543 | 1477 | ||
1544 | if (tid->clear_ps_filter || tid->an->no_ps_filter) { | 1478 | if (tid->clear_ps_filter || tid->an->no_ps_filter) { |
1545 | tid->clear_ps_filter = false; | 1479 | tid->clear_ps_filter = false; |
@@ -1548,7 +1482,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
1548 | 1482 | ||
1549 | ath_tx_fill_desc(sc, bf, txq, aggr_len); | 1483 | ath_tx_fill_desc(sc, bf, txq, aggr_len); |
1550 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); | 1484 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); |
1551 | return true; | 1485 | return 0; |
1552 | } | 1486 | } |
1553 | 1487 | ||
1554 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | 1488 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, |
@@ -1611,52 +1545,49 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, | |||
1611 | { | 1545 | { |
1612 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1546 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1613 | struct ath_atx_tid *tid; | 1547 | struct ath_atx_tid *tid; |
1614 | struct ath_txq *txq; | 1548 | struct ieee80211_txq *queue; |
1615 | int tidno; | 1549 | int tidno; |
1616 | 1550 | ||
1617 | ath_dbg(common, XMIT, "%s called\n", __func__); | 1551 | ath_dbg(common, XMIT, "%s called\n", __func__); |
1618 | 1552 | ||
1619 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | 1553 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { |
1620 | tid = ath_node_to_tid(an, tidno); | 1554 | tid = ath_node_to_tid(an, tidno); |
1621 | txq = tid->txq; | 1555 | queue = container_of((void *)tid, |
1622 | 1556 | struct ieee80211_txq, drv_priv); | |
1623 | ath_txq_lock(sc, txq); | ||
1624 | |||
1625 | if (list_empty(&tid->list)) { | ||
1626 | ath_txq_unlock(sc, txq); | ||
1627 | continue; | ||
1628 | } | ||
1629 | 1557 | ||
1630 | if (!skb_queue_empty(&tid->retry_q)) | 1558 | if (!skb_queue_empty(&tid->retry_q)) |
1631 | ieee80211_sta_set_buffered(sta, tid->tidno, true); | 1559 | ieee80211_sta_set_buffered(sta, tid->tidno, true); |
1632 | 1560 | ||
1633 | list_del_init(&tid->list); | ||
1634 | |||
1635 | ath_txq_unlock(sc, txq); | ||
1636 | } | 1561 | } |
1637 | } | 1562 | } |
1638 | 1563 | ||
1639 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) | 1564 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) |
1640 | { | 1565 | { |
1641 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1566 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1567 | struct ieee80211_txq *queue; | ||
1642 | struct ath_atx_tid *tid; | 1568 | struct ath_atx_tid *tid; |
1643 | struct ath_txq *txq; | 1569 | struct ath_txq *txq; |
1644 | int tidno; | 1570 | int tidno; |
1571 | bool sched, wake = false; | ||
1645 | 1572 | ||
1646 | ath_dbg(common, XMIT, "%s called\n", __func__); | 1573 | ath_dbg(common, XMIT, "%s called\n", __func__); |
1647 | 1574 | ||
1648 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | 1575 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { |
1649 | tid = ath_node_to_tid(an, tidno); | 1576 | tid = ath_node_to_tid(an, tidno); |
1650 | txq = tid->txq; | 1577 | txq = tid->txq; |
1578 | queue = container_of((void *)tid, | ||
1579 | struct ieee80211_txq, drv_priv); | ||
1651 | 1580 | ||
1652 | ath_txq_lock(sc, txq); | 1581 | ath_txq_lock(sc, txq); |
1653 | tid->clear_ps_filter = true; | 1582 | tid->clear_ps_filter = true; |
1654 | if (ath_tid_has_buffered(tid)) { | 1583 | sched = !skb_queue_empty(&tid->retry_q); |
1655 | ath_tx_queue_tid(sc, tid); | 1584 | ath_txq_unlock(sc, txq); |
1656 | ath_txq_schedule(sc, txq); | 1585 | |
1657 | } | 1586 | if (sched && ieee80211_schedule_txq(sc->hw, queue)) |
1658 | ath_txq_unlock_complete(sc, txq); | 1587 | wake = true; |
1659 | } | 1588 | } |
1589 | if (wake) | ||
1590 | ath_txq_schedule(sc); | ||
1660 | } | 1591 | } |
1661 | 1592 | ||
1662 | void ath9k_release_buffered_frames(struct ieee80211_hw *hw, | 1593 | void ath9k_release_buffered_frames(struct ieee80211_hw *hw, |
@@ -1948,86 +1879,44 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) | |||
1948 | /* For each acq entry, for each tid, try to schedule packets | 1879 | /* For each acq entry, for each tid, try to schedule packets |
1949 | * for transmit until ampdu_depth has reached min Q depth. | 1880 | * for transmit until ampdu_depth has reached min Q depth. |
1950 | */ | 1881 | */ |
1951 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | 1882 | void ath_txq_schedule(struct ath_softc *sc) |
1952 | { | 1883 | { |
1884 | struct ieee80211_hw *hw = sc->hw; | ||
1953 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1885 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1886 | struct ieee80211_txq *queue; | ||
1954 | struct ath_atx_tid *tid; | 1887 | struct ath_atx_tid *tid; |
1955 | struct list_head *tid_list; | 1888 | struct ath_txq *txq; |
1956 | struct ath_acq *acq; | 1889 | int ret = 0; |
1957 | bool active = AIRTIME_ACTIVE(sc->airtime_flags); | ||
1958 | 1890 | ||
1959 | if (txq->mac80211_qnum < 0) | 1891 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) |
1960 | return; | 1892 | return; |
1961 | 1893 | ||
1962 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) | 1894 | queue = ieee80211_next_txq(hw); |
1895 | if (!queue) | ||
1963 | return; | 1896 | return; |
1964 | 1897 | ||
1965 | spin_lock_bh(&sc->chan_lock); | 1898 | tid = (struct ath_atx_tid *)queue->drv_priv; |
1966 | rcu_read_lock(); | 1899 | txq = tid->txq; |
1967 | acq = &sc->cur_chan->acq[txq->mac80211_qnum]; | ||
1968 | 1900 | ||
1969 | if (sc->cur_chan->stopped) | 1901 | ath_txq_lock(sc, txq); |
1902 | if (txq->mac80211_qnum < 0) | ||
1970 | goto out; | 1903 | goto out; |
1971 | 1904 | ||
1972 | begin: | 1905 | spin_lock_bh(&sc->chan_lock); |
1973 | tid_list = &acq->acq_new; | 1906 | rcu_read_lock(); |
1974 | if (list_empty(tid_list)) { | ||
1975 | tid_list = &acq->acq_old; | ||
1976 | if (list_empty(tid_list)) | ||
1977 | goto out; | ||
1978 | } | ||
1979 | tid = list_first_entry(tid_list, struct ath_atx_tid, list); | ||
1980 | |||
1981 | if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) { | ||
1982 | spin_lock_bh(&acq->lock); | ||
1983 | tid->an->airtime_deficit[txq->mac80211_qnum] += ATH_AIRTIME_QUANTUM; | ||
1984 | list_move_tail(&tid->list, &acq->acq_old); | ||
1985 | spin_unlock_bh(&acq->lock); | ||
1986 | goto begin; | ||
1987 | } | ||
1988 | |||
1989 | if (!ath_tid_has_buffered(tid)) { | ||
1990 | spin_lock_bh(&acq->lock); | ||
1991 | if ((tid_list == &acq->acq_new) && !list_empty(&acq->acq_old)) | ||
1992 | list_move_tail(&tid->list, &acq->acq_old); | ||
1993 | else { | ||
1994 | list_del_init(&tid->list); | ||
1995 | } | ||
1996 | spin_unlock_bh(&acq->lock); | ||
1997 | goto begin; | ||
1998 | } | ||
1999 | |||
2000 | 1907 | ||
2001 | /* | 1908 | if (!sc->cur_chan->stopped) |
2002 | * If we succeed in scheduling something, immediately restart to make | 1909 | ret = ath_tx_sched_aggr(sc, txq, tid); |
2003 | * sure we keep the HW busy. | ||
2004 | */ | ||
2005 | if(ath_tx_sched_aggr(sc, txq, tid)) { | ||
2006 | if (!active) { | ||
2007 | spin_lock_bh(&acq->lock); | ||
2008 | list_move_tail(&tid->list, &acq->acq_old); | ||
2009 | spin_unlock_bh(&acq->lock); | ||
2010 | } | ||
2011 | goto begin; | ||
2012 | } | ||
2013 | 1910 | ||
2014 | out: | ||
2015 | rcu_read_unlock(); | 1911 | rcu_read_unlock(); |
2016 | spin_unlock_bh(&sc->chan_lock); | 1912 | spin_unlock_bh(&sc->chan_lock); |
2017 | } | ||
2018 | 1913 | ||
2019 | void ath_txq_schedule_all(struct ath_softc *sc) | 1914 | out: |
2020 | { | ||
2021 | struct ath_txq *txq; | ||
2022 | int i; | ||
2023 | 1915 | ||
2024 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | 1916 | if (ret != -ENOENT) |
2025 | txq = sc->tx.txq_map[i]; | 1917 | ieee80211_schedule_txq(hw, queue); |
2026 | 1918 | ||
2027 | spin_lock_bh(&txq->axq_lock); | 1919 | ath_txq_unlock(sc, txq); |
2028 | ath_txq_schedule(sc, txq); | ||
2029 | spin_unlock_bh(&txq->axq_lock); | ||
2030 | } | ||
2031 | } | 1920 | } |
2032 | 1921 | ||
2033 | /***********/ | 1922 | /***********/ |
@@ -2645,7 +2534,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2645 | 2534 | ||
2646 | if (list_empty(&txq->axq_q)) { | 2535 | if (list_empty(&txq->axq_q)) { |
2647 | txq->axq_link = NULL; | 2536 | txq->axq_link = NULL; |
2648 | ath_txq_schedule(sc, txq); | ||
2649 | break; | 2537 | break; |
2650 | } | 2538 | } |
2651 | bf = list_first_entry(&txq->axq_q, struct ath_buf, list); | 2539 | bf = list_first_entry(&txq->axq_q, struct ath_buf, list); |
@@ -2697,6 +2585,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2697 | ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); | 2585 | ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); |
2698 | } | 2586 | } |
2699 | ath_txq_unlock_complete(sc, txq); | 2587 | ath_txq_unlock_complete(sc, txq); |
2588 | ath_txq_schedule(sc); | ||
2700 | } | 2589 | } |
2701 | 2590 | ||
2702 | void ath_tx_tasklet(struct ath_softc *sc) | 2591 | void ath_tx_tasklet(struct ath_softc *sc) |
@@ -2711,6 +2600,7 @@ void ath_tx_tasklet(struct ath_softc *sc) | |||
2711 | ath_tx_processq(sc, &sc->tx.txq[i]); | 2600 | ath_tx_processq(sc, &sc->tx.txq[i]); |
2712 | } | 2601 | } |
2713 | rcu_read_unlock(); | 2602 | rcu_read_unlock(); |
2603 | ath_txq_schedule(sc); | ||
2714 | } | 2604 | } |
2715 | 2605 | ||
2716 | void ath_tx_edma_tasklet(struct ath_softc *sc) | 2606 | void ath_tx_edma_tasklet(struct ath_softc *sc) |
@@ -2796,6 +2686,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
2796 | ath_txq_unlock_complete(sc, txq); | 2686 | ath_txq_unlock_complete(sc, txq); |
2797 | } | 2687 | } |
2798 | rcu_read_unlock(); | 2688 | rcu_read_unlock(); |
2689 | ath_txq_schedule(sc); | ||
2799 | } | 2690 | } |
2800 | 2691 | ||
2801 | /*****************/ | 2692 | /*****************/ |
@@ -2875,7 +2766,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) | |||
2875 | tid->baw_head = tid->baw_tail = 0; | 2766 | tid->baw_head = tid->baw_tail = 0; |
2876 | tid->active = false; | 2767 | tid->active = false; |
2877 | tid->clear_ps_filter = true; | 2768 | tid->clear_ps_filter = true; |
2878 | tid->has_queued = false; | ||
2879 | __skb_queue_head_init(&tid->retry_q); | 2769 | __skb_queue_head_init(&tid->retry_q); |
2880 | INIT_LIST_HEAD(&tid->list); | 2770 | INIT_LIST_HEAD(&tid->list); |
2881 | acno = TID_TO_WME_AC(tidno); | 2771 | acno = TID_TO_WME_AC(tidno); |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 906e90223066..45155803c875 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -105,9 +105,12 @@ | |||
105 | * The driver is expected to initialize its private per-queue data for stations | 105 | * The driver is expected to initialize its private per-queue data for stations |
106 | * and interfaces in the .add_interface and .sta_add ops. | 106 | * and interfaces in the .add_interface and .sta_add ops. |
107 | * | 107 | * |
108 | * The driver can't access the queue directly. To dequeue a frame, it calls | 108 | * The driver can't access the queue directly. To obtain the next queue to pull |
109 | * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it | 109 | * frames from, the driver calls ieee80211_next_txq(). To dequeue a frame from a |
110 | * calls the .wake_tx_queue driver op. | 110 | * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a |
111 | * queue, it calls the .wake_tx_queue driver op. The driver is expected to | ||
112 | * re-schedule the txq using ieee80211_schedule_txq() if it is still active | ||
113 | * after the driver has finished pulling packets from it. | ||
111 | * | 114 | * |
112 | * For AP powersave TIM handling, the driver only needs to indicate if it has | 115 | * For AP powersave TIM handling, the driver only needs to indicate if it has |
113 | * buffered packets in the driver specific data structures by calling | 116 | * buffered packets in the driver specific data structures by calling |
@@ -3731,8 +3734,7 @@ struct ieee80211_ops { | |||
3731 | struct ieee80211_vif *vif, | 3734 | struct ieee80211_vif *vif, |
3732 | struct ieee80211_tdls_ch_sw_params *params); | 3735 | struct ieee80211_tdls_ch_sw_params *params); |
3733 | 3736 | ||
3734 | void (*wake_tx_queue)(struct ieee80211_hw *hw, | 3737 | void (*wake_tx_queue)(struct ieee80211_hw *hw); |
3735 | struct ieee80211_txq *txq); | ||
3736 | void (*sync_rx_queues)(struct ieee80211_hw *hw); | 3738 | void (*sync_rx_queues)(struct ieee80211_hw *hw); |
3737 | 3739 | ||
3738 | int (*start_nan)(struct ieee80211_hw *hw, | 3740 | int (*start_nan)(struct ieee80211_hw *hw, |
@@ -5883,7 +5885,7 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); | |||
5883 | * ieee80211_tx_dequeue - dequeue a packet from a software tx queue | 5885 | * ieee80211_tx_dequeue - dequeue a packet from a software tx queue |
5884 | * | 5886 | * |
5885 | * @hw: pointer as obtained from ieee80211_alloc_hw() | 5887 | * @hw: pointer as obtained from ieee80211_alloc_hw() |
5886 | * @txq: pointer obtained from station or virtual interface | 5888 | * @txq: pointer obtained from ieee80211_next_txq() |
5887 | * | 5889 | * |
5888 | * Returns the skb if successful, %NULL if no frame was available. | 5890 | * Returns the skb if successful, %NULL if no frame was available. |
5889 | */ | 5891 | */ |
@@ -5891,6 +5893,29 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
5891 | struct ieee80211_txq *txq); | 5893 | struct ieee80211_txq *txq); |
5892 | 5894 | ||
5893 | /** | 5895 | /** |
5896 | * ieee80211_schedule_txq - add txq to scheduling loop | ||
5897 | * | ||
5898 | * @hw: pointer as obtained from ieee80211_alloc_hw() | ||
5899 | * @txq: pointer obtained from station or virtual interface | ||
5900 | * | ||
5901 | * Returns %true if the txq was actually added to the scheduling, | ||
5902 | * %false otherwise. | ||
5903 | */ | ||
5904 | bool ieee80211_schedule_txq(struct ieee80211_hw *hw, | ||
5905 | struct ieee80211_txq *txq); | ||
5906 | |||
5907 | /** | ||
5908 | * ieee80211_next_txq - get next tx queue to pull packets from | ||
5909 | * | ||
5910 | * @hw: pointer as obtained from ieee80211_alloc_hw() | ||
5911 | * | ||
5912 | * Returns the next txq if successful, %NULL if no queue is eligible. If a txq | ||
5913 | * is returned, it will have been removed from the scheduler queue and needs to | ||
5914 | * be re-scheduled with ieee80211_schedule_txq() to continue to be active. | ||
5915 | */ | ||
5916 | struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw); | ||
5917 | |||
5918 | /** | ||
5894 | * ieee80211_txq_get_depth - get pending frame/byte count of given txq | 5919 | * ieee80211_txq_get_depth - get pending frame/byte count of given txq |
5895 | * | 5920 | * |
5896 | * The values are not guaranteed to be coherent with regard to each other, i.e. | 5921 | * 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 595c662a61e8..6c6cad98ce92 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -226,9 +226,13 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable) | |||
226 | clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags); | 226 | clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags); |
227 | 227 | ||
228 | clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); | 228 | clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); |
229 | |||
230 | if (!ieee80211_schedule_txq(&sta->sdata->local->hw, txq)) | ||
231 | return; | ||
232 | |||
229 | local_bh_disable(); | 233 | local_bh_disable(); |
230 | rcu_read_lock(); | 234 | rcu_read_lock(); |
231 | drv_wake_tx_queue(sta->sdata->local, txqi); | 235 | drv_wake_tx_queue(sta->sdata->local); |
232 | rcu_read_unlock(); | 236 | rcu_read_unlock(); |
233 | local_bh_enable(); | 237 | local_bh_enable(); |
234 | } | 238 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c7f93fd9ca7a..cdd76306cb8f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -1158,16 +1158,10 @@ drv_tdls_recv_channel_switch(struct ieee80211_local *local, | |||
1158 | trace_drv_return_void(local); | 1158 | trace_drv_return_void(local); |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | static inline void drv_wake_tx_queue(struct ieee80211_local *local, | 1161 | static inline void drv_wake_tx_queue(struct ieee80211_local *local) |
1162 | struct txq_info *txq) | ||
1163 | { | 1162 | { |
1164 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif); | 1163 | trace_drv_wake_tx_queue(local); |
1165 | 1164 | local->ops->wake_tx_queue(&local->hw); | |
1166 | if (!check_sdata_in_driver(sdata)) | ||
1167 | return; | ||
1168 | |||
1169 | trace_drv_wake_tx_queue(local, sdata, txq); | ||
1170 | local->ops->wake_tx_queue(&local->hw, &txq->txq); | ||
1171 | } | 1165 | } |
1172 | 1166 | ||
1173 | static inline int drv_start_nan(struct ieee80211_local *local, | 1167 | static inline int drv_start_nan(struct ieee80211_local *local, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26900025de2f..4155838c7bef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -832,6 +832,7 @@ struct txq_info { | |||
832 | struct codel_vars def_cvars; | 832 | struct codel_vars def_cvars; |
833 | struct codel_stats cstats; | 833 | struct codel_stats cstats; |
834 | struct sk_buff_head frags; | 834 | struct sk_buff_head frags; |
835 | struct list_head schedule_order; | ||
835 | unsigned long flags; | 836 | unsigned long flags; |
836 | 837 | ||
837 | /* keep last! */ | 838 | /* keep last! */ |
@@ -1122,6 +1123,10 @@ struct ieee80211_local { | |||
1122 | struct codel_vars *cvars; | 1123 | struct codel_vars *cvars; |
1123 | struct codel_params cparams; | 1124 | struct codel_params cparams; |
1124 | 1125 | ||
1126 | /* protects active_txqs and txqi->schedule_order */ | ||
1127 | spinlock_t active_txq_lock; | ||
1128 | struct list_head active_txqs; | ||
1129 | |||
1125 | const struct ieee80211_ops *ops; | 1130 | const struct ieee80211_ops *ops; |
1126 | 1131 | ||
1127 | /* | 1132 | /* |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..935d6e2491b1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -619,6 +619,9 @@ 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); | ||
623 | spin_lock_init(&local->active_txq_lock); | ||
624 | |||
622 | INIT_LIST_HEAD(&local->chanctx_list); | 625 | INIT_LIST_HEAD(&local->chanctx_list); |
623 | mutex_init(&local->chanctx_mtx); | 626 | mutex_init(&local->chanctx_mtx); |
624 | 627 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 0c5627f8a104..e0bcf16df494 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1237,12 +1237,17 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1237 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 1237 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
1238 | 1238 | ||
1239 | if (sta->sta.txq[0]) { | 1239 | if (sta->sta.txq[0]) { |
1240 | bool wake = false; | ||
1241 | |||
1240 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { | 1242 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
1241 | if (!txq_has_queue(sta->sta.txq[i])) | 1243 | if (!txq_has_queue(sta->sta.txq[i])) |
1242 | continue; | 1244 | continue; |
1243 | 1245 | ||
1244 | drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); | 1246 | if (ieee80211_schedule_txq(&local->hw, sta->sta.txq[i])) |
1247 | wake = true; | ||
1245 | } | 1248 | } |
1249 | if (wake) | ||
1250 | drv_wake_tx_queue(local); | ||
1246 | } | 1251 | } |
1247 | 1252 | ||
1248 | skb_queue_head_init(&pending); | 1253 | skb_queue_head_init(&pending); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 591ad02e1fa4..08eaad85942e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -2550,35 +2550,9 @@ TRACE_EVENT(drv_tdls_recv_channel_switch, | |||
2550 | ) | 2550 | ) |
2551 | ); | 2551 | ); |
2552 | 2552 | ||
2553 | TRACE_EVENT(drv_wake_tx_queue, | 2553 | DEFINE_EVENT(local_only_evt, drv_wake_tx_queue, |
2554 | TP_PROTO(struct ieee80211_local *local, | 2554 | TP_PROTO(struct ieee80211_local *local), |
2555 | struct ieee80211_sub_if_data *sdata, | 2555 | TP_ARGS(local) |
2556 | struct txq_info *txq), | ||
2557 | |||
2558 | TP_ARGS(local, sdata, txq), | ||
2559 | |||
2560 | TP_STRUCT__entry( | ||
2561 | LOCAL_ENTRY | ||
2562 | VIF_ENTRY | ||
2563 | STA_ENTRY | ||
2564 | __field(u8, ac) | ||
2565 | __field(u8, tid) | ||
2566 | ), | ||
2567 | |||
2568 | TP_fast_assign( | ||
2569 | struct ieee80211_sta *sta = txq->txq.sta; | ||
2570 | |||
2571 | LOCAL_ASSIGN; | ||
2572 | VIF_ASSIGN; | ||
2573 | STA_ASSIGN; | ||
2574 | __entry->ac = txq->txq.ac; | ||
2575 | __entry->tid = txq->txq.tid; | ||
2576 | ), | ||
2577 | |||
2578 | TP_printk( | ||
2579 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ac:%d tid:%d", | ||
2580 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ac, __entry->tid | ||
2581 | ) | ||
2582 | ); | 2556 | ); |
2583 | 2557 | ||
2584 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ | 2558 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 25904af38839..842881ca8f20 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1439,6 +1439,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, | |||
1439 | codel_vars_init(&txqi->def_cvars); | 1439 | codel_vars_init(&txqi->def_cvars); |
1440 | codel_stats_init(&txqi->cstats); | 1440 | codel_stats_init(&txqi->cstats); |
1441 | __skb_queue_head_init(&txqi->frags); | 1441 | __skb_queue_head_init(&txqi->frags); |
1442 | INIT_LIST_HEAD(&txqi->schedule_order); | ||
1442 | 1443 | ||
1443 | txqi->txq.vif = &sdata->vif; | 1444 | txqi->txq.vif = &sdata->vif; |
1444 | 1445 | ||
@@ -1462,6 +1463,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local, | |||
1462 | 1463 | ||
1463 | fq_tin_reset(fq, tin, fq_skb_free_func); | 1464 | fq_tin_reset(fq, tin, fq_skb_free_func); |
1464 | ieee80211_purge_tx_queue(&local->hw, &txqi->frags); | 1465 | ieee80211_purge_tx_queue(&local->hw, &txqi->frags); |
1466 | list_del_init(&txqi->schedule_order); | ||
1465 | } | 1467 | } |
1466 | 1468 | ||
1467 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) | 1469 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) |
@@ -1558,7 +1560,8 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, | |||
1558 | ieee80211_txq_enqueue(local, txqi, skb); | 1560 | ieee80211_txq_enqueue(local, txqi, skb); |
1559 | spin_unlock_bh(&fq->lock); | 1561 | spin_unlock_bh(&fq->lock); |
1560 | 1562 | ||
1561 | drv_wake_tx_queue(local, txqi); | 1563 | if (ieee80211_schedule_txq(&local->hw, &txqi->txq)) |
1564 | drv_wake_tx_queue(local); | ||
1562 | 1565 | ||
1563 | return true; | 1566 | return true; |
1564 | } | 1567 | } |
@@ -3553,6 +3556,50 @@ out: | |||
3553 | } | 3556 | } |
3554 | EXPORT_SYMBOL(ieee80211_tx_dequeue); | 3557 | EXPORT_SYMBOL(ieee80211_tx_dequeue); |
3555 | 3558 | ||
3559 | bool ieee80211_schedule_txq(struct ieee80211_hw *hw, | ||
3560 | struct ieee80211_txq *txq) | ||
3561 | { | ||
3562 | struct ieee80211_local *local = hw_to_local(hw); | ||
3563 | struct txq_info *txqi = to_txq_info(txq); | ||
3564 | bool ret = false; | ||
3565 | |||
3566 | spin_lock_bh(&local->active_txq_lock); | ||
3567 | |||
3568 | if (list_empty(&txqi->schedule_order)) { | ||
3569 | list_add_tail(&txqi->schedule_order, &local->active_txqs); | ||
3570 | ret = true; | ||
3571 | } | ||
3572 | |||
3573 | spin_unlock_bh(&local->active_txq_lock); | ||
3574 | |||
3575 | return ret; | ||
3576 | } | ||
3577 | EXPORT_SYMBOL(ieee80211_schedule_txq); | ||
3578 | |||
3579 | struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw) | ||
3580 | { | ||
3581 | struct ieee80211_local *local = hw_to_local(hw); | ||
3582 | struct txq_info *txqi = NULL; | ||
3583 | |||
3584 | spin_lock_bh(&local->active_txq_lock); | ||
3585 | |||
3586 | if (list_empty(&local->active_txqs)) | ||
3587 | goto out; | ||
3588 | |||
3589 | txqi = list_first_entry(&local->active_txqs, | ||
3590 | struct txq_info, schedule_order); | ||
3591 | list_del_init(&txqi->schedule_order); | ||
3592 | |||
3593 | out: | ||
3594 | spin_unlock_bh(&local->active_txq_lock); | ||
3595 | |||
3596 | if (!txqi) | ||
3597 | return NULL; | ||
3598 | |||
3599 | return &txqi->txq; | ||
3600 | } | ||
3601 | EXPORT_SYMBOL(ieee80211_next_txq); | ||
3602 | |||
3556 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | 3603 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
3557 | struct net_device *dev, | 3604 | struct net_device *dev, |
3558 | u32 info_flags) | 3605 | u32 info_flags) |