* [RFC-v2] wifi: mt76: mt7996: disable NAPI before deleting in dma_cleanup
@ 2026-09-22 19:20 greearb
0 siblings, 0 replies; only message in thread
From: greearb @ 2026-09-22 19:20 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
NAPI should be disabled before deleted, this stops
a warning seen when trying to rmmod mt7996e.
When removing mt7996e module, softirqd would go to 100%
cpu usage. It appears the problem is lack of cleanup of
the irq objects and proper kill of the irq_tasklet.
NAPI was started on rx queues that had zero ndesc,
so be sure to start/stop NAPI on those other queues
by adding a new iterator.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/mediatek/mt76/dma.c | 18 ++++++++++------
drivers/net/wireless/mediatek/mt76/mt76.h | 7 +++++++
.../net/wireless/mediatek/mt76/mt7996/dma.c | 10 +++++++++
.../net/wireless/mediatek/mt76/mt7996/init.c | 16 +++++++++++++-
.../net/wireless/mediatek/mt76/mt7996/mac.c | 21 ++++++++-----------
.../wireless/mediatek/mt76/mt7996/mt7996.h | 1 +
.../net/wireless/mediatek/mt76/mt7996/pci.c | 11 ++++++++--
7 files changed, 63 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index a67880a9281c..468d36299567 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -1127,8 +1127,10 @@ static void
mt76_dma_rx_queue_init(struct mt76_dev *dev, enum mt76_rxq_id qid,
int (*poll)(struct napi_struct *napi, int budget))
{
- netif_napi_add(dev->napi_dev, &dev->napi[qid], poll);
+ /* This may or may not assign ndesc > 0, add NAPI regardless. */
mt76_dma_rx_fill_buf(dev, &dev->q_rx[qid], false);
+ dev->q_rx[qid].napified = true;
+ netif_napi_add(dev->napi_dev, &dev->napi[qid], poll);
napi_enable(&dev->napi[qid]);
}
@@ -1214,13 +1216,17 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++)
mt76_dma_tx_cleanup(dev, dev->q_mcu[i], true);
- mt76_for_each_q_rx(dev, i) {
+ mt76_for_each_q_rx_napi(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
- netif_napi_del(&dev->napi[i]);
- mt76_dma_rx_cleanup(dev, q);
-
- page_pool_destroy(q->page_pool);
+ if (q->napified) {
+ netif_napi_del(&dev->napi[i]);
+ q->napified = false;
+ }
+ if (q->ndesc) {
+ mt76_dma_rx_cleanup(dev, q);
+ page_pool_destroy(q->page_pool);
+ }
}
if (mtk_wed_device_active(&dev->mmio.wed))
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 62b41c8bb7c0..827c49ef3edd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -251,6 +251,7 @@ struct mt76_queue {
int buf_size;
bool stopped;
bool blocked;
+ bool napified;
u8 buf_offset;
u16 flags;
@@ -1286,10 +1287,16 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q,
#define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__)
+/* For all rx queues that have ndesc > 0 */
#define mt76_for_each_q_rx(dev, i) \
for (i = 0; i < ARRAY_SIZE((dev)->q_rx); i++) \
if ((dev)->q_rx[i].ndesc)
+/* For all rx queues that have ndesc or NAPI enabled */
+#define mt76_for_each_q_rx_napi(dev, i) \
+ for (i = 0; i < ARRAY_SIZE((dev)->q_rx); i++) \
+ if ((dev)->q_rx[i].napified || (dev)->q_rx[i].ndesc)
+
#define mt76_dereference(p, dev) \
rcu_dereference_protected(p, lockdep_is_held(&(dev)->mutex))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 3d9353811a02..48bdbbb7c78f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -1051,7 +1051,17 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
void mt7996_dma_cleanup(struct mt7996_dev *dev)
{
+ int i;
+
mt7996_dma_disable(dev, true);
+ /* mt76_dma_cleanup will delete the napi and clean up rx-queues,
+ * we just need to disable it here to match whatever mt7921 is doing.
+ */
+ mt76_for_each_q_rx_napi(&dev->mt76, i) {
+ if (dev->mt76.q_rx[i].napified)
+ napi_disable(&dev->mt76.napi[i]);
+ }
+
mt76_dma_cleanup(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index fb635a092584..45fc76cecd04 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -1807,6 +1807,18 @@ int mt7996_register_device(struct mt7996_dev *dev)
return ret;
}
+static void mt7996_cleanup_irqs(struct mt7996_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct pci_dev *pdev = to_pci_dev(mdev->dev);
+
+ mt7996_put_hif2(dev, dev->hif2); /* frees hif2 irq */
+
+ devm_free_irq(mdev->dev, pdev->irq, dev);
+ if (!mtk_wed_device_active(&dev->mt76.mmio.wed))
+ pci_free_irq_vectors(pdev);
+}
+
void mt7996_unregister_device(struct mt7996_dev *dev)
{
cancel_work_sync(&dev->dump_work);
@@ -1825,7 +1837,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
if (mt7996_has_hwrro(dev) &&
!mtk_wed_device_active(&dev->mt76.mmio.wed))
mt7996_rro_msdu_page_map_free(dev);
- tasklet_disable(&dev->mt76.irq_tasklet);
+ tasklet_kill(&dev->mt76.irq_tasklet);
+
+ mt7996_cleanup_irqs(dev);
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 1cba381a78b8..396024acd645 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2311,13 +2311,12 @@ mt7996_mac_restart(struct mt7996_dev *dev)
/* disable all tx/rx napi */
mt76_worker_disable(&dev->mt76.tx_worker);
- mt76_for_each_q_rx(mdev, i) {
+ mt76_for_each_q_rx_napi(mdev, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
mt76_queue_is_wed_rro(&mdev->q_rx[i]))
continue;
- if (mdev->q_rx[i].ndesc)
- napi_disable(&dev->mt76.napi[i]);
+ napi_disable(&dev->mt76.napi[i]);
}
napi_disable(&dev->mt76.tx_napi);
@@ -2327,17 +2326,15 @@ mt7996_mac_restart(struct mt7996_dev *dev)
mt7996_dma_reset(dev, true);
- mt76_for_each_q_rx(mdev, i) {
+ mt76_for_each_q_rx_napi(mdev, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
mt76_queue_is_wed_rro(&mdev->q_rx[i]))
continue;
- if (mdev->q_rx[i].ndesc) {
- napi_enable(&dev->mt76.napi[i]);
- local_bh_disable();
- napi_schedule(&dev->mt76.napi[i]);
- local_bh_enable();
- }
+ napi_enable(&dev->mt76.napi[i]);
+ local_bh_disable();
+ napi_schedule(&dev->mt76.napi[i]);
+ local_bh_enable();
}
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
@@ -2585,7 +2582,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mutex_lock(&dev->mt76.mutex);
mt76_worker_disable(&dev->mt76.tx_worker);
- mt76_for_each_q_rx(&dev->mt76, i) {
+ mt76_for_each_q_rx_napi(&dev->mt76, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
@@ -2645,7 +2642,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_for_each_phy(dev, phy)
clear_bit(MT76_RESET, &phy->mt76->state);
- mt76_for_each_q_rx(&dev->mt76, i) {
+ mt76_for_each_q_rx_napi(&dev->mt76, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 2a0cdb56f822..79c57e88e107 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -678,6 +678,7 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link);
int mt7996_register_device(struct mt7996_dev *dev);
void mt7996_unregister_device(struct mt7996_dev *dev);
+void mt7996_put_hif2(struct mt7996_dev *dev, struct mt7996_hif *hif);
int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index b7d9193e042f..5c686cf66d0a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -53,11 +53,19 @@ static struct mt7996_hif *mt7996_pci_get_hif2(u32 idx)
return hif;
}
-static void mt7996_put_hif2(struct mt7996_hif *hif)
+void mt7996_put_hif2(struct mt7996_dev *dev, struct mt7996_hif *hif)
{
+ struct pci_dev *hif2_dev;
+
if (!hif)
return;
+ hif2_dev = container_of(hif->dev, struct pci_dev, dev);
+
+ devm_free_irq(dev->mt76.dev, hif->irq, dev);
+ if (!mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ pci_free_irq_vectors(hif2_dev);
+
put_device(hif->dev);
}
@@ -237,7 +245,6 @@ static void mt7996_pci_remove(struct pci_dev *pdev)
mdev = pci_get_drvdata(pdev);
dev = container_of(mdev, struct mt7996_dev, mt76);
- mt7996_put_hif2(dev->hif2);
mt7996_unregister_device(dev);
}
--
2.42.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-22 19:20 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-22 19:20 [RFC-v2] wifi: mt76: mt7996: disable NAPI before deleting in dma_cleanup greearb
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox