diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/usb.c')
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/usb.c | 218 |
1 files changed, 80 insertions, 138 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index a981da6c35a5..7d3f0a2e5fa0 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -497,8 +497,8 @@ mt76u_get_next_rx_entry(struct mt76_queue *q) spin_lock_irqsave(&q->lock, flags); if (q->queued > 0) { - urb = q->entry[q->head].urb; - q->head = (q->head + 1) % q->ndesc; + urb = q->entry[q->tail].urb; + q->tail = (q->tail + 1) % q->ndesc; q->queued--; } spin_unlock_irqrestore(&q->lock, flags); @@ -616,16 +616,16 @@ static void mt76u_complete_rx(struct urb *urb) default: dev_err_ratelimited(dev->dev, "rx urb failed: %d\n", urb->status); - /* fall through */ + fallthrough; case 0: break; } spin_lock_irqsave(&q->lock, flags); - if (WARN_ONCE(q->entry[q->tail].urb != urb, "rx urb mismatch")) + if (WARN_ONCE(q->entry[q->head].urb != urb, "rx urb mismatch")) goto out; - q->tail = (q->tail + 1) % q->ndesc; + q->head = (q->head + 1) % q->ndesc; q->queued++; tasklet_schedule(&dev->usb.rx_tasklet); out: @@ -672,17 +672,11 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_rx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; - struct mt76_queue *q; int i; rcu_read_lock(); - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_process_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); } @@ -756,27 +750,19 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_free_rx(struct mt76_dev *dev) { - struct mt76_queue *q; int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_free_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_free_rx_queue(dev, &dev->q_rx[i]); } void mt76u_stop_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j; + int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int j; for (j = 0; j < q->ndesc; j++) usb_poison_urb(q->entry[j].urb); @@ -788,14 +774,11 @@ EXPORT_SYMBOL_GPL(mt76u_stop_rx); int mt76u_resume_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j, err; + int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int err, j; for (j = 0; j < q->ndesc; j++) usb_unpoison_urb(q->entry[j].urb); @@ -809,43 +792,27 @@ int mt76u_resume_rx(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76u_resume_rx); -static void mt76u_tx_tasklet(unsigned long data) +static void mt76u_tx_worker(struct mt76_worker *w) { - struct mt76_dev *dev = (struct mt76_dev *)data; + struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker); struct mt76_queue_entry entry; - struct mt76_sw_queue *sq; struct mt76_queue *q; bool wake; int i; for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u32 n_dequeued = 0, n_sw_dequeued = 0; + q = dev->q_tx[i]; - sq = &dev->q_tx[i]; - q = sq->q; - - while (q->queued > n_dequeued) { - if (!q->entry[q->head].done) + while (q->queued > 0) { + if (!q->entry[q->tail].done) break; - if (q->entry[q->head].schedule) { - q->entry[q->head].schedule = false; - n_sw_dequeued++; - } - - entry = q->entry[q->head]; - q->entry[q->head].done = false; - q->head = (q->head + 1) % q->ndesc; - n_dequeued++; + entry = q->entry[q->tail]; + q->entry[q->tail].done = false; - dev->drv->tx_complete_skb(dev, i, &entry); + mt76_queue_tx_complete(dev, q, &entry); } - spin_lock_bh(&q->lock); - - sq->swq_queued -= n_sw_dequeued; - q->queued -= n_dequeued; - wake = q->stopped && q->queued < q->ndesc - 8; if (wake) q->stopped = false; @@ -853,13 +820,11 @@ static void mt76u_tx_tasklet(unsigned long data) if (!q->queued) wake_up(&dev->tx_wait); - spin_unlock_bh(&q->lock); - mt76_txq_schedule(&dev->phy, i); if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) - queue_work(dev->usb.wq, &dev->usb.stat_work); + queue_work(dev->wq, &dev->usb.stat_work); if (wake) ieee80211_wake_queue(dev->hw, i); } @@ -885,7 +850,7 @@ static void mt76u_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - queue_work(usb->wq, &usb->stat_work); + queue_work(dev->wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->phy.state); } @@ -899,7 +864,7 @@ static void mt76u_complete_tx(struct urb *urb) dev_err(dev->dev, "tx urb failed: %d\n", urb->status); e->done = true; - tasklet_schedule(&dev->tx_tasklet); + mt76_worker_schedule(&dev->tx_worker); } static int @@ -921,45 +886,16 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, return urb->num_sgs; } -int mt76u_skb_dma_info(struct sk_buff *skb, u32 info) -{ - struct sk_buff *iter, *last = skb; - u32 pad; - - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - /* Add zero pad of 4 - 7 bytes */ - pad = round_up(skb->len, 4) + 4 - skb->len; - - /* First packet of a A-MSDU burst keeps track of the whole burst - * length, need to update length of it and the last packet. - */ - skb_walk_frags(skb, iter) { - last = iter; - if (!iter->next) { - skb->data_len += pad; - skb->len += pad; - break; - } - } - - if (skb_pad(last, pad)) - return -ENOMEM; - __skb_put(last, pad); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76u_skb_dma_info); - static int mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { - struct mt76_queue *q = dev->q_tx[qid].q; + struct mt76_queue *q = dev->q_tx[qid]; struct mt76_tx_info tx_info = { .skb = skb, }; - u16 idx = q->tail; + u16 idx = q->head; int err; if (q->queued == q->ndesc) @@ -978,7 +914,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, q->entry[idx].urb, mt76u_complete_tx, &q->entry[idx]); - q->tail = (q->tail + 1) % q->ndesc; + q->head = (q->head + 1) % q->ndesc; q->entry[idx].skb = tx_info.skb; q->queued++; @@ -990,7 +926,7 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) struct urb *urb; int err; - while (q->first != q->tail) { + while (q->first != q->head) { urb = q->entry[q->first].urb; trace_submit_urb(dev, urb); @@ -1009,8 +945,20 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) { - if (mt76_chip(dev) == 0x7663) - return ac ^ 0x3; + if (mt76_chip(dev) == 0x7663) { + static const u8 lmac_queue_map[] = { + /* ac to lmac mapping */ + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 4, + }; + + if (WARN_ON(ac >= ARRAY_SIZE(lmac_queue_map))) + return 1; /* BE */ + + return lmac_queue_map[ac]; + } return mt76_ac_to_hwq(ac); } @@ -1021,10 +969,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) int i, j, err; for (i = 0; i <= MT_TXQ_PSD; i++) { - INIT_LIST_HEAD(&dev->q_tx[i].swq); - if (i >= IEEE80211_NUM_ACS) { - dev->q_tx[i].q = dev->q_tx[0].q; + dev->q_tx[i] = dev->q_tx[0]; continue; } @@ -1034,7 +980,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) spin_lock_init(&q->lock); q->hw_idx = mt76u_ac_to_hwq(dev, i); - dev->q_tx[i].q = q; + dev->q_tx[i] = q; q->entry = devm_kcalloc(dev->dev, MT_NUM_TX_ENTRIES, sizeof(*q->entry), @@ -1055,11 +1001,16 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) static void mt76u_free_tx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j; + int i; for (i = 0; i < IEEE80211_NUM_ACS; i++) { - q = dev->q_tx[i].q; + struct mt76_queue *q; + int j; + + q = dev->q_tx[i]; + if (!q) + continue; + for (j = 0; j < q->ndesc; j++) usb_free_urb(q->entry[j].urb); } @@ -1067,45 +1018,48 @@ static void mt76u_free_tx(struct mt76_dev *dev) void mt76u_stop_tx(struct mt76_dev *dev) { - struct mt76_queue_entry entry; - struct mt76_queue *q; - int i, j, ret; + int ret; + + mt76_worker_disable(&dev->tx_worker); ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy), HZ / 5); if (!ret) { + struct mt76_queue_entry entry; + struct mt76_queue *q; + int i, j; + dev_err(dev->dev, "timed out waiting for pending tx\n"); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - q = dev->q_tx[i].q; + q = dev->q_tx[i]; + if (!q) + continue; + for (j = 0; j < q->ndesc; j++) usb_kill_urb(q->entry[j].urb); } - tasklet_kill(&dev->tx_tasklet); - /* On device removal we maight queue skb's, but mt76u_tx_kick() * will fail to submit urb, cleanup those skb's manually. */ for (i = 0; i < IEEE80211_NUM_ACS; i++) { - q = dev->q_tx[i].q; - - /* Assure we are in sync with killed tasklet. */ - spin_lock_bh(&q->lock); - while (q->queued) { - entry = q->entry[q->head]; - q->head = (q->head + 1) % q->ndesc; - q->queued--; - - dev->drv->tx_complete_skb(dev, i, &entry); - } - spin_unlock_bh(&q->lock); + q = dev->q_tx[i]; + if (!q) + continue; + + entry = q->entry[q->tail]; + q->entry[q->tail].done = false; + + mt76_queue_tx_complete(dev, q, &entry); } } cancel_work_sync(&dev->usb.stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); + mt76_worker_enable(&dev->tx_worker); + mt76_tx_status_check(dev, NULL, true); } EXPORT_SYMBOL_GPL(mt76u_stop_tx); @@ -1137,15 +1091,6 @@ static const struct mt76_queue_ops usb_queue_ops = { .kick = mt76u_tx_kick, }; -void mt76u_deinit(struct mt76_dev *dev) -{ - if (dev->usb.wq) { - destroy_workqueue(dev->usb.wq); - dev->usb.wq = NULL; - } -} -EXPORT_SYMBOL_GPL(mt76u_deinit); - int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, bool ext) { @@ -1164,14 +1109,10 @@ int mt76u_init(struct mt76_dev *dev, mt76u_ops.rmw = ext ? mt76u_rmw_ext : mt76u_rmw; mt76u_ops.write_copy = ext ? mt76u_copy_ext : mt76u_copy; + dev->tx_worker.fn = mt76u_tx_worker; tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev); - tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev); INIT_WORK(&usb->stat_work, mt76u_tx_status_data); - usb->wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0); - if (!usb->wq) - return -ENOMEM; - usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1); if (usb->data_len < 32) usb->data_len = 32; @@ -1195,7 +1136,8 @@ int mt76u_init(struct mt76_dev *dev, return 0; error: - mt76u_deinit(dev); + destroy_workqueue(dev->wq); + return err; } EXPORT_SYMBOL_GPL(mt76u_init); |