Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
@ 2026-08-19  9:03 Jonas Hort
  2026-08-22 20:18 ` Jonas Hort
  0 siblings, 1 reply; 15+ messages in thread
From: Jonas Hort @ 2026-08-19  9:03 UTC (permalink / raw)
  To: Devin Wittmayer
  Cc: Thorsten Leemhuis, regressions, linux-wireless, Felix Fietkau,
	lorenzo.bianconi83

Thanks for the detailed breakdown.

I'll build v7.0 vanilla and test it, as suggested. Fair warning
though: I'm on vacation this week, so I'll pick this up next week.
I've also never compiled a kernel before, so it'll likely take me a
bit of trial and error the first time around - please bear with me
if it takes a little longer than expected.

Will report back once I have results.

Thanks again,
Jonas

19.08.2026 03:18:34 Devin Wittmayer <lucid_duck@justthetip.ca>:

> Thank you very much, that answers both things.
> 
> The ROC tracing is the more useful of the two even though it came back
> negative. Two of the three freezes have no ROC activity in them at all, so a
> link switch that never finished cannot be what starts this. The middle one
> does have rocabort, mloroc and rocwork in it, but one out of three makes
> that look like the exception rather than the pattern. So the area I sent you
> looking at is out, and that is worth knowing before you spend nights on
> builds.
> 
> One other thing worth saying first. There is a five patch mt76 series on the
> list at the moment and two of the patches look like they were written for
> exactly this bug. I do not think they were, and it is your own numbers that
> show it. The failure 4/5 fixes stops mt76_txq_schedule_list from servicing
> the queue, and the one 5/5 fixes stops mt76_txq_send_burst once the non-AQL
> count reaches its cap. Both of those keep frames from ever reaching the
> hardware, so if either were your problem head would be sitting still
> alongside tail. Yours does the opposite. Head climbs 390 to 408 while tail
> stays at 260, so the frames are getting into the ring and nothing is
> finishing them, which is the far end of the same path. 2/5 is a use after
> free when an interface goes away, so it does not fit either. I would not
> expect that series to change what you see.
> 
> On the bisect I would build v7.0 next. There are 32 mt7925 commits between
> 7.0 and 7.1 and 19 of them are one run of work from Sean Wang, reworking how
> the driver tracks the per link mlink and WCID for an MLO station. That is
> the kind of change that fits a bug only showing up with two links up. If
> v7.0 comes back clean, that series is where I would look. If v7.0 is already
> broken then it is off the hook and 6.19 becomes the next split. The mt76
> core and mac80211 both moved in the same window, so mt7925 is where I would
> look first rather than the only place worth looking.
> 
> Devin
> 
> Am 17.08.26 um 23:34 schrieb Jonas Hort:
> 
>> Quick follow-up: managed to confirm 6.18 as a clean baseline on my
>> own hardware now (not just secondhand from others in the forum
>> thread) - running Linux 6.18.42-1-cachyos-lts with MLO active
>> (5GHz+6GHz, same FritzBox 5690 Pro) for 3 hours straight, no freeze
>> at all.
> 
> Am 17.08.26 um 16:25 schrieb Jonas Hort:
> 
>> One correction to how I described this earlier: the connection does
>> NOT reliably self-heal on its own. I have manually intervened every
>> single time to restore connectivity [...]
>> 
>> Update on the ROC tracing: three real freezes captured now with the
>> kprobes active (all confirmed via the WFDMA0 tail-frozen signature).
>> 
>> - Freeze #1 (15:37): no ROC activity in the trace.
>> - Freeze #2 (15:43): [...] The trace shows several ROC events
>>   (rocabort, mloroc, rocwork) clustered together.
>> - Freeze #3 (16:15): no ROC activity again.
>> 
>> Uploaded all three logs to the bugzilla ticket if useful:
>> https://bugzilla.kernel.org/show_bug.cgi?id=221884

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-19  9:03 [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active Jonas Hort
@ 2026-08-22 20:18 ` Jonas Hort
  2026-08-23 20:54   ` Jonas Hort
  0 siblings, 1 reply; 15+ messages in thread
From: Jonas Hort @ 2026-08-22 20:18 UTC (permalink / raw)
  To: Devin Wittmayer
  Cc: Thorsten Leemhuis, regressions, linux-wireless, Felix Fietkau,
	lorenzo.bianconi83

Quick update: v7.0 vanilla has been running clean for over 2 hours now 
with MLO active (5GHz+6GHz, same FritzBox 5690 Pro), no freeze at all.

Am 19.08.26 um 11:03 schrieb Jonas Hort:
> Thanks for the detailed breakdown.
>
> I'll build v7.0 vanilla and test it, as suggested. Fair warning
> though: I'm on vacation this week, so I'll pick this up next week.
> I've also never compiled a kernel before, so it'll likely take me a
> bit of trial and error the first time around - please bear with me
> if it takes a little longer than expected.
>
> Will report back once I have results.
>
> Thanks again,
> Jonas
>
> 19.08.2026 03:18:34 Devin Wittmayer <lucid_duck@justthetip.ca>:
>
>> Thank you very much, that answers both things.
>>
>> The ROC tracing is the more useful of the two even though it came back
>> negative. Two of the three freezes have no ROC activity in them at all, so a
>> link switch that never finished cannot be what starts this. The middle one
>> does have rocabort, mloroc and rocwork in it, but one out of three makes
>> that look like the exception rather than the pattern. So the area I sent you
>> looking at is out, and that is worth knowing before you spend nights on
>> builds.
>>
>> One other thing worth saying first. There is a five patch mt76 series on the
>> list at the moment and two of the patches look like they were written for
>> exactly this bug. I do not think they were, and it is your own numbers that
>> show it. The failure 4/5 fixes stops mt76_txq_schedule_list from servicing
>> the queue, and the one 5/5 fixes stops mt76_txq_send_burst once the non-AQL
>> count reaches its cap. Both of those keep frames from ever reaching the
>> hardware, so if either were your problem head would be sitting still
>> alongside tail. Yours does the opposite. Head climbs 390 to 408 while tail
>> stays at 260, so the frames are getting into the ring and nothing is
>> finishing them, which is the far end of the same path. 2/5 is a use after
>> free when an interface goes away, so it does not fit either. I would not
>> expect that series to change what you see.
>>
>> On the bisect I would build v7.0 next. There are 32 mt7925 commits between
>> 7.0 and 7.1 and 19 of them are one run of work from Sean Wang, reworking how
>> the driver tracks the per link mlink and WCID for an MLO station. That is
>> the kind of change that fits a bug only showing up with two links up. If
>> v7.0 comes back clean, that series is where I would look. If v7.0 is already
>> broken then it is off the hook and 6.19 becomes the next split. The mt76
>> core and mac80211 both moved in the same window, so mt7925 is where I would
>> look first rather than the only place worth looking.
>>
>> Devin
>>
>> Am 17.08.26 um 23:34 schrieb Jonas Hort:
>>
>>> Quick follow-up: managed to confirm 6.18 as a clean baseline on my
>>> own hardware now (not just secondhand from others in the forum
>>> thread) - running Linux 6.18.42-1-cachyos-lts with MLO active
>>> (5GHz+6GHz, same FritzBox 5690 Pro) for 3 hours straight, no freeze
>>> at all.
>> Am 17.08.26 um 16:25 schrieb Jonas Hort:
>>
>>> One correction to how I described this earlier: the connection does
>>> NOT reliably self-heal on its own. I have manually intervened every
>>> single time to restore connectivity [...]
>>>
>>> Update on the ROC tracing: three real freezes captured now with the
>>> kprobes active (all confirmed via the WFDMA0 tail-frozen signature).
>>>
>>> - Freeze #1 (15:37): no ROC activity in the trace.
>>> - Freeze #2 (15:43): [...] The trace shows several ROC events
>>>    (rocabort, mloroc, rocwork) clustered together.
>>> - Freeze #3 (16:15): no ROC activity again.
>>>
>>> Uploaded all three logs to the bugzilla ticket if useful:
>>> https://bugzilla.kernel.org/show_bug.cgi?id=221884

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-22 20:18 ` Jonas Hort
@ 2026-08-23 20:54   ` Jonas Hort
  2026-08-24  4:50     ` Devin Wittmayer
  2026-08-24  4:52     ` Thorsten Leemhuis
  0 siblings, 2 replies; 15+ messages in thread
From: Jonas Hort @ 2026-08-23 20:54 UTC (permalink / raw)
  To: Devin Wittmayer
  Cc: Thorsten Leemhuis, regressions, linux-wireless, Felix Fietkau,
	lorenzo.bianconi83

Bisect is done. First bad commit:

ff643b81bc38eaff6c0ab783a62e4ba9e10d2476
wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
Sean Wang, 2026-03-06
https://patch.msgid.link/20260306232238.2039675-4-sean.wang@kernel.org

Bisected on vanilla, path-restricted to
drivers/net/wireless/mediatek/mt76/mt7925/, using v7.0 as good and
v7.1 as bad. Each step was booted and tested with MLO active
(5GHz+6GHz, FritzBox 5690 Pro), and every "bad" verdict was confirmed
by the WFDMA0 signature (tail frozen while head keeps advancing),
not just by the connection dropping.

   ea757740dd87  pass WCID indices to bss_basic_tlv()      good (45 min 
clean)
   ff643b81bc38  pass mlink and mconf to sta_mld_tlv()     bad (freeze 
after ~4 min)
   dc019e3294c7  pass mlink to mcu_sta_update()            bad (freeze 
after ~3 min)
   9e4d518a4707  pass mlink to mac_link_sta_remove()       bad (freeze 
after ~4 min)
   cf9db836b1e0  pass mlink to set_link_key()              bad (freeze 
after ~4 min)

git bisect log and the incident logs for each step are available if
useful - happy to attach them to the bugzilla ticket or send them
here.

Let me know if you want anything else tested.

Thanks,
Jonas

Am 22.08.26 um 22:18 schrieb Jonas Hort:
> Quick update: v7.0 vanilla has been running clean for over 2 hours now 
> with MLO active (5GHz+6GHz, same FritzBox 5690 Pro), no freeze at all.
>
> Am 19.08.26 um 11:03 schrieb Jonas Hort:
>> Thanks for the detailed breakdown.
>>
>> I'll build v7.0 vanilla and test it, as suggested. Fair warning
>> though: I'm on vacation this week, so I'll pick this up next week.
>> I've also never compiled a kernel before, so it'll likely take me a
>> bit of trial and error the first time around - please bear with me
>> if it takes a little longer than expected.
>>
>> Will report back once I have results.
>>
>> Thanks again,
>> Jonas
>>
>> 19.08.2026 03:18:34 Devin Wittmayer <lucid_duck@justthetip.ca>:
>>
>>> Thank you very much, that answers both things.
>>>
>>> The ROC tracing is the more useful of the two even though it came back
>>> negative. Two of the three freezes have no ROC activity in them at 
>>> all, so a
>>> link switch that never finished cannot be what starts this. The 
>>> middle one
>>> does have rocabort, mloroc and rocwork in it, but one out of three 
>>> makes
>>> that look like the exception rather than the pattern. So the area I 
>>> sent you
>>> looking at is out, and that is worth knowing before you spend nights on
>>> builds.
>>>
>>> One other thing worth saying first. There is a five patch mt76 
>>> series on the
>>> list at the moment and two of the patches look like they were 
>>> written for
>>> exactly this bug. I do not think they were, and it is your own 
>>> numbers that
>>> show it. The failure 4/5 fixes stops mt76_txq_schedule_list from 
>>> servicing
>>> the queue, and the one 5/5 fixes stops mt76_txq_send_burst once the 
>>> non-AQL
>>> count reaches its cap. Both of those keep frames from ever reaching the
>>> hardware, so if either were your problem head would be sitting still
>>> alongside tail. Yours does the opposite. Head climbs 390 to 408 
>>> while tail
>>> stays at 260, so the frames are getting into the ring and nothing is
>>> finishing them, which is the far end of the same path. 2/5 is a use 
>>> after
>>> free when an interface goes away, so it does not fit either. I would 
>>> not
>>> expect that series to change what you see.
>>>
>>> On the bisect I would build v7.0 next. There are 32 mt7925 commits 
>>> between
>>> 7.0 and 7.1 and 19 of them are one run of work from Sean Wang, 
>>> reworking how
>>> the driver tracks the per link mlink and WCID for an MLO station. 
>>> That is
>>> the kind of change that fits a bug only showing up with two links 
>>> up. If
>>> v7.0 comes back clean, that series is where I would look. If v7.0 is 
>>> already
>>> broken then it is off the hook and 6.19 becomes the next split. The 
>>> mt76
>>> core and mac80211 both moved in the same window, so mt7925 is where 
>>> I would
>>> look first rather than the only place worth looking.
>>>
>>> Devin
>>>
>>> Am 17.08.26 um 23:34 schrieb Jonas Hort:
>>>
>>>> Quick follow-up: managed to confirm 6.18 as a clean baseline on my
>>>> own hardware now (not just secondhand from others in the forum
>>>> thread) - running Linux 6.18.42-1-cachyos-lts with MLO active
>>>> (5GHz+6GHz, same FritzBox 5690 Pro) for 3 hours straight, no freeze
>>>> at all.
>>> Am 17.08.26 um 16:25 schrieb Jonas Hort:
>>>
>>>> One correction to how I described this earlier: the connection does
>>>> NOT reliably self-heal on its own. I have manually intervened every
>>>> single time to restore connectivity [...]
>>>>
>>>> Update on the ROC tracing: three real freezes captured now with the
>>>> kprobes active (all confirmed via the WFDMA0 tail-frozen signature).
>>>>
>>>> - Freeze #1 (15:37): no ROC activity in the trace.
>>>> - Freeze #2 (15:43): [...] The trace shows several ROC events
>>>>    (rocabort, mloroc, rocwork) clustered together.
>>>> - Freeze #3 (16:15): no ROC activity again.
>>>>
>>>> Uploaded all three logs to the bugzilla ticket if useful:
>>>> https://bugzilla.kernel.org/show_bug.cgi?id=221884

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-23 20:54   ` Jonas Hort
@ 2026-08-24  4:50     ` Devin Wittmayer
  2026-08-24  4:52     ` Thorsten Leemhuis
  1 sibling, 0 replies; 15+ messages in thread
From: Devin Wittmayer @ 2026-08-24  4:50 UTC (permalink / raw)
  To: Jonas Hort
  Cc: Sean Wang, Felix Fietkau, Thorsten Leemhuis, regressions,
	linux-wireless, lorenzo.bianconi83

On Sun, 2026-08-23 at 20:54 +0000, Jonas Hort wrote:
> Bisect is done. First bad commit:
>
> ff643b81bc38eaff6c0ab783a62e4ba9e10d2476
> wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()

Jonas, that is a careful bisect and it holds up here.  The commit is Sean
Wang's, absent from v7.0, present in v7.1, and ea757740dd87 really is its
parent.  Adding Sean, who knows this code far better than I do.

The part I would look at first is the link count.  Before, it came from the
number of valid links, capped at two.  After, the primary is always written
and a second only when the caller passes one, with the count taken from
however many got written.  So a two link station updated on the primary
would tell firmware it has one link where it used to say two.  Subtle, and
easy to miss in a change that is otherwise a straight simplification.

That is from reading the diff rather than reproducing it, so Sean may well
see something I have not.  Nothing has touched that function since, so 7.1,
7.2 and mainline all behave the same way.

Jonas, yes please to the bisect log.  If the setup is still up, that commit
also added a rate limited warning about a missing primary mconf, so it may
be worth grepping your failing runs for MLD_TLV_LINK.

Thank you for the work you put into this, it was not a small ask.

Devin

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-23 20:54   ` Jonas Hort
  2026-08-24  4:50     ` Devin Wittmayer
@ 2026-08-24  4:52     ` Thorsten Leemhuis
  2026-08-24  8:18       ` Jonas Hort
  1 sibling, 1 reply; 15+ messages in thread
From: Thorsten Leemhuis @ 2026-08-24  4:52 UTC (permalink / raw)
  To: Sean Wang
  Cc: regressions, linux-wireless, Devin Wittmayer, Felix Fietkau,
	Jonas Hort, lorenzo.bianconi83, linux-mediatek

On 8/23/26 22:54, Jonas Hort wrote:
> Bisect is done. First bad commit:
>
> ff643b81bc38eaff6c0ab783a62e4ba9e10d2476
> wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
> Sean Wang, 2026-03-06
> https://patch.msgid.link/20260306232238.2039675-4-sean.wang@kernel.org

Then let's add Sean to the list of recipients. :-D

Sean, FWIW, this thread starts here:

https://lore.kernel.org/all/066b30cc-a9e6-4aeb-964d-71551e8ea3ef@posteo.de/t/#u

To quote the summary: "WiFi 7 MLO (5GHz+6GHz) on MT7925 silently stops
passing traffic after a few minutes, while the driver continues to
report a fully healthy link. Root cause appears to be a stalled WFDMA0
TX hardware queue."

Ciao, Thorsten
> Bisected on vanilla, path-restricted to
> drivers/net/wireless/mediatek/mt76/mt7925/, using v7.0 as good and
> v7.1 as bad. Each step was booted and tested with MLO active
> (5GHz+6GHz, FritzBox 5690 Pro), and every "bad" verdict was confirmed
> by the WFDMA0 signature (tail frozen while head keeps advancing),
> not just by the connection dropping.
> 
>   ea757740dd87  pass WCID indices to bss_basic_tlv()      good (45 min
> clean)
>   ff643b81bc38  pass mlink and mconf to sta_mld_tlv()     bad (freeze
> after ~4 min)
>   dc019e3294c7  pass mlink to mcu_sta_update()            bad (freeze
> after ~3 min)
>   9e4d518a4707  pass mlink to mac_link_sta_remove()       bad (freeze
> after ~4 min)
>   cf9db836b1e0  pass mlink to set_link_key()              bad (freeze
> after ~4 min)
> 
> git bisect log and the incident logs for each step are available if
> useful - happy to attach them to the bugzilla ticket or send them
> here.
> 
> Let me know if you want anything else tested.
> 
> Thanks,
> Jonas
> 
> Am 22.08.26 um 22:18 schrieb Jonas Hort:
>> Quick update: v7.0 vanilla has been running clean for over 2 hours now
>> with MLO active (5GHz+6GHz, same FritzBox 5690 Pro), no freeze at all.
>>
>> Am 19.08.26 um 11:03 schrieb Jonas Hort:
>>> Thanks for the detailed breakdown.
>>>
>>> I'll build v7.0 vanilla and test it, as suggested. Fair warning
>>> though: I'm on vacation this week, so I'll pick this up next week.
>>> I've also never compiled a kernel before, so it'll likely take me a
>>> bit of trial and error the first time around - please bear with me
>>> if it takes a little longer than expected.
>>>
>>> Will report back once I have results.
>>>
>>> Thanks again,
>>> Jonas
>>>
>>> 19.08.2026 03:18:34 Devin Wittmayer <lucid_duck@justthetip.ca>:
>>>
>>>> Thank you very much, that answers both things.
>>>>
>>>> The ROC tracing is the more useful of the two even though it came back
>>>> negative. Two of the three freezes have no ROC activity in them at
>>>> all, so a
>>>> link switch that never finished cannot be what starts this. The
>>>> middle one
>>>> does have rocabort, mloroc and rocwork in it, but one out of three
>>>> makes
>>>> that look like the exception rather than the pattern. So the area I
>>>> sent you
>>>> looking at is out, and that is worth knowing before you spend nights on
>>>> builds.
>>>>
>>>> One other thing worth saying first. There is a five patch mt76
>>>> series on the
>>>> list at the moment and two of the patches look like they were
>>>> written for
>>>> exactly this bug. I do not think they were, and it is your own
>>>> numbers that
>>>> show it. The failure 4/5 fixes stops mt76_txq_schedule_list from
>>>> servicing
>>>> the queue, and the one 5/5 fixes stops mt76_txq_send_burst once the
>>>> non-AQL
>>>> count reaches its cap. Both of those keep frames from ever reaching the
>>>> hardware, so if either were your problem head would be sitting still
>>>> alongside tail. Yours does the opposite. Head climbs 390 to 408
>>>> while tail
>>>> stays at 260, so the frames are getting into the ring and nothing is
>>>> finishing them, which is the far end of the same path. 2/5 is a use
>>>> after
>>>> free when an interface goes away, so it does not fit either. I would
>>>> not
>>>> expect that series to change what you see.
>>>>
>>>> On the bisect I would build v7.0 next. There are 32 mt7925 commits
>>>> between
>>>> 7.0 and 7.1 and 19 of them are one run of work from Sean Wang,
>>>> reworking how
>>>> the driver tracks the per link mlink and WCID for an MLO station.
>>>> That is
>>>> the kind of change that fits a bug only showing up with two links
>>>> up. If
>>>> v7.0 comes back clean, that series is where I would look. If v7.0 is
>>>> already
>>>> broken then it is off the hook and 6.19 becomes the next split. The
>>>> mt76
>>>> core and mac80211 both moved in the same window, so mt7925 is where
>>>> I would
>>>> look first rather than the only place worth looking.
>>>>
>>>> Devin
>>>>
>>>> Am 17.08.26 um 23:34 schrieb Jonas Hort:
>>>>
>>>>> Quick follow-up: managed to confirm 6.18 as a clean baseline on my
>>>>> own hardware now (not just secondhand from others in the forum
>>>>> thread) - running Linux 6.18.42-1-cachyos-lts with MLO active
>>>>> (5GHz+6GHz, same FritzBox 5690 Pro) for 3 hours straight, no freeze
>>>>> at all.
>>>> Am 17.08.26 um 16:25 schrieb Jonas Hort:
>>>>
>>>>> One correction to how I described this earlier: the connection does
>>>>> NOT reliably self-heal on its own. I have manually intervened every
>>>>> single time to restore connectivity [...]
>>>>>
>>>>> Update on the ROC tracing: three real freezes captured now with the
>>>>> kprobes active (all confirmed via the WFDMA0 tail-frozen signature).
>>>>>
>>>>> - Freeze #1 (15:37): no ROC activity in the trace.
>>>>> - Freeze #2 (15:43): [...] The trace shows several ROC events
>>>>>    (rocabort, mloroc, rocwork) clustered together.
>>>>> - Freeze #3 (16:15): no ROC activity again.
>>>>>
>>>>> Uploaded all three logs to the bugzilla ticket if useful:
>>>>> https://bugzilla.kernel.org/show_bug.cgi?id=221884


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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-24  4:52     ` Thorsten Leemhuis
@ 2026-08-24  8:18       ` Jonas Hort
  2026-08-29 22:13         ` Devin Wittmayer
  0 siblings, 1 reply; 15+ messages in thread
From: Jonas Hort @ 2026-08-24  8:18 UTC (permalink / raw)
  To: Thorsten Leemhuis, Sean Wang
  Cc: regressions, linux-wireless, Devin Wittmayer, Felix Fietkau,
	lorenzo.bianconi83, linux-mediatek

Thanks Devin, and thanks for pulling Sean in.

git biscet log:
# bad: [8cd9520d35a6c38db6567e97dd93b1f11f185dc6] Linux 7.1
# good: [028ef9c96e96197026887c0f092424679298aae8] Linux 7.0
git bisect start 'v7.1' 'v7.0' '--' 
'drivers/net/wireless/mediatek/mt76/mt7925/'
# good: [ea757740dd87c0b00c4844dd3282dff4d83fa3c7] wifi: mt76: mt7925: 
pass WCID indices to bss_basic_tlv()
git bisect good ea757740dd87c0b00c4844dd3282dff4d83fa3c7
# bad: [cf9db836b1e069a3d6a80c72b9bdc12df78b0dd1] wifi: mt76: mt7925: 
pass mlink to set_link_key()
git bisect bad cf9db836b1e069a3d6a80c72b9bdc12df78b0dd1
# bad: [9e4d518a4707175e1154876b760d4f2b39967e9d] wifi: mt76: mt7925: 
pass mlink to mac_link_sta_remove()
git bisect bad 9e4d518a4707175e1154876b760d4f2b39967e9d
# bad: [dc019e3294c7e3c6e997bb11732d46ce0d9211e9] wifi: mt76: mt7925: 
pass mlink to mcu_sta_update()
git bisect bad dc019e3294c7e3c6e997bb11732d46ce0d9211e9
# bad: [ff643b81bc38eaff6c0ab783a62e4ba9e10d2476] wifi: mt76: mt7925: 
pass mlink and mconf to sta_mld_tlv()
git bisect bad ff643b81bc38eaff6c0ab783a62e4ba9e10d2476
# first 'bad' commit: [ff643b81bc38eaff6c0ab783a62e4ba9e10d2476] wifi: 
mt76: mt7925: pass mlink and mconf to sta_mld_tlv()

On the warning: no hits. I grepped all incident logs for MLD_TLV_LINK
and for anything mentioning primary/mconf, and also checked the
current boot directly. The only mt7925 lines present are the usual
init ones:

   mt7925e 0000:09:00.0: ASIC revision: 79250000
   mt7925e 0000:09:00.0: HW/SW Version: 0x8a108a10, Build Time: 
20260605184651a
   mt7925e 0000:09:00.0: WM Firmware Version: ____000000, Build Time: 
20260605184805

Each incident log captures journalctl -k for the 5 minutes leading up
to the freeze plus the last 400 dmesg lines, so if it had fired around
the stall it should have been in there. Still on the ff643b81bc38
kernel here, so happy to re-check with a different search term if I
grepped for the wrong thing.

Setup is still up and I can build and test whatever is useful.

Thanks,
Jonas
Am 24.08.26 um 06:52 schrieb Thorsten Leemhuis:
> On 8/23/26 22:54, Jonas Hort wrote:
>> Bisect is done. First bad commit:
>>
>> ff643b81bc38eaff6c0ab783a62e4ba9e10d2476
>> wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()
>> Sean Wang, 2026-03-06
>> https://patch.msgid.link/20260306232238.2039675-4-sean.wang@kernel.org
> Then let's add Sean to the list of recipients. :-D
>
> Sean, FWIW, this thread starts here:
>
> https://lore.kernel.org/all/066b30cc-a9e6-4aeb-964d-71551e8ea3ef@posteo.de/t/#u
>
> To quote the summary: "WiFi 7 MLO (5GHz+6GHz) on MT7925 silently stops
> passing traffic after a few minutes, while the driver continues to
> report a fully healthy link. Root cause appears to be a stalled WFDMA0
> TX hardware queue."
>
> Ciao, Thorsten
>> Bisected on vanilla, path-restricted to
>> drivers/net/wireless/mediatek/mt76/mt7925/, using v7.0 as good and
>> v7.1 as bad. Each step was booted and tested with MLO active
>> (5GHz+6GHz, FritzBox 5690 Pro), and every "bad" verdict was confirmed
>> by the WFDMA0 signature (tail frozen while head keeps advancing),
>> not just by the connection dropping.
>>
>>    ea757740dd87  pass WCID indices to bss_basic_tlv()      good (45 min
>> clean)
>>    ff643b81bc38  pass mlink and mconf to sta_mld_tlv()     bad (freeze
>> after ~4 min)
>>    dc019e3294c7  pass mlink to mcu_sta_update()            bad (freeze
>> after ~3 min)
>>    9e4d518a4707  pass mlink to mac_link_sta_remove()       bad (freeze
>> after ~4 min)
>>    cf9db836b1e0  pass mlink to set_link_key()              bad (freeze
>> after ~4 min)
>>
>> git bisect log and the incident logs for each step are available if
>> useful - happy to attach them to the bugzilla ticket or send them
>> here.
>>
>> Let me know if you want anything else tested.
>>
>> Thanks,
>> Jonas
>>
>> Am 22.08.26 um 22:18 schrieb Jonas Hort:
>>> Quick update: v7.0 vanilla has been running clean for over 2 hours now
>>> with MLO active (5GHz+6GHz, same FritzBox 5690 Pro), no freeze at all.
>>>
>>> Am 19.08.26 um 11:03 schrieb Jonas Hort:
>>>> Thanks for the detailed breakdown.
>>>>
>>>> I'll build v7.0 vanilla and test it, as suggested. Fair warning
>>>> though: I'm on vacation this week, so I'll pick this up next week.
>>>> I've also never compiled a kernel before, so it'll likely take me a
>>>> bit of trial and error the first time around - please bear with me
>>>> if it takes a little longer than expected.
>>>>
>>>> Will report back once I have results.
>>>>
>>>> Thanks again,
>>>> Jonas
>>>>
>>>> 19.08.2026 03:18:34 Devin Wittmayer <lucid_duck@justthetip.ca>:
>>>>
>>>>> Thank you very much, that answers both things.
>>>>>
>>>>> The ROC tracing is the more useful of the two even though it came back
>>>>> negative. Two of the three freezes have no ROC activity in them at
>>>>> all, so a
>>>>> link switch that never finished cannot be what starts this. The
>>>>> middle one
>>>>> does have rocabort, mloroc and rocwork in it, but one out of three
>>>>> makes
>>>>> that look like the exception rather than the pattern. So the area I
>>>>> sent you
>>>>> looking at is out, and that is worth knowing before you spend nights on
>>>>> builds.
>>>>>
>>>>> One other thing worth saying first. There is a five patch mt76
>>>>> series on the
>>>>> list at the moment and two of the patches look like they were
>>>>> written for
>>>>> exactly this bug. I do not think they were, and it is your own
>>>>> numbers that
>>>>> show it. The failure 4/5 fixes stops mt76_txq_schedule_list from
>>>>> servicing
>>>>> the queue, and the one 5/5 fixes stops mt76_txq_send_burst once the
>>>>> non-AQL
>>>>> count reaches its cap. Both of those keep frames from ever reaching the
>>>>> hardware, so if either were your problem head would be sitting still
>>>>> alongside tail. Yours does the opposite. Head climbs 390 to 408
>>>>> while tail
>>>>> stays at 260, so the frames are getting into the ring and nothing is
>>>>> finishing them, which is the far end of the same path. 2/5 is a use
>>>>> after
>>>>> free when an interface goes away, so it does not fit either. I would
>>>>> not
>>>>> expect that series to change what you see.
>>>>>
>>>>> On the bisect I would build v7.0 next. There are 32 mt7925 commits
>>>>> between
>>>>> 7.0 and 7.1 and 19 of them are one run of work from Sean Wang,
>>>>> reworking how
>>>>> the driver tracks the per link mlink and WCID for an MLO station.
>>>>> That is
>>>>> the kind of change that fits a bug only showing up with two links
>>>>> up. If
>>>>> v7.0 comes back clean, that series is where I would look. If v7.0 is
>>>>> already
>>>>> broken then it is off the hook and 6.19 becomes the next split. The
>>>>> mt76
>>>>> core and mac80211 both moved in the same window, so mt7925 is where
>>>>> I would
>>>>> look first rather than the only place worth looking.
>>>>>
>>>>> Devin
>>>>>
>>>>> Am 17.08.26 um 23:34 schrieb Jonas Hort:
>>>>>
>>>>>> Quick follow-up: managed to confirm 6.18 as a clean baseline on my
>>>>>> own hardware now (not just secondhand from others in the forum
>>>>>> thread) - running Linux 6.18.42-1-cachyos-lts with MLO active
>>>>>> (5GHz+6GHz, same FritzBox 5690 Pro) for 3 hours straight, no freeze
>>>>>> at all.
>>>>> Am 17.08.26 um 16:25 schrieb Jonas Hort:
>>>>>
>>>>>> One correction to how I described this earlier: the connection does
>>>>>> NOT reliably self-heal on its own. I have manually intervened every
>>>>>> single time to restore connectivity [...]
>>>>>>
>>>>>> Update on the ROC tracing: three real freezes captured now with the
>>>>>> kprobes active (all confirmed via the WFDMA0 tail-frozen signature).
>>>>>>
>>>>>> - Freeze #1 (15:37): no ROC activity in the trace.
>>>>>> - Freeze #2 (15:43): [...] The trace shows several ROC events
>>>>>>     (rocabort, mloroc, rocwork) clustered together.
>>>>>> - Freeze #3 (16:15): no ROC activity again.
>>>>>>
>>>>>> Uploaded all three logs to the bugzilla ticket if useful:
>>>>>> https://bugzilla.kernel.org/show_bug.cgi?id=221884

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-24  8:18       ` Jonas Hort
@ 2026-08-29 22:13         ` Devin Wittmayer
  2026-10-02 17:31           ` Jonas Hort
  2026-10-02 18:11           ` Jonas Hort
  0 siblings, 2 replies; 15+ messages in thread
From: Devin Wittmayer @ 2026-08-29 22:13 UTC (permalink / raw)
  To: Jonas Hort, Sean Wang, Thorsten Leemhuis
  Cc: Sean Wang, Felix Fietkau, lorenzo.bianconi83, regressions,
	linux-wireless, linux-mediatek

On Mon, 2026-08-24 at 08:18 +0000, Jonas Hort wrote:
> Setup is still up and I can build and test whatever is useful.

Your bisect holds here, on a different machine and a different access
point, running your June firmware. Three states, each replicated:

  both commits reverted        clean, two runs of six minutes
  only the later one reverted  stalls, two runs
  neither reverted             stalls, three runs

Tail welded and head climbing, which is your signature. The tree is
7.2-rc5 with one unrelated ACPI patch of mine, nowhere near this path.

db134691924f lands fifteen commits after ff643b81bc38, and reverting it
alone still stalls, so the builder rewrite is the one that matters.
Reverting the builder on its own is not available either: v7.0's version
dereferences a link pointer that the later commit leaves unpublished
until after the firmware call, so it would need a check neither version
has.

A correction to my last message. I pointed you at the link count, since
the new code reports one link whenever the update concerns the primary.
That undercount is real but it's not the cause. Telling firmware one
link always is clean over two six-minute runs. Skipping the
undercounting update entirely, so firmware is never told anything wrong,
stalls on both runs. Writing the entries in v7.0's order stalls on all
three.

On the August firmware, stock still stalls, twice, the detector firing
95 and 141 seconds into the run.

The band pair matters. Same driver, same August firmware, two runs each:

  5 GHz + 6 GHz     stalls
  2.4 GHz + 5 GHz   clean, full duration
  2.4 GHz + 6 GHz   clean, full duration

Not the channel width. Narrowing the 5 GHz link to 40 MHz, so that pair
carries the same narrow-plus-wide mix as the clean ones, still stalls on
both runs.

The sharpest pair there is the two runs where the iperf3 stream never
established, leaving only the UDP pressure: 5 plus 6 stalled with the
queue peaking at 187, and 2.4 plus 6 stayed clean at 186. The other
three clean runs peaked above 1000.

Sean, the two things I can't see from out here: what firmware does with
a multi-link record naming one link while a second is associated, and
why 5 plus 6 should differ from 2.4 plus 6.

Jonas, thank you for the bisect. Five steps, every bad verdict confirmed
on the queue signature.

Devin

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-29 22:13         ` Devin Wittmayer
@ 2026-10-02 17:31           ` Jonas Hort
  2026-10-02 18:11           ` Jonas Hort
  1 sibling, 0 replies; 15+ messages in thread
