Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths
@ 2026-06-13 22:41 Sean Wang
  2026-06-13 22:41 ` [PATCH 1/6] wifi: mt76: mt7925: stop init retries on hung bus Sean Wang
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

This series hardens mt792x USB reset and disconnect handling.

When the USB control path starts timing out, later register accesses can
keep entering the same dead transport. Each timed-out vendor request may
block for seconds, so reset or disconnect can be delayed by repeated
accesses that can no longer make progress.

Avoid this by failing fast once the USB bus is known to be hung, stopping
reset/init retry paths that cannot recover the device, draining UDMA before
WFSYS reset, and quiescing USB activity before unregistering the device.

This series does the following:
- stop mt7925 init retries once the USB bus is hung
- skip mt7925 reset work once the USB bus is hung
- switch later USB register accesses to no-op bus ops after bus hang
- drain USB UDMA before WFSYS reset
- enable the USB UDMA TX timeout limit
- stop pending USB work and TX paths before unregistering the device

The series is based on wireless-next commit:

21352612198c ("b43: add RF power offset for N-PHY r8 + radio 2057 r8")

It also cherry-picks the following patch from patchwork as a dependency:

wifi: mt76: mt76u: use a threaded NAPI for the RX path
Link: https://lore.kernel.org/all/20260609105301.196302-1-phial@phiality.com/

Sean Wang (6):
  wifi: mt76: mt7925: stop init retries on hung bus
  wifi: mt76: mt7925: skip reset work on hung bus
  wifi: mt76: mt792x: stop USB register access after bus hang
  wifi: mt76: mt792x: drain USB UDMA before WFSYS reset
  wifi: mt76: mt792x: enable USB UDMA TX timeout
  wifi: mt76: mt792x: quiesce USB paths on disconnect

 drivers/net/wireless/mediatek/mt76/mt76.h     |   1 +
 .../net/wireless/mediatek/mt76/mt7925/init.c  |   8 ++
 .../net/wireless/mediatek/mt76/mt7925/mac.c   |   6 +
 .../net/wireless/mediatek/mt76/mt7925/usb.c   |   7 +
 .../net/wireless/mediatek/mt76/mt792x_usb.c   | 124 ++++++++++++++++--
 drivers/net/wireless/mediatek/mt76/usb.c      |  11 ++
 6 files changed, 145 insertions(+), 12 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/6] wifi: mt76: mt7925: stop init retries on hung bus
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  2026-06-13 22:41 ` [PATCH 2/6] wifi: mt76: mt7925: skip reset work " Sean Wang
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

Stop retrying hardware init once the bus is marked hung.

The control path is no longer usable at that point, so more retries only
issue failing device accesses, including MCU commands or register
operations, and delay teardown. Exit early and let the failed device be
torn down quickly.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt7925/init.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
index e85b0d104fbe..e9ca5aa1e407 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
@@ -137,10 +137,18 @@ static int mt7925_init_hardware(struct mt792x_dev *dev)
 	set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
 
 	for (i = 0; i < MT792x_MCU_INIT_RETRY_COUNT; i++) {
+		if (atomic_read(&dev->mt76.bus_hung)) {
+			ret = -EIO;
+			break;
+		}
+
 		ret = __mt7925_init_hardware(dev);
 		if (!ret)
 			break;
 
+		if (atomic_read(&dev->mt76.bus_hung))
+			break;
+
 		mt792x_init_reset(dev);
 	}
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/6] wifi: mt76: mt7925: skip reset work on hung bus
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
  2026-06-13 22:41 ` [PATCH 1/6] wifi: mt76: mt7925: stop init retries on hung bus Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  2026-06-13 22:41 ` [PATCH 3/6] wifi: mt76: mt792x: stop USB register access after bus hang Sean Wang
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

Skip mt7925 reset handling once the bus is marked hung.

