mt76: convert from tx tasklet to tx worker thread
authorFelix Fietkau <nbd@nbd.name>
Fri, 24 Jul 2020 14:11:52 +0000 (16:11 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 24 Sep 2020 16:10:18 +0000 (18:10 +0200)
This improves performance by allowing the scheduler to move the tx scheduling
work to idle CPUs. Since tx scheduling work is very latency sensitive and
kept short via AQL, sched_set_fifo_low is used to keep worker priority above
normal tasks

Signed-off-by: Felix Fietkau <nbd@nbd.name>
20 files changed:
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/mediatek/mt76/mac80211.c
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt7603/dma.c
drivers/net/wireless/mediatek/mt76/mt7603/mac.c
drivers/net/wireless/mediatek/mt76/mt7615/dma.c
drivers/net/wireless/mediatek/mt76/mt7615/mac.c
drivers/net/wireless/mediatek/mt76/mt7615/main.c
drivers/net/wireless/mediatek/mt76/mt7615/pci.c
drivers/net/wireless/mediatek/mt76/mt7615/usb.c
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
drivers/net/wireless/mediatek/mt76/mt7915/dma.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/testmode.c
drivers/net/wireless/mediatek/mt76/tx.c
drivers/net/wireless/mediatek/mt76/usb.c

index 240f04b..7f669a2 100644 (file)
@@ -592,6 +592,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);
index 67316a5..ae98a49 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
  */
+#include <linux/sched.h>
 #include <linux/of.h>
 #include "mt76.h"
 
@@ -436,14 +437,13 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
        skb_queue_head_init(&dev->mcu.res_q);
        init_waitqueue_head(&dev->mcu.wait);
        mutex_init(&dev->mcu.mutex);
+       dev->tx_worker.fn = mt76_tx_worker;
 
        INIT_LIST_HEAD(&dev->txwi_cache);
 
        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);
@@ -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, NULL, "tx"));
+       sched_set_fifo_low(dev->tx_worker.task);
+
+       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;
index 59eed53..2d44fe5 100644 (file)
@@ -604,7 +604,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;
 
@@ -906,7 +906,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,
index b51b894..46be157 100644 (file)
@@ -163,7 +163,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;
 }
@@ -246,6 +246,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);
 }
index 91a4f70..97679eb 100644 (file)
@@ -1402,7 +1402,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]);
@@ -1451,7 +1451,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);
 
index 242638f..bf8ae14 100644 (file)
@@ -297,6 +297,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);
 }
index 9d0edba..ab1fbf4 100644 (file)
@@ -1462,7 +1462,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,
@@ -1888,7 +1888,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);
@@ -2130,7 +2130,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);
@@ -2151,7 +2151,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);
 
index bdade41..3c0101a 100644 (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,
index b9794f8..dbd29d8 100644 (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]);
index 23a2133..f0ad83a 100644 (file)
@@ -180,9 +180,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;
 }
index 5e56748..dda11c7 100644 (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);
 }
 
index 4aff4f8..23b0e7d 100644 (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 */
index 4016ffe..cf68731 100644 (file)
@@ -149,9 +149,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);
@@ -176,7 +178,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;
 }
@@ -195,8 +197,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);
 
@@ -323,13 +324,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);
@@ -447,7 +441,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) {
@@ -504,7 +498,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);
 
index 377cf9c..4d50dad 100644 (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]);
index 101a0fe..48a3ebc 100644 (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);
 }
 
index a183b76..875badc 100644 (file)
@@ -372,6 +372,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);
 }
index 4d6e414..54088d8 100644 (file)
@@ -951,7 +951,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, struct mt76_queue_entry *e)
@@ -1223,7 +1223,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]);
@@ -1243,7 +1243,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);
 
index a38abb6..883f59c 100644 (file)
@@ -161,7 +161,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
@@ -169,11 +169,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);
 
index 8a12a89..5914312 100644 (file)
@@ -604,9 +604,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)
@@ -649,7 +649,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);
 
index 18dbeca..edbcabd 100644 (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_queue *q;
        bool wake;
@@ -864,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
@@ -1020,6 +1020,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
 {
        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) {
@@ -1038,8 +1040,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.
                 */
@@ -1058,6 +1058,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);
@@ -1107,8 +1109,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);