From: Jonas Hort @ 2026-10-02 17:31 UTC (permalink / raw)
  To: Devin Wittmayer, Sean Wang, Thorsten Leemhuis
  Cc: Sean Wang, Felix Fietkau, lorenzo.bianconi83, regressions,
	linux-wireless, linux-mediatek

Hi all,

Friendly ping on this one - any news on the mt7925 MLO stall?

No pressure, I know everyone's busy. My setup is still in place, so
I'm happy to build and test patches or collect further traces if
that would help. Nothing has changed here: still reproducible with
the 5 GHz + 6 GHz pair.

Thanks for all the help so far.
Jonas

Am 30.08.26 um 00:13 schrieb Devin Wittmayer:
> On Mon, 2026-08-24 at 08:18 +0000, Jonas Hort wrote:
>> Setup is still up and I can build and test whatever is useful.
> Your bisect holds here, on a different machine and a different access
> point, running your June firmware. Three states, each replicated:
>
>    both commits reverted        clean, two runs of six minutes
>    only the later one reverted  stalls, two runs
>    neither reverted             stalls, three runs
>
> Tail welded and head climbing, which is your signature. The tree is
> 7.2-rc5 with one unrelated ACPI patch of mine, nowhere near this path.
>
> db134691924f lands fifteen commits after ff643b81bc38, and reverting it
> alone still stalls, so the builder rewrite is the one that matters.
> Reverting the builder on its own is not available either: v7.0's version
> dereferences a link pointer that the later commit leaves unpublished
> until after the firmware call, so it would need a check neither version
> has.
>
> A correction to my last message. I pointed you at the link count, since
> the new code reports one link whenever the update concerns the primary.
> That undercount is real but it's not the cause. Telling firmware one
> link always is clean over two six-minute runs. Skipping the
> undercounting update entirely, so firmware is never told anything wrong,
> stalls on both runs. Writing the entries in v7.0's order stalls on all
> three.
>
> On the August firmware, stock still stalls, twice, the detector firing
> 95 and 141 seconds into the run.
>
> The band pair matters. Same driver, same August firmware, two runs each:
>
>    5 GHz + 6 GHz     stalls
>    2.4 GHz + 5 GHz   clean, full duration
>    2.4 GHz + 6 GHz   clean, full duration
>
> Not the channel width. Narrowing the 5 GHz link to 40 MHz, so that pair
> carries the same narrow-plus-wide mix as the clean ones, still stalls on
> both runs.
>
> The sharpest pair there is the two runs where the iperf3 stream never
> established, leaving only the UDP pressure: 5 plus 6 stalled with the
> queue peaking at 187, and 2.4 plus 6 stayed clean at 186. The other
> three clean runs peaked above 1000.
>
> Sean, the two things I can't see from out here: what firmware does with
> a multi-link record naming one link while a second is associated, and
> why 5 plus 6 should differ from 2.4 plus 6.
>
> Jonas, thank you for the bisect. Five steps, every bad verdict confirmed
> on the queue signature.
>
> Devin

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-08-29 22:13         ` Devin Wittmayer
  2026-10-02 17:31           ` Jonas Hort
@ 2026-10-02 18:11           ` Jonas Hort
  2026-10-03 18:03             ` Devin Wittmayer
  1 sibling, 1 reply; 15+ messages in thread
From: Jonas Hort @ 2026-10-02 18:11 UTC (permalink / raw)
  To: Devin Wittmayer, Sean Wang, Thorsten Leemhuis
  Cc: Sean Wang, Felix Fietkau, lorenzo.bianconi83, regressions,
	linux-wireless, linux-mediatek

Hi all,

I just came across this patch from Andrei Rusu de Castro, posted on
2026-09-02 with "Fixes: ff643b81bc38" (the commit I bisected to):

Patch wifi: mt76: mt7925: stabilize STA_REC_MLD link selection
https://ratatoskr.run/linux-wireless/2026/09/17497919

Could this be the fix for this regression? Devin, you mentioned the
link count undercount is real but likely not the root cause - does
this patch change that assessment?

I'm happy to test it on my hardware if that helps.

Thanks,
Jonas

Am 30.08.26 um 00:13 schrieb Devin Wittmayer:
> On Mon, 2026-08-24 at 08:18 +0000, Jonas Hort wrote:
>> Setup is still up and I can build and test whatever is useful.
> Your bisect holds here, on a different machine and a different access
> point, running your June firmware. Three states, each replicated:
>
>    both commits reverted        clean, two runs of six minutes
>    only the later one reverted  stalls, two runs
>    neither reverted             stalls, three runs
>
> Tail welded and head climbing, which is your signature. The tree is
> 7.2-rc5 with one unrelated ACPI patch of mine, nowhere near this path.
>
> db134691924f lands fifteen commits after ff643b81bc38, and reverting it
> alone still stalls, so the builder rewrite is the one that matters.
> Reverting the builder on its own is not available either: v7.0's version
> dereferences a link pointer that the later commit leaves unpublished
> until after the firmware call, so it would need a check neither version
> has.
>
> A correction to my last message. I pointed you at the link count, since
> the new code reports one link whenever the update concerns the primary.
> That undercount is real but it's not the cause. Telling firmware one
> link always is clean over two six-minute runs. Skipping the
> undercounting update entirely, so firmware is never told anything wrong,
> stalls on both runs. Writing the entries in v7.0's order stalls on all
> three.
>
> On the August firmware, stock still stalls, twice, the detector firing
> 95 and 141 seconds into the run.
>
> The band pair matters. Same driver, same August firmware, two runs each:
>
>    5 GHz + 6 GHz     stalls
>    2.4 GHz + 5 GHz   clean, full duration
>    2.4 GHz + 6 GHz   clean, full duration
>
> Not the channel width. Narrowing the 5 GHz link to 40 MHz, so that pair
> carries the same narrow-plus-wide mix as the clean ones, still stalls on
> both runs.
>
> The sharpest pair there is the two runs where the iperf3 stream never
> established, leaving only the UDP pressure: 5 plus 6 stalled with the
> queue peaking at 187, and 2.4 plus 6 stayed clean at 186. The other
> three clean runs peaked above 1000.
>
> Sean, the two things I can't see from out here: what firmware does with
> a multi-link record naming one link while a second is associated, and
> why 5 plus 6 should differ from 2.4 plus 6.
>
> Jonas, thank you for the bisect. Five steps, every bad verdict confirmed
> on the queue signature.
>
> Devin

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-10-02 18:11           ` Jonas Hort
@ 2026-10-03 18:03             ` Devin Wittmayer
  2026-10-04 15:48               ` Andrei Rusu de Castro
  0 siblings, 1 reply; 15+ messages in thread
From: Devin Wittmayer @ 2026-10-03 18:03 UTC (permalink / raw)
  To: Jonas Hort, Sean Wang, Thorsten Leemhuis
  Cc: Sean Wang, Felix Fietkau, lorenzo.bianconi83,
	Andrei Rusu de Castro, regressions, linux-wireless,
	linux-mediatek

On Fri, 2026-10-02 at 18:11 +0000, Jonas Hort wrote:
> I just came across this patch from Andrei Rusu de Castro, posted on
> 2026-09-02 with "Fixes: ff643b81bc38" (the commit I bisected to):
>
> Patch wifi: mt76: mt7925: stabilize STA_REC_MLD link selection
>
> Could this be the fix for this regression? Devin, you mentioned the
> link count undercount is real but likely not the root cause - does
> this patch change that assessment?

The patch you found does not fix this stall. Andrei never claimed it
would and it did no harm here, so this is not an argument against it.

  bench A   2 Sep   MT7925 PCIe, 7.2.0-rc5 + lockdep, morrownr @ 6b0ef22e
  bench B   3 Oct   MT7925U USB, 7.2.6, morrownr @ 8e9309b
  both      firmware 20260813113118, DevLabMLD on 5745 and 6135 MHz,
            iw scan every 4 s under bulk upload. Neither is in-tree.

  run                     bench   last worked   at 600 s
  stock                     A        120 s        dead
  + the patch               A        141 s        dead
  stock                     B        122 s        dead
  + the patch, run 1        B        123 s        dead
  + the patch, run 2        B        123 s        dead
  primary link only         B        583 s        alive

Every two-link run died between 120 and 141 seconds, patched or not, and
none recovered. Each stayed associated on both links, reporting a healthy
rate while the AP heard nothing from the client.

The patch describes both links on every update. In August I got to that
same record another way, dropping the undercounting update, and it
stalled then too.

The arm that stays up describes the primary link only. Not a fix, it
hides the second link, but the stall tracks whether that second link is
in the record.

Thanks for your patience, and for the bisect and for finding the patch
yourself.

Devin

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

* Re: [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active
  2026-10-03 18:03             ` Devin Wittmayer