A hung bus cannot be recovered by issuing another device reset. Continuing
the reset path may only send more failing MCU or register accesses and
delay teardown. Return early from reset work and the USB reset path so the
failed device can be torn down quickly.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 6 ++++++
 drivers/net/wireless/mediatek/mt76/mt7925/usb.c | 7 +++++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 0641a7131d7c..d7e4ebe92342 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1310,6 +1310,9 @@ void mt7925_mac_reset_work(struct work_struct *work)
 	struct mt76_connac_pm *pm = &dev->pm;
 	int i, ret;
 
+	if (atomic_read(&dev->mt76.bus_hung))
+		return;
+
 	dev_dbg(dev->mt76.dev, "chip reset\n");
 	dev->hw_full_reset = true;
 	ieee80211_stop_queues(hw);
@@ -1327,6 +1330,9 @@ void mt7925_mac_reset_work(struct work_struct *work)
 			break;
 	}
 
+	if (atomic_read(&dev->mt76.bus_hung))
+		return;
+
 	if (i == 10)
 		dev_err(dev->mt76.dev, "chip reset failed\n");
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
index e9f58492bf7d..49ad4fe9eb1b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
@@ -81,6 +81,13 @@ static int mt7925u_mac_reset(struct mt792x_dev *dev)
 {
 	int err;
 
+	if (atomic_read(&dev->mt76.bus_hung))
+		return 0;
+
+	mt792xu_reset_on_bus_error(dev);
+	if (atomic_read(&dev->mt76.bus_hung))
+		return 0;
+
 	mt76_txq_schedule_all(&dev->mphy);
 	mt76_worker_disable(&dev->mt76.tx_worker);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/6] wifi: mt76: mt792x: stop USB register access after bus hang
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
  2026-06-13 22:41 ` [PATCH 1/6] wifi: mt76: mt7925: stop init retries on hung bus Sean Wang
  2026-06-13 22:41 ` [PATCH 2/6] wifi: mt76: mt7925: skip reset work " Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  2026-06-13 22:41 ` [PATCH 4/6] wifi: mt76: mt792x: drain USB UDMA before WFSYS reset Sean Wang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

Mark the mt792x USB bus hung on the first control timeout and switch
register access to no-op bus ops. Each failed vendor request may spend
up to MT_VEND_REQ_MAX_RETRY * MT_VEND_REQ_TOUT_MS, about 3 seconds, and
teardown/reset paths can keep issuing such requests after the device has
stopped responding.

Also skip the USB WFSYS reset path after bus_hung is set, since it uses
UHW vendor requests as well.

mt7925u 1-2:1.3: vendor request req:63 off:0018 failed:-110
mt7925u 1-2:1.3: vendor request req:63 off:0018 failed:-110
mt7925u 1-2:1.3: vendor request req:63 off:0018 failed:-110
mt7925u 1-2:1.3: vendor request req:63 off:0018 failed:-110
mt7925u 1-2:1.3: vendor request req:63 off:0018 failed:-110

Avoid repeating those register reads after the bus is known to be hung by
switching register access to no-op handlers.

