| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: ISC |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> |
|---|
| 3 | | - * |
|---|
| 4 | | - * Permission to use, copy, modify, and/or distribute this software for any |
|---|
| 5 | | - * purpose with or without fee is hereby granted, provided that the above |
|---|
| 6 | | - * copyright notice and this permission notice appear in all copies. |
|---|
| 7 | | - * |
|---|
| 8 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|---|
| 9 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|---|
| 10 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|---|
| 11 | | - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|---|
| 12 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|---|
| 13 | | - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|---|
| 14 | | - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|---|
| 15 | 4 | */ |
|---|
| 16 | 5 | |
|---|
| 17 | 6 | #include "mt76.h" |
|---|
| 18 | | - |
|---|
| 19 | | -static struct mt76_txwi_cache * |
|---|
| 20 | | -mt76_alloc_txwi(struct mt76_dev *dev) |
|---|
| 21 | | -{ |
|---|
| 22 | | - struct mt76_txwi_cache *t; |
|---|
| 23 | | - dma_addr_t addr; |
|---|
| 24 | | - int size; |
|---|
| 25 | | - |
|---|
| 26 | | - size = (sizeof(*t) + L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1); |
|---|
| 27 | | - t = devm_kzalloc(dev->dev, size, GFP_ATOMIC); |
|---|
| 28 | | - if (!t) |
|---|
| 29 | | - return NULL; |
|---|
| 30 | | - |
|---|
| 31 | | - addr = dma_map_single(dev->dev, &t->txwi, sizeof(t->txwi), |
|---|
| 32 | | - DMA_TO_DEVICE); |
|---|
| 33 | | - t->dma_addr = addr; |
|---|
| 34 | | - |
|---|
| 35 | | - return t; |
|---|
| 36 | | -} |
|---|
| 37 | | - |
|---|
| 38 | | -static struct mt76_txwi_cache * |
|---|
| 39 | | -__mt76_get_txwi(struct mt76_dev *dev) |
|---|
| 40 | | -{ |
|---|
| 41 | | - struct mt76_txwi_cache *t = NULL; |
|---|
| 42 | | - |
|---|
| 43 | | - spin_lock_bh(&dev->lock); |
|---|
| 44 | | - if (!list_empty(&dev->txwi_cache)) { |
|---|
| 45 | | - t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache, |
|---|
| 46 | | - list); |
|---|
| 47 | | - list_del(&t->list); |
|---|
| 48 | | - } |
|---|
| 49 | | - spin_unlock_bh(&dev->lock); |
|---|
| 50 | | - |
|---|
| 51 | | - return t; |
|---|
| 52 | | -} |
|---|
| 53 | | - |
|---|
| 54 | | -struct mt76_txwi_cache * |
|---|
| 55 | | -mt76_get_txwi(struct mt76_dev *dev) |
|---|
| 56 | | -{ |
|---|
| 57 | | - struct mt76_txwi_cache *t = __mt76_get_txwi(dev); |
|---|
| 58 | | - |
|---|
| 59 | | - if (t) |
|---|
| 60 | | - return t; |
|---|
| 61 | | - |
|---|
| 62 | | - return mt76_alloc_txwi(dev); |
|---|
| 63 | | -} |
|---|
| 64 | | - |
|---|
| 65 | | -void |
|---|
| 66 | | -mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t) |
|---|
| 67 | | -{ |
|---|
| 68 | | - if (!t) |
|---|
| 69 | | - return; |
|---|
| 70 | | - |
|---|
| 71 | | - spin_lock_bh(&dev->lock); |
|---|
| 72 | | - list_add(&t->list, &dev->txwi_cache); |
|---|
| 73 | | - spin_unlock_bh(&dev->lock); |
|---|
| 74 | | -} |
|---|
| 75 | | - |
|---|
| 76 | | -void mt76_tx_free(struct mt76_dev *dev) |
|---|
| 77 | | -{ |
|---|
| 78 | | - struct mt76_txwi_cache *t; |
|---|
| 79 | | - |
|---|
| 80 | | - while ((t = __mt76_get_txwi(dev)) != NULL) |
|---|
| 81 | | - dma_unmap_single(dev->dev, t->dma_addr, sizeof(t->txwi), |
|---|
| 82 | | - DMA_TO_DEVICE); |
|---|
| 83 | | -} |
|---|
| 84 | 7 | |
|---|
| 85 | 8 | static int |
|---|
| 86 | 9 | mt76_txq_get_qid(struct ieee80211_txq *txq) |
|---|
| .. | .. |
|---|
| 92 | 15 | } |
|---|
| 93 | 16 | |
|---|
| 94 | 17 | void |
|---|
| 95 | | -mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, |
|---|
| 96 | | - struct mt76_wcid *wcid, struct sk_buff *skb) |
|---|
| 18 | +mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb) |
|---|
| 19 | +{ |
|---|
| 20 | + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
|---|
| 21 | + struct ieee80211_txq *txq; |
|---|
| 22 | + struct mt76_txq *mtxq; |
|---|
| 23 | + u8 tid; |
|---|
| 24 | + |
|---|
| 25 | + if (!sta || !ieee80211_is_data_qos(hdr->frame_control) || |
|---|
| 26 | + !ieee80211_is_data_present(hdr->frame_control)) |
|---|
| 27 | + return; |
|---|
| 28 | + |
|---|
| 29 | + tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
|---|
| 30 | + txq = sta->txq[tid]; |
|---|
| 31 | + mtxq = (struct mt76_txq *)txq->drv_priv; |
|---|
| 32 | + if (!mtxq->aggr) |
|---|
| 33 | + return; |
|---|
| 34 | + |
|---|
| 35 | + mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; |
|---|
| 36 | +} |
|---|
| 37 | +EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn); |
|---|
| 38 | + |
|---|
| 39 | +void |
|---|
| 40 | +mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list) |
|---|
| 41 | + __acquires(&dev->status_list.lock) |
|---|
| 42 | +{ |
|---|
| 43 | + __skb_queue_head_init(list); |
|---|
| 44 | + spin_lock_bh(&dev->status_list.lock); |
|---|
| 45 | +} |
|---|
| 46 | +EXPORT_SYMBOL_GPL(mt76_tx_status_lock); |
|---|
| 47 | + |
|---|
| 48 | +void |
|---|
| 49 | +mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) |
|---|
| 50 | + __releases(&dev->status_list.lock) |
|---|
| 51 | +{ |
|---|
| 52 | + struct ieee80211_hw *hw; |
|---|
| 53 | + struct sk_buff *skb; |
|---|
| 54 | + |
|---|
| 55 | + spin_unlock_bh(&dev->status_list.lock); |
|---|
| 56 | + |
|---|
| 57 | + while ((skb = __skb_dequeue(list)) != NULL) { |
|---|
| 58 | + hw = mt76_tx_status_get_hw(dev, skb); |
|---|
| 59 | + ieee80211_tx_status(hw, skb); |
|---|
| 60 | + } |
|---|
| 61 | + |
|---|
| 62 | +} |
|---|
| 63 | +EXPORT_SYMBOL_GPL(mt76_tx_status_unlock); |
|---|
| 64 | + |
|---|
| 65 | +static void |
|---|
| 66 | +__mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, |
|---|
| 67 | + struct sk_buff_head *list) |
|---|
| 68 | +{ |
|---|
| 69 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 70 | + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); |
|---|
| 71 | + u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE; |
|---|
| 72 | + |
|---|
| 73 | + flags |= cb->flags; |
|---|
| 74 | + cb->flags = flags; |
|---|
| 75 | + |
|---|
| 76 | + if ((flags & done) != done) |
|---|
| 77 | + return; |
|---|
| 78 | + |
|---|
| 79 | + __skb_unlink(skb, &dev->status_list); |
|---|
| 80 | + |
|---|
| 81 | + /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ |
|---|
| 82 | + if (flags & MT_TX_CB_TXS_FAILED) { |
|---|
| 83 | + ieee80211_tx_info_clear_status(info); |
|---|
| 84 | + info->status.rates[0].idx = -1; |
|---|
| 85 | + info->flags |= IEEE80211_TX_STAT_ACK; |
|---|
| 86 | + } |
|---|
| 87 | + |
|---|
| 88 | + __skb_queue_tail(list, skb); |
|---|
| 89 | +} |
|---|
| 90 | + |
|---|
| 91 | +void |
|---|
| 92 | +mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, |
|---|
| 93 | + struct sk_buff_head *list) |
|---|
| 94 | +{ |
|---|
| 95 | + __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list); |
|---|
| 96 | +} |
|---|
| 97 | +EXPORT_SYMBOL_GPL(mt76_tx_status_skb_done); |
|---|
| 98 | + |
|---|
| 99 | +int |
|---|
| 100 | +mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, |
|---|
| 101 | + struct sk_buff *skb) |
|---|
| 102 | +{ |
|---|
| 103 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 104 | + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); |
|---|
| 105 | + int pid; |
|---|
| 106 | + |
|---|
| 107 | + if (!wcid) |
|---|
| 108 | + return MT_PACKET_ID_NO_ACK; |
|---|
| 109 | + |
|---|
| 110 | + if (info->flags & IEEE80211_TX_CTL_NO_ACK) |
|---|
| 111 | + return MT_PACKET_ID_NO_ACK; |
|---|
| 112 | + |
|---|
| 113 | + if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | |
|---|
| 114 | + IEEE80211_TX_CTL_RATE_CTRL_PROBE))) |
|---|
| 115 | + return MT_PACKET_ID_NO_SKB; |
|---|
| 116 | + |
|---|
| 117 | + spin_lock_bh(&dev->status_list.lock); |
|---|
| 118 | + |
|---|
| 119 | + memset(cb, 0, sizeof(*cb)); |
|---|
| 120 | + wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; |
|---|
| 121 | + if (wcid->packet_id == MT_PACKET_ID_NO_ACK || |
|---|
| 122 | + wcid->packet_id == MT_PACKET_ID_NO_SKB) |
|---|
| 123 | + wcid->packet_id = MT_PACKET_ID_FIRST; |
|---|
| 124 | + |
|---|
| 125 | + pid = wcid->packet_id; |
|---|
| 126 | + cb->wcid = wcid->idx; |
|---|
| 127 | + cb->pktid = pid; |
|---|
| 128 | + cb->jiffies = jiffies; |
|---|
| 129 | + |
|---|
| 130 | + __skb_queue_tail(&dev->status_list, skb); |
|---|
| 131 | + spin_unlock_bh(&dev->status_list.lock); |
|---|
| 132 | + |
|---|
| 133 | + return pid; |
|---|
| 134 | +} |
|---|
| 135 | +EXPORT_SYMBOL_GPL(mt76_tx_status_skb_add); |
|---|
| 136 | + |
|---|
| 137 | +struct sk_buff * |
|---|
| 138 | +mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, |
|---|
| 139 | + struct sk_buff_head *list) |
|---|
| 140 | +{ |
|---|
| 141 | + struct sk_buff *skb, *tmp; |
|---|
| 142 | + |
|---|
| 143 | + skb_queue_walk_safe(&dev->status_list, skb, tmp) { |
|---|
| 144 | + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); |
|---|
| 145 | + |
|---|
| 146 | + if (wcid && cb->wcid != wcid->idx) |
|---|
| 147 | + continue; |
|---|
| 148 | + |
|---|
| 149 | + if (cb->pktid == pktid) |
|---|
| 150 | + return skb; |
|---|
| 151 | + |
|---|
| 152 | + if (pktid >= 0 && !time_after(jiffies, cb->jiffies + |
|---|
| 153 | + MT_TX_STATUS_SKB_TIMEOUT)) |
|---|
| 154 | + continue; |
|---|
| 155 | + |
|---|
| 156 | + __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED | |
|---|
| 157 | + MT_TX_CB_TXS_DONE, list); |
|---|
| 158 | + } |
|---|
| 159 | + |
|---|
| 160 | + return NULL; |
|---|
| 161 | +} |
|---|
| 162 | +EXPORT_SYMBOL_GPL(mt76_tx_status_skb_get); |
|---|
| 163 | + |
|---|
| 164 | +void |
|---|
| 165 | +mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush) |
|---|
| 166 | +{ |
|---|
| 167 | + struct sk_buff_head list; |
|---|
| 168 | + |
|---|
| 169 | + mt76_tx_status_lock(dev, &list); |
|---|
| 170 | + mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list); |
|---|
| 171 | + mt76_tx_status_unlock(dev, &list); |
|---|
| 172 | +} |
|---|
| 173 | +EXPORT_SYMBOL_GPL(mt76_tx_status_check); |
|---|
| 174 | + |
|---|
| 175 | +static void |
|---|
| 176 | +mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) |
|---|
| 177 | +{ |
|---|
| 178 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 179 | + struct mt76_wcid *wcid; |
|---|
| 180 | + int pending; |
|---|
| 181 | + |
|---|
| 182 | + if (info->tx_time_est) |
|---|
| 183 | + return; |
|---|
| 184 | + |
|---|
| 185 | + if (wcid_idx >= ARRAY_SIZE(dev->wcid)) |
|---|
| 186 | + return; |
|---|
| 187 | + |
|---|
| 188 | + rcu_read_lock(); |
|---|
| 189 | + |
|---|
| 190 | + wcid = rcu_dereference(dev->wcid[wcid_idx]); |
|---|
| 191 | + if (wcid) { |
|---|
| 192 | + pending = atomic_dec_return(&wcid->non_aql_packets); |
|---|
| 193 | + if (pending < 0) |
|---|
| 194 | + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); |
|---|
| 195 | + } |
|---|
| 196 | + |
|---|
| 197 | + rcu_read_unlock(); |
|---|
| 198 | +} |
|---|
| 199 | + |
|---|
| 200 | +void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) |
|---|
| 201 | +{ |
|---|
| 202 | + struct ieee80211_hw *hw; |
|---|
| 203 | + struct sk_buff_head list; |
|---|
| 204 | + |
|---|
| 205 | +#ifdef CONFIG_NL80211_TESTMODE |
|---|
| 206 | + if (skb == dev->test.tx_skb) { |
|---|
| 207 | + dev->test.tx_done++; |
|---|
| 208 | + if (dev->test.tx_queued == dev->test.tx_done) |
|---|
| 209 | + wake_up(&dev->tx_wait); |
|---|
| 210 | + } |
|---|
| 211 | +#endif |
|---|
| 212 | + |
|---|
| 213 | + mt76_tx_check_non_aql(dev, wcid_idx, skb); |
|---|
| 214 | + |
|---|
| 215 | + if (!skb->prev) { |
|---|
| 216 | + hw = mt76_tx_status_get_hw(dev, skb); |
|---|
| 217 | + ieee80211_free_txskb(hw, skb); |
|---|
| 218 | + return; |
|---|
| 219 | + } |
|---|
| 220 | + |
|---|
| 221 | + mt76_tx_status_lock(dev, &list); |
|---|
| 222 | + __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list); |
|---|
| 223 | + mt76_tx_status_unlock(dev, &list); |
|---|
| 224 | +} |
|---|
| 225 | +EXPORT_SYMBOL_GPL(mt76_tx_complete_skb); |
|---|
| 226 | + |
|---|
| 227 | +static int |
|---|
| 228 | +__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb, |
|---|
| 229 | + struct mt76_wcid *wcid, struct ieee80211_sta *sta, |
|---|
| 230 | + bool *stop) |
|---|
| 97 | 231 | { |
|---|
| 98 | 232 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 99 | 233 | struct mt76_queue *q; |
|---|
| 234 | + bool non_aql; |
|---|
| 235 | + int pending; |
|---|
| 236 | + int idx; |
|---|
| 237 | + |
|---|
| 238 | + non_aql = !info->tx_time_est; |
|---|
| 239 | + idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta); |
|---|
| 240 | + if (idx < 0 || !sta || !non_aql) |
|---|
| 241 | + return idx; |
|---|
| 242 | + |
|---|
| 243 | + wcid = (struct mt76_wcid *)sta->drv_priv; |
|---|
| 244 | + q = dev->q_tx[qid]; |
|---|
| 245 | + q->entry[idx].wcid = wcid->idx; |
|---|
| 246 | + pending = atomic_inc_return(&wcid->non_aql_packets); |
|---|
| 247 | + if (stop && pending >= MT_MAX_NON_AQL_PKT) |
|---|
| 248 | + *stop = true; |
|---|
| 249 | + |
|---|
| 250 | + return idx; |
|---|
| 251 | +} |
|---|
| 252 | + |
|---|
| 253 | +void |
|---|
| 254 | +mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, |
|---|
| 255 | + struct mt76_wcid *wcid, struct sk_buff *skb) |
|---|
| 256 | +{ |
|---|
| 257 | + struct mt76_dev *dev = phy->dev; |
|---|
| 258 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 259 | + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
|---|
| 260 | + struct mt76_queue *q; |
|---|
| 100 | 261 | int qid = skb_get_queue_mapping(skb); |
|---|
| 262 | + bool ext_phy = phy != &dev->phy; |
|---|
| 263 | + |
|---|
| 264 | + if (mt76_testmode_enabled(dev)) { |
|---|
| 265 | + ieee80211_free_txskb(phy->hw, skb); |
|---|
| 266 | + return; |
|---|
| 267 | + } |
|---|
| 101 | 268 | |
|---|
| 102 | 269 | if (WARN_ON(qid >= MT_TXQ_PSD)) { |
|---|
| 103 | 270 | qid = MT_TXQ_BE; |
|---|
| 104 | 271 | skb_set_queue_mapping(skb, qid); |
|---|
| 105 | 272 | } |
|---|
| 106 | 273 | |
|---|
| 107 | | - if (!wcid->tx_rate_set) |
|---|
| 274 | + if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && |
|---|
| 275 | + !ieee80211_is_data(hdr->frame_control) && |
|---|
| 276 | + !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { |
|---|
| 277 | + qid = MT_TXQ_PSD; |
|---|
| 278 | + skb_set_queue_mapping(skb, qid); |
|---|
| 279 | + } |
|---|
| 280 | + |
|---|
| 281 | + if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET)) |
|---|
| 108 | 282 | ieee80211_get_tx_rates(info->control.vif, sta, skb, |
|---|
| 109 | 283 | info->control.rates, 1); |
|---|
| 110 | 284 | |
|---|
| 111 | | - q = &dev->q_tx[qid]; |
|---|
| 285 | + if (ext_phy) |
|---|
| 286 | + info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; |
|---|
| 287 | + |
|---|
| 288 | + q = dev->q_tx[qid]; |
|---|
| 112 | 289 | |
|---|
| 113 | 290 | spin_lock_bh(&q->lock); |
|---|
| 114 | | - dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta); |
|---|
| 291 | + __mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL); |
|---|
| 115 | 292 | dev->queue_ops->kick(dev, q); |
|---|
| 116 | 293 | |
|---|
| 117 | | - if (q->queued > q->ndesc - 8) |
|---|
| 118 | | - ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb)); |
|---|
| 294 | + if (q->queued > q->ndesc - 8 && !q->stopped) { |
|---|
| 295 | + ieee80211_stop_queue(phy->hw, skb_get_queue_mapping(skb)); |
|---|
| 296 | + q->stopped = true; |
|---|
| 297 | + } |
|---|
| 298 | + |
|---|
| 119 | 299 | spin_unlock_bh(&q->lock); |
|---|
| 120 | 300 | } |
|---|
| 121 | 301 | EXPORT_SYMBOL_GPL(mt76_tx); |
|---|
| 122 | 302 | |
|---|
| 123 | 303 | static struct sk_buff * |
|---|
| 124 | | -mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps) |
|---|
| 304 | +mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq) |
|---|
| 125 | 305 | { |
|---|
| 126 | 306 | struct ieee80211_txq *txq = mtxq_to_txq(mtxq); |
|---|
| 307 | + struct ieee80211_tx_info *info; |
|---|
| 308 | + bool ext_phy = phy != &phy->dev->phy; |
|---|
| 127 | 309 | struct sk_buff *skb; |
|---|
| 128 | 310 | |
|---|
| 129 | | - skb = skb_dequeue(&mtxq->retry_q); |
|---|
| 130 | | - if (skb) { |
|---|
| 131 | | - u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
|---|
| 132 | | - |
|---|
| 133 | | - if (ps && skb_queue_empty(&mtxq->retry_q)) |
|---|
| 134 | | - ieee80211_sta_set_buffered(txq->sta, tid, false); |
|---|
| 135 | | - |
|---|
| 136 | | - return skb; |
|---|
| 137 | | - } |
|---|
| 138 | | - |
|---|
| 139 | | - skb = ieee80211_tx_dequeue(dev->hw, txq); |
|---|
| 311 | + skb = ieee80211_tx_dequeue(phy->hw, txq); |
|---|
| 140 | 312 | if (!skb) |
|---|
| 141 | 313 | return NULL; |
|---|
| 142 | 314 | |
|---|
| 315 | + info = IEEE80211_SKB_CB(skb); |
|---|
| 316 | + if (ext_phy) |
|---|
| 317 | + info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; |
|---|
| 318 | + |
|---|
| 143 | 319 | return skb; |
|---|
| 144 | | -} |
|---|
| 145 | | - |
|---|
| 146 | | -static void |
|---|
| 147 | | -mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) |
|---|
| 148 | | -{ |
|---|
| 149 | | - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
|---|
| 150 | | - |
|---|
| 151 | | - if (!ieee80211_is_data_qos(hdr->frame_control) || |
|---|
| 152 | | - !ieee80211_is_data_present(hdr->frame_control)) |
|---|
| 153 | | - return; |
|---|
| 154 | | - |
|---|
| 155 | | - mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; |
|---|
| 156 | 320 | } |
|---|
| 157 | 321 | |
|---|
| 158 | 322 | static void |
|---|
| 159 | 323 | mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, |
|---|
| 160 | 324 | struct sk_buff *skb, bool last) |
|---|
| 161 | 325 | { |
|---|
| 162 | | - struct mt76_wcid *wcid = (struct mt76_wcid *) sta->drv_priv; |
|---|
| 326 | + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; |
|---|
| 163 | 327 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
|---|
| 164 | | - struct mt76_queue *hwq = &dev->q_tx[MT_TXQ_PSD]; |
|---|
| 165 | 328 | |
|---|
| 166 | 329 | info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; |
|---|
| 167 | 330 | if (last) |
|---|
| 168 | | - info->flags |= IEEE80211_TX_STATUS_EOSP; |
|---|
| 331 | + info->flags |= IEEE80211_TX_STATUS_EOSP | |
|---|
| 332 | + IEEE80211_TX_CTL_REQ_TX_STATUS; |
|---|
| 169 | 333 | |
|---|
| 170 | 334 | mt76_skb_set_moredata(skb, !last); |
|---|
| 171 | | - dev->queue_ops->tx_queue_skb(dev, hwq, skb, wcid, sta); |
|---|
| 335 | + __mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL); |
|---|
| 172 | 336 | } |
|---|
| 173 | 337 | |
|---|
| 174 | 338 | void |
|---|
| .. | .. |
|---|
| 177 | 341 | enum ieee80211_frame_release_type reason, |
|---|
| 178 | 342 | bool more_data) |
|---|
| 179 | 343 | { |
|---|
| 180 | | - struct mt76_dev *dev = hw->priv; |
|---|
| 344 | + struct mt76_phy *phy = hw->priv; |
|---|
| 345 | + struct mt76_dev *dev = phy->dev; |
|---|
| 181 | 346 | struct sk_buff *last_skb = NULL; |
|---|
| 182 | | - struct mt76_queue *hwq = &dev->q_tx[MT_TXQ_PSD]; |
|---|
| 347 | + struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD]; |
|---|
| 183 | 348 | int i; |
|---|
| 184 | 349 | |
|---|
| 185 | 350 | spin_lock_bh(&hwq->lock); |
|---|
| 186 | 351 | for (i = 0; tids && nframes; i++, tids >>= 1) { |
|---|
| 187 | 352 | struct ieee80211_txq *txq = sta->txq[i]; |
|---|
| 188 | | - struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; |
|---|
| 353 | + struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv; |
|---|
| 189 | 354 | struct sk_buff *skb; |
|---|
| 190 | 355 | |
|---|
| 191 | 356 | if (!(tids & 1)) |
|---|
| 192 | 357 | continue; |
|---|
| 193 | 358 | |
|---|
| 194 | 359 | do { |
|---|
| 195 | | - skb = mt76_txq_dequeue(dev, mtxq, true); |
|---|
| 360 | + skb = mt76_txq_dequeue(phy, mtxq); |
|---|
| 196 | 361 | if (!skb) |
|---|
| 197 | 362 | break; |
|---|
| 198 | | - |
|---|
| 199 | | - if (mtxq->aggr) |
|---|
| 200 | | - mt76_check_agg_ssn(mtxq, skb); |
|---|
| 201 | 363 | |
|---|
| 202 | 364 | nframes--; |
|---|
| 203 | 365 | if (last_skb) |
|---|
| .. | .. |
|---|
| 210 | 372 | if (last_skb) { |
|---|
| 211 | 373 | mt76_queue_ps_skb(dev, sta, last_skb, true); |
|---|
| 212 | 374 | dev->queue_ops->kick(dev, hwq); |
|---|
| 375 | + } else { |
|---|
| 376 | + ieee80211_sta_eosp(sta); |
|---|
| 213 | 377 | } |
|---|
| 378 | + |
|---|
| 214 | 379 | spin_unlock_bh(&hwq->lock); |
|---|
| 215 | 380 | } |
|---|
| 216 | 381 | EXPORT_SYMBOL_GPL(mt76_release_buffered_frames); |
|---|
| 217 | 382 | |
|---|
| 218 | 383 | static int |
|---|
| 219 | | -mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_queue *hwq, |
|---|
| 220 | | - struct mt76_txq *mtxq, bool *empty) |
|---|
| 384 | +mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, |
|---|
| 385 | + struct mt76_txq *mtxq) |
|---|
| 221 | 386 | { |
|---|
| 387 | + struct mt76_dev *dev = phy->dev; |
|---|
| 222 | 388 | struct ieee80211_txq *txq = mtxq_to_txq(mtxq); |
|---|
| 223 | | - struct ieee80211_tx_info *info; |
|---|
| 389 | + enum mt76_txq_id qid = mt76_txq_get_qid(txq); |
|---|
| 224 | 390 | struct mt76_wcid *wcid = mtxq->wcid; |
|---|
| 391 | + struct ieee80211_tx_info *info; |
|---|
| 225 | 392 | struct sk_buff *skb; |
|---|
| 226 | | - int n_frames = 1, limit; |
|---|
| 227 | | - struct ieee80211_tx_rate tx_rate; |
|---|
| 228 | | - bool ampdu; |
|---|
| 229 | | - bool probe; |
|---|
| 393 | + int n_frames = 1; |
|---|
| 394 | + bool stop = false; |
|---|
| 230 | 395 | int idx; |
|---|
| 231 | 396 | |
|---|
| 232 | | - skb = mt76_txq_dequeue(dev, mtxq, false); |
|---|
| 233 | | - if (!skb) { |
|---|
| 234 | | - *empty = true; |
|---|
| 397 | + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) |
|---|
| 235 | 398 | return 0; |
|---|
| 236 | | - } |
|---|
| 399 | + |
|---|
| 400 | + if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) |
|---|
| 401 | + return 0; |
|---|
| 402 | + |
|---|
| 403 | + skb = mt76_txq_dequeue(phy, mtxq); |
|---|
| 404 | + if (!skb) |
|---|
| 405 | + return 0; |
|---|
| 237 | 406 | |
|---|
| 238 | 407 | info = IEEE80211_SKB_CB(skb); |
|---|
| 239 | | - if (!wcid->tx_rate_set) |
|---|
| 408 | + if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) |
|---|
| 240 | 409 | ieee80211_get_tx_rates(txq->vif, txq->sta, skb, |
|---|
| 241 | 410 | info->control.rates, 1); |
|---|
| 242 | | - tx_rate = info->control.rates[0]; |
|---|
| 243 | 411 | |
|---|
| 244 | | - probe = (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); |
|---|
| 245 | | - ampdu = IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU; |
|---|
| 246 | | - limit = ampdu ? 16 : 3; |
|---|
| 247 | | - |
|---|
| 248 | | - if (ampdu) |
|---|
| 249 | | - mt76_check_agg_ssn(mtxq, skb); |
|---|
| 250 | | - |
|---|
| 251 | | - idx = dev->queue_ops->tx_queue_skb(dev, hwq, skb, wcid, txq->sta); |
|---|
| 252 | | - |
|---|
| 412 | + idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop); |
|---|
| 253 | 413 | if (idx < 0) |
|---|
| 254 | 414 | return idx; |
|---|
| 255 | 415 | |
|---|
| 256 | 416 | do { |
|---|
| 257 | | - bool cur_ampdu; |
|---|
| 258 | | - |
|---|
| 259 | | - if (probe) |
|---|
| 260 | | - break; |
|---|
| 261 | | - |
|---|
| 262 | | - if (test_bit(MT76_OFFCHANNEL, &dev->state) || |
|---|
| 263 | | - test_bit(MT76_RESET, &dev->state)) |
|---|
| 417 | + if (test_bit(MT76_STATE_PM, &phy->state) || |
|---|
| 418 | + test_bit(MT76_RESET, &phy->state)) |
|---|
| 264 | 419 | return -EBUSY; |
|---|
| 265 | 420 | |
|---|
| 266 | | - skb = mt76_txq_dequeue(dev, mtxq, false); |
|---|
| 267 | | - if (!skb) { |
|---|
| 268 | | - *empty = true; |
|---|
| 421 | + if (stop) |
|---|
| 269 | 422 | break; |
|---|
| 270 | | - } |
|---|
| 423 | + |
|---|
| 424 | + if (q->queued + MT_TXQ_FREE_THR >= q->ndesc) |
|---|
| 425 | + break; |
|---|
| 426 | + |
|---|
| 427 | + skb = mt76_txq_dequeue(phy, mtxq); |
|---|
| 428 | + if (!skb) |
|---|
| 429 | + break; |
|---|
| 271 | 430 | |
|---|
| 272 | 431 | info = IEEE80211_SKB_CB(skb); |
|---|
| 273 | | - cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; |
|---|
| 432 | + if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) |
|---|
| 433 | + ieee80211_get_tx_rates(txq->vif, txq->sta, skb, |
|---|
| 434 | + info->control.rates, 1); |
|---|
| 274 | 435 | |
|---|
| 275 | | - if (ampdu != cur_ampdu || |
|---|
| 276 | | - (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { |
|---|
| 277 | | - skb_queue_tail(&mtxq->retry_q, skb); |
|---|
| 278 | | - break; |
|---|
| 279 | | - } |
|---|
| 280 | | - |
|---|
| 281 | | - info->control.rates[0] = tx_rate; |
|---|
| 282 | | - |
|---|
| 283 | | - if (cur_ampdu) |
|---|
| 284 | | - mt76_check_agg_ssn(mtxq, skb); |
|---|
| 285 | | - |
|---|
| 286 | | - idx = dev->queue_ops->tx_queue_skb(dev, hwq, skb, wcid, |
|---|
| 287 | | - txq->sta); |
|---|
| 436 | + idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop); |
|---|
| 288 | 437 | if (idx < 0) |
|---|
| 289 | | - return idx; |
|---|
| 438 | + break; |
|---|
| 290 | 439 | |
|---|
| 291 | 440 | n_frames++; |
|---|
| 292 | | - } while (n_frames < limit); |
|---|
| 441 | + } while (1); |
|---|
| 293 | 442 | |
|---|
| 294 | | - if (!probe) { |
|---|
| 295 | | - hwq->swq_queued++; |
|---|
| 296 | | - hwq->entry[idx].schedule = true; |
|---|
| 297 | | - } |
|---|
| 298 | | - |
|---|
| 299 | | - dev->queue_ops->kick(dev, hwq); |
|---|
| 443 | + dev->queue_ops->kick(dev, q); |
|---|
| 300 | 444 | |
|---|
| 301 | 445 | return n_frames; |
|---|
| 302 | 446 | } |
|---|
| 303 | 447 | |
|---|
| 304 | 448 | static int |
|---|
| 305 | | -mt76_txq_schedule_list(struct mt76_dev *dev, struct mt76_queue *hwq) |
|---|
| 449 | +mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) |
|---|
| 306 | 450 | { |
|---|
| 307 | | - struct mt76_txq *mtxq, *mtxq_last; |
|---|
| 308 | | - int len = 0; |
|---|
| 451 | + struct mt76_dev *dev = phy->dev; |
|---|
| 452 | + struct mt76_queue *q = dev->q_tx[qid]; |
|---|
| 453 | + struct ieee80211_txq *txq; |
|---|
| 454 | + struct mt76_txq *mtxq; |
|---|
| 455 | + struct mt76_wcid *wcid; |
|---|
| 456 | + int ret = 0; |
|---|
| 309 | 457 | |
|---|
| 310 | | -restart: |
|---|
| 311 | | - mtxq_last = list_last_entry(&hwq->swq, struct mt76_txq, list); |
|---|
| 312 | | - while (!list_empty(&hwq->swq)) { |
|---|
| 313 | | - bool empty = false; |
|---|
| 314 | | - int cur; |
|---|
| 458 | + spin_lock_bh(&q->lock); |
|---|
| 459 | + while (1) { |
|---|
| 460 | + if (test_bit(MT76_STATE_PM, &phy->state) || |
|---|
| 461 | + test_bit(MT76_RESET, &phy->state)) { |
|---|
| 462 | + ret = -EBUSY; |
|---|
| 463 | + break; |
|---|
| 464 | + } |
|---|
| 315 | 465 | |
|---|
| 316 | | - if (test_bit(MT76_OFFCHANNEL, &dev->state) || |
|---|
| 317 | | - test_bit(MT76_RESET, &dev->state)) |
|---|
| 318 | | - return -EBUSY; |
|---|
| 466 | + if (q->queued + MT_TXQ_FREE_THR >= q->ndesc) |
|---|
| 467 | + break; |
|---|
| 319 | 468 | |
|---|
| 320 | | - mtxq = list_first_entry(&hwq->swq, struct mt76_txq, list); |
|---|
| 469 | + txq = ieee80211_next_txq(phy->hw, qid); |
|---|
| 470 | + if (!txq) |
|---|
| 471 | + break; |
|---|
| 472 | + |
|---|
| 473 | + mtxq = (struct mt76_txq *)txq->drv_priv; |
|---|
| 474 | + wcid = mtxq->wcid; |
|---|
| 475 | + if (wcid && test_bit(MT_WCID_FLAG_PS, &wcid->flags)) |
|---|
| 476 | + continue; |
|---|
| 477 | + |
|---|
| 321 | 478 | if (mtxq->send_bar && mtxq->aggr) { |
|---|
| 322 | 479 | struct ieee80211_txq *txq = mtxq_to_txq(mtxq); |
|---|
| 323 | 480 | struct ieee80211_sta *sta = txq->sta; |
|---|
| .. | .. |
|---|
| 326 | 483 | u8 tid = txq->tid; |
|---|
| 327 | 484 | |
|---|
| 328 | 485 | mtxq->send_bar = false; |
|---|
| 329 | | - spin_unlock_bh(&hwq->lock); |
|---|
| 486 | + spin_unlock_bh(&q->lock); |
|---|
| 330 | 487 | ieee80211_send_bar(vif, sta->addr, tid, agg_ssn); |
|---|
| 331 | | - spin_lock_bh(&hwq->lock); |
|---|
| 332 | | - goto restart; |
|---|
| 488 | + spin_lock_bh(&q->lock); |
|---|
| 333 | 489 | } |
|---|
| 334 | 490 | |
|---|
| 335 | | - list_del_init(&mtxq->list); |
|---|
| 336 | | - |
|---|
| 337 | | - cur = mt76_txq_send_burst(dev, hwq, mtxq, &empty); |
|---|
| 338 | | - if (!empty) |
|---|
| 339 | | - list_add_tail(&mtxq->list, &hwq->swq); |
|---|
| 340 | | - |
|---|
| 341 | | - if (cur < 0) |
|---|
| 342 | | - return cur; |
|---|
| 343 | | - |
|---|
| 344 | | - len += cur; |
|---|
| 345 | | - |
|---|
| 346 | | - if (mtxq == mtxq_last) |
|---|
| 347 | | - break; |
|---|
| 491 | + ret += mt76_txq_send_burst(phy, q, mtxq); |
|---|
| 492 | + ieee80211_return_txq(phy->hw, txq, false); |
|---|
| 348 | 493 | } |
|---|
| 494 | + spin_unlock_bh(&q->lock); |
|---|
| 349 | 495 | |
|---|
| 350 | | - return len; |
|---|
| 496 | + return ret; |
|---|
| 351 | 497 | } |
|---|
| 352 | 498 | |
|---|
| 353 | | -void mt76_txq_schedule(struct mt76_dev *dev, struct mt76_queue *hwq) |
|---|
| 499 | +void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid) |
|---|
| 354 | 500 | { |
|---|
| 355 | 501 | int len; |
|---|
| 356 | 502 | |
|---|
| 357 | | - rcu_read_lock(); |
|---|
| 358 | | - do { |
|---|
| 359 | | - if (hwq->swq_queued >= 4 || list_empty(&hwq->swq)) |
|---|
| 360 | | - break; |
|---|
| 503 | + if (qid >= 4) |
|---|
| 504 | + return; |
|---|
| 361 | 505 | |
|---|
| 362 | | - len = mt76_txq_schedule_list(dev, hwq); |
|---|
| 506 | + rcu_read_lock(); |
|---|
| 507 | + |
|---|
| 508 | + do { |
|---|
| 509 | + ieee80211_txq_schedule_start(phy->hw, qid); |
|---|
| 510 | + len = mt76_txq_schedule_list(phy, qid); |
|---|
| 511 | + ieee80211_txq_schedule_end(phy->hw, qid); |
|---|
| 363 | 512 | } while (len > 0); |
|---|
| 513 | + |
|---|
| 364 | 514 | rcu_read_unlock(); |
|---|
| 365 | 515 | } |
|---|
| 366 | 516 | EXPORT_SYMBOL_GPL(mt76_txq_schedule); |
|---|
| 367 | 517 | |
|---|
| 368 | | -void mt76_txq_schedule_all(struct mt76_dev *dev) |
|---|
| 518 | +void mt76_txq_schedule_all(struct mt76_phy *phy) |
|---|
| 369 | 519 | { |
|---|
| 370 | 520 | int i; |
|---|
| 371 | 521 | |
|---|
| 372 | | - for (i = 0; i <= MT_TXQ_BK; i++) { |
|---|
| 373 | | - struct mt76_queue *q = &dev->q_tx[i]; |
|---|
| 374 | | - |
|---|
| 375 | | - spin_lock_bh(&q->lock); |
|---|
| 376 | | - mt76_txq_schedule(dev, q); |
|---|
| 377 | | - spin_unlock_bh(&q->lock); |
|---|
| 378 | | - } |
|---|
| 522 | + for (i = 0; i <= MT_TXQ_BK; i++) |
|---|
| 523 | + mt76_txq_schedule(phy, i); |
|---|
| 379 | 524 | } |
|---|
| 380 | 525 | EXPORT_SYMBOL_GPL(mt76_txq_schedule_all); |
|---|
| 526 | + |
|---|
| 527 | +void mt76_tx_worker(struct mt76_worker *w) |
|---|
| 528 | +{ |
|---|
| 529 | + struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker); |
|---|
| 530 | + |
|---|
| 531 | + mt76_txq_schedule_all(&dev->phy); |
|---|
| 532 | + if (dev->phy2) |
|---|
| 533 | + mt76_txq_schedule_all(dev->phy2); |
|---|
| 534 | + |
|---|
| 535 | +#ifdef CONFIG_NL80211_TESTMODE |
|---|
| 536 | + if (dev->test.tx_pending) |
|---|
| 537 | + mt76_testmode_tx_pending(dev); |
|---|
| 538 | +#endif |
|---|
| 539 | +} |
|---|
| 381 | 540 | |
|---|
| 382 | 541 | void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, |
|---|
| 383 | 542 | bool send_bar) |
|---|
| .. | .. |
|---|
| 386 | 545 | |
|---|
| 387 | 546 | for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { |
|---|
| 388 | 547 | struct ieee80211_txq *txq = sta->txq[i]; |
|---|
| 548 | + struct mt76_queue *hwq; |
|---|
| 389 | 549 | struct mt76_txq *mtxq; |
|---|
| 390 | 550 | |
|---|
| 391 | 551 | if (!txq) |
|---|
| 392 | 552 | continue; |
|---|
| 393 | 553 | |
|---|
| 554 | + hwq = dev->q_tx[mt76_txq_get_qid(txq)]; |
|---|
| 394 | 555 | mtxq = (struct mt76_txq *)txq->drv_priv; |
|---|
| 395 | 556 | |
|---|
| 396 | | - spin_lock_bh(&mtxq->hwq->lock); |
|---|
| 557 | + spin_lock_bh(&hwq->lock); |
|---|
| 397 | 558 | mtxq->send_bar = mtxq->aggr && send_bar; |
|---|
| 398 | | - if (!list_empty(&mtxq->list)) |
|---|
| 399 | | - list_del_init(&mtxq->list); |
|---|
| 400 | | - spin_unlock_bh(&mtxq->hwq->lock); |
|---|
| 559 | + spin_unlock_bh(&hwq->lock); |
|---|
| 401 | 560 | } |
|---|
| 402 | 561 | } |
|---|
| 403 | 562 | EXPORT_SYMBOL_GPL(mt76_stop_tx_queues); |
|---|
| 404 | 563 | |
|---|
| 405 | 564 | void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) |
|---|
| 406 | 565 | { |
|---|
| 407 | | - struct mt76_dev *dev = hw->priv; |
|---|
| 408 | | - struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; |
|---|
| 409 | | - struct mt76_queue *hwq = mtxq->hwq; |
|---|
| 566 | + struct mt76_phy *phy = hw->priv; |
|---|
| 567 | + struct mt76_dev *dev = phy->dev; |
|---|
| 410 | 568 | |
|---|
| 411 | | - spin_lock_bh(&hwq->lock); |
|---|
| 412 | | - if (list_empty(&mtxq->list)) |
|---|
| 413 | | - list_add_tail(&mtxq->list, &hwq->swq); |
|---|
| 414 | | - mt76_txq_schedule(dev, hwq); |
|---|
| 415 | | - spin_unlock_bh(&hwq->lock); |
|---|
| 569 | + if (!test_bit(MT76_STATE_RUNNING, &phy->state)) |
|---|
| 570 | + return; |
|---|
| 571 | + |
|---|
| 572 | + mt76_worker_schedule(&dev->tx_worker); |
|---|
| 416 | 573 | } |
|---|
| 417 | 574 | EXPORT_SYMBOL_GPL(mt76_wake_tx_queue); |
|---|
| 418 | 575 | |
|---|
| 419 | | -void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq) |
|---|
| 576 | +u8 mt76_ac_to_hwq(u8 ac) |
|---|
| 420 | 577 | { |
|---|
| 421 | | - struct mt76_txq *mtxq; |
|---|
| 422 | | - struct mt76_queue *hwq; |
|---|
| 423 | | - struct sk_buff *skb; |
|---|
| 578 | + static const u8 wmm_queue_map[] = { |
|---|
| 579 | + [IEEE80211_AC_BE] = 0, |
|---|
| 580 | + [IEEE80211_AC_BK] = 1, |
|---|
| 581 | + [IEEE80211_AC_VI] = 2, |
|---|
| 582 | + [IEEE80211_AC_VO] = 3, |
|---|
| 583 | + }; |
|---|
| 424 | 584 | |
|---|
| 425 | | - if (!txq) |
|---|
| 426 | | - return; |
|---|
| 585 | + if (WARN_ON(ac >= IEEE80211_NUM_ACS)) |
|---|
| 586 | + return 0; |
|---|
| 427 | 587 | |
|---|
| 428 | | - mtxq = (struct mt76_txq *) txq->drv_priv; |
|---|
| 429 | | - hwq = mtxq->hwq; |
|---|
| 430 | | - |
|---|
| 431 | | - spin_lock_bh(&hwq->lock); |
|---|
| 432 | | - if (!list_empty(&mtxq->list)) |
|---|
| 433 | | - list_del(&mtxq->list); |
|---|
| 434 | | - spin_unlock_bh(&hwq->lock); |
|---|
| 435 | | - |
|---|
| 436 | | - while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL) |
|---|
| 437 | | - ieee80211_free_txskb(dev->hw, skb); |
|---|
| 588 | + return wmm_queue_map[ac]; |
|---|
| 438 | 589 | } |
|---|
| 439 | | -EXPORT_SYMBOL_GPL(mt76_txq_remove); |
|---|
| 590 | +EXPORT_SYMBOL_GPL(mt76_ac_to_hwq); |
|---|
| 440 | 591 | |
|---|
| 441 | | -void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) |
|---|
| 592 | +int mt76_skb_adjust_pad(struct sk_buff *skb, int pad) |
|---|
| 442 | 593 | { |
|---|
| 443 | | - struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; |
|---|
| 594 | + struct sk_buff *iter, *last = skb; |
|---|
| 444 | 595 | |
|---|
| 445 | | - INIT_LIST_HEAD(&mtxq->list); |
|---|
| 446 | | - skb_queue_head_init(&mtxq->retry_q); |
|---|
| 596 | + /* First packet of a A-MSDU burst keeps track of the whole burst |
|---|
| 597 | + * length, need to update length of it and the last packet. |
|---|
| 598 | + */ |
|---|
| 599 | + skb_walk_frags(skb, iter) { |
|---|
| 600 | + last = iter; |
|---|
| 601 | + if (!iter->next) { |
|---|
| 602 | + skb->data_len += pad; |
|---|
| 603 | + skb->len += pad; |
|---|
| 604 | + break; |
|---|
| 605 | + } |
|---|
| 606 | + } |
|---|
| 447 | 607 | |
|---|
| 448 | | - mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)]; |
|---|
| 608 | + if (skb_pad(last, pad)) |
|---|
| 609 | + return -ENOMEM; |
|---|
| 610 | + |
|---|
| 611 | + __skb_put(last, pad); |
|---|
| 612 | + |
|---|
| 613 | + return 0; |
|---|
| 449 | 614 | } |
|---|
| 450 | | -EXPORT_SYMBOL_GPL(mt76_txq_init); |
|---|
| 615 | +EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad); |
|---|
| 616 | + |
|---|
| 617 | +void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, |
|---|
| 618 | + struct mt76_queue_entry *e) |
|---|
| 619 | +{ |
|---|
| 620 | + if (e->skb) |
|---|
| 621 | + dev->drv->tx_complete_skb(dev, e); |
|---|
| 622 | + |
|---|
| 623 | + spin_lock_bh(&q->lock); |
|---|
| 624 | + q->tail = (q->tail + 1) % q->ndesc; |
|---|
| 625 | + q->queued--; |
|---|
| 626 | + spin_unlock_bh(&q->lock); |
|---|
| 627 | +} |
|---|
| 628 | +EXPORT_SYMBOL_GPL(mt76_queue_tx_complete); |
|---|