@ 2026-10-04 15:48               ` Andrei Rusu de Castro
  2026-10-04 15:49                 ` [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add Andrei Rusu de Castro
  0 siblings, 1 reply; 15+ messages in thread
From: Andrei Rusu de Castro @ 2026-10-04 15:48 UTC (permalink / raw)
  To: linux-wireless, Devin Wittmayer, Jonas Hort
  Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Sean Wang, Thorsten Leemhuis, regressions,
	linux-mediatek

Hi Devin, Jonas,

I reproduced the stall with my September patch on an MT7925 PCIe Z13
and traced the station commands sent to firmware. The missing case was
the primary update inside secondary link addition.

mt7925_mac_link_sta_add() updates the primary WCID first, then the new
secondary WCID. The new secondary is not in msta->link[] or valid_links
until both commands succeed. My first patch included an unpublished
link only when that link was the subject of the current command. It
therefore still sent a one-link MLD description to the primary WCID,
followed by a two-link description to the secondary WCID.

These are the captured fields during secondary addition, omitting an
earlier primary-only association update:

                           command WCID   count   entries (WCID/BSS)
  September patch                1          1     1/0
                                 2          2     1/0, 2/1
  September patch + early        1          2     1/0, 2/1
    link publication             2          2     1/0, 2/1
  v2                             1          2     1/0, 2/1
                                 2          2     1/0, 2/1

V2 passes the initialized pending secondary explicitly through both
station updates, without publishing it early. It keeps the existing
publication-after-success and host error cleanup. It also keeps stable
membership for subsequent updates. There is no new shared pending state.

On Linux 7.3-rc5 with firmware 20260813113118 and an ASUS GT-BE98:

  upstream MLD path           stalled at 157 seconds
  September patch            stalled at 289 seconds; repeated at 150
  v2                         813 seconds, 48 samples, no failures
  v2, second clean boot      812 seconds, no sustained stall under
                              20 Mbit/s traffic in each direction

The AP advertises three links. The active client pair was 5+6 GHz
(active_links=0x3, valid_links=0x7). Failed runs had roughly 27-second
full-band scans; both v2 runs returned to roughly 6.3-7.1 seconds.
The second v2 run transferred about 1.9 GB in each direction over 760
seconds. It had one gateway-ping timeout after a neighbor flush, with
REACHABLE neighbor state and successful IP/HTTPS probes in the same
sample, so it did not pass the strict zero-failure gate. Traffic did not
enter the persistent associated-but-dead state.

Tests used the in-tree driver plus the selected fix, with the separate
scheduled-scan withdrawal and WM2 reset correction held constant. Other
local platform patches did not change between these arms. My production
variant additionally retains the applicable local safety guards in a
separate patch; those guards are not part of this submission. That
variant passed the full zero-failure gate on two PCIe Z13 machines
(813 and 810 seconds), and both booted it successfully as their normal
default. Five ordinary reconnects also passed on the first local variant.

The changed objects build with W=1 and -Werror on both the tested rc5
source and the current mt76 integration branch. Source-extracted fixtures
exercise the pending-link records and host cleanup at eight failing MCU
command positions. Those tests do not establish firmware rollback after
a partly successful add.

Direct debugfs link switches and chip-reset tests exposed failures or
aggregation teardown warnings that also occur with my previous working
full-revert kernel. V2 is not claimed to resolve those. USB hardware and
your exact FritzBox setup have not been tested here.

The v2 posted in reply to this message is based on mt76 commit
0dbc9c9fa9b9. Could you try it on
the setups where the September patch still stalled?

Thanks,
Andrei


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

* [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add
  2026-10-04 15:48               ` Andrei Rusu de Castro
@ 2026-10-04 15:49                 ` Andrei Rusu de Castro
  2026-10-04 18:25                   ` Jonas Hort
  2026-10-05  2:44                   ` Devin Wittmayer
  0 siblings, 2 replies; 15+ messages in thread
From: Andrei Rusu de Castro @ 2026-10-04 15:49 UTC (permalink / raw)
  To: linux-wireless, Devin Wittmayer, Jonas Hort
  Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Sean Wang, Thorsten Leemhuis, regressions,
	linux-mediatek

mt7925_mac_link_sta_add() sends an ASSOC update for the primary WCID
before sending the update for a new secondary WCID. The new link is
published in msta->link[] and msta->valid_links only after both commands
succeed.

Selecting the secondary entry from the subject of each command gives
the primary STA_REC_MLD one link and the secondary STA_REC_MLD two
links. Enumerating published links alone still omits the pending link
from the primary command. Firmware-bound command captures reproduce
this n=1/n=2 sequence during a secondary addition.

Build each MLD TLV from the station's published links and an explicit
pending link. Pass the initialized pending link through both add-time
station updates, including the update whose subject is the primary.
Keep the primary first, bound entries by the firmware array, and skip
links without station and BSS state. Other update callers have no
pending link.

This leaves msta->link[] publication after successful link setup and
preserves the existing add-failure cleanup. The pending pointer is used
synchronously to populate the command, not stored in shared state.

Fixes: ff643b81bc38 ("wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()")
Link: https://lore.kernel.org/linux-wireless/066b30cc-a9e6-4aeb-964d-71551e8ea3ef@posteo.de/
Signed-off-by: Andrei Rusu de Castro <arc@empyreal.works>
---
Changes since v1:
- Carry an explicit initialized pending link through both add-time updates,
  not just the update whose subject is the pending secondary.
- Preserve msta->link[] publication after successful setup.
- Describe consistency between per-WCID commands without assuming a
  shared firmware record overwritten by the last command.

V1: https://lore.kernel.org/all/20260902-mt7925-0cbea623@empyreal.works/

Tested on MT7925 PCIe, Linux 7.3-rc5, firmware 20260813113118, ASUS
GT-BE98 advertising three links with a 5+6 GHz active pair. The in-tree
MLD path stalled after 157 seconds, v1 after 289 and 150 seconds. V2
passed a 48-sample, 813-second scan/traffic run; full-band scans returned
to 6.3-7.1 seconds from about 27 seconds. A second clean boot did not
stall through 812 seconds and 760 seconds of bilateral 20 Mbit/s traffic.
One gateway ping timed out while same-sample IP/HTTPS passed, so that
second run did not pass the strict zero-failure gate.

The local deployment variant, with separate retained safety guards,
passed the same gate on two PCIe Z13 machines (813 and 810 seconds).
Both then passed ordinary default boots. The scheduled-scan withdrawal
and independent WM2 reset correction were retained throughout testing.
USB hardware and the reporter's FritzBox setup remain untested here.

W=1/-Werror builds of changed objects pass on both rc5 and the mt76 base
below. Source-extracted fixtures under ASan/UBSan cover pending-link
encoding and host cleanup at eight failed BSS/STA command positions;
they do not model firmware rollback. Direct partial-link switches and
reset aggregation warnings also fail on the old full-revert baseline
and are not claimed fixed by this patch.

 .../net/wireless/mediatek/mt76/mt7925/mac.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt7925/main.c  | 16 ++---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 59 +++++++++++++++----
 .../wireless/mediatek/mt76/mt7925/mt7925.h    |  3 +-
 4 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 101f571b027f..cbc18dbcbad9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1502,7 +1502,7 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
 					    true, NULL);
 		mt7925_mcu_sta_update(dev, NULL, vif,
 				      &mvif->sta.deflink, true,
-				      MT76_STA_INFO_STATE_NONE);
+				      MT76_STA_INFO_STATE_NONE, NULL);
 		mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);
 	}
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index c882952f5df1..f536fffffa08 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1006,7 +1006,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
 	    link_sta == mlink->pri_link) {
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_NONE);
+					    MT76_STA_INFO_STATE_NONE, NULL);
 		if (ret)
 			goto out_pm;
 	} else if (ieee80211_vif_is_mld(vif) &&
@@ -1028,19 +1028,19 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
 
 		ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
 					    pri_mlink, true,
-					    MT76_STA_INFO_STATE_ASSOC);
+					    MT76_STA_INFO_STATE_ASSOC, mlink);
 		if (ret)
 			goto out_pm;
 
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_ASSOC);
+					    MT76_STA_INFO_STATE_ASSOC, mlink);
 		if (ret)
 			goto out_pm;
 	} else {
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_NONE);
+					    MT76_STA_INFO_STATE_NONE, NULL);
 		if (ret)
 			goto out_pm;
 	}
@@ -1248,7 +1248,7 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
 	memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));
 
 	mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true,
-			      MT76_STA_INFO_STATE_ASSOC);
+			      MT76_STA_INFO_STATE_ASSOC, NULL);
 
 	mt792x_mutex_release(dev);
 }
@@ -1308,7 +1308,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
 	mt76_connac_pm_wake(&dev->mphy, &dev->pm);
 
 	mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
-			      MT76_STA_INFO_STATE_NONE);
+			      MT76_STA_INFO_STATE_NONE, NULL);
 	mt7925_mac_wtbl_update(dev, mlink->wcid.idx,
 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
@@ -1979,7 +1979,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
 	err = mt7925_mcu_sta_update(dev, NULL, vif,
 				    &mvif->sta.deflink, true,
-				    MT76_STA_INFO_STATE_NONE);
+				    MT76_STA_INFO_STATE_NONE, NULL);
 out:
 	mt792x_mutex_release(dev);
 
@@ -2123,7 +2123,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
 	if (changed & BSS_CHANGED_ASSOC) {
 		mt7925_mcu_sta_update(dev, NULL, vif,
 				      &mvif->sta.deflink, true,
-				      MT76_STA_INFO_STATE_ASSOC);
+				      MT76_STA_INFO_STATE_ASSOC, NULL);
 		mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc);
 
 		if (ieee80211_vif_is_mld(vif))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 2afd3f5e3266..634062730e65 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2065,14 +2065,18 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
 		       struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta,
 		       struct mt792x_bss_conf *mconf,
-		       struct mt792x_link_sta *mlink)
+		       struct mt792x_link_sta *mlink,
+		       struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 	struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
 	struct mt792x_dev *dev = mvif->phy->dev;
+	unsigned long valid = msta->valid_links;
 	struct mt792x_bss_conf *mconf_pri;
 	struct sta_rec_mld *mld;
+	unsigned int link_id;
 	struct tlv *tlv;
+	u8 max_links;
 	u8 cnt = 0;
 
 	/* Primary link always uses driver's deflink WCID. */
@@ -2101,11 +2105,44 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
 	mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
 	mld->link[cnt++].bss_idx = mconf_pri->mt76.idx;
 
-	/* Optionally encode the currently-updated secondary link. */
-	if (mlink && mlink != &msta->deflink && mconf) {
-		mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
-		mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
-		mld->link[cnt++].bss_idx = mconf->mt76.idx;
+	/* Describe the same station links in each per-WCID STA_REC_MLD,
+	 * rather than selecting the secondary from the current command.
+	 */
+	max_links = ARRAY_SIZE(mld->link);
+
+	/* Adding a secondary link updates both primary and secondary STA
+	 * records before publishing the new link in msta->link[]. Include it
+	 * in both commands without moving that publication before success.
+	 */
+	if (pending && pending != &msta->deflink)
+		valid |= BIT(pending->wcid.link_id);
+
+	for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
+		struct mt792x_link_sta *mlink_sec;
+		struct mt792x_bss_conf *mconf_sec;
+
+		if (cnt == max_links)
+			break;
+
+		if (link_id == msta->deflink_id)
+			continue;
+
+		mlink_sec = mt792x_sta_to_link(msta, link_id);
+		if (!mlink_sec && pending && link_id == pending->wcid.link_id)
+			mlink_sec = pending;
+		if (!mlink_sec || mlink_sec == &msta->deflink)
+			continue;
+
+		mconf_sec = rcu_dereference_protected(mvif->link_conf[link_id],
+						      lockdep_is_held(&dev->mt76.mutex));
+		if (!mconf_sec)
+			continue;
+
+		if (cnt == 1)
+			mld->secondary_id = cpu_to_le16(mlink_sec->wcid.idx);
+
+		mld->link[cnt].wlan_id = cpu_to_le16(mlink_sec->wcid.idx);
+		mld->link[cnt++].bss_idx = mconf_sec->mt76.idx;
 	}
 
 	mld->link_num = cnt;
@@ -2124,7 +2161,8 @@ mt7925_mcu_sta_remove_tlv(struct sk_buff *skb)
 
 static int
 mt7925_mcu_sta_cmd(struct mt76_phy *phy,
-		   struct mt76_sta_cmd_info *info)
+		   struct mt76_sta_cmd_info *info,
+		   struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;
 	struct mt76_dev *dev = phy->dev;
@@ -2165,7 +2203,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
 		if (info->state != MT76_STA_INFO_STATE_NONE) {
 			mt7925_mcu_sta_mld_tlv(skb, info->vif,
 					       info->link_sta->sta,
-					       mconf, mlink);
+					       mconf, mlink, pending);
 
 			mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);
 		}
@@ -2190,7 +2228,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 			  struct ieee80211_vif *vif,
 			  struct mt792x_link_sta *mlink,
 			  bool enable,
-			  enum mt76_sta_info_state state)
+			  enum mt76_sta_info_state state,
+			  struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 	int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi);
@@ -2208,7 +2247,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 	info.wcid = &mlink->wcid;
 	info.newly = state != MT76_STA_INFO_STATE_ASSOC;
 
-	return mt7925_mcu_sta_cmd(&dev->mphy, &info);
+	return mt7925_mcu_sta_cmd(&dev->mphy, &info, pending);
 }
 
 int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 33782d9ba9ed..49fa94e5cfd9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -286,7 +286,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 			  struct ieee80211_vif *vif,
 			  struct mt792x_link_sta *mlink,
 			  bool enable,
-			  enum mt76_sta_info_state state);
+			  enum mt76_sta_info_state state,
+			  struct mt792x_link_sta *pending);
 int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag);
 int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf);
 int mt7925_mcu_set_eeprom(struct mt792x_dev *dev);

base-commit: 0dbc9c9fa9b92767c2d556504f38b544cb57a96a
-- 
2.54.0



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

