From 2f1318a06d0a9703f0085522361a4bc66f61d808 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 24 Jul 2020 16:11:52 +0200 Subject: [PATCH] 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 --- dma.c | 1 + mac80211.c | 14 +++++++++++--- mt76.h | 4 ++-- mt7603/dma.c | 3 +-- mt7603/mac.c | 4 ++-- mt7615/dma.c | 3 +-- mt7615/mac.c | 8 ++++---- mt7615/main.c | 2 +- mt7615/pci.c | 3 ++- mt7615/usb.c | 2 -- mt76x0/pci.c | 2 +- mt76x02_dma.h | 1 - mt76x02_mmio.c | 22 ++++++++-------------- mt76x2/pci.c | 3 ++- mt76x2/pci_init.c | 2 +- mt7915/dma.c | 1 - mt7915/mac.c | 6 +++--- testmode.c | 6 +++--- tx.c | 6 +++--- usb.c | 14 ++++++++------ 20 files changed, 54 insertions(+), 53 deletions(-) diff --git a/dma.c b/dma.c index 345162a7..67fd5072 100644 --- a/dma.c +++ b/dma.c @@ -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); diff --git a/mac80211.c b/mac80211.c index 8b41558c..4fdecdc4 100644 --- a/mac80211.c +++ b/mac80211.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2016 Felix Fietkau */ +#include #include #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; diff --git a/mt76.h b/mt76.h index 64a75393..f82df8ca 100644 --- a/mt76.h +++ b/mt76.h @@ -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, diff --git a/mt7603/dma.c b/mt7603/dma.c index a08b8528..9ec86da9 100644 --- a/mt7603/dma.c +++ b/mt7603/dma.c @@ -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); } diff --git a/mt7603/mac.c b/mt7603/mac.c index 625dc6d5..cbf21f40 100644 --- a/mt7603/mac.c +++ b/mt7603/mac.c @@ -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); diff --git a/mt7615/dma.c b/mt7615/dma.c index 3b375fdf..09504b0b 100644 --- a/mt7615/dma.c +++ b/mt7615/dma.c @@ -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); } diff --git a/mt7615/mac.c b/mt7615/mac.c index e3663c7c..6306e714 100644 --- a/mt7615/mac.c +++ b/mt7615/mac.c @@ -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); diff --git a/mt7615/main.c b/mt7615/main.c index ff2a9489..267faba3 100644 --- a/mt7615/main.c +++ b/mt7615/main.c @@ -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, diff --git a/mt7615/pci.c b/mt7615/pci.c index b9794f8a..dbd29d89 100644 --- a/mt7615/pci.c +++ b/mt7615/pci.c @@ -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]); diff --git a/mt7615/usb.c b/mt7615/usb.c index f1b4a631..7e83c350 100644 --- a/mt7615/usb.c +++ b/mt7615/usb.c @@ -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; } diff --git a/mt76x0/pci.c b/mt76x0/pci.c index 5e567483..dda11c70 100644 --- a/mt76x0/pci.c +++ b/mt76x0/pci.c @@ -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); } diff --git a/mt76x02_dma.h b/mt76x02_dma.h index 4aff4f8e..23b0e7d1 100644 --- a/mt76x02_dma.h +++ b/mt76x02_dma.h @@ -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 */ diff --git a/mt76x02_mmio.c b/mt76x02_mmio.c index 1389ba1f..156fed61 100644 --- a/mt76x02_mmio.c +++ b/mt76x02_mmio.c @@ -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); diff --git a/mt76x2/pci.c b/mt76x2/pci.c index 377cf9c0..4d50dad2 100644 --- a/mt76x2/pci.c +++ b/mt76x2/pci.c @@ -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]); diff --git a/mt76x2/pci_init.c b/mt76x2/pci_init.c index 101a0fe0..48a3ebc9 100644 --- a/mt76x2/pci_init.c +++ b/mt76x2/pci_init.c @@ -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); } diff --git a/mt7915/dma.c b/mt7915/dma.c index bdc69460..c8829987 100644 --- a/mt7915/dma.c +++ b/mt7915/dma.c @@ -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); } diff --git a/mt7915/mac.c b/mt7915/mac.c index efdef23c..353f7edc 100644 --- a/mt7915/mac.c +++ b/mt7915/mac.c @@ -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); diff --git a/testmode.c b/testmode.c index 75bb02cd..3be4e2ff 100644 --- a/testmode.c +++ b/testmode.c @@ -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); diff --git a/tx.c b/tx.c index 85bd8c6b..af82915b 100644 --- a/tx.c +++ b/tx.c @@ -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); diff --git a/usb.c b/usb.c index 5f19f9e5..e0450f5a 100644 --- a/usb.c +++ b/usb.c @@ -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);