Fixes: 0d2afe09fad5 ("mt76: mt7921: add mt7921u driver")
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt76.h     |  1 +
 .../net/wireless/mediatek/mt76/mt792x_usb.c   | 79 ++++++++++++++++---
 drivers/net/wireless/mediatek/mt76/usb.c      | 11 +++
 3 files changed, 82 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 07955555f84d..122e77a5f2f4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -672,6 +672,7 @@ struct mt76_usb {
 
 	u8 out_ep[__MT_EP_OUT_MAX];
 	u8 in_ep[__MT_EP_IN_MAX];
+	void (*ctrl_timeout)(struct mt76_dev *dev, int err);
 	bool sg_en;
 
 	struct mt76u_mcu {
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 910132e94956..d86b0918c2f8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -31,10 +31,75 @@ static void mt792xu_reset_work(struct work_struct *work)
 	atomic_set(&dev->usb_reset_pending, 0);
 }
 
+static void mt792xu_queue_usb_reset(struct mt792x_dev *dev, int err)
+{
+	if (!atomic_xchg(&dev->usb_reset_pending, 1)) {
+		dev_warn(dev->mt76.dev,
+			 "USB transport access failed (%d), queueing device reset\n",
+			 err);
+
+		schedule_work(&dev->usb_reset_work);
+	}
+}
+
+static u32 mt792xu_bus_hung_rr(struct mt76_dev *mdev, u32 offset)
+{
+	return 0;
+}
+
+static void mt792xu_bus_hung_wr(struct mt76_dev *mdev, u32 offset, u32 val)
+{
+}
+
+static u32 mt792xu_bus_hung_rmw(struct mt76_dev *mdev, u32 offset,
+				u32 mask, u32 val)
+{
+	return 0;
+}
+
+static void mt792xu_bus_hung_write_copy(struct mt76_dev *mdev, u32 offset,
+					const void *data, int len)
+{
+}
+
+static void mt792xu_bus_hung_read_copy(struct mt76_dev *mdev, u32 offset,
+				       void *data, int len)
+{
+	memset(data, 0, len);
+}
+
+static const struct mt76_bus_ops mt792xu_bus_hung_ops = {
+	.rr = mt792xu_bus_hung_rr,
+	.wr = mt792xu_bus_hung_wr,
+	.rmw = mt792xu_bus_hung_rmw,
+	.write_copy = mt792xu_bus_hung_write_copy,
+	.read_copy = mt792xu_bus_hung_read_copy,
+	.type = MT76_BUS_USB,
+};
+
+static void mt792xu_set_bus_hung(struct mt792x_dev *dev)
+{
+	atomic_set(&dev->mt76.bus_hung, true);
+
+	if (READ_ONCE(dev->mt76.bus) == &mt792xu_bus_hung_ops)
+		return;
+
+	WRITE_ONCE(dev->mt76.bus, &mt792xu_bus_hung_ops);
+}
+
+static void mt792xu_ctrl_timeout(struct mt76_dev *mdev, int err)
+{
+	struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+
+	mt792xu_set_bus_hung(dev);
+	mt792xu_queue_usb_reset(dev, err);
+}
+
 void mt792xu_reset_work_init(struct mt792x_dev *dev)
 {
 	INIT_WORK(&dev->usb_reset_work, mt792xu_reset_work);
 	atomic_set(&dev->usb_reset_pending, 0);
+	dev->mt76.usb.ctrl_timeout = mt792xu_ctrl_timeout;
 }
 EXPORT_SYMBOL_GPL(mt792xu_reset_work_init);
 
@@ -68,15 +133,8 @@ int mt792xu_reset_on_bus_error(struct mt792x_dev *dev)
 		err = mt792xu_check_bus(dev);
 
 	if (err) {
-		atomic_set(&dev->mt76.bus_hung, true);
-
-		if (!atomic_xchg(&dev->usb_reset_pending, 1)) {
-			dev_warn(dev->mt76.dev,
-				 "USB transport access failed (%d), queueing device reset\n",
-				 err);
-
-			schedule_work(&dev->usb_reset_work);
-		}
+		mt792xu_set_bus_hung(dev);
+		mt792xu_queue_usb_reset(dev, err);
 
 		return err;
 	}
@@ -344,6 +402,9 @@ int mt792xu_wfsys_reset(struct mt792x_dev *dev)
 	u32 val;
 	int i;
 
+	if (atomic_read(&dev->mt76.bus_hung))
+		return -EIO;
+
 	mt792xu_epctl_rst_opt(dev, false);
 
 	val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 77a8e35b1f86..ce68e1d0c786 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -30,6 +30,8 @@ int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type,
 	for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
 		if (test_bit(MT76_REMOVED, &dev->phy.state))
 			return -EIO;
+		if (dev->usb.ctrl_timeout && atomic_read(&dev->bus_hung))
+			return -EIO;
 
 		ret = usb_control_msg(udev, pipe, req, req_type, val,
 				      offset, buf, len, MT_VEND_REQ_TOUT_MS);
@@ -42,6 +44,15 @@ int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type,
 
 	dev_err(dev->dev, "vendor request req:%02x off:%04x failed:%d\n",
 		req, offset, ret);
+
+	if (dev->usb.ctrl_timeout) {
+		atomic_set(&dev->bus_hung, true);
+		dev_err(dev->dev, "vendor request req:%02x off:%04x timed out, marking bus hung\n",
+			req, offset);
+		dev->usb.ctrl_timeout(dev, ret);
+		return ret;
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(__mt76u_vendor_request);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/6] wifi: mt76: mt792x: drain USB UDMA before WFSYS reset
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
                   ` (2 preceding siblings ...)
  2026-06-13 22:41 ` [PATCH 3/6] wifi: mt76: mt792x: stop USB register access after bus hang Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  2026-06-13 22:41 ` [PATCH 5/6] wifi: mt76: mt792x: enable USB UDMA TX timeout Sean Wang
  2026-06-13 22:41 ` [PATCH 6/6] wifi: mt76: mt792x: quiesce USB paths on disconnect Sean Wang
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

Stop USB UDMA RX/TX and wait for idle before WFSYS reset.
Warn if the engine remains busy.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 .../net/wireless/mediatek/mt76/mt792x_usb.c   | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index d86b0918c2f8..43191a8a9ea4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -11,6 +11,8 @@
 #include "mt792x.h"
 #include "mt76_connac2_mac.h"
 
+#define MT792X_USB_UDMA_IDLE_TIMEOUT	1000
+
 static int mt792xu_read32(struct mt76_dev *dev, u32 addr, void *buf)
 {
 	return __mt76u_vendor_request(dev, MT_VEND_READ_EXT,
@@ -339,6 +341,23 @@ static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset)
 	mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val);
 }
 
