* [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
@ 2026-02-27 9:48 bryam vargas
2026-02-27 9:58 ` bryam vargas
2026-03-09 6:42 ` Sean Wang
0 siblings, 2 replies; 14+ messages in thread
From: bryam vargas @ 2026-02-27 9:48 UTC (permalink / raw)
To: linux-wireless; +Cc: nbd, lorenzo
From 0a29ccaeb2211451b88ad71c4c0cdbc418b7d64d Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Fri, 27 Feb 2026 04:30:01 -0500
Subject: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in
mt76_connac_mcu_set_rate_txpower()
mt76_connac_mcu_set_rate_txpower() sends the TX power SKU table to the
firmware but never updates mphy->txpower_cur. This causes mt76_get_txpower()
to always report 3 dBm regardless of the actual configured power level,
since txpower_cur remains at its zero-initialized value and only the
path delta for 2 chains (6 units of 0.5 dBm) gets applied.
Fix this by calculating the effective TX power using the same approach
as mt7915: mt76_get_power_bound() applies SAR constraints and chain
delta, then mt76_get_rate_power_limits() applies the per-rate EEPROM
limits, yielding the actual value the firmware will use.
Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
.../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index fc3e672..4ed31ff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -2272,6 +2272,20 @@ int mt76_connac_mcu_set_rate_txpower(struct
mt76_phy *phy)
return err;
}
+ /* Update txpower_cur so mt76_get_txpower() reports the actual
+ * configured TX power instead of always returning 3 dBm due to
+ * txpower_cur being left at its zero-initialized value.
+ * The value is stored in 0.5 dBm units as used by the SKU table.
+ */
+ if (phy->chandef.chan) {
+ struct mt76_power_limits limits;
+ s8 tx_power;
+
+ tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
+ tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
+ &limits, tx_power);
+ phy->txpower_cur = tx_power;
+ }
return 0;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-02-27 9:48 [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower() bryam vargas
@ 2026-02-27 9:58 ` bryam vargas
2026-03-09 6:01 ` Sean Wang
2026-03-09 6:42 ` Sean Wang
1 sibling, 1 reply; 14+ messages in thread
From: bryam vargas @ 2026-02-27 9:58 UTC (permalink / raw)
To: linux-wireless; +Cc: nbd, lorenzo
[PATCH 2/2] mt76: mt7921u: add USB reset on SEFI chip recovery
From 86976b5908219204f7719d947fd6c5f1c5e11c7f Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Fri, 27 Feb 2026 04:30:01 -0500
Subject: [PATCH 2/2] mt76: mt7921u: add USB reset on SEFI chip recovery
The MT7921U chip is susceptible to Single Event Functional Interrupts
(SEFIs) caused by cosmic radiation, particularly at high altitudes.
When a SEFI occurs, the chip becomes unresponsive and requires a USB
reset to recover.
Add usb_queue_reset_device() calls in the SEFI detection path to
trigger automatic recovery instead of leaving the interface hung.
Tested-on: Minisforum NAB9 (MT7921U USB adapter) at 2400m altitude,
Bogotá, Colombia. Cosmic radiation causes periodic SEFI
events; USB reset restores connectivity without intervention.
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
drivers/net/wireless/mediatek/mt76/mt7921/usb.c | 12 ++++++++++++
drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 100bdba..8c8c78f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -86,6 +86,7 @@ static int mt7921u_mcu_init(struct mt792x_dev *dev)
static int mt7921u_mac_reset(struct mt792x_dev *dev)
{
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
int err;
mt76_txq_schedule_all(&dev->mphy);
@@ -100,6 +101,17 @@ static int mt7921u_mac_reset(struct mt792x_dev *dev)
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
+ /* When the chip enters a latched state (SEFI - Single Event
+ * Functional Interrupt, e.g. from cosmic radiation at altitude),
+ * all register writes over USB become silent no-ops.
+ * usb_queue_reset_device() electrically resets the chip via the
+ * USB hub regardless of internal state -- identical to probe().
+ * Async variant required to avoid deadlock in workqueue context.
+ */
+ dev_warn(dev->mt76.dev,
+ "mt7921u: scheduling USB reset for chip recovery\n");
+ usb_queue_reset_device(intf);
+
mt792xu_wfsys_reset(dev);
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 76272a0..cfd385e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -269,6 +269,8 @@ EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
int mt792xu_init_reset(struct mt792x_dev *dev)
{
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
+
set_bit(MT76_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
@@ -277,6 +279,14 @@ int mt792xu_init_reset(struct mt792x_dev *dev)
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
+ /* Same rationale as mt7921u_mac_reset(): if the chip is in a
+ * latched state (SEFI), register writes over USB are no-ops.
+ * Schedule a USB port reset before software reset sequence.
+ */
+ dev_warn(dev->mt76.dev,
+ "mt7921u: scheduling USB device reset (init_reset path)\n");
+ usb_queue_reset_device(intf);
+
mt792xu_wfsys_reset(dev);
clear_bit(MT76_RESET, &dev->mphy.state);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-02-27 9:58 ` bryam vargas
@ 2026-03-09 6:01 ` Sean Wang
0 siblings, 0 replies; 14+ messages in thread
From: Sean Wang @ 2026-03-09 6:01 UTC (permalink / raw)
To: bryam vargas
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
On Fri, Feb 27, 2026 at 3:58 AM bryam vargas
<bryamestebanvargas@gmail.com> wrote:
>
> [PATCH 2/2] mt76: mt7921u: add USB reset on SEFI chip recovery
> From 86976b5908219204f7719d947fd6c5f1c5e11c7f Mon Sep 17 00:00:00 2001
> From: bryam <bryamestebanvargas@gmail.com>
> Date: Fri, 27 Feb 2026 04:30:01 -0500
> Subject: [PATCH 2/2] mt76: mt7921u: add USB reset on SEFI chip recovery
>
> The MT7921U chip is susceptible to Single Event Functional Interrupts
> (SEFIs) caused by cosmic radiation, particularly at high altitudes.
> When a SEFI occurs, the chip becomes unresponsive and requires a USB
> reset to recover.
>
> Add usb_queue_reset_device() calls in the SEFI detection path to
> trigger automatic recovery instead of leaving the interface hung.
>
> Tested-on: Minisforum NAB9 (MT7921U USB adapter) at 2400m altitude,
> Bogotá, Colombia. Cosmic radiation causes periodic SEFI
> events; USB reset restores connectivity without intervention.
>
> Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
> ---
> drivers/net/wireless/mediatek/mt76/mt7921/usb.c | 12 ++++++++++++
> drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 10 ++++++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> index 100bdba..8c8c78f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> @@ -86,6 +86,7 @@ static int mt7921u_mcu_init(struct mt792x_dev *dev)
>
> static int mt7921u_mac_reset(struct mt792x_dev *dev)
> {
> + struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
> int err;
>
> mt76_txq_schedule_all(&dev->mphy);
> @@ -100,6 +101,17 @@ static int mt7921u_mac_reset(struct mt792x_dev *dev)
> mt76u_stop_rx(&dev->mt76);
> mt76u_stop_tx(&dev->mt76);
>
> + /* When the chip enters a latched state (SEFI - Single Event
> + * Functional Interrupt, e.g. from cosmic radiation at altitude),
> + * all register writes over USB become silent no-ops.
> + * usb_queue_reset_device() electrically resets the chip via the
> + * USB hub regardless of internal state -- identical to probe().
> + * Async variant required to avoid deadlock in workqueue context.
> + */
> + dev_warn(dev->mt76.dev,
> + "mt7921u: scheduling USB reset for chip recovery\n");
> + usb_queue_reset_device(intf);
Hi,
usb_queue_reset_device() is asynchronous. After scheduling the reset,
the driver continues the normal reset flow and still performs reset
operations on the same device, which creates race conditions.
Also, mt792xu_init_reset() also assumes the USB bus is still
functioning, since it relies on normal USB transactions to reset
WFSYS.
A USB reset should be triggered only after detecting USB transaction
errors or after repeated mt792xu_init_reset() failures.
In this case then we could try triggering a USB reset in software to
see if the USB bus can recover.
Thanks.
> +
> mt792xu_wfsys_reset(dev);
>
> clear_bit(MT76_MCU_RESET, &dev->mphy.state);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> index 76272a0..cfd385e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> @@ -269,6 +269,8 @@ EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
>
> int mt792xu_init_reset(struct mt792x_dev *dev)
> {
> + struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
> +
> set_bit(MT76_RESET, &dev->mphy.state);
>
> wake_up(&dev->mt76.mcu.wait);
> @@ -277,6 +279,14 @@ int mt792xu_init_reset(struct mt792x_dev *dev)
> mt76u_stop_rx(&dev->mt76);
> mt76u_stop_tx(&dev->mt76);
>
> + /* Same rationale as mt7921u_mac_reset(): if the chip is in a
> + * latched state (SEFI), register writes over USB are no-ops.
> + * Schedule a USB port reset before software reset sequence.
> + */
> + dev_warn(dev->mt76.dev,
> + "mt7921u: scheduling USB device reset (init_reset path)\n");
> + usb_queue_reset_device(intf);
> +
> mt792xu_wfsys_reset(dev);
>
> clear_bit(MT76_RESET, &dev->mphy.state);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-02-27 9:48 [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower() bryam vargas
2026-02-27 9:58 ` bryam vargas
@ 2026-03-09 6:42 ` Sean Wang
2026-03-09 16:36 ` bryam vargas
1 sibling, 1 reply; 14+ messages in thread
From: Sean Wang @ 2026-03-09 6:42 UTC (permalink / raw)
To: bryam vargas
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Hi,
On Fri, Feb 27, 2026 at 3:53 AM bryam vargas
<bryamestebanvargas@gmail.com> wrote:
>
> From 0a29ccaeb2211451b88ad71c4c0cdbc418b7d64d Mon Sep 17 00:00:00 2001
> From: bryam <bryamestebanvargas@gmail.com>
> Date: Fri, 27 Feb 2026 04:30:01 -0500
> Subject: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in
> mt76_connac_mcu_set_rate_txpower()
>
> mt76_connac_mcu_set_rate_txpower() sends the TX power SKU table to the
> firmware but never updates mphy->txpower_cur. This causes mt76_get_txpower()
> to always report 3 dBm regardless of the actual configured power level,
> since txpower_cur remains at its zero-initialized value and only the
> path delta for 2 chains (6 units of 0.5 dBm) gets applied.
>
> Fix this by calculating the effective TX power using the same approach
> as mt7915: mt76_get_power_bound() applies SAR constraints and chain
> delta, then mt76_get_rate_power_limits() applies the per-rate EEPROM
> limits, yielding the actual value the firmware will use.
I wonder if this would fit better in .get_txpower instead.
mt76_connac_mcu_set_rate_txpower() is primarily a programming path
that pushes the SKU table to firmware. Updating txpower_cur there
mixes write-side configuration with reporting logic.
It might be cleaner to handle this in .get_txpower with an
mt7921-specific callback that derives the reported TX power from the
SKU limits instead of updating the cached value in the write path.
>
> Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
> Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
> ---
> .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
> b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
> index fc3e672..4ed31ff 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
> @@ -2272,6 +2272,20 @@ int mt76_connac_mcu_set_rate_txpower(struct
> mt76_phy *phy)
> return err;
> }
>
> + /* Update txpower_cur so mt76_get_txpower() reports the actual
> + * configured TX power instead of always returning 3 dBm due to
> + * txpower_cur being left at its zero-initialized value.
> + * The value is stored in 0.5 dBm units as used by the SKU table.
> + */
> + if (phy->chandef.chan) {
> + struct mt76_power_limits limits;
> + s8 tx_power;
> +
> + tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
> + tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
> + &limits, tx_power);
> + phy->txpower_cur = tx_power;
> + }
> return 0;
> }
> EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-09 6:42 ` Sean Wang
@ 2026-03-09 16:36 ` bryam vargas
2026-03-11 20:55 ` bryam vargas
0 siblings, 1 reply; 14+ messages in thread
From: bryam vargas @ 2026-03-09 16:36 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Hi Sean,
Thank you for the thorough review.
For patch 1, I agree that updating txpower_cur in the write path mixes
concerns. I'll implement a mt7921-specific .get_txpower callback that
derives the reported TX power directly from the SKU limits instead.
For patch 2, you're right about the race condition — scheduling an
async USB reset while the driver continues the normal reset flow is
problematic. I'll rework this to trigger the USB reset only after
detecting USB transaction errors or repeated mt792xu_init_reset()
failures, as you suggested.
I'll send a v2 series addressing both points.
Best regards,
Bryam Vargas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-09 16:36 ` bryam vargas
@ 2026-03-11 20:55 ` bryam vargas
2026-03-11 20:57 ` bryam vargas
0 siblings, 1 reply; 14+ messages in thread
From: bryam vargas @ 2026-03-11 20:55 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Changes in v2:
- patch 1: implement mt7921-specific .get_txpower callback instead of
updating txpower_cur in the write path, as suggested by Sean Wang
- patch 2: trigger USB reset only when mt792xu_wfsys_reset() returns
-ETIMEDOUT, avoiding the race condition with async
usb_queue_reset_device(), as suggested by Sean Wang
Both patches compile clean against v6.18 and tested for two days on
MT7921U USB at 2400m altitude (Bogotá, Colombia).
Bryam Vargas (2):
mt76: mt7921: add mt7921-specific get_txpower callback
mt76: mt7921u: trigger USB reset only on wfsys timeout
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-11 20:55 ` bryam vargas
@ 2026-03-11 20:57 ` bryam vargas
2026-03-11 20:58 ` bryam vargas
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: bryam vargas @ 2026-03-11 20:57 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
From 6c75ad481f0c3667d6ae2a2c8f7c2df08b1d52b5 Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Mon, 9 Mar 2026 11:52:53 -0500
Subject: [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
Instead of updating txpower_cur in the write path
(mt76_connac_mcu_set_rate_txpower), implement a mt7921-specific
.get_txpower callback that derives the reported TX power directly
from the SKU limits at query time.
This avoids mixing write-side configuration with reporting logic.
The callback uses mt76_get_power_bound() for SAR constraints and
chain delta, then mt76_get_rate_power_limits() for per-rate EEPROM
limits, yielding the actual TX power value.
Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
.../net/wireless/mediatek/mt76/mt7921/main.c | 27 ++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 67383c4..35454e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -1517,6 +1517,31 @@ static void mt7921_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(hw->wiphy, ret ? false : true);
}
+
+static int mt7921_get_txpower(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, int *dbm)
+{
+ struct mt76_phy *phy = mt76_vif_phy(hw, vif);
+ struct mt76_power_limits limits;
+ int n_chains, delta;
+ s8 tx_power;
+
+ if (!phy)
+ return -EINVAL;
+
+ if (!phy->chandef.chan)
+ return mt76_get_txpower(hw, vif, link_id, dbm);
+
+ n_chains = hweight16(phy->chainmask);
+ delta = mt76_tx_power_path_delta(n_chains);
+ tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
+ tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
+ &limits, tx_power);
+ *dbm = DIV_ROUND_UP(tx_power + delta, 2);
+ return 0;
+}
+
const struct ieee80211_ops mt7921_ops = {
.tx = mt792x_tx,
.start = mt7921_start,
@@ -1541,7 +1566,7 @@ const struct ieee80211_ops mt7921_ops = {
.wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.channel_switch_beacon = mt7921_channel_switch_beacon,
- .get_txpower = mt76_get_txpower,
+ .get_txpower = mt7921_get_txpower,
.get_stats = mt792x_get_stats,
.get_et_sset_count = mt792x_get_et_sset_count,
.get_et_strings = mt792x_get_et_strings,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-11 20:57 ` bryam vargas
@ 2026-03-11 20:58 ` bryam vargas
2026-03-12 0:49 ` bryam vargas
2026-03-12 5:49 ` Sean Wang
2026-03-12 5:24 ` Sean Wang
2026-03-12 17:38 ` [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback Lucid Duck
2 siblings, 2 replies; 14+ messages in thread
From: bryam vargas @ 2026-03-11 20:58 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
From 9fabc33e722f321b4048ada6d4667ddacbb1495a Mon Sep 17 00:00:00 2001
From: bryam <bryamestebanvargas@gmail.com>
Date: Mon, 9 Mar 2026 12:25:37 -0500
Subject: [PATCH v2 2/2] mt76: mt7921u: trigger USB reset only on wfsys timeout
Instead of unconditionally scheduling a USB device reset at the start
of the reset sequence, trigger it only when mt792xu_wfsys_reset()
returns -ETIMEDOUT, which indicates the chip is in a latched state
(SEFI - Single Event Functional Interrupt) where register writes over
USB become silent no-ops.
This avoids the race condition where usb_queue_reset_device() was
scheduled asynchronously while the driver continued normal reset
operations on the same device.
Tested-on: Minisforum NAB9 (MT7921U USB adapter) at 2400m altitude,
Bogota, Colombia. Cosmic radiation causes periodic SEFI
events; USB reset restores connectivity without intervention.
Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
---
.../net/wireless/mediatek/mt76/mt7921/usb.c | 32 +++++++++----------
.../net/wireless/mediatek/mt76/mt792x_usb.c | 16 ++++------
2 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 8c8c78f..44c7437 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -86,33 +86,33 @@ static int mt7921u_mcu_init(struct mt792x_dev *dev)
static int mt7921u_mac_reset(struct mt792x_dev *dev)
{
- struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
int err;
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
-
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
-
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
-
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
- /* When the chip enters a latched state (SEFI - Single Event
- * Functional Interrupt, e.g. from cosmic radiation at altitude),
- * all register writes over USB become silent no-ops.
- * usb_queue_reset_device() electrically resets the chip via the
- * USB hub regardless of internal state -- identical to probe().
- * Async variant required to avoid deadlock in workqueue context.
- */
- dev_warn(dev->mt76.dev,
- "mt7921u: scheduling USB reset for chip recovery\n");
- usb_queue_reset_device(intf);
-
- mt792xu_wfsys_reset(dev);
+ err = mt792xu_wfsys_reset(dev);
+ if (err == -ETIMEDOUT) {
+ /* Chip is in a latched state (SEFI - Single Event Functional
+ * Interrupt, e.g. from cosmic radiation at altitude).
+ * Register writes over USB become silent no-ops; schedule an
+ * electrical USB reset via the hub as last resort.
+ * usb_queue_reset_device() is async to avoid deadlock in
+ * workqueue context.
+ */
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
+
+ dev_warn(dev->mt76.dev,
+ "mt7921u: wfsys reset timed out, scheduling USB reset\n");
+ usb_queue_reset_device(intf);
+ goto out;
+ }
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
err = mt76u_resume_rx(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index cfd385e..4737384 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -269,7 +269,6 @@ EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
int mt792xu_init_reset(struct mt792x_dev *dev)
{
- struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
set_bit(MT76_RESET, &dev->mphy.state);
@@ -279,15 +278,14 @@ int mt792xu_init_reset(struct mt792x_dev *dev)
mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
- /* Same rationale as mt7921u_mac_reset(): if the chip is in a
- * latched state (SEFI), register writes over USB are no-ops.
- * Schedule a USB port reset before software reset sequence.
- */
- dev_warn(dev->mt76.dev,
- "mt7921u: scheduling USB device reset (init_reset path)\n");
- usb_queue_reset_device(intf);
+ if (mt792xu_wfsys_reset(dev) == -ETIMEDOUT) {
+ struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
+
+ dev_warn(dev->mt76.dev,
+ "mt792xu: wfsys reset timed out, scheduling USB reset\n");
+ usb_queue_reset_device(intf);
+ }
- mt792xu_wfsys_reset(dev);
clear_bit(MT76_RESET, &dev->mphy.state);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-11 20:58 ` bryam vargas
@ 2026-03-12 0:49 ` bryam vargas
2026-03-12 5:49 ` Sean Wang
1 sibling, 0 replies; 14+ messages in thread
From: bryam vargas @ 2026-03-12 0:49 UTC (permalink / raw)
To: Sean Wang; +Cc: linux-wireless, nbd, lorenzo
Subject: mt76: mt7921u: WF_MIB registers inaccessible over USB — right
approach for survey fix?
Hi Sean,
Thank you for the v1 review. I've just sent v2 addressing both points.
While investigating why iw reports zero channel time on mt7921u, I
traced the issue to mt792x_phy_update_channel(): it reads
MT_MIB_SDR9/36/37 via mt76_rr(), which works fine on PCIe (direct
MMIO), but on USB these are hardware MAC counters in the WF_MIB block
that the firmware does not map in its USB vendor request table — so
they always return 0.
Evidence:
- iw dev wlan0 survey dump reports 0ms for active/busy/rx/tx time
after transmitting 638 MiB
- Disabling power save has no effect (rules out pm_wake early return)
- mt7925 USB has the same issue (same mt792x_update_channel path)
- WTBL registers (MT_WTBL_AC0_CTT_OFFSET) work fine over USB — used in
mac.c for per-station airtime
Before writing a patch, I wanted to ask:
1. Is there an existing MCU command that can retrieve MIB counters
(busy/tx/rx time) from the firmware in the mt7921 USB case? I didn't
find one in mt7921/mcu.c or mt76_connac_mcu.c.
2. Alternatively, would it be acceptable to accumulate survey data
from the per-station airtime counters (airtime_ac[], already read via
WTBL in mt7921_mac_sta_poll()) into chan_state->cc_tx/cc_rx? This
would give approximate but functional channel utilization reporting.
3. Is there a reason the WF_MIB block is intentionally not exposed
over USB in the firmware?
Any guidance on the preferred approach would be appreciated before I
write a patch.
Best regards,
Bryam Vargas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-11 20:57 ` bryam vargas
2026-03-11 20:58 ` bryam vargas
@ 2026-03-12 5:24 ` Sean Wang
2026-03-12 17:38 ` [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback Lucid Duck
2 siblings, 0 replies; 14+ messages in thread
From: Sean Wang @ 2026-03-12 5:24 UTC (permalink / raw)
To: bryam vargas, lucid_duck
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Hi,
I just realized that Lucid already implemented another approach to
obtain the TX power here:
https://lore.kernel.org/linux-wireless/20260130215839.53270-1-lucid_duck@justthetip.ca/
We should respect his work. Could you also take a look at it and reply
to his patch to avoid potential rework?
On Wed, Mar 11, 2026 at 3:57 PM bryam vargas
<bryamestebanvargas@gmail.com> wrote:
>
> From 6c75ad481f0c3667d6ae2a2c8f7c2df08b1d52b5 Mon Sep 17 00:00:00 2001
> From: bryam <bryamestebanvargas@gmail.com>
> Date: Mon, 9 Mar 2026 11:52:53 -0500
> Subject: [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
>
> Instead of updating txpower_cur in the write path
> (mt76_connac_mcu_set_rate_txpower), implement a mt7921-specific
> .get_txpower callback that derives the reported TX power directly
> from the SKU limits at query time.
>
> This avoids mixing write-side configuration with reporting logic.
> The callback uses mt76_get_power_bound() for SAR constraints and
> chain delta, then mt76_get_rate_power_limits() for per-rate EEPROM
> limits, yielding the actual TX power value.
>
> Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
> Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
> ---
> .../net/wireless/mediatek/mt76/mt7921/main.c | 27 ++++++++++++++++++-
> 1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> index 67383c4..35454e5 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> @@ -1517,6 +1517,31 @@ static void mt7921_rfkill_poll(struct ieee80211_hw *hw)
> wiphy_rfkill_set_hw_state(hw->wiphy, ret ? false : true);
> }
>
> +
> +static int mt7921_get_txpower(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + unsigned int link_id, int *dbm)
> +{
> + struct mt76_phy *phy = mt76_vif_phy(hw, vif);
> + struct mt76_power_limits limits;
> + int n_chains, delta;
> + s8 tx_power;
> +
> + if (!phy)
> + return -EINVAL;
> +
> + if (!phy->chandef.chan)
> + return mt76_get_txpower(hw, vif, link_id, dbm);
> +
> + n_chains = hweight16(phy->chainmask);
> + delta = mt76_tx_power_path_delta(n_chains);
> + tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
> + tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
> + &limits, tx_power);
> + *dbm = DIV_ROUND_UP(tx_power + delta, 2);
how can you make sure it is the result of the maximum rate power used
in the loop within mt76_connac_mcu_rate_txpower_band (updated with
each call) ?
> + return 0;
> +}
> +
> const struct ieee80211_ops mt7921_ops = {
> .tx = mt792x_tx,
> .start = mt7921_start,
> @@ -1541,7 +1566,7 @@ const struct ieee80211_ops mt7921_ops = {
> .wake_tx_queue = mt76_wake_tx_queue,
> .release_buffered_frames = mt76_release_buffered_frames,
> .channel_switch_beacon = mt7921_channel_switch_beacon,
> - .get_txpower = mt76_get_txpower,
> + .get_txpower = mt7921_get_txpower,
> .get_stats = mt792x_get_stats,
> .get_et_sset_count = mt792x_get_et_sset_count,
> .get_et_strings = mt792x_get_et_strings,
> --
> 2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-11 20:58 ` bryam vargas
2026-03-12 0:49 ` bryam vargas
@ 2026-03-12 5:49 ` Sean Wang
2026-03-12 16:30 ` bryam vargas
1 sibling, 1 reply; 14+ messages in thread
From: Sean Wang @ 2026-03-12 5:49 UTC (permalink / raw)
To: bryam vargas
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
On Wed, Mar 11, 2026 at 3:58 PM bryam vargas
<bryamestebanvargas@gmail.com> wrote:
>
> From 9fabc33e722f321b4048ada6d4667ddacbb1495a Mon Sep 17 00:00:00 2001
> From: bryam <bryamestebanvargas@gmail.com>
> Date: Mon, 9 Mar 2026 12:25:37 -0500
> Subject: [PATCH v2 2/2] mt76: mt7921u: trigger USB reset only on wfsys timeout
>
> Instead of unconditionally scheduling a USB device reset at the start
> of the reset sequence, trigger it only when mt792xu_wfsys_reset()
> returns -ETIMEDOUT, which indicates the chip is in a latched state
> (SEFI - Single Event Functional Interrupt) where register writes over
how do you know that `-ETIMEDOUT` means the chip entered a latched
state or a SEFI condition?
> USB become silent no-ops.
>
> This avoids the race condition where usb_queue_reset_device() was
> scheduled asynchronously while the driver continued normal reset
> operations on the same device.
>
> Tested-on: Minisforum NAB9 (MT7921U USB adapter) at 2400m altitude,
> Bogota, Colombia. Cosmic radiation causes periodic SEFI
> events; USB reset restores connectivity without intervention.
>
> Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
> ---
> .../net/wireless/mediatek/mt76/mt7921/usb.c | 32 +++++++++----------
> .../net/wireless/mediatek/mt76/mt792x_usb.c | 16 ++++------
> 2 files changed, 23 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> index 8c8c78f..44c7437 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
> @@ -86,33 +86,33 @@ static int mt7921u_mcu_init(struct mt792x_dev *dev)
>
> static int mt7921u_mac_reset(struct mt792x_dev *dev)
> {
> - struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
> int err;
>
> mt76_txq_schedule_all(&dev->mphy);
> mt76_worker_disable(&dev->mt76.tx_worker);
> -
> set_bit(MT76_RESET, &dev->mphy.state);
> set_bit(MT76_MCU_RESET, &dev->mphy.state);
> -
> wake_up(&dev->mt76.mcu.wait);
> skb_queue_purge(&dev->mt76.mcu.res_q);
> -
> mt76u_stop_rx(&dev->mt76);
> mt76u_stop_tx(&dev->mt76);
>
> - /* When the chip enters a latched state (SEFI - Single Event
> - * Functional Interrupt, e.g. from cosmic radiation at altitude),
> - * all register writes over USB become silent no-ops.
> - * usb_queue_reset_device() electrically resets the chip via the
> - * USB hub regardless of internal state -- identical to probe().
> - * Async variant required to avoid deadlock in workqueue context.
> - */
> - dev_warn(dev->mt76.dev,
> - "mt7921u: scheduling USB reset for chip recovery\n");
> - usb_queue_reset_device(intf);
> -
I also cannot find these changes in the current codebase. What tree
did you build this patch on?
> - mt792xu_wfsys_reset(dev);
> + err = mt792xu_wfsys_reset(dev);
> + if (err == -ETIMEDOUT) {
> + /* Chip is in a latched state (SEFI - Single Event Functional
> + * Interrupt, e.g. from cosmic radiation at altitude).
> + * Register writes over USB become silent no-ops; schedule an
> + * electrical USB reset via the hub as last resort.
> + * usb_queue_reset_device() is async to avoid deadlock in
> + * workqueue context.
The comment does not make sense to me. A timeout in
`mt792xu_wfsys_reset()` is not sufficient evidence to conclude the
device is in a latched state, and definitely not enough to attribute
it to SEFI or cosmic radiation.
> + */
> + struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
> +
> + dev_warn(dev->mt76.dev,
> + "mt7921u: wfsys reset timed out, scheduling USB reset\n");
> + usb_queue_reset_device(intf);
That is not the way I suggested. This also still keeps the same
fundamental problem from v1. usb_queue_reset_device() is asynchronous
and you are still injecting a USB-level reset into an ongoing reset
flow to interfere with the MAC reset recovery path. Gating it on
-ETIMEDOUT changes when it happens, but does not eliminate the race
itself.
I do not think we should add this recovery path without first
understanding the actual failure. In some cases this may not even be a
device reset issue, but a USB bus/topology stability issue, Suggest
file a bug with complete logs and reproduction details first.
> + goto out;
> + }
>
> clear_bit(MT76_MCU_RESET, &dev->mphy.state);
> err = mt76u_resume_rx(&dev->mt76);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> index cfd385e..4737384 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
> @@ -269,7 +269,6 @@ EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
>
> int mt792xu_init_reset(struct mt792x_dev *dev)
> {
> - struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
>
> set_bit(MT76_RESET, &dev->mphy.state);
>
> @@ -279,15 +278,14 @@ int mt792xu_init_reset(struct mt792x_dev *dev)
> mt76u_stop_rx(&dev->mt76);
> mt76u_stop_tx(&dev->mt76);
>
> - /* Same rationale as mt7921u_mac_reset(): if the chip is in a
> - * latched state (SEFI), register writes over USB are no-ops.
> - * Schedule a USB port reset before software reset sequence.
> - */
> - dev_warn(dev->mt76.dev,
> - "mt7921u: scheduling USB device reset (init_reset path)\n");
> - usb_queue_reset_device(intf);
> + if (mt792xu_wfsys_reset(dev) == -ETIMEDOUT) {
> + struct usb_interface *intf = to_usb_interface(dev->mt76.dev);
> +
> + dev_warn(dev->mt76.dev,
> + "mt792xu: wfsys reset timed out, scheduling USB reset\n");
> + usb_queue_reset_device(intf);
> + }
>
> - mt792xu_wfsys_reset(dev);
>
> clear_bit(MT76_RESET, &dev->mphy.state);
>
> --
> 2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-12 5:49 ` Sean Wang
@ 2026-03-12 16:30 ` bryam vargas
2026-03-12 18:22 ` bryam vargas
0 siblings, 1 reply; 14+ messages in thread
From: bryam vargas @ 2026-03-12 16:30 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Hi Sean,
Thanks for the thorough v2 review on both patches — really helpful.
I spent the last few days digging deeper into the txpower reporting
path across mt76 sub-drivers (mt7615, mt7915, mt7996, mt7921, mt7925)
to find the most efficient fix. Turns out, Razvan Grigore already
nailed it 13 months ago:
https://patchwork.kernel.org/project/linux-wireless/patch/20250211081247.5892-3-razvan.grigore@vampirebyte.ro/
His patch adds 3 lines to mt7921_set_tx_sar_pwr() — same pattern as
mt7915 (mcu.c:3393) and mt7996 (mcu.c:4802):
tx_power = mt76_get_power_bound(mphy, hw->conf.power_level);
tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
&limits_array, tx_power);
mphy->txpower_cur = tx_power;
This runs before mt76_connac_mcu_set_rate_txpower(), so it uses the
same SAR-bounded, DT-capped value that the firmware receives. And
since set_tx_sar_pwr() is called from all four paths you pointed out
(init, config, regd_update, set_sar_specs), it covers every scenario
— including the ones Lucid Duck's BSS_CHANGED_TXPOWER approach misses
when not associated.
I'm withdrawing both of my patches. Razvan's approach is the right
one, and I don't want to duplicate his work.
What I'll focus on instead:
- Testing: I'll verify Razvan's patch on my MT7921U (NAB9, 2400m
altitude, daily use serving real users) and provide Tested-by.
- SEFI/USB reset: You're right that v2 was premature. I'll file a
proper bug with full dmesg, lsusb topology, and usbmon captures
first, then propose a fix only after the failure mode is understood.
- WF_MIB over USB: Still interested in your thoughts on my March 12
email about MT_MIB_SDR9/36/37 returning 0 on mt7921u. From what
I've seen, the USB variant has several gaps beyond txpower — survey
data, channel time counters — that I'd like to help close.
Best regards,
Bryam Vargas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
2026-03-11 20:57 ` bryam vargas
2026-03-11 20:58 ` bryam vargas
2026-03-12 5:24 ` Sean Wang
@ 2026-03-12 17:38 ` Lucid Duck
2 siblings, 0 replies; 14+ messages in thread
From: Lucid Duck @ 2026-03-12 17:38 UTC (permalink / raw)
To: bryam vargas
Cc: Sean Wang, Felix Fietkau, Lorenzo Bianconi, linux-wireless,
linux-mediatek
Hi Bryam, Sean,
I tested this on my MT7921AU USB adapter (Alfa AWUS036AXML, Fedora,
kernel 6.18.16, ISED/Canada). The callback itself is clean and with
one fix it gives correct values on all three bands, stable across a
full gauntlet. Nice work.
chanctx channel source (affects all mt7921 phy->chandef readers)
-----------------------------------------------------------------
This one bit me during testing and is worth flagging because it
affects more than just the callback. mt7921 uses the chanctx model,
and mt7921_add_chanctx() stores the context in dev->new_ctx without
updating phy->chandef. So phy->chandef.chan stays stuck on whatever
channel the firmware scanned at probe time -- channel 229 (6 GHz) on
my system. I confirmed via debugfs: "Tx power table (channel 229)"
while actually connected to 2.4 GHz ch6.
Because the callback reads phy->chandef.chan->max_power, it returns
12 dBm on every band. mt76_get_power_bound() has the same issue
internally since it also reads phy->chandef.chan.
The fix that worked for me: read the channel from the VIF chanctx
(falling back to phy->chandef.chan when unassociated) and inline the
SAR + delta math to avoid get_power_bound:
rcu_read_lock();
ctx = rcu_dereference(vif->bss_conf.chanctx_conf);
chan = ctx ? ctx->def.chan : phy->chandef.chan;
rcu_read_unlock();
if (!chan)
return mt76_get_txpower(hw, vif, link_id, dbm);
n_chains = hweight16(phy->chainmask);
delta = mt76_tx_power_path_delta(n_chains);
tx_power = mt76_get_sar_power(phy, chan, chan->max_power * 2);
tx_power -= delta;
tx_power = mt76_get_rate_power_limits(phy, chan, &limits, tx_power);
*dbm = DIV_ROUND_UP(tx_power + delta, 2);
A note on Sean's rate power loop direction
-------------------------------------------
Sean's feedback on both our patches points toward deriving the
reported value from mt76_connac_mcu_rate_txpower_band() -- the loop
that computes per-rate power limits before sending SKU tables to
firmware. That would sidestep the chanctx issue entirely since
txpower_cur gets written at configuration time rather than computed
at query time.
Looking at the code, mt7915 already does this (mt7915/mcu.c:3396):
tx_power = mt76_get_rate_power_limits(...);
mphy->txpower_cur = tx_power;
The connac equivalent calls mt76_get_rate_power_limits() in the same
loop but discards the return value. If that were fixed to match
mt7915, the existing mt76_get_txpower() would report correctly
without a per-driver callback.
That approach would also cover user txpower limits for free --
`iw dev set txpower fixed 1500` currently succeeds but the callback
reports the regulatory ceiling because it starts from chan->max_power.
The rate power loop already reads 2 * phy->hw->conf.power_level
(mt76_connac_mcu.c:2162), so user limits would be reflected
automatically.
Either way, happy to help test whatever direction v3 takes.
Test results (chanctx fix applied)
------------------------------------
Alfa AWUS036AXML (MT7921AU, USB, 2x2 MIMO)
Kernel 6.18.16-200.fc43.x86_64, ISED/Canada
Per-band (10 runs each):
2.4 GHz ch6: 30.00 dBm (ISED: 30) 10/10 PASS
5 GHz ch100: 26.00 dBm (ISED: 26) 10/10 PASS
6 GHz ch5: 12.00 dBm (ISED: 12) 10/10 PASS
Band switching: 18/18 correct
Rapid cycling (20/band): 60/60 PASS
Regdomain (CA/US/CA): 9/9 PASS (5 GHz: 26->24->26)
60-min soak (5 GHz): 61/61 PASS, zero drift
USB torture (module reload, monitor cycling, assoc interrupt):
20/20 PASS
Kernel errors: zero across all phases
Tested-by: Lucid Duck <lucid_duck@justthetip.ca>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
2026-03-12 16:30 ` bryam vargas
@ 2026-03-12 18:22 ` bryam vargas
0 siblings, 0 replies; 14+ messages in thread
From: bryam vargas @ 2026-03-12 18:22 UTC (permalink / raw)
To: Sean Wang
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
Subject: Bug: mt7921u unrecoverable chip hang requiring system reboot
(USB device disappears from bus)
Hi,
I'm filing a bug report for a recurring failure mode on the MT7921U USB
WiFi adapter where the chip becomes completely unresponsive and
eventually disappears from the USB bus, requiring a full system reboot
to recover.
This follows up on Sean Wang's suggestion to document the failure before
proposing driver-level recovery mechanisms.
== Hardware ==
System: Minisforum NAB9 (Intel i9-12900H)
Adapter: MediaTek MT7921AU USB (VID 35bc, PID 0107)
Kernel: 6.18.x (Ubuntu 24.04)
Location: Bogotá, Colombia (2400m altitude)
Uptime: Continuous operation as home server (6-12 daily users)
== Symptoms ==
The MT7921U periodically enters a state where:
1. nmcli device show / iw dev wlan0 info time out
2. WiFi scan requests hang indefinitely
3. The interface exists in ip link but is non-functional
4. All software recovery attempts fail (driver reload, USB
unbind/rebind, USB controller reset, uhubctl power cycle)
5. The device eventually disappears from lsusb entirely
6. Only a full system reboot restores the adapter
== Structured Event Log ==
I run an automated monitoring script (net-rescue.sh) that checks chip
responsiveness every 10 minutes and logs events with timestamps and
system uptime. Here is the complete chip-events.log from January
through March 2026:
Recoverable events (soft USB reset succeeds):
2026-01-11 20:29 HANG -> RECOVERED (soft_usb_reset) [8s]
2026-01-11 20:34 HANG -> RECOVERED (soft_usb_reset) [7s]
2026-01-11 20:45 HANG -> RECOVERED (soft_usb_reset) [8s]
2026-01-11 20:55 HANG -> RECOVERED (soft_usb_reset) [7s]
2026-01-14 09:34 HANG -> RECOVERED (soft_usb_reset) [373s]
2026-01-16 13:37 HANG -> RECOVERED (soft_usb_reset) [313s]
2026-01-17 15:21 HANG -> RECOVERED (soft_usb_reset) [129s]
2026-02-28 13:49 HANG -> RECOVERED (soft_usb_reset) [99s]
Unrecoverable events (all escalation levels fail):
2026-01-13 17:16 HANG -> FAILED (all_recovery_attempts_failed)
2026-01-26 14:10 HANG -> FAILED (all_recovery_attempts_failed)
2026-02-09 14:33 HANG -> FAILED (all_recovery_attempts_failed)
2026-02-11 11:07 HANG -> FAILED -> 14x DISAPPEARED over 3+ hours
2026-02-22 09:45 HANG -> FAILED -> 35x DISAPPEARED over 6+ hours
The DISAPPEARED entries mean the device is no longer visible on the
USB bus at all. The monitoring script runs every ~10 minutes, so each
DISAPPEARED entry is a separate detection cycle confirming the device
remains absent.
The Feb 11 and Feb 22 incidents are the most telling: after the initial
hang and failed recovery, the chip vanished from the bus entirely and
stayed gone for hours until the daily 2:00 AM scheduled reboot
restored it.
== Recovery Escalation (all fail in unrecoverable case) ==
Level 1: USB deauthorize/reauthorize via sysfs
Level 2: modprobe -r mt7921u / modprobe mt7921u
Level 3: USB unbind/rebind via /sys/bus/usb/drivers/usb/
Level 4: uhubctl power cycle (physical power cut to USB port)
Level 5: xhci_pci / ehci_pci module reload
When the chip enters the unrecoverable state, mt792xu_wfsys_reset()
cannot succeed because the chip does not respond to USB vendor
requests. Even cutting physical power to the USB port via uhubctl
and restoring it does not bring the device back. Only a full system
reboot (which resets the xHCI controller at BIOS level) recovers it.
== Pattern Analysis ==
From the event log:
- 10 HANG events over ~2 months of continuous operation
- 8 recovered via soft USB reset (80% success rate)
- 5 required system reboot (escalation completely failed)
- 2 incidents with extended DISAPPEARED state (3-6 hours)
The Jan 11 cluster (4 HANGs in 30 minutes) suggests a transient
condition that resolves with soft resets. The Feb 11 and Feb 22
incidents represent a different, more severe failure where the
chip enters a state that no software recovery can address.
== Pending Data ==
I can provide the following on request or when the next event occurs:
- Full dmesg around HANG/DISAPPEARED transitions
- lsusb -t (USB topology) and lsusb -v -d 0e8d:7961
- usbmon traces during the failure
- journalctl entries from net-rescue.service
The static USB data (topology, device descriptor) I can provide
immediately. The dynamic data (dmesg during failure) requires waiting
for the next natural occurrence, as the system has been stable since
the last incident.
== Related Reports ==
https://github.com/openwrt/mt76/issues/838
https://github.com/morrownr/USB-WiFi/issues/410
https://github.com/raspberrypi/linux/issues/5193
All describe the same symptom: mt7921u interface becomes a zombie
(UP but unable to TX/RX), requiring physical USB unplug or system
reboot.
== Note on Environment ==
This system operates at 2400m altitude where atmospheric neutron
flux is elevated compared to sea level. I initially attributed these
events to cosmic radiation-induced SEFI (Single Event Functional
Interrupt), but as Sean correctly pointed out, the failure mode needs
to be understood before attributing a cause. The structured event log
is provided as evidence of the failure pattern regardless of root
cause.
This is a home server under active development running multiple
services (ERP, Minecraft, Tailscale, DNS/DHCP, containers). When the
chip enters the unrecoverable state and I'm not physically near the
hardware, the system can remain without WiFi connectivity for days
until I can manually reboot it.
Best regards,
Bryam Vargas
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-03-12 18:22 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-27 9:48 [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower() bryam vargas
2026-02-27 9:58 ` bryam vargas
2026-03-09 6:01 ` Sean Wang
2026-03-09 6:42 ` Sean Wang
2026-03-09 16:36 ` bryam vargas
2026-03-11 20:55 ` bryam vargas
2026-03-11 20:57 ` bryam vargas
2026-03-11 20:58 ` bryam vargas
2026-03-12 0:49 ` bryam vargas
2026-03-12 5:49 ` Sean Wang
2026-03-12 16:30 ` bryam vargas
2026-03-12 18:22 ` bryam vargas
2026-03-12 5:24 ` Sean Wang
2026-03-12 17:38 ` [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback Lucid Duck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox