mt76: convert from tx tasklet to tx worker thread

This should improve performance by allowing the scheduler to move the tx
scheduling work to idle CPUs

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2020-08-22 15:56:57 +02:00
parent 87a6942906
commit 2f1318a06d
20 changed files with 54 additions and 53 deletions
+1
View File
@@ -606,6 +606,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
{
int i;
mt76_worker_disable(&dev->tx_worker);
netif_napi_del(&dev->tx_napi);
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
mt76_dma_tx_cleanup(dev, i, true);
+11 -3
View File
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2016 Felix Fietkau <[email protected]>
*/
#include <uapi/linux/sched/types.h>
#include <linux/of.h>
#include "mt76.h"
@@ -442,8 +443,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
dev->wq = alloc_ordered_workqueue("mt76", 0);
if (!dev->wq) {
ieee80211_free_hw(hw);
@@ -457,6 +456,7 @@ EXPORT_SYMBOL_GPL(mt76_alloc_device);
int mt76_register_device(struct mt76_dev *dev, bool vht,
struct ieee80211_rate *rates, int n_rates)
{
struct sched_param sparam = {.sched_priority = 1};
struct ieee80211_hw *hw = dev->hw;
struct mt76_phy *phy = &dev->phy;
int ret;
@@ -486,7 +486,14 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
return ret;
}
return ieee80211_register_hw(hw);
ret = ieee80211_register_hw(hw);
if (ret)
return ret;
WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, mt76_tx_worker, "tx"));
sched_setscheduler(dev->tx_worker.task, SCHED_FIFO, &sparam);
return 0;
}
EXPORT_SYMBOL_GPL(mt76_register_device);
@@ -503,6 +510,7 @@ EXPORT_SYMBOL_GPL(mt76_unregister_device);
void mt76_free_device(struct mt76_dev *dev)
{
mt76_worker_teardown(&dev->tx_worker);
if (dev->wq) {
destroy_workqueue(dev->wq);
dev->wq = NULL;
+2 -2
View File
@@ -610,7 +610,7 @@ struct mt76_dev {
const struct mt76_queue_ops *queue_ops;
int tx_dma_idx[4];
struct tasklet_struct tx_tasklet;
struct mt76_worker tx_worker;
struct napi_struct tx_napi;
struct delayed_work mac_work;
@@ -920,7 +920,7 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
void mt76_txq_schedule_all(struct mt76_phy *phy);
void mt76_tx_tasklet(unsigned long data);
void mt76_tx_worker(struct mt76_worker *w);
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
+1 -2
View File
@@ -165,7 +165,7 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
mt7603_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
return 0;
}
@@ -249,6 +249,5 @@ void mt7603_dma_cleanup(struct mt7603_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN |
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
+2 -2
View File
@@ -1405,7 +1405,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
/* lock/unlock all queues to ensure that no tx is pending */
mt76_txq_schedule_all(&dev->mphy);
tasklet_disable(&dev->mt76.tx_tasklet);
mt76_worker_disable(&dev->mt76.tx_worker);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
@@ -1454,7 +1454,7 @@ skip_dma_reset:
clear_bit(MT76_RESET, &dev->mphy.state);
mutex_unlock(&dev->mt76.mutex);
tasklet_enable(&dev->mt76.tx_tasklet);
mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
+1 -2
View File
@@ -118,7 +118,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
mt7615_tx_cleanup(dev);
mt7615_pm_power_save_sched(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
if (napi_complete_done(napi, 0))
mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
@@ -324,6 +324,5 @@ void mt7615_dma_cleanup(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN);
mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
+4 -4
View File
@@ -1447,7 +1447,7 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
rcu_read_unlock();
mt7615_pm_power_save_sched(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
}
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -1872,7 +1872,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
}
spin_unlock_bh(&dev->pm.txq_lock);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
out:
ieee80211_wake_queues(mphy->hw);
@@ -2114,7 +2114,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
if (ext_phy)
mt76_txq_schedule_all(ext_phy);
tasklet_disable(&dev->mt76.tx_tasklet);
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
napi_disable(&dev->mt76.tx_napi);
@@ -2135,7 +2135,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
tasklet_enable(&dev->mt76.tx_tasklet);
mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
+1 -1
View File
@@ -707,7 +707,7 @@ mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
}
dev->pm.last_activity = jiffies;
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
}
static void mt7615_tx(struct ieee80211_hw *hw,
+2 -1
View File
@@ -88,7 +88,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
}
napi_disable(&mdev->tx_napi);
tasklet_kill(&mdev->tx_tasklet);
mt76_worker_disable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_disable(&mdev->napi[i]);
@@ -162,6 +162,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
if (pdma_reset)
dev_err(mdev->dev, "PDMA engine must be reinitialized\n");
mt76_worker_enable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
-2
View File
@@ -179,9 +179,7 @@ static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state)
}
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
tasklet_kill(&dev->mt76.tx_tasklet);
return 0;
}
+1 -1
View File
@@ -204,7 +204,7 @@ static void mt76x0e_cleanup(struct mt76x02_dev *dev)
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
mt76x0_chip_onoff(dev, false, false);
mt76x0e_stop_hw(dev);
mt76x02_dma_cleanup(dev);
mt76_dma_cleanup(&dev->mt76);
mt76x02_mcu_cleanup(dev);
}
-1
View File
@@ -61,6 +61,5 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
int mt76x02_dma_init(struct mt76x02_dev *dev);
void mt76x02_dma_disable(struct mt76x02_dev *dev);
void mt76x02_dma_cleanup(struct mt76x02_dev *dev);
#endif /* __MT76x02_DMA_H */
+8 -14
View File
@@ -150,9 +150,11 @@ static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev)
mt76x02_send_tx_status(dev, &stat, &update);
}
static void mt76x02_tx_tasklet(unsigned long data)
static void mt76x02_tx_worker(struct mt76_worker *w)
{
struct mt76x02_dev *dev = (struct mt76x02_dev *)data;
struct mt76x02_dev *dev;
dev = container_of(w, struct mt76x02_dev, mt76.tx_worker);
mt76x02_mac_poll_tx_status(dev, false);
mt76x02_process_tx_status_fifo(dev);
@@ -177,7 +179,7 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
return 0;
}
@@ -196,8 +198,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
if (!status_fifo)
return -ENOMEM;
tasklet_init(&dev->mt76.tx_tasklet, mt76x02_tx_tasklet,
(unsigned long)dev);
dev->mt76.tx_worker.fn = mt76x02_tx_worker;
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
(unsigned long)dev);
@@ -325,13 +326,6 @@ static void mt76x02_dma_enable(struct mt76x02_dev *dev)
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
}
void mt76x02_dma_cleanup(struct mt76x02_dev *dev)
{
tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup);
void mt76x02_dma_disable(struct mt76x02_dev *dev)
{
u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
@@ -449,7 +443,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
set_bit(MT76_RESET, &dev->mphy.state);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
tasklet_disable(&dev->mt76.tx_tasklet);
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.tx_napi);
mt76_for_each_q_rx(&dev->mt76, i) {
@@ -506,7 +500,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
clear_bit(MT76_RESET, &dev->mphy.state);
tasklet_enable(&dev->mt76.tx_tasklet);
mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
+2 -1
View File
@@ -113,7 +113,7 @@ mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state)
napi_disable(&mdev->tx_napi);
tasklet_kill(&mdev->pre_tbtt_tasklet);
tasklet_kill(&mdev->tx_tasklet);
mt76_worker_disable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i)
napi_disable(&mdev->napi[i]);
@@ -147,6 +147,7 @@ mt76x2e_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
mt76_worker_enable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
+1 -1
View File
@@ -283,7 +283,7 @@ void mt76x2_cleanup(struct mt76x02_dev *dev)
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
mt76x2_stop_hardware(dev);
mt76x02_dma_cleanup(dev);
mt76_dma_cleanup(&dev->mt76);
mt76x02_mcu_cleanup(dev);
}
-1
View File
@@ -273,6 +273,5 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev)
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
+3 -3
View File
@@ -1010,7 +1010,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
dev_kfree_skb(skb);
mt7915_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
mt76_worker_schedule(&dev->mt76.tx_worker);
}
void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
@@ -1283,7 +1283,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (ext_phy)
mt76_txq_schedule_all(ext_phy);
tasklet_disable(&dev->mt76.tx_tasklet);
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
napi_disable(&dev->mt76.napi[2]);
@@ -1303,7 +1303,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
tasklet_enable(&dev->mt76.tx_tasklet);
mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
+3 -3
View File
@@ -160,7 +160,7 @@ mt76_testmode_tx_start(struct mt76_dev *dev)
td->tx_queued = 0;
td->tx_done = 0;
td->tx_pending = td->tx_count;
tasklet_schedule(&dev->tx_tasklet);
mt76_worker_schedule(&dev->tx_worker);
}
static void
@@ -168,11 +168,11 @@ mt76_testmode_tx_stop(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
tasklet_disable(&dev->tx_tasklet);
mt76_worker_disable(&dev->tx_worker);
td->tx_pending = 0;
tasklet_enable(&dev->tx_tasklet);
mt76_worker_enable(&dev->tx_worker);
wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ);
+3 -3
View File
@@ -576,9 +576,9 @@ void mt76_txq_schedule_all(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
void mt76_tx_tasklet(unsigned long data)
void mt76_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);
mt76_txq_schedule_all(&dev->phy);
if (dev->phy2)
@@ -621,7 +621,7 @@ void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
if (!test_bit(MT76_STATE_RUNNING, &phy->state))
return;
tasklet_schedule(&dev->tx_tasklet);
mt76_worker_schedule(&dev->tx_worker);
}
EXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
+8 -6
View File
@@ -792,9 +792,9 @@ 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;
@@ -882,7 +882,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
@@ -1037,6 +1037,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
struct mt76_queue *q;
int i, j, ret;
mt76_worker_disable(&dev->tx_worker);
ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy),
HZ / 5);
if (!ret) {
@@ -1048,8 +1050,6 @@ void mt76u_stop_tx(struct mt76_dev *dev)
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.
*/
@@ -1072,6 +1072,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
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);
@@ -1121,8 +1123,8 @@ 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->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);