diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/tx.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/tx.c | 94 |
1 files changed, 59 insertions, 35 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 1809b03292c3..513916469ca2 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -100,7 +100,8 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, return; /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ - if (flags & MT_TX_CB_TXS_FAILED) { + if (flags & MT_TX_CB_TXS_FAILED && + (dev->drv->drv_flags & MT_DRV_IGNORE_TXS_FAILED)) { info->status.rates[0].count = 0; info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; @@ -308,11 +309,14 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, int idx; non_aql = !info->tx_time_est; - idx = dev->queue_ops->tx_queue_skb(dev, q, qid, skb, wcid, sta); + idx = dev->queue_ops->tx_queue_skb(phy, q, qid, skb, wcid, sta); if (idx < 0 || !sta) return idx; wcid = (struct mt76_wcid *)sta->drv_priv; + if (!wcid->sta) + return idx; + q->entry[idx].wcid = wcid->idx; if (!non_aql) @@ -330,6 +334,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct sk_buff_head *head; if (mt76_testmode_enabled(phy)) { ieee80211_free_txskb(phy->hw, skb); @@ -345,9 +350,15 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); - spin_lock_bh(&wcid->tx_pending.lock); - __skb_queue_tail(&wcid->tx_pending, skb); - spin_unlock_bh(&wcid->tx_pending.lock); + if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || + (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) + head = &wcid->tx_offchannel; + else + head = &wcid->tx_pending; + + spin_lock_bh(&head->lock); + __skb_queue_tail(head, skb); + spin_unlock_bh(&head->lock); spin_lock_bh(&phy->tx_lock); if (list_empty(&wcid->tx_list)) @@ -478,8 +489,8 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, return idx; do { - if (test_bit(MT76_RESET, &phy->state)) - return -EBUSY; + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + break; if (stop || mt76_txq_stopped(q)) break; @@ -512,24 +523,16 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, static int mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) { - struct mt76_queue *q = phy->q_tx[qid]; struct mt76_dev *dev = phy->dev; struct ieee80211_txq *txq; struct mt76_txq *mtxq; struct mt76_wcid *wcid; + struct mt76_queue *q; int ret = 0; while (1) { int n_frames = 0; - if (test_bit(MT76_RESET, &phy->state)) - return -EBUSY; - - if (dev->queue_ops->tx_cleanup && - q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { - dev->queue_ops->tx_cleanup(dev, q, false); - } - txq = ieee80211_next_txq(phy->hw, qid); if (!txq) break; @@ -539,6 +542,16 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) continue; + phy = mt76_dev_phy(dev, wcid->phy_idx); + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + continue; + + q = phy->q_tx[qid]; + if (dev->queue_ops->tx_cleanup && + q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { + dev->queue_ops->tx_cleanup(dev, q, false); + } + if (mtxq->send_bar && mtxq->aggr) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); struct ieee80211_sta *sta = txq->sta; @@ -586,7 +599,8 @@ void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid) EXPORT_SYMBOL_GPL(mt76_txq_schedule); static int -mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid) +mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, + struct sk_buff_head *head) { struct mt76_dev *dev = phy->dev; struct ieee80211_sta *sta; @@ -594,8 +608,8 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid) struct sk_buff *skb; int ret = 0; - spin_lock(&wcid->tx_pending.lock); - while ((skb = skb_peek(&wcid->tx_pending)) != NULL) { + spin_lock(&head->lock); + while ((skb = skb_peek(head)) != NULL) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int qid = skb_get_queue_mapping(skb); @@ -607,13 +621,13 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid) qid = MT_TXQ_PSD; q = phy->q_tx[qid]; - if (mt76_txq_stopped(q)) { + if (mt76_txq_stopped(q) || test_bit(MT76_RESET, &phy->state)) { ret = -1; break; } - __skb_unlink(skb, &wcid->tx_pending); - spin_unlock(&wcid->tx_pending.lock); + __skb_unlink(skb, head); + spin_unlock(&head->lock); sta = wcid_to_sta(wcid); spin_lock(&q->lock); @@ -621,15 +635,17 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid) dev->queue_ops->kick(dev, q); spin_unlock(&q->lock); - spin_lock(&wcid->tx_pending.lock); + spin_lock(&head->lock); } - spin_unlock(&wcid->tx_pending.lock); + spin_unlock(&head->lock); return ret; } static void mt76_txq_schedule_pending(struct mt76_phy *phy) { + LIST_HEAD(tx_list); + if (list_empty(&phy->tx_list)) return; @@ -637,22 +653,27 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) rcu_read_lock(); spin_lock(&phy->tx_lock); - while (!list_empty(&phy->tx_list)) { - struct mt76_wcid *wcid = NULL; + list_splice_init(&phy->tx_list, &tx_list); + while (!list_empty(&tx_list)) { + struct mt76_wcid *wcid; int ret; - wcid = list_first_entry(&phy->tx_list, struct mt76_wcid, tx_list); + wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list); list_del_init(&wcid->tx_list); spin_unlock(&phy->tx_lock); - ret = mt76_txq_schedule_pending_wcid(phy, wcid); + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); + if (ret >= 0 && !phy->offchannel) + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); spin_lock(&phy->tx_lock); - if (ret) { - if (list_empty(&wcid->tx_list)) - list_add_tail(&wcid->tx_list, &phy->tx_list); + if (!skb_queue_empty(&wcid->tx_pending) && + !skb_queue_empty(&wcid->tx_offchannel) && + list_empty(&wcid->tx_list)) + list_add_tail(&wcid->tx_list, &phy->tx_list); + + if (ret < 0) break; - } } spin_unlock(&phy->tx_lock); @@ -662,9 +683,14 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) void mt76_txq_schedule_all(struct mt76_phy *phy) { + struct mt76_phy *main_phy = &phy->dev->phy; int i; mt76_txq_schedule_pending(phy); + + if (phy != main_phy && phy->hw == main_phy->hw) + return; + for (i = 0; i <= MT_TXQ_BK; i++) mt76_txq_schedule(phy, i); } @@ -675,6 +701,7 @@ void mt76_tx_worker_run(struct mt76_dev *dev) struct mt76_phy *phy; int i; + mt76_txq_schedule_all(&dev->phy); for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { phy = dev->phys[i]; if (!phy) @@ -730,9 +757,6 @@ void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - if (!test_bit(MT76_STATE_RUNNING, &phy->state)) - return; - mt76_worker_schedule(&dev->tx_worker); } EXPORT_SYMBOL_GPL(mt76_wake_tx_queue); |