* Re: [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add
  2026-10-04 15:49                 ` [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add Andrei Rusu de Castro
@ 2026-10-04 18:25                   ` Jonas Hort
  2026-10-05  2:44                   ` Devin Wittmayer
  1 sibling, 0 replies; 15+ messages in thread
From: Jonas Hort @ 2026-10-04 18:25 UTC (permalink / raw)
  To: Andrei Rusu de Castro, linux-wireless, Devin Wittmayer
  Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Sean Wang, Thorsten Leemhuis, regressions,
	linux-mediatek

Hi Andrei,

Tested v2 on top of v7.3-rc5 on my setup:

   hardware   MT7925 PCIe (mt7925e)
   firmware   20260813113118
   AP         FritzBox 5690 Pro, FRITZ!OS 8.25
   links      5GHz + 6GHz MLO (5200 + 6135 MHz)

   stock 7.1.8 / 7.2-rc7   stalled after 3-5 minutes (WFDMA0 tail frozen)
   v7.3-rc5 + v2           46 minutes, no stall

Both links stayed active throughout, with about 4.2 GB received and
340 MB sent during the run. My watchdog (ping + WFDMA0 queue
monitoring) did not trigger once.

Tested-by: Jonas Hort <jonas.hort@posteo.de>

Thanks for the fix!
Jonas

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

* Re: [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add
  2026-10-04 15:49                 ` [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add Andrei Rusu de Castro
  2026-10-04 18:25                   ` Jonas Hort
@ 2026-10-05  2:44                   ` Devin Wittmayer
  1 sibling, 0 replies; 15+ messages in thread
From: Devin Wittmayer @ 2026-10-05  2:44 UTC (permalink / raw)
  To: Andrei Rusu de Castro
  Cc: linux-wireless, Jonas Hort, Felix Fietkau, Lorenzo Bianconi,
	Ryder Lee, Shayne Chen, Sean Wang, Sean Wang, Thorsten Leemhuis,
	regressions, linux-mediatek

Andrei Rusu de Castro wrote:
> USB hardware and the reporter's FritzBox setup remain untested here.

Tested on a Netgear A9000 (MT7925U, USB), Linux 7.2.6, firmware
20260813113118, morrownr/mt76 at ce4ee3e, against a two-link mt7996
AP MLD on 5745 and 6135 MHz.

Your STA_REC_MLD capture reproduces here. Without v2 the AP got
nothing on 5745 in any run I checked. With v2, 5745 carried traffic
under the scan load from my earlier report:

                                      stock          v2
  scan load, 600 s, mean per ~10 s    249, 267 MB    801, 837 MB
  scan load, 600 s, lowest ~10 s      126 B, 33 MB   643, 687 MB
  scan load, share of bytes on 5745   0              about 60%
  scanning off, share on 5745         0              0

Stock dipped under that load but did not stall for good this time, so
the stall result is Jonas's run, not mine.

Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>

Thanks,
Devin

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

* Re: [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add
       [not found] <1069791187.985419.1791205960502.ref@mail.yahoo.com>
@ 2026-10-05 13:12 ` Tamer Ahmed
  0 siblings, 0 replies; 15+ messages in thread
From: Tamer Ahmed @ 2026-10-05 13:12 UTC (permalink / raw)
  To: Andrei Rusu de Castro
  Cc: linux-wireless@vger.kernel.org, Devin Wittmayer, Jonas Hort,
	Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Sean Wang, Thorsten Leemhuis,
	regressions@lists.linux.dev, linux-mediatek@lists.infradead.org


[-- Attachment #1.1: Type: text/plain, Size: 2671 bytes --]

Hi Andrei,

I tested v2 on an MT7925 PCIe card against a DD-WRT Wi-Fi 7 AP that
advertises three links (2.4, 5 and 6 GHz). Results below, in case they
help.

Setup:
- MT7925 PCIe (14c3:7925, subsystem 103c:8c94), firmware
  WIFI_RAM_CODE 20260813113118 / patch 20260813113015a
- Fedora 44, kernel 7.2.8-200.fc44; mt76 rebuilt out of tree from the
  7.2.8 sources with the patches listed below
- AP: <router model and DD-WRT build>, one MLO SSID with three links;
  WPA3-SAE
- wpa_supplicant 2.11 with hostap commit b048a294a ("MLD: Iterate
  per-link in wpa_clear_keys() for MLO group keys") backported; without
  it, every intra-MLD reconnect logged "link ID must be set for MLO
  group key" and often failed
- Test: 15 minutes, ~1 MB/s download, nl80211 rescan every 60 s,
  gateway ping plus HTTP probe every 5 s

Results:

1) Stock 7.2.8: a two-link (5+6 GHz) association stalled after about
   160 s. Traffic stopped without any disconnect, and a scan was left
   pending ("Reject scan trigger since one is already pending"). The
   same signature appeared after about 2 h on a 2.4+6 GHz association.

2) 7.2.8 + v2 alone: MLO associations failed (AP-side 4-way handshake
   timeouts). After MLO teardown, associations to a separate legacy
   SSID on the same AP were repeatedly deauthenticated by the AP with
   reason 6 (Class 2 frame received from nonauthenticated STA),
   followed by SA Query timeouts on the STA. This matches what
   "wifi: mt76: mt7925: restore the legacy BSS after MLO teardown"
   describes. I did not isolate whether v2 contributed.

3) 7.2.8 + the seven mt76 commits below + your v2 (eight patches in
   total): PASS. 900 s on a three-link (2.4+5+6 GHz) association:
   176/176 probes OK, no disconnects. All 61 full-band scans completed
   (median 8.4 s, max 10.0 s), none stuck.

     wifi: mt76: mt7925: guard BSS capability lookups
     wifi: mt76: check the owner of a remain-on-channel request
     wifi: mt76: mt7925: fix lock inversion between dev->mutex and iflist_mtx
     wifi: mt76: mt7925: check drv_pmctrl return in the PCIe reset path
     wifi: mt76: mt7925: restore the reset state when fw_pmctrl fails
     wifi: mt76: mt7925: fix the lock inversion in suspend and resume
     wifi: mt76: mt7925: restore the legacy BSS after MLO teardown

Caveats: this is a single 15-minute run on a backported 7.2.8 base,
and I did not bisect which of the commits above, besides v2, are
required. I'm continuing to run it day to day and can report back.
Tested-by: Tamer Ahmed <tbmostafa@yahoo.com>

Thanks for working on this.

[-- Attachment #1.2: Type: text/html, Size: 3299 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-wifi-mt76-mt7925-guard-BSS-capability-lookups.patch --]
[-- Type: text/x-patch, Size: 3061 bytes --]

From 66103e694e3baae13de9739184224acfcbfbfb7b Mon Sep 17 00:00:00 2001
From: Sean Wang <sean.wang@mediatek.com>
Date: Wed, 24 Jun 2026 19:18:27 -0500
Subject: [PATCH 1/8] wifi: mt76: mt7925: guard BSS capability lookups

mt7925 BSS setup may dereference missing channel data or query HE 6 GHz
capabilities for an iftype without HE support.

Guard both lookups before adding NAN paths that can use partially
configured BSS state.

Co-developed-by: Stella Liu <yu-ching.liu@mediatek.com>
Signed-off-by: Stella Liu <yu-ching.liu@mediatek.com>
Co-developed-by: Jeremy Yu <chengwei.yu@mediatek.com>
Signed-off-by: Jeremy Yu <chengwei.yu@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Link: https://patch.msgid.link/20260625001834.475094-3-sean.wang@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 26 ++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 53c1423..56518c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2378,11 +2378,18 @@ void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy,
 {
 	struct cfg80211_chan_def *chandef = ctx ? &ctx->def :
 						  &link_conf->chanreq.oper;
-	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
-	enum nl80211_band band = chandef->chan->band;
 	struct bss_rlm_tlv *req;
+	enum nl80211_band band;
+	int freq1, freq2;
 	struct tlv *tlv;
 
+	if (WARN_ON_ONCE(!chandef || !chandef->chan))
+		return;
+
+	freq1 = chandef->center_freq1;
+	freq2 = chandef->center_freq2;
+	band = chandef->chan->band;
+
 	tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req));
 	req = (struct bss_rlm_tlv *)tlv;
 	req->control_channel = chandef->chan->hw_value;
@@ -2520,8 +2527,8 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
 			enum nl80211_band band,
 			struct ieee80211_link_sta *link_sta)
 {
-	struct ieee80211_he_6ghz_capa *he_6ghz_capa;
-	const struct ieee80211_sta_eht_cap *eht_cap;
+	struct ieee80211_he_6ghz_capa *he_6ghz_capa = NULL;
+	const struct ieee80211_sta_eht_cap *eht_cap = NULL;
 	__le16 capa = 0;
 	u8 mode = 0;
 
@@ -2529,11 +2536,18 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
 		he_6ghz_capa = &link_sta->he_6ghz_capa;
 		eht_cap = &link_sta->eht_cap;
 	} else {
+		const struct ieee80211_sta_he_cap *he_cap;
 		struct ieee80211_supported_band *sband;
 
 		sband = phy->hw->wiphy->bands[band];
-		capa = ieee80211_get_he_6ghz_capa(sband, vif->type);
-		he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa;
+
+		he_cap = (band == NL80211_BAND_6GHZ) ?
+			 ieee80211_get_he_iftype_cap(sband, vif->type) : NULL;
+
+		if (he_cap) {
+			capa = ieee80211_get_he_6ghz_capa(sband, vif->type);
+			he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa;
+		}
 
 		eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);
 	}
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-wifi-mt76-check-the-owner-of-a-remain-on-channel-req.patch --]
[-- Type: text/x-patch, Size: 2304 bytes --]

From aecfeee548e4eee87f47fa40906ea412ff2e97f2 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 18 Aug 2026 12:58:22 +0000
Subject: [PATCH 2/8] wifi: mt76: check the owner of a remain-on-channel
 request

mvif->roc_phy points to the phy of the request that started last for the
interface. That request can end, and the phy can start a request for a
different interface. The driver does not always clear the pointer.

Two callers trust the pointer:

- mt76_vif_cleanup() aborts the request on that phy when the driver removes
  the interface.
- mt76_cancel_remain_on_channel() aborts the request on that phy for the
  interface.

If the phy holds a request for a different interface, both callers abort the
wrong request. The request of the interface stays active. Its work then runs
after the driver removes the interface. The work tears the link down through
the freed bss_conf.

Compare phy->roc_vif with the interface in both callers before the abort.

Link: https://patch.msgid.link/20260818125825.395538-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/channel.c  | 2 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c
index 28ad7bc..1d26356 100644
--- a/drivers/net/wireless/mediatek/mt76/channel.c
+++ b/drivers/net/wireless/mediatek/mt76/channel.c
@@ -423,7 +423,7 @@ int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
 	struct mt76_vif_data *mvif = mlink->mvif;
 	struct mt76_phy *phy = mvif->roc_phy;
 
-	if (!phy)
+	if (!phy || phy->roc_vif != vif)
 		return 0;
 
 	mt76_abort_roc(phy);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index f922777..b863a92 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -2106,7 +2106,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
 
 	rcu_assign_pointer(mvif->link[0], NULL);
 	mt76_abort_scan(dev);
-	if (mvif->roc_phy)
+	if (mvif->roc_phy && mvif->roc_phy->roc_vif == vif)
 		mt76_abort_roc(mvif->roc_phy);
 }
 EXPORT_SYMBOL_GPL(mt76_vif_cleanup);
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-wifi-mt76-mt7925-fix-lock-inversion-between-dev-mute.patch --]
[-- Type: text/x-patch, Size: 1708 bytes --]

From a9587ea180a58063ce5286e64037f93ac7756108 Mon Sep 17 00:00:00 2001
From: Devin Wittmayer <lucid_duck@justthetip.ca>
Date: Sun, 9 Aug 2026 21:53:38 -0700
Subject: [PATCH 3/8] wifi: mt76: mt7925: fix lock inversion between dev->mutex
 and iflist_mtx

mt7925_config() has the same inversion as mt7921_config(): it holds
dev->mutex across ieee80211_iterate_active_interfaces(), which takes
local->iflist_mtx, while mac80211 calls drv_unassign_vif_chanctx() with
iflist_mtx already held.

.config is only reached through drv_config(), which asserts the wiphy
mutex, so use ieee80211_iterate_active_interfaces_mtx() here too.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260810045338.118923-3-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt7925/main.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 9f080da..982cbd8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -818,9 +818,9 @@ static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-		ieee80211_iterate_active_interfaces(hw,
-						    IEEE80211_IFACE_ITER_RESUME_ALL,
-						    mt7925_sniffer_interface_iter, dev);
+		ieee80211_iterate_active_interfaces_mtx(hw,
+							IEEE80211_IFACE_ITER_RESUME_ALL,
+							mt7925_sniffer_interface_iter, dev);
 	}
 
 out:
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-wifi-mt76-mt7925-check-drv_pmctrl-return-in-the-PCIe.patch --]
[-- Type: text/x-patch, Size: 1795 bytes --]

From 0de8ed4134b5ea731f84adc9dcf5c05501a7b08f Mon Sep 17 00:00:00 2001
From: Devin Wittmayer <lucid_duck@justthetip.ca>
Date: Sun, 9 Aug 2026 13:55:59 -0700
Subject: [PATCH 4/8] wifi: mt76: mt7925: check drv_pmctrl return in the PCIe
 reset path

mt7925e_mac_reset() ignores the return value of
mt792xe_mcu_drv_pmctrl(), unlike the two pmctrl calls later in the same
function. When the driver-own handshake fails,
__mt792xe_mcu_drv_pmctrl() returns -EIO without reinitialising WPDMA or
clearing MT76_STATE_PM, and the reset carries on: it writes the
interrupt enable registers, cycles NAPI, resets WPDMA and calls
mt7925_run_firmware() on a chip the driver does not own.

Return the error instead. The call is the first statement in the
function, before MT76_RESET is set and before the TX worker and NAPI
are disabled, so nothing needs unwinding.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260809205559.32116-1-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
index 9768394..2ce9ad0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
@@ -73,7 +73,9 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
 	const struct mt792x_irq_map *irq_map = dev->irq_map;
 	int i, err;
 
-	mt792xe_mcu_drv_pmctrl(dev);
+	err = mt792xe_mcu_drv_pmctrl(dev);
+	if (err)
+		return err;
 
 	mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
 
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-wifi-mt76-mt7925-restore-the-reset-state-when-fw_pmc.patch --]
[-- Type: text/x-patch, Size: 1346 bytes --]

From efb449e0872747072f1b383bd59de1cec8deebfb Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 27 Aug 2026 18:21:15 +0200
Subject: [PATCH 5/8] wifi: mt76: mt7925: restore the reset state when
 fw_pmctrl fails

mt7925e_mac_reset() returns directly when mt792xe_mcu_fw_pmctrl()
fails, leaving MT76_RESET set and the TX worker parked. Every other
error path jumps to out, which clears both. mt7925_mac_reset_work()
clears neither, so once every reset attempt fails there, TX stays
blocked until another reset succeeds.

Jump to out instead.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Link: https://patch.msgid.link/20260827162115.1449757-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
index 2ce9ad0..a2ef7a0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
@@ -129,7 +129,7 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
 
 	err = mt792xe_mcu_fw_pmctrl(dev);
 	if (err)
-		return err;
+		goto out;
 
 	err = __mt792xe_mcu_drv_pmctrl(dev);
 	if (err)
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-wifi-mt76-mt7925-fix-the-lock-inversion-in-suspend-a.patch --]
[-- Type: text/x-patch, Size: 1965 bytes --]

From ac5d29815d432aa6c014206a8dafceb060561ce4 Mon Sep 17 00:00:00 2001
From: Devin Wittmayer <lucid_duck@justthetip.ca>
Date: Sat, 29 Aug 2026 23:42:01 -0700
Subject: [PATCH 6/8] wifi: mt76: mt7925: fix the lock inversion in suspend and
 resume

Same as the previous patch, other driver.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260830064201.92285-3-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt7925/main.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 982cbd8..b3e3268 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1648,10 +1648,10 @@ static int mt7925_suspend(struct ieee80211_hw *hw,
 	mt792x_mutex_acquire(dev);
 
 	clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
-	ieee80211_iterate_active_interfaces(hw,
-					    IEEE80211_IFACE_ITER_RESUME_ALL,
-					    mt7925_mcu_set_suspend_iter,
-					    &dev->mphy);
+	ieee80211_iterate_active_interfaces_mtx(hw,
+						IEEE80211_IFACE_ITER_RESUME_ALL,
+						mt7925_mcu_set_suspend_iter,
+						&dev->mphy);
 
 	mt792x_mutex_release(dev);
 
@@ -1666,10 +1666,10 @@ static int mt7925_resume(struct ieee80211_hw *hw)
 	mt792x_mutex_acquire(dev);
 
 	set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
-	ieee80211_iterate_active_interfaces(hw,
-					    IEEE80211_IFACE_ITER_RESUME_ALL,
-					    mt7925_mcu_set_suspend_iter,
-					    &dev->mphy);
+	ieee80211_iterate_active_interfaces_mtx(hw,
+						IEEE80211_IFACE_ITER_RESUME_ALL,
+						mt7925_mcu_set_suspend_iter,
+						&dev->mphy);
 
 	ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
 				     MT792x_WATCHDOG_TIME);
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-wifi-mt76-mt7925-restore-the-legacy-BSS-after-MLO-te.patch --]
[-- Type: text/x-patch, Size: 1850 bytes --]

From 7a447a1450c56e58ec7ef656108ab1a60485ed21 Mon Sep 17 00:00:00 2001
From: Aaron Ma <aaron.ma@canonical.com>
Date: Wed, 26 Aug 2026 12:36:58 +0800
Subject: [PATCH 7/8] wifi: mt76: mt7925: restore the legacy BSS after MLO
 teardown

Removing the last link of an MLD interface leaves the firmware with the
MLD BSS and DEV entry: the removal loop skips the deflink, and the
hweight16(mvif->valid_links) fallback reads the stale pre-update
valid_links, which is still non-zero. The entry keeps the per-link MAC
address, so every subsequent legacy association fails authentication
until the interface is removed or the module is reloaded.

Remove the deflink BSS and add it back as a legacy BSS on the transition
to zero links.

Fixes: 69acd6d910b0 ("wifi: mt76: mt7925: add mt7925_change_vif_links")
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
Link: https://patch.msgid.link/20260826043658.2255553-1-aaron.ma@canonical.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt7925/main.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index b3e3268..4535083 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -2220,6 +2220,18 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
 	mvif->valid_links = new_links;
 
+	/* Restore the legacy BSS after disabling MLO */
+	if (old_links && !new_links) {
+		mt792x_mac_link_bss_remove(dev, &mvif->bss_conf,
+					   &mvif->sta.deflink);
+		err = mt7925_mac_link_bss_add(dev, &vif->bss_conf,
+					      &mvif->sta.deflink);
+		if (err < 0) {
+			mt792x_mutex_release(dev);
+			return err;
+		}
+	}
+
 	mt792x_mutex_release(dev);
 
 	return 0;
-- 
2.55.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-wifi-mt76-mt7925-keep-MLD-membership-consistent-duri.patch --]
[-- Type: text/x-patch, Size: 10019 bytes --]

From 9ac45a634d857d5c141e09d93b0ef1a1377eaae1 Mon Sep 17 00:00:00 2001
From: Andrei Rusu de Castro <arc@empyreal.works>
Date: Sun, 4 Oct 2026 15:49:02 +0000
Subject: [PATCH 8/8] wifi: mt76: mt7925: keep MLD membership consistent during
 link add

mt7925_mac_link_sta_add() sends an ASSOC update for the primary WCID
before sending the update for a new secondary WCID. The new link is
published in msta->link[] and msta->valid_links only after both commands
succeed.

Selecting the secondary entry from the subject of each command gives
the primary STA_REC_MLD one link and the secondary STA_REC_MLD two
links. Enumerating published links alone still omits the pending link
from the primary command. Firmware-bound command captures reproduce
this n=1/n=2 sequence during a secondary addition.

Build each MLD TLV from the station's published links and an explicit
pending link. Pass the initialized pending link through both add-time
station updates, including the update whose subject is the primary.
Keep the primary first, bound entries by the firmware array, and skip
links without station and BSS state. Other update callers have no
pending link.

This leaves msta->link[] publication after successful link setup and
preserves the existing add-failure cleanup. The pending pointer is used
synchronously to populate the command, not stored in shared state.

Fixes: ff643b81bc38 ("wifi: mt76: mt7925: pass mlink and mconf to sta_mld_tlv()")
Link: https://lore.kernel.org/linux-wireless/066b30cc-a9e6-4aeb-964d-71551e8ea3ef@posteo.de/
Signed-off-by: Andrei Rusu de Castro <arc@empyreal.works>
Tested-by: Jonas Hort <jonas.hort@posteo.de>
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
---
 .../net/wireless/mediatek/mt76/mt7925/mac.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt7925/main.c  | 16 ++---
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 59 +++++++++++++++----
 .../wireless/mediatek/mt76/mt7925/mt7925.h    |  3 +-
 4 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index b52b678..0c40043 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1303,7 +1303,7 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
 					    true, NULL);
 		mt7925_mcu_sta_update(dev, NULL, vif,
 				      &mvif->sta.deflink, true,
-				      MT76_STA_INFO_STATE_NONE);
+				      MT76_STA_INFO_STATE_NONE, NULL);
 		mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);
 	}
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 4535083..369299e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -969,7 +969,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
 	    link_sta == mlink->pri_link) {
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_NONE);
+					    MT76_STA_INFO_STATE_NONE, NULL);
 		if (ret)
 			goto out_pm;
 	} else if (ieee80211_vif_is_mld(vif) &&
@@ -991,19 +991,19 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
 
 		ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
 					    pri_mlink, true,
-					    MT76_STA_INFO_STATE_ASSOC);
+					    MT76_STA_INFO_STATE_ASSOC, mlink);
 		if (ret)
 			goto out_pm;
 
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_ASSOC);
+					    MT76_STA_INFO_STATE_ASSOC, mlink);
 		if (ret)
 			goto out_pm;
 	} else {
 		ret = mt7925_mcu_sta_update(dev, link_sta, vif,
 					    mlink, true,
-					    MT76_STA_INFO_STATE_NONE);
+					    MT76_STA_INFO_STATE_NONE, NULL);
 		if (ret)
 			goto out_pm;
 	}
@@ -1211,7 +1211,7 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
 	memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));
 
 	mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true,
-			      MT76_STA_INFO_STATE_ASSOC);
+			      MT76_STA_INFO_STATE_ASSOC, NULL);
 
 	mt792x_mutex_release(dev);
 }
@@ -1254,7 +1254,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
 	mt76_connac_pm_wake(&dev->mphy, &dev->pm);
 
 	mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
-			      MT76_STA_INFO_STATE_NONE);
+			      MT76_STA_INFO_STATE_NONE, NULL);
 	mt7925_mac_wtbl_update(dev, mlink->wcid.idx,
 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
@@ -1895,7 +1895,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
 	err = mt7925_mcu_sta_update(dev, NULL, vif,
 				    &mvif->sta.deflink, true,
-				    MT76_STA_INFO_STATE_NONE);
+				    MT76_STA_INFO_STATE_NONE, NULL);
 out:
 	mt792x_mutex_release(dev);
 
@@ -2039,7 +2039,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
 	if (changed & BSS_CHANGED_ASSOC) {
 		mt7925_mcu_sta_update(dev, NULL, vif,
 				      &mvif->sta.deflink, true,
-				      MT76_STA_INFO_STATE_ASSOC);
+				      MT76_STA_INFO_STATE_ASSOC, NULL);
 		mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc);
 
 		if (ieee80211_vif_is_mld(vif))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 56518c4..175020f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1971,14 +1971,18 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
 		       struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta,
 		       struct mt792x_bss_conf *mconf,
-		       struct mt792x_link_sta *mlink)
+		       struct mt792x_link_sta *mlink,
+		       struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 	struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
 	struct mt792x_dev *dev = mvif->phy->dev;
+	unsigned long valid = msta->valid_links;
 	struct mt792x_bss_conf *mconf_pri;
 	struct sta_rec_mld *mld;
+	unsigned int link_id;
 	struct tlv *tlv;
+	u8 max_links;
 	u8 cnt = 0;
 
 	/* Primary link always uses driver's deflink WCID. */
@@ -2007,11 +2011,44 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
 	mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
 	mld->link[cnt++].bss_idx = mconf_pri->mt76.idx;
 
-	/* Optionally encode the currently-updated secondary link. */
-	if (mlink && mlink != &msta->deflink && mconf) {
-		mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
-		mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
-		mld->link[cnt++].bss_idx = mconf->mt76.idx;
+	/* Describe the same station links in each per-WCID STA_REC_MLD,
+	 * rather than selecting the secondary from the current command.
+	 */
+	max_links = ARRAY_SIZE(mld->link);
+
+	/* Adding a secondary link updates both primary and secondary STA
+	 * records before publishing the new link in msta->link[]. Include it
+	 * in both commands without moving that publication before success.
+	 */
+	if (pending && pending != &msta->deflink)
+		valid |= BIT(pending->wcid.link_id);
+
+	for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
+		struct mt792x_link_sta *mlink_sec;
+		struct mt792x_bss_conf *mconf_sec;
+
+		if (cnt == max_links)
+			break;
+
+		if (link_id == msta->deflink_id)
+			continue;
+
+		mlink_sec = mt792x_sta_to_link(msta, link_id);
+		if (!mlink_sec && pending && link_id == pending->wcid.link_id)
+			mlink_sec = pending;
+		if (!mlink_sec || mlink_sec == &msta->deflink)
+			continue;
+
+		mconf_sec = rcu_dereference_protected(mvif->link_conf[link_id],
+						      lockdep_is_held(&dev->mt76.mutex));
+		if (!mconf_sec)
+			continue;
+
+		if (cnt == 1)
+			mld->secondary_id = cpu_to_le16(mlink_sec->wcid.idx);
+
+		mld->link[cnt].wlan_id = cpu_to_le16(mlink_sec->wcid.idx);
+		mld->link[cnt++].bss_idx = mconf_sec->mt76.idx;
 	}
 
 	mld->link_num = cnt;
@@ -2030,7 +2067,8 @@ mt7925_mcu_sta_remove_tlv(struct sk_buff *skb)
 
 static int
 mt7925_mcu_sta_cmd(struct mt76_phy *phy,
-		   struct mt76_sta_cmd_info *info)
+		   struct mt76_sta_cmd_info *info,
+		   struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;
 	struct mt76_dev *dev = phy->dev;
@@ -2071,7 +2109,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
 		if (info->state != MT76_STA_INFO_STATE_NONE) {
 			mt7925_mcu_sta_mld_tlv(skb, info->vif,
 					       info->link_sta->sta,
-					       mconf, mlink);
+					       mconf, mlink, pending);
 
 			mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);
 		}
@@ -2096,7 +2134,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 			  struct ieee80211_vif *vif,
 			  struct mt792x_link_sta *mlink,
 			  bool enable,
-			  enum mt76_sta_info_state state)
+			  enum mt76_sta_info_state state,
+			  struct mt792x_link_sta *pending)
 {
 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 	int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi);
@@ -2114,7 +2153,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 	info.wcid = &mlink->wcid;
 	info.newly = state != MT76_STA_INFO_STATE_ASSOC;
 
-	return mt7925_mcu_sta_cmd(&dev->mphy, &info);
+	return mt7925_mcu_sta_cmd(&dev->mphy, &info, pending);
 }
 
 int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 4cc2594..5c71779 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -278,7 +278,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
 			  struct ieee80211_vif *vif,
 			  struct mt792x_link_sta *mlink,
 			  bool enable,
-			  enum mt76_sta_info_state state);
+			  enum mt76_sta_info_state state,
+			  struct mt792x_link_sta *pending);
 int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag);
 int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf);
 int mt7925_mcu_set_eeprom(struct mt792x_dev *dev);
-- 
2.55.0


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

end of thread, other threads:[~2026-10-05 13:13 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-19  9:03 [REGRESSION] mt7925: MLO connectivity silently stalls with 6GHz link active Jonas Hort
2026-08-22 20:18 ` Jonas Hort
2026-08-23 20:54   ` Jonas Hort
2026-08-24  4:50     ` Devin Wittmayer
2026-08-24  4:52     ` Thorsten Leemhuis
2026-08-24  8:18       ` Jonas Hort
2026-08-29 22:13         ` Devin Wittmayer
2026-10-02 17:31           ` Jonas Hort
2026-10-02 18:11           ` Jonas Hort
2026-10-03 18:03             ` Devin Wittmayer
2026-10-04 15:48               ` Andrei Rusu de Castro
2026-10-04 15:49                 ` [PATCH v2] wifi: mt76: mt7925: keep MLD membership consistent during link add Andrei Rusu de Castro
2026-10-04 18:25                   ` Jonas Hort
2026-10-05  2:44                   ` Devin Wittmayer
     [not found] <1069791187.985419.1791205960502.ref@mail.yahoo.com>
2026-10-05 13:12 ` Tamer Ahmed

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