Linux-mediatek Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: JB Tsai <jb.tsai@mediatek.com>
To: <nbd@nbd.name>, <lorenzo@kernel.org>
Cc: <linux-wireless@vger.kernel.org>,
	<linux-mediatek@lists.infradead.org>, <Sean.Wang@mediatek.com>,
	<Evan-ym.Li@mediatek.com>, <jb.tsai@mediatek.com>,
	Yin-Ming Li <evan-ym.li@mediatek.com>,
	Sean Wang <sean.wang@mediatek.com>
Subject: [PATCH 2/3] wifi: mt76: mt7921: drain PCIe activity before freeing queues
Date: Tue, 3 Nov 2026 17:10:09 +0800	[thread overview]
Message-ID: <20261103091010.1148974-2-jb.tsai@mediatek.com> (raw)
In-Reply-To: <20261103091010.1148974-1-jb.tsai@mediatek.com>

From: Yin-Ming Li <evan-ym.li@mediatek.com>

The PCIe remove path sets MT76_REMOVED before unregistering mac80211,
making the IRQ handler return without servicing MCU responses. It also
disables the IRQ tasklet only after DMA cleanup, so a previously scheduled
tasklet can run while queues are being torn down.

Use the common work-quiescing helper while IRQs, NAPI and the MCU command
queues remain available. Delay publishing REMOVED until mac80211
unregistration returns, so the IRQ handler remains available during
teardown even when individual MCU commands fail.

Mask both device interrupt sources and flush the write before publishing
REMOVED. Synchronize the IRQ, disable its tasklet, and disable and delete
RX NAPI before releasing TX tokens. Let common DMA cleanup skip an
already-deleted RX NAPI context to avoid disabling it twice.

After DMA cleanup has also stopped TX NAPI, drain the tasklet that its
last poll might have scheduled. Add a REMOVED guard so this final tasklet
cannot access freed queues. Purge scan and coredump state after stopping
their producers and before freeing the device.

Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Yin-Ming Li <evan-ym.li@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/dma.c        |  4 ++-
 drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 40 ++++++++++++++++++-------
 drivers/net/wireless/mediatek/mt76/mt792x_dma.c |  3 ++
 3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index f695a14596062c4cd5445913f014907a421b2c22..25d4640f09eea7335c422b36b9c3ef52fe388830 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -1217,7 +1217,9 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
 	mt76_for_each_q_rx(dev, i) {
 		struct mt76_queue *q = &dev->q_rx[i];
 
-		if (!mt76_queue_is_wed_rro(q)) {
+		/* A driver may have removed RX NAPI before releasing TX tokens. */
+		if (!mt76_queue_is_wed_rro(q) &&
+		    test_bit(NAPI_STATE_LISTED, &dev->napi[i].state)) {
 			napi_disable(&dev->napi[i]);
 			netif_napi_del(&dev->napi[i]);
 		}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 5180597aed757777dc3d5c287f2bbdee39ce243d..2e05dbaf8b2805522410609e90f422b348826e43 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -43,28 +43,47 @@ static int mt7921e_init_reset(struct mt792x_dev *dev)
 
 static void mt7921e_unregister_device(struct mt792x_dev *dev)
 {
 	int i;
-	struct mt76_connac_pm *pm = &dev->pm;
+	struct pci_dev *pdev = to_pci_dev(dev->mt76.dev);
 	struct ieee80211_hw *hw = mt76_hw(dev);
 
 	if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN)
 		wiphy_rfkill_stop_polling(hw->wiphy);
 
-	cancel_work_sync(&dev->init_work);
-	mt76_unregister_device(&dev->mt76);
-	mt76_for_each_q_rx(&dev->mt76, i)
+	mt7921_unregister_device(dev);
+
+	/*
+	 * Mask device interrupts before MT76_REMOVED makes the handler return
+	 * IRQ_NONE. Drain the IRQ and tasklet before tearing down the queues.
+	 */
+	mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
+	mt76_wr(dev, dev->pcie_reg->imask, 0);
+	mt76_rr(dev, dev->pcie_reg->imask);
+	set_bit(MT76_REMOVED, &dev->mphy.state);
+	synchronize_irq(pdev->irq);
+	tasklet_disable(&dev->mt76.irq_tasklet);
+
+	mt76_for_each_q_rx(&dev->mt76, i) {
 		napi_disable(&dev->mt76.napi[i]);
-	cancel_delayed_work_sync(&pm->ps_work);
-	cancel_work_sync(&pm->wake_work);
-	cancel_work_sync(&dev->reset_work);
+		netif_napi_del(&dev->mt76.napi[i]);
+	}
+	skb_queue_purge(&dev->phy.scan_event_list);
+	cancel_delayed_work_sync(&dev->coredump.work);
+	skb_queue_purge(&dev->coredump.msg_list);
 
 	mt76_connac2_tx_token_put(&dev->mt76);
-	__mt792x_mcu_drv_pmctrl(dev);
 	mt792x_dma_cleanup(dev);
+
+	/*
+	 * TX NAPI is now disabled too; drain a tasklet queued by its last poll.
+	 * MT76_REMOVED makes that tasklet return without touching freed queues.
+	 */
+	tasklet_enable(&dev->mt76.irq_tasklet);
+	tasklet_kill(&dev->mt76.irq_tasklet);
+	mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
+
 	mt792x_wfsys_reset(dev);
 	skb_queue_purge(&dev->mt76.mcu.res_q);
-
-	tasklet_disable(&dev->mt76.irq_tasklet);
 }
 
 static u32 __mt7921_reg_addr(struct mt792x_dev *dev, u32 addr)
@@ -458,7 +477,6 @@ static void mt7921_pci_remove(struct pci_dev *pdev)
 	if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source"))
 		device_init_wakeup(dev->mt76.dev, false);
 
-	set_bit(MT76_REMOVED, &mdev->phy.state);
 	mt7921e_unregister_device(dev);
 	devm_free_irq(&pdev->dev, pdev->irq, dev);
 	mt76_free_device(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
index 8ad94fa583405d561429a1c5d212e9f83d616328..06877816640f51829b50205ab93126385d26f16a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
@@ -31,6 +31,9 @@ void mt792x_irq_tasklet(unsigned long data)
 	const struct mt792x_irq_map *irq_map = dev->irq_map;
 	u32 intr, mask = 0;
 
+	if (test_bit(MT76_REMOVED, &dev->mphy.state))
+		return;
+
 	mt76_wr(dev, irq_map->host_irq_enable, 0);
 
 	intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA);
-- 
2.43.0


  reply	other threads:[~2026-11-03  9:10 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03  9:10 [PATCH 1/3] wifi: mt76: mt7921: quiesce work before unregistering JB Tsai
2026-11-03  9:10 ` JB Tsai [this message]
2026-11-03  9:10 ` [PATCH 3/3] wifi: mt76: mt7921: disable SDIO work before bus teardown JB Tsai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261103091010.1148974-2-jb.tsai@mediatek.com \
    --to=jb.tsai@mediatek.com \
    --cc=Evan-ym.Li@mediatek.com \
    --cc=Sean.Wang@mediatek.com \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=lorenzo@kernel.org \
    --cc=nbd@nbd.name \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox