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, 262 insertions, 173 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 90d16a38475f..b29fdbd21ead 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c | |||
| @@ -2574,7 +2574,9 @@ 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); | ||
| 2577 | 2578 | ||
| 2579 | INIT_LIST_HEAD(&ar->txqs); | ||
| 2578 | INIT_LIST_HEAD(&ar->peers); | 2580 | INIT_LIST_HEAD(&ar->peers); |
| 2579 | init_waitqueue_head(&ar->peer_mapping_wq); | 2581 | init_waitqueue_head(&ar->peer_mapping_wq); |
| 2580 | init_waitqueue_head(&ar->htt.empty_tx_wq); | 2582 | 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 4a79fdce9a08..643041ef3271 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
| @@ -347,6 +347,7 @@ struct ath10k_peer { | |||
| 347 | }; | 347 | }; |
| 348 | 348 | ||
| 349 | struct ath10k_txq { | 349 | struct ath10k_txq { |
| 350 | struct list_head list; | ||
| 350 | unsigned long num_fw_queued; | 351 | unsigned long num_fw_queued; |
| 351 | unsigned long num_push_allowed; | 352 | unsigned long num_push_allowed; |
| 352 | }; | 353 | }; |
| @@ -894,7 +895,10 @@ struct ath10k { | |||
| 894 | 895 | ||
| 895 | /* protects shared structure data */ | 896 | /* protects shared structure data */ |
| 896 | spinlock_t data_lock; | 897 | spinlock_t data_lock; |
| 898 | /* protects: ar->txqs, artxq->list */ | ||
| 899 | spinlock_t txqs_lock; | ||
| 897 | 900 | ||
| 901 | struct list_head txqs; | ||
| 898 | struct list_head arvifs; | 902 | struct list_head arvifs; |
| 899 | struct list_head peers; | 903 | struct list_head peers; |
| 900 | struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS]; | 904 | 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 cca4cd82853b..0a947eef348d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
| @@ -3830,10 +3830,12 @@ 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); | ||
| 3833 | } | 3834 | } |
| 3834 | 3835 | ||
| 3835 | static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) | 3836 | static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) |
| 3836 | { | 3837 | { |
| 3838 | struct ath10k_txq *artxq; | ||
| 3837 | struct ath10k_skb_cb *cb; | 3839 | struct ath10k_skb_cb *cb; |
| 3838 | struct sk_buff *msdu; | 3840 | struct sk_buff *msdu; |
| 3839 | int msdu_id; | 3841 | int msdu_id; |
| @@ -3841,6 +3843,12 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) | |||
| 3841 | if (!txq) | 3843 | if (!txq) |
| 3842 | return; | 3844 | return; |
| 3843 | 3845 | ||
| 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 | |||
| 3844 | spin_lock_bh(&ar->htt.tx_lock); | 3852 | spin_lock_bh(&ar->htt.tx_lock); |
| 3845 | idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) { | 3853 | idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) { |
| 3846 | cb = ATH10K_SKB_CB(msdu); | 3854 | cb = ATH10K_SKB_CB(msdu); |
| @@ -3970,17 +3978,23 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, | |||
| 3970 | void ath10k_mac_tx_push_pending(struct ath10k *ar) | 3978 | void ath10k_mac_tx_push_pending(struct ath10k *ar) |
| 3971 | { | 3979 | { |
| 3972 | struct ieee80211_hw *hw = ar->hw; | 3980 | struct ieee80211_hw *hw = ar->hw; |
| 3973 | struct ieee80211_txq *txq, *first = NULL; | 3981 | struct ieee80211_txq *txq; |
| 3982 | struct ath10k_txq *artxq; | ||
| 3983 | struct ath10k_txq *last; | ||
| 3974 | int ret; | 3984 | int ret; |
| 3975 | int max; | 3985 | int max; |
| 3976 | 3986 | ||
| 3977 | if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) | 3987 | if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) |
| 3978 | return; | 3988 | return; |
| 3979 | 3989 | ||
| 3990 | spin_lock_bh(&ar->txqs_lock); | ||
| 3980 | rcu_read_lock(); | 3991 | rcu_read_lock(); |
| 3981 | 3992 | ||
| 3982 | txq = ieee80211_next_txq(hw); | 3993 | last = list_last_entry(&ar->txqs, struct ath10k_txq, list); |
| 3983 | while (txq) { | 3994 | while (!list_empty(&ar->txqs)) { |
| 3995 | artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list); | ||
| 3996 | txq = container_of((void *)artxq, struct ieee80211_txq, | ||
| 3997 | drv_priv); | ||
| 3984 | 3998 | ||
| 3985 | /* Prevent aggressive sta/tid taking over tx queue */ | 3999 | /* Prevent aggressive sta/tid taking over tx queue */ |
| 3986 | max = 16; | 4000 | max = 16; |
| @@ -3991,21 +4005,18 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar) | |||
| 3991 | break; | 4005 | break; |
| 3992 | } | 4006 | } |
| 3993 | 4007 | ||
| 4008 | list_del_init(&artxq->list); | ||
| 3994 | if (ret != -ENOENT) | 4009 | if (ret != -ENOENT) |
| 3995 | ieee80211_schedule_txq(hw, txq); | 4010 | list_add_tail(&artxq->list, &ar->txqs); |
| 3996 | 4011 | ||
| 3997 | ath10k_htt_tx_txq_update(hw, txq); | 4012 | ath10k_htt_tx_txq_update(hw, txq); |
| 3998 | 4013 | ||
| 3999 | if (first == txq || (ret < 0 && ret != -ENOENT)) | 4014 | if (artxq == last || (ret < 0 && ret != -ENOENT)) |
| 4000 | break; | 4015 | break; |
| 4001 | |||
| 4002 | if (!first) | ||
| 4003 | first = txq; | ||
| 4004 | |||
| 4005 | txq = ieee80211_next_txq(hw); | ||
| 4006 | } | 4016 | } |
| 4007 | 4017 | ||
| 4008 | rcu_read_unlock(); | 4018 | rcu_read_unlock(); |
| 4019 | spin_unlock_bh(&ar->txqs_lock); | ||
| 4009 | } | 4020 | } |
| 4010 | 4021 | ||
| 4011 | /************/ | 4022 | /************/ |
| @@ -4239,22 +4250,34 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, | |||
| 4239 | } | 4250 | } |
| 4240 | } | 4251 | } |
| 4241 | 4252 | ||
| 4242 | static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw) | 4253 | static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, |
| 4254 | struct ieee80211_txq *txq) | ||
| 4243 | { | 4255 | { |
| 4244 | struct ieee80211_txq *txq; | 4256 | struct ath10k *ar = hw->priv; |
| 4257 | struct ath10k_txq *artxq = (void *)txq->drv_priv; | ||
| 4258 | struct ieee80211_txq *f_txq; | ||
| 4259 | struct ath10k_txq *f_artxq; | ||
| 4245 | int ret = 0; | 4260 | int ret = 0; |
| 4246 | int max = 16; | 4261 | int max = 16; |
| 4247 | 4262 | ||
| 4248 | txq = ieee80211_next_txq(hw); | 4263 | spin_lock_bh(&ar->txqs_lock); |
| 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); | ||
| 4249 | 4270 | ||
| 4250 | while (ath10k_mac_tx_can_push(hw, txq) && max--) { | 4271 | while (ath10k_mac_tx_can_push(hw, f_txq) && max--) { |
| 4251 | ret = ath10k_mac_tx_push_txq(hw, txq); | 4272 | ret = ath10k_mac_tx_push_txq(hw, f_txq); |
| 4252 | if (ret) | 4273 | if (ret) |
| 4253 | break; | 4274 | break; |
| 4254 | } | 4275 | } |
| 4255 | if (ret != -ENOENT) | 4276 | if (ret != -ENOENT) |
| 4256 | ieee80211_schedule_txq(hw, txq); | 4277 | list_add_tail(&f_artxq->list, &ar->txqs); |
| 4278 | spin_unlock_bh(&ar->txqs_lock); | ||
| 4257 | 4279 | ||
| 4280 | ath10k_htt_tx_txq_update(hw, f_txq); | ||
| 4258 | ath10k_htt_tx_txq_update(hw, txq); | 4281 | ath10k_htt_tx_txq_update(hw, txq); |
| 4259 | } | 4282 | } |
| 4260 | 4283 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index face2bb7f357..ef0de4f1312c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
| @@ -246,8 +246,12 @@ 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; | ||
| 249 | }; | 250 | }; |
| 250 | 251 | ||
| 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 | |||
| 251 | struct ath_node { | 255 | struct ath_node { |
| 252 | struct ath_softc *sc; | 256 | struct ath_softc *sc; |
| 253 | struct ieee80211_sta *sta; /* station struct we're part of */ | 257 | struct ieee80211_sta *sta; /* station struct we're part of */ |
| @@ -587,7 +591,8 @@ bool ath_drain_all_txq(struct ath_softc *sc); | |||
| 587 | void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); | 591 | void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); |
| 588 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); | 592 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); |
| 589 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); | 593 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); |
| 590 | void ath_txq_schedule(struct ath_softc *sc); | 594 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); |
| 595 | void ath_txq_schedule_all(struct ath_softc *sc); | ||
| 591 | int ath_tx_init(struct ath_softc *sc, int nbufs); | 596 | int ath_tx_init(struct ath_softc *sc, int nbufs); |
| 592 | int ath_txq_update(struct ath_softc *sc, int qnum, | 597 | int ath_txq_update(struct ath_softc *sc, int qnum, |
| 593 | struct ath9k_tx_queue_info *q); | 598 | struct ath9k_tx_queue_info *q); |
| @@ -613,7 +618,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, | |||
| 613 | u16 tids, int nframes, | 618 | u16 tids, int nframes, |
| 614 | enum ieee80211_frame_release_type reason, | 619 | enum ieee80211_frame_release_type reason, |
| 615 | bool more_data); | 620 | bool more_data); |
| 616 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw); | 621 | void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); |
| 617 | 622 | ||
| 618 | /********/ | 623 | /********/ |
| 619 | /* VIFs */ | 624 | /* VIFs */ |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f7dfcdf508ce..a3be8add56e1 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(sc); | 269 | ath_txq_schedule_all(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 a768e841524d..2197aee2bb72 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
| @@ -1057,6 +1057,8 @@ 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)); | ||
| 1060 | spin_unlock_bh(&acq->lock); | 1062 | spin_unlock_bh(&acq->lock); |
| 1061 | } | 1063 | } |
| 1062 | ath_debug_airtime(sc, an, airtime, 0); | 1064 | 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 bd438062a6db..396bf05c6bf6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
| @@ -112,11 +112,62 @@ 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 ath9k_wake_tx_queue(struct ieee80211_hw *hw) | 115 | void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) |
| 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) | ||
| 116 | { | 154 | { |
| 117 | struct ath_softc *sc = hw->priv; | 155 | 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); | ||
| 118 | 165 | ||
| 119 | ath_txq_schedule(sc); | 166 | tid->has_queued = true; |
| 167 | ath_tx_queue_tid(sc, tid); | ||
| 168 | ath_txq_schedule(sc, txq); | ||
| 169 | |||
| 170 | ath_txq_unlock(sc, txq); | ||
| 120 | } | 171 | } |
| 121 | 172 | ||
| 122 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) | 173 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) |
| @@ -179,9 +230,14 @@ ath_tid_pull(struct ath_atx_tid *tid) | |||
| 179 | struct ath_frame_info *fi; | 230 | struct ath_frame_info *fi; |
| 180 | int q; | 231 | int q; |
| 181 | 232 | ||
| 233 | if (!tid->has_queued) | ||
| 234 | return NULL; | ||
| 235 | |||
| 182 | skb = ieee80211_tx_dequeue(hw, txq); | 236 | skb = ieee80211_tx_dequeue(hw, txq); |
| 183 | if (!skb) | 237 | if (!skb) { |
| 238 | tid->has_queued = false; | ||
| 184 | return NULL; | 239 | return NULL; |
| 240 | } | ||
| 185 | 241 | ||
| 186 | if (ath_tx_prepare(hw, skb, &txctl)) { | 242 | if (ath_tx_prepare(hw, skb, &txctl)) { |
| 187 | ieee80211_free_txskb(hw, skb); | 243 | ieee80211_free_txskb(hw, skb); |
| @@ -198,6 +254,12 @@ ath_tid_pull(struct ath_atx_tid *tid) | |||
| 198 | return skb; | 254 | return skb; |
| 199 | } | 255 | } |
| 200 | 256 | ||
| 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 | |||
| 201 | static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) | 263 | static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) |
| 202 | { | 264 | { |
| 203 | struct sk_buff *skb; | 265 | struct sk_buff *skb; |
| @@ -609,10 +671,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 609 | 671 | ||
| 610 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); | 672 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); |
| 611 | if (!an->sleeping) { | 673 | if (!an->sleeping) { |
| 612 | struct ieee80211_txq *queue = container_of( | 674 | ath_tx_queue_tid(sc, tid); |
| 613 | (void *)tid, struct ieee80211_txq, drv_priv); | ||
| 614 | |||
| 615 | ieee80211_schedule_txq(sc->hw, queue); | ||
| 616 | 675 | ||
| 617 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) | 676 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) |
| 618 | tid->clear_ps_filter = true; | 677 | tid->clear_ps_filter = true; |
| @@ -660,6 +719,8 @@ static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an, | |||
| 660 | 719 | ||
| 661 | spin_lock_bh(&acq->lock); | 720 | spin_lock_bh(&acq->lock); |
| 662 | an->airtime_deficit[q] -= airtime; | 721 | an->airtime_deficit[q] -= airtime; |
| 722 | if (an->airtime_deficit[q] <= 0) | ||
| 723 | __ath_tx_queue_tid(sc, tid); | ||
| 663 | spin_unlock_bh(&acq->lock); | 724 | spin_unlock_bh(&acq->lock); |
| 664 | } | 725 | } |
| 665 | ath_debug_airtime(sc, an, 0, airtime); | 726 | ath_debug_airtime(sc, an, 0, airtime); |
| @@ -709,6 +770,8 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, | |||
| 709 | } else | 770 | } else |
| 710 | ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); | 771 | ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); |
| 711 | 772 | ||
| 773 | if (!flush) | ||
| 774 | ath_txq_schedule(sc, txq); | ||
| 712 | } | 775 | } |
| 713 | 776 | ||
| 714 | static bool ath_lookup_legacy(struct ath_buf *bf) | 777 | static bool ath_lookup_legacy(struct ath_buf *bf) |
| @@ -1443,8 +1506,8 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, | |||
| 1443 | } while (1); | 1506 | } while (1); |
| 1444 | } | 1507 | } |
| 1445 | 1508 | ||
| 1446 | static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | 1509 | static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, |
| 1447 | struct ath_atx_tid *tid) | 1510 | struct ath_atx_tid *tid) |
| 1448 | { | 1511 | { |
| 1449 | struct ath_buf *bf; | 1512 | struct ath_buf *bf; |
| 1450 | struct ieee80211_tx_info *tx_info; | 1513 | struct ieee80211_tx_info *tx_info; |
| @@ -1452,18 +1515,21 @@ static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 1452 | int aggr_len = 0; | 1515 | int aggr_len = 0; |
| 1453 | bool aggr; | 1516 | bool aggr; |
| 1454 | 1517 | ||
| 1518 | if (!ath_tid_has_buffered(tid)) | ||
| 1519 | return false; | ||
| 1520 | |||
| 1455 | INIT_LIST_HEAD(&bf_q); | 1521 | INIT_LIST_HEAD(&bf_q); |
| 1456 | 1522 | ||
| 1457 | bf = ath_tx_get_tid_subframe(sc, txq, tid); | 1523 | bf = ath_tx_get_tid_subframe(sc, txq, tid); |
| 1458 | if (!bf) | 1524 | if (!bf) |
| 1459 | return -ENOENT; | 1525 | return false; |
| 1460 | 1526 | ||
| 1461 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | 1527 | tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); |
| 1462 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); | 1528 | aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); |
| 1463 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || | 1529 | if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || |
| 1464 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { | 1530 | (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { |
| 1465 | __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); | 1531 | __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); |
| 1466 | return -ENOBUFS; | 1532 | return false; |
| 1467 | } | 1533 | } |
| 1468 | 1534 | ||
| 1469 | ath_set_rates(tid->an->vif, tid->an->sta, bf); | 1535 | ath_set_rates(tid->an->vif, tid->an->sta, bf); |
| @@ -1473,7 +1539,7 @@ static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 1473 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf); | 1539 | ath_tx_form_burst(sc, txq, tid, &bf_q, bf); |
| 1474 | 1540 | ||
| 1475 | if (list_empty(&bf_q)) | 1541 | if (list_empty(&bf_q)) |
| 1476 | return -ENOENT; | 1542 | return false; |
| 1477 | 1543 | ||
| 1478 | if (tid->clear_ps_filter || tid->an->no_ps_filter) { | 1544 | if (tid->clear_ps_filter || tid->an->no_ps_filter) { |
| 1479 | tid->clear_ps_filter = false; | 1545 | tid->clear_ps_filter = false; |
| @@ -1482,7 +1548,7 @@ static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 1482 | 1548 | ||
| 1483 | ath_tx_fill_desc(sc, bf, txq, aggr_len); | 1549 | ath_tx_fill_desc(sc, bf, txq, aggr_len); |
| 1484 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); | 1550 | ath_tx_txqaddbuf(sc, txq, &bf_q, false); |
| 1485 | return 0; | 1551 | return true; |
| 1486 | } | 1552 | } |
| 1487 | 1553 | ||
| 1488 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | 1554 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, |
| @@ -1545,49 +1611,52 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, | |||
| 1545 | { | 1611 | { |
| 1546 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1612 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1547 | struct ath_atx_tid *tid; | 1613 | struct ath_atx_tid *tid; |
| 1548 | struct ieee80211_txq *queue; | 1614 | struct ath_txq *txq; |
| 1549 | int tidno; | 1615 | int tidno; |
| 1550 | 1616 | ||
| 1551 | ath_dbg(common, XMIT, "%s called\n", __func__); | 1617 | ath_dbg(common, XMIT, "%s called\n", __func__); |
| 1552 | 1618 | ||
| 1553 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | 1619 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { |
| 1554 | tid = ath_node_to_tid(an, tidno); | 1620 | tid = ath_node_to_tid(an, tidno); |
| 1555 | queue = container_of((void *)tid, | 1621 | txq = tid->txq; |
| 1556 | struct ieee80211_txq, drv_priv); | 1622 | |
| 1623 | ath_txq_lock(sc, txq); | ||
| 1624 | |||
| 1625 | if (list_empty(&tid->list)) { | ||
| 1626 | ath_txq_unlock(sc, txq); | ||
| 1627 | continue; | ||
| 1628 | } | ||
| 1557 | 1629 | ||
| 1558 | if (!skb_queue_empty(&tid->retry_q)) | 1630 | if (!skb_queue_empty(&tid->retry_q)) |
| 1559 | ieee80211_sta_set_buffered(sta, tid->tidno, true); | 1631 | ieee80211_sta_set_buffered(sta, tid->tidno, true); |
| 1560 | 1632 | ||
| 1633 | list_del_init(&tid->list); | ||
| 1634 | |||
| 1635 | ath_txq_unlock(sc, txq); | ||
| 1561 | } | 1636 | } |
| 1562 | } | 1637 | } |
| 1563 | 1638 | ||
| 1564 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) | 1639 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) |
| 1565 | { | 1640 | { |
| 1566 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1641 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1567 | struct ieee80211_txq *queue; | ||
| 1568 | struct ath_atx_tid *tid; | 1642 | struct ath_atx_tid *tid; |
| 1569 | struct ath_txq *txq; | 1643 | struct ath_txq *txq; |
| 1570 | int tidno; | 1644 | int tidno; |
| 1571 | bool sched, wake = false; | ||
| 1572 | 1645 | ||
| 1573 | ath_dbg(common, XMIT, "%s called\n", __func__); | 1646 | ath_dbg(common, XMIT, "%s called\n", __func__); |
| 1574 | 1647 | ||
| 1575 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | 1648 | for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { |
| 1576 | tid = ath_node_to_tid(an, tidno); | 1649 | tid = ath_node_to_tid(an, tidno); |
| 1577 | txq = tid->txq; | 1650 | txq = tid->txq; |
| 1578 | queue = container_of((void *)tid, | ||
| 1579 | struct ieee80211_txq, drv_priv); | ||
| 1580 | 1651 | ||
| 1581 | ath_txq_lock(sc, txq); | 1652 | ath_txq_lock(sc, txq); |
| 1582 | tid->clear_ps_filter = true; | 1653 | tid->clear_ps_filter = true; |
| 1583 | sched = !skb_queue_empty(&tid->retry_q); | 1654 | if (ath_tid_has_buffered(tid)) { |
| 1584 | ath_txq_unlock(sc, txq); | 1655 | ath_tx_queue_tid(sc, tid); |
| 1585 | 1656 | ath_txq_schedule(sc, txq); | |
| 1586 | if (sched && ieee80211_schedule_txq(sc->hw, queue)) | 1657 | } |
| 1587 | wake = true; | 1658 | ath_txq_unlock_complete(sc, txq); |
| 1588 | } | 1659 | } |
| 1589 | if (wake) | ||
| 1590 | ath_txq_schedule(sc); | ||
| 1591 | } | 1660 | } |
| 1592 | 1661 | ||
| 1593 | void ath9k_release_buffered_frames(struct ieee80211_hw *hw, | 1662 | void ath9k_release_buffered_frames(struct ieee80211_hw *hw, |
| @@ -1879,44 +1948,86 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1879 | /* For each acq entry, for each tid, try to schedule packets | 1948 | /* For each acq entry, for each tid, try to schedule packets |
| 1880 | * for transmit until ampdu_depth has reached min Q depth. | 1949 | * for transmit until ampdu_depth has reached min Q depth. |
| 1881 | */ | 1950 | */ |
| 1882 | void ath_txq_schedule(struct ath_softc *sc) | 1951 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) |
| 1883 | { | 1952 | { |
| 1884 | struct ieee80211_hw *hw = sc->hw; | ||
| 1885 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1953 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1886 | struct ieee80211_txq *queue; | ||
| 1887 | struct ath_atx_tid *tid; | 1954 | struct ath_atx_tid *tid; |
| 1888 | struct ath_txq *txq; | 1955 | struct list_head *tid_list; |
| 1889 | int ret = 0; | 1956 | struct ath_acq *acq; |
| 1957 | bool active = AIRTIME_ACTIVE(sc->airtime_flags); | ||
| 1890 | 1958 | ||
| 1891 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) | 1959 | if (txq->mac80211_qnum < 0) |
| 1892 | return; | 1960 | return; |
| 1893 | 1961 | ||
| 1894 | queue = ieee80211_next_txq(hw); | 1962 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) |
| 1895 | if (!queue) | ||
| 1896 | return; | 1963 | return; |
| 1897 | 1964 | ||
| 1898 | tid = (struct ath_atx_tid *)queue->drv_priv; | 1965 | spin_lock_bh(&sc->chan_lock); |
| 1899 | txq = tid->txq; | 1966 | rcu_read_lock(); |
| 1967 | acq = &sc->cur_chan->acq[txq->mac80211_qnum]; | ||
| 1900 | 1968 | ||
| 1901 | ath_txq_lock(sc, txq); | 1969 | if (sc->cur_chan->stopped) |
| 1902 | if (txq->mac80211_qnum < 0) | ||
| 1903 | goto out; | 1970 | goto out; |
| 1904 | 1971 | ||
| 1905 | spin_lock_bh(&sc->chan_lock); | 1972 | begin: |
| 1906 | rcu_read_lock(); | 1973 | tid_list = &acq->acq_new; |
| 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); | ||
| 1907 | 1980 | ||
| 1908 | if (!sc->cur_chan->stopped) | 1981 | if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) { |
| 1909 | ret = ath_tx_sched_aggr(sc, txq, tid); | 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 | } | ||
| 1910 | 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 | |||
| 2001 | /* | ||
| 2002 | * If we succeed in scheduling something, immediately restart to make | ||
| 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 | |||
| 2014 | out: | ||
| 1911 | rcu_read_unlock(); | 2015 | rcu_read_unlock(); |
| 1912 | spin_unlock_bh(&sc->chan_lock); | 2016 | spin_unlock_bh(&sc->chan_lock); |
| 2017 | } | ||
| 1913 | 2018 | ||
| 1914 | out: | 2019 | void ath_txq_schedule_all(struct ath_softc *sc) |
| 2020 | { | ||
| 2021 | struct ath_txq *txq; | ||
| 2022 | int i; | ||
| 1915 | 2023 | ||
| 1916 | if (ret != -ENOENT) | 2024 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| 1917 | ieee80211_schedule_txq(hw, queue); | 2025 | txq = sc->tx.txq_map[i]; |
| 1918 | 2026 | ||
| 1919 | ath_txq_unlock(sc, txq); | 2027 | spin_lock_bh(&txq->axq_lock); |
| 2028 | ath_txq_schedule(sc, txq); | ||
| 2029 | spin_unlock_bh(&txq->axq_lock); | ||
| 2030 | } | ||
| 1920 | } | 2031 | } |
| 1921 | 2032 | ||
| 1922 | /***********/ | 2033 | /***********/ |
| @@ -2534,6 +2645,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 2534 | 2645 | ||
| 2535 | if (list_empty(&txq->axq_q)) { | 2646 | if (list_empty(&txq->axq_q)) { |
| 2536 | txq->axq_link = NULL; | 2647 | txq->axq_link = NULL; |
| 2648 | ath_txq_schedule(sc, txq); | ||
| 2537 | break; | 2649 | break; |
| 2538 | } | 2650 | } |
| 2539 | bf = list_first_entry(&txq->axq_q, struct ath_buf, list); | 2651 | bf = list_first_entry(&txq->axq_q, struct ath_buf, list); |
| @@ -2585,7 +2697,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 2585 | ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); | 2697 | ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); |
| 2586 | } | 2698 | } |
| 2587 | ath_txq_unlock_complete(sc, txq); | 2699 | ath_txq_unlock_complete(sc, txq); |
| 2588 | ath_txq_schedule(sc); | ||
| 2589 | } | 2700 | } |
| 2590 | 2701 | ||
| 2591 | void ath_tx_tasklet(struct ath_softc *sc) | 2702 | void ath_tx_tasklet(struct ath_softc *sc) |
| @@ -2600,7 +2711,6 @@ void ath_tx_tasklet(struct ath_softc *sc) | |||
| 2600 | ath_tx_processq(sc, &sc->tx.txq[i]); | 2711 | ath_tx_processq(sc, &sc->tx.txq[i]); |
| 2601 | } | 2712 | } |
| 2602 | rcu_read_unlock(); | 2713 | rcu_read_unlock(); |
| 2603 | ath_txq_schedule(sc); | ||
| 2604 | } | 2714 | } |
| 2605 | 2715 | ||
| 2606 | void ath_tx_edma_tasklet(struct ath_softc *sc) | 2716 | void ath_tx_edma_tasklet(struct ath_softc *sc) |
| @@ -2686,7 +2796,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
| 2686 | ath_txq_unlock_complete(sc, txq); | 2796 | ath_txq_unlock_complete(sc, txq); |
| 2687 | } | 2797 | } |
| 2688 | rcu_read_unlock(); | 2798 | rcu_read_unlock(); |
| 2689 | ath_txq_schedule(sc); | ||
| 2690 | } | 2799 | } |
| 2691 | 2800 | ||
| 2692 | /*****************/ | 2801 | /*****************/ |
| @@ -2766,6 +2875,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) | |||
| 2766 | tid->baw_head = tid->baw_tail = 0; | 2875 | tid->baw_head = tid->baw_tail = 0; |
| 2767 | tid->active = false; | 2876 | tid->active = false; |
| 2768 | tid->clear_ps_filter = true; | 2877 | tid->clear_ps_filter = true; |
| 2878 | tid->has_queued = false; | ||
| 2769 | __skb_queue_head_init(&tid->retry_q); | 2879 | __skb_queue_head_init(&tid->retry_q); |
| 2770 | INIT_LIST_HEAD(&tid->list); | 2880 | INIT_LIST_HEAD(&tid->list); |
| 2771 | acno = TID_TO_WME_AC(tidno); | 2881 | acno = TID_TO_WME_AC(tidno); |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 45155803c875..906e90223066 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -105,12 +105,9 @@ | |||
| 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 obtain the next queue to pull | 108 | * The driver can't access the queue directly. To dequeue a frame, it calls |
| 109 | * frames from, the driver calls ieee80211_next_txq(). To dequeue a frame from a | 109 | * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it |
| 110 | * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a | 110 | * calls the .wake_tx_queue driver op. |
| 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. | ||
| 114 | * | 111 | * |
| 115 | * For AP powersave TIM handling, the driver only needs to indicate if it has | 112 | * 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 | 113 | * buffered packets in the driver specific data structures by calling |
| @@ -3734,7 +3731,8 @@ struct ieee80211_ops { | |||
| 3734 | struct ieee80211_vif *vif, | 3731 | struct ieee80211_vif *vif, |
| 3735 | struct ieee80211_tdls_ch_sw_params *params); | 3732 | struct ieee80211_tdls_ch_sw_params *params); |
| 3736 | 3733 | ||
| 3737 | void (*wake_tx_queue)(struct ieee80211_hw *hw); | 3734 | void (*wake_tx_queue)(struct ieee80211_hw *hw, |
| 3735 | struct ieee80211_txq *txq); | ||
| 3738 | void (*sync_rx_queues)(struct ieee80211_hw *hw); | 3736 | void (*sync_rx_queues)(struct ieee80211_hw *hw); |
| 3739 | 3737 | ||
| 3740 | int (*start_nan)(struct ieee80211_hw *hw, | 3738 | int (*start_nan)(struct ieee80211_hw *hw, |
| @@ -5885,7 +5883,7 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); | |||
| 5885 | * ieee80211_tx_dequeue - dequeue a packet from a software tx queue | 5883 | * ieee80211_tx_dequeue - dequeue a packet from a software tx queue |
| 5886 | * | 5884 | * |
| 5887 | * @hw: pointer as obtained from ieee80211_alloc_hw() | 5885 | * @hw: pointer as obtained from ieee80211_alloc_hw() |
| 5888 | * @txq: pointer obtained from ieee80211_next_txq() | 5886 | * @txq: pointer obtained from station or virtual interface |
| 5889 | * | 5887 | * |
| 5890 | * Returns the skb if successful, %NULL if no frame was available. | 5888 | * Returns the skb if successful, %NULL if no frame was available. |
| 5891 | */ | 5889 | */ |
| @@ -5893,29 +5891,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
| 5893 | struct ieee80211_txq *txq); | 5891 | struct ieee80211_txq *txq); |
| 5894 | 5892 | ||
| 5895 | /** | 5893 | /** |
| 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 | /** | ||
| 5919 | * ieee80211_txq_get_depth - get pending frame/byte count of given txq | 5894 | * ieee80211_txq_get_depth - get pending frame/byte count of given txq |
| 5920 | * | 5895 | * |
| 5921 | * The values are not guaranteed to be coherent with regard to each other, i.e. | 5896 | * 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 6c6cad98ce92..595c662a61e8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -226,13 +226,9 @@ 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 | |||
| 233 | local_bh_disable(); | 229 | local_bh_disable(); |
| 234 | rcu_read_lock(); | 230 | rcu_read_lock(); |
| 235 | drv_wake_tx_queue(sta->sdata->local); | 231 | drv_wake_tx_queue(sta->sdata->local, txqi); |
| 236 | rcu_read_unlock(); | 232 | rcu_read_unlock(); |
| 237 | local_bh_enable(); | 233 | local_bh_enable(); |
| 238 | } | 234 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index cdd76306cb8f..c7f93fd9ca7a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -1158,10 +1158,16 @@ 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) | ||
| 1162 | { | 1163 | { |
| 1163 | trace_drv_wake_tx_queue(local); | 1164 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif); |
| 1164 | local->ops->wake_tx_queue(&local->hw); | 1165 | |
| 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); | ||
| 1165 | } | 1171 | } |
| 1166 | 1172 | ||
| 1167 | static inline int drv_start_nan(struct ieee80211_local *local, | 1173 | 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 4155838c7bef..26900025de2f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -832,7 +832,6 @@ 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; | ||
| 836 | unsigned long flags; | 835 | unsigned long flags; |
| 837 | 836 | ||
| 838 | /* keep last! */ | 837 | /* keep last! */ |
| @@ -1123,10 +1122,6 @@ struct ieee80211_local { | |||
| 1123 | struct codel_vars *cvars; | 1122 | struct codel_vars *cvars; |
| 1124 | struct codel_params cparams; | 1123 | struct codel_params cparams; |
| 1125 | 1124 | ||
| 1126 | /* protects active_txqs and txqi->schedule_order */ | ||
| 1127 | spinlock_t active_txq_lock; | ||
| 1128 | struct list_head active_txqs; | ||
| 1129 | |||
| 1130 | const struct ieee80211_ops *ops; | 1125 | const struct ieee80211_ops *ops; |
| 1131 | 1126 | ||
| 1132 | /* | 1127 | /* |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 935d6e2491b1..0785d04a80bc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -619,9 +619,6 @@ 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 | |||
| 625 | INIT_LIST_HEAD(&local->chanctx_list); | 622 | INIT_LIST_HEAD(&local->chanctx_list); |
| 626 | mutex_init(&local->chanctx_mtx); | 623 | mutex_init(&local->chanctx_mtx); |
| 627 | 624 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e0bcf16df494..0c5627f8a104 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -1237,17 +1237,12 @@ 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 | |||
| 1242 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { | 1240 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
| 1243 | if (!txq_has_queue(sta->sta.txq[i])) | 1241 | if (!txq_has_queue(sta->sta.txq[i])) |
| 1244 | continue; | 1242 | continue; |
| 1245 | 1243 | ||
| 1246 | if (ieee80211_schedule_txq(&local->hw, sta->sta.txq[i])) | 1244 | drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); |
| 1247 | wake = true; | ||
| 1248 | } | 1245 | } |
| 1249 | if (wake) | ||
| 1250 | drv_wake_tx_queue(local); | ||
| 1251 | } | 1246 | } |
| 1252 | 1247 | ||
| 1253 | skb_queue_head_init(&pending); | 1248 | skb_queue_head_init(&pending); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 08eaad85942e..591ad02e1fa4 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -2550,9 +2550,35 @@ TRACE_EVENT(drv_tdls_recv_channel_switch, | |||
| 2550 | ) | 2550 | ) |
| 2551 | ); | 2551 | ); |
| 2552 | 2552 | ||
| 2553 | DEFINE_EVENT(local_only_evt, drv_wake_tx_queue, | 2553 | TRACE_EVENT(drv_wake_tx_queue, |
| 2554 | TP_PROTO(struct ieee80211_local *local), | 2554 | TP_PROTO(struct ieee80211_local *local, |
| 2555 | TP_ARGS(local) | 2555 | struct ieee80211_sub_if_data *sdata, |
| 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 | ) | ||
| 2556 | ); | 2582 | ); |
| 2557 | 2583 | ||
| 2558 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ | 2584 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 842881ca8f20..25904af38839 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -1439,7 +1439,6 @@ 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); | ||
| 1443 | 1442 | ||
| 1444 | txqi->txq.vif = &sdata->vif; | 1443 | txqi->txq.vif = &sdata->vif; |
| 1445 | 1444 | ||
| @@ -1463,7 +1462,6 @@ void ieee80211_txq_purge(struct ieee80211_local *local, | |||
| 1463 | 1462 | ||
| 1464 | fq_tin_reset(fq, tin, fq_skb_free_func); | 1463 | fq_tin_reset(fq, tin, fq_skb_free_func); |
| 1465 | ieee80211_purge_tx_queue(&local->hw, &txqi->frags); | 1464 | ieee80211_purge_tx_queue(&local->hw, &txqi->frags); |
| 1466 | list_del_init(&txqi->schedule_order); | ||
| 1467 | } | 1465 | } |
| 1468 | 1466 | ||
| 1469 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) | 1467 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) |
| @@ -1560,8 +1558,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, | |||
| 1560 | ieee80211_txq_enqueue(local, txqi, skb); | 1558 | ieee80211_txq_enqueue(local, txqi, skb); |
| 1561 | spin_unlock_bh(&fq->lock); | 1559 | spin_unlock_bh(&fq->lock); |
| 1562 | 1560 | ||
| 1563 | if (ieee80211_schedule_txq(&local->hw, &txqi->txq)) | 1561 | drv_wake_tx_queue(local, txqi); |
| 1564 | drv_wake_tx_queue(local); | ||
| 1565 | 1562 | ||
| 1566 | return true; | 1563 | return true; |
| 1567 | } | 1564 | } |
| @@ -3556,50 +3553,6 @@ out: | |||
| 3556 | } | 3553 | } |
| 3557 | EXPORT_SYMBOL(ieee80211_tx_dequeue); | 3554 | EXPORT_SYMBOL(ieee80211_tx_dequeue); |
| 3558 | 3555 | ||
| 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 | |||
| 3603 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | 3556 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
| 3604 | struct net_device *dev, | 3557 | struct net_device *dev, |
| 3605 | u32 info_flags) | 3558 | u32 info_flags) |