+static void mt792xu_wait_udma_idle(struct mt792x_dev *dev)
+{
+	u32 mask = MT_WL_RX_BUSY | MT_WL_TX_BUSY;
+	u32 val;
+
+	mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH);
+
+	if (mt76_poll_msec(dev, MT_UDMA_WLCFG_0, mask, 0,
+			   MT792X_USB_UDMA_IDLE_TIMEOUT))
+		return;
+
+	val = mt76_rr(dev, MT_UDMA_WLCFG_0);
+
+	dev_warn(dev->mt76.dev,
+		 "UDMA busy before WFSYS reset: WLCFG0=0x%08x\n", val);
+}
+
 struct mt792xu_wfsys_desc {
 	u32 rst_reg;
 	u32 done_reg;
@@ -405,6 +424,7 @@ int mt792xu_wfsys_reset(struct mt792x_dev *dev)
 	if (atomic_read(&dev->mt76.bus_hung))
 		return -EIO;
 
+	mt792xu_wait_udma_idle(dev);
 	mt792xu_epctl_rst_opt(dev, false);
 
 	val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/6] wifi: mt76: mt792x: enable USB UDMA TX timeout
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
                   ` (3 preceding siblings ...)
  2026-06-13 22:41 ` [PATCH 4/6] wifi: mt76: mt792x: drain USB UDMA before WFSYS reset Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  2026-06-13 22:41 ` [PATCH 6/6] wifi: mt76: mt792x: quiesce USB paths on disconnect Sean Wang
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

Configure the USB UDMA TX timeout limit and enable timeout detection
during DMA initialization, matching the vendor driver setup. Use a
longer timeout to avoid false alarms.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 43191a8a9ea4..c4da1b900d47 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -11,6 +11,7 @@
 #include "mt792x.h"
 #include "mt76_connac2_mac.h"
 
+#define MT792X_USB_TX_TIMEOUT_LIMIT	50000
 #define MT792X_USB_UDMA_IDLE_TIMEOUT	1000
 
 static int mt792xu_read32(struct mt76_dev *dev, u32 addr, void *buf)
@@ -396,6 +397,10 @@ int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
 	mt76_set(dev, MT_UDMA_WLCFG_0,
 		 MT_WL_RX_EN | MT_WL_TX_EN |
 		 MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN);
+	mt76_rmw(dev, MT_UDMA_WLCFG_1, MT_WL_TX_TMOUT_LMT,
+		 FIELD_PREP(MT_WL_TX_TMOUT_LMT,
+			    MT792X_USB_TX_TIMEOUT_LIMIT));
+	mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_TX_TMOUT_FUNC_EN);
 	mt76_clear(dev, MT_UDMA_WLCFG_0,
 		   MT_WL_RX_AGG_TO | MT_WL_RX_AGG_LMT);
 	mt76_clear(dev, MT_UDMA_WLCFG_1, MT_WL_RX_AGG_PKT_LMT);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/6] wifi: mt76: mt792x: quiesce USB paths on disconnect
  2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
                   ` (4 preceding siblings ...)
  2026-06-13 22:41 ` [PATCH 5/6] wifi: mt76: mt792x: enable USB UDMA TX timeout Sean Wang
@ 2026-06-13 22:41 ` Sean Wang
  5 siblings, 0 replies; 7+ messages in thread
From: Sean Wang @ 2026-06-13 22:41 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek, Sean Wang

From: Sean Wang <sean.wang@mediatek.com>

USB disconnect can leave reset/init work, TX worker, and MCU waiters active
while the device is being removed. Stop those paths before unregistering
the device to avoid teardown waiting on firmware or queue activity after
disconnect.

Run WFSYS reset after USB queue deinit so removal does not issue the reset
while USB traffic may still be queued.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
 .../net/wireless/mediatek/mt76/mt792x_usb.c   | 20 ++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index c4da1b900d47..e5d2d2f6a388 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -230,9 +230,9 @@ EXPORT_SYMBOL_GPL(mt792xu_mcu_power_on);
 static void mt792xu_cleanup(struct mt792x_dev *dev)
 {
 	clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
-	mt792xu_wfsys_reset(dev);
 	skb_queue_purge(&dev->mt76.mcu.res_q);
 	mt76u_queues_deinit(&dev->mt76);
+	mt792xu_wfsys_reset(dev);
 }
 
 static u32 mt792xu_uhw_rr(struct mt76_dev *dev, u32 addr)
@@ -494,13 +494,27 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
 {
 	struct mt792x_dev *dev = usb_get_intfdata(usb_intf);
 
-	mt792xu_reset_work_cleanup(dev);
+	if (!dev)
+		return;
+
+	set_bit(MT76_RESET, &dev->mphy.state);
+	set_bit(MT76_MCU_RESET, &dev->mphy.state);
+	clear_bit(MT76_STATE_RUNNING, &dev->mphy.state);
+	wake_up(&dev->mt76.mcu.wait);
+	skb_queue_purge(&dev->mt76.mcu.res_q);
+
+	cancel_work_sync(&dev->reset_work);
 	cancel_work_sync(&dev->init_work);
-	if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
+	mt76_worker_disable(&dev->mt76.tx_worker);
+	mt792xu_reset_work_cleanup(dev);
+	if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) {
+		set_bit(MT76_REMOVED, &dev->mphy.state);
 		return;
+	}
 
 	mt76_unregister_device(&dev->mt76);
 	mt792xu_cleanup(dev);
+	set_bit(MT76_REMOVED, &dev->mphy.state);
 
 	usb_set_intfdata(usb_intf, NULL);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-06-13 22:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-13 22:41 [PATCH 0/6] wifi: mt76: mt792x: harden USB reset and disconnect paths Sean Wang
2026-06-13 22:41 ` [PATCH 1/6] wifi: mt76: mt7925: stop init retries on hung bus Sean Wang
2026-06-13 22:41 ` [PATCH 2/6] wifi: mt76: mt7925: skip reset work " Sean Wang
2026-06-13 22:41 ` [PATCH 3/6] wifi: mt76: mt792x: stop USB register access after bus hang Sean Wang
2026-06-13 22:41 ` [PATCH 4/6] wifi: mt76: mt792x: drain USB UDMA before WFSYS reset Sean Wang
2026-06-13 22:41 ` [PATCH 5/6] wifi: mt76: mt792x: enable USB UDMA TX timeout Sean Wang
2026-06-13 22:41 ` [PATCH 6/6] wifi: mt76: mt792x: quiesce USB paths on disconnect Sean Wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox