Commit Graph

4106 Commits

Author SHA1 Message Date
Lu Huang
52f6a065e0 wifi: mt76: mt7996: fix uninitialized buf read in mt7996_variant_fem_init()
When the eFuse block covering MT7976C_EFUSE_OFFSET is invalid,
mt7996_mcu_get_eeprom() returns -EINVAL without writing buf, but
mt7996_variant_fem_init() tolerates -EINVAL and keeps running, so
buf[idx] == 0xc reads uninitialized stack memory.  A stale 0x0c byte
misclassifies a 0x7976 aDie as 7976C, selects MT7996_FEM_INT and the
wrong default EEPROM, overriding valid calibration data.  Only consult
the eFuse byte when the read succeeded; with an invalid eFuse, fall
back to the three explicit aDie version checks.

Fixes: e8cb33ad54 ("wifi: mt76: mt7996: add support for more variants")
Cc: stable@vger.kernel.org
Signed-off-by: Lu Huang <huanglu@kylinos.cn>
Link: https://patch.msgid.link/20260930085435.1424493-1-huanglu@kylinos.cn
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Devin Wittmayer
af97bf5a7e wifi: mt76: mt792x: pick the SAR table layout from the table itself
The SAR power tables are parsed with a version byte from a different
ACPI table, never their own.

Some firmware declares version 1 and ships version 2 tables. The
entries then start a byte early, and the 6 GHz limits the table
carries are dropped, because the older layout has no room for them.

  ASUS GA503RM, MTCL declares v1:
  MTGS  28 bytes   v1: (28-6) % 5 = 2, no fit   v2: 3 tables
  MTDS  19 bytes   v1: (19-6) % 6 = 1, no fit   v2: 1 table

The layouts accept disjoint lengths, so take whichever one fits and
keep it per table.

Reported-by: Sagun Kayastha <sgn.kayastha@gmail.com>
Closes: https://github.com/morrownr/mt76/issues/62
Fixes: f965333e49 ("mt76: mt7921: introduce ACPI SAR support")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260905013551.24635-1-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Junjie Cao
45f53d98cb wifi: mt76: mt792x: treat 0xff ACPI SAR entries as no limit
Some ASUS firmware carries 0xff in MTGS power slots. The driver narrows
the byte to s8, so the slot reads as -1 in its 0.5 dBm units, wins the
min() against the regulatory limit and caps every rate the driver
programs. On an ASUS Zenbook 14 UM3406HA (MT7922) all six MTGS tables
hold 0xff in every power byte, and txpower_sku shows tmac 3 on every
supported OFDM/HT/VHT/HE rate against EEPROM entries of 25-39, under
both the FR and the world regulatory domain. Huy Nguyen Dinh Quang saw
the same clamp on a Vivobook S 14 M5406WA, with 5 GHz TX at ~40 Mbps,
and proposed skipping the geo entry.

Skip a geo entry whose power byte is 0xff. The MTDS entry is narrowed
the same way on its way into the geo lookup, so give it the same
treatment, and clamp the dynamic value plus offset at 127 so a no-limit
entry cannot wrap.

Fixes: f965333e49 ("mt76: mt7921: introduce ACPI SAR support")
Link: https://bugzilla.redhat.com/show_bug.cgi?id=2515420
Reported-by: Huy Nguyen Dinh Quang <huynguyendinhquang@gmail.com>
Closes: https://lore.kernel.org/linux-wireless/20260827134820.2607530-1-huynguyendinhquang@gmail.com/
Signed-off-by: Junjie Cao <junjie.cao@intel.com>
Tested-by: Cristian Fleischer <cristian.fleischer@gmail.com>
Link: https://patch.msgid.link/acb947435fc78d5c06039c7bd5609c735468b0ee.1789002236.git.junjie.cao@intel.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Cristian Papa
456de496b5 wifi: mt76: mt7603: initialize global station WCID
mt7603 uses a driver-private global station WCID for frames that have
neither a station nor a vif, including frames injected through a monitor
interface. Unlike the core global WCID initialized by
mt76_register_device(), this WCID is published without ever being passed
to mt76_wcid_init().

Since commit 0335c034e7 ("wifi: mt76: fix race condition related to
checking tx queue fill status"), mt76_tx() queues every such frame on the
WCID's tx_pending or tx_offchannel queue and links its tx_list. The first
injected frame therefore reaches __skb_queue_tail() with an uninitialized
sk_buff_head and dereferences a NULL prev pointer.

Initialize the WCID before publishing it.

The fix was tested on an MT7603 PCIe device. Three wildcard probe requests
were injected through a monitor interface. The hardware queue head and tail
advanced from 0 to 3 and a second radio captured the third request over the
air. No oops or reset occurred. After restoring AP mode, a 150 MB transfer
also completed without a reset.

Fixes: 0335c034e7 ("wifi: mt76: fix race condition related to checking tx queue fill status")
Cc: stable@vger.kernel.org
Signed-off-by: Cristian Papa <pcristian292@gmail.com>
Link: https://patch.msgid.link/20260904010702.16306-1-pcristian292@gmail.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Devin Wittmayer
5796b2bf9f wifi: mt76: mt7925: don't put the band auto marker in TGID
band_idx starts out as 0xff, which tells the firmware to pick the band on
its own. A remain-on-channel grant normally writes a real index over it
before anything else looks. Two cases never see that: an MLD station
throws the grant away, and an AP has no association to trigger one.

The TX descriptor reads the same field into a two-bit slot, so the marker
comes out as 3. Every data frame from those two goes out tagged band 3.
Beacons are fine, they reach the firmware separately and never build a
descriptor.

Same numbers on an MT7925 and on a Netgear A9000:

                        stock         patched
  station, one link     0x00000001    0x00000001
  station, two links    0x00003001    0x00000001
  AP                    0x00003013    0x00000013
  real band index, STA  0x00001001    0x00001001
  real band index, AP   0x00001013    0x00001013

Only the marker cases move.

Fixes: 0cb349d742 ("wifi: mt76: mt7925: update mt7925_mac_link_bss_add for MLO")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260911024428.65244-1-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Nicolas Cavallari
916c484d29 wifi: mt76: mt7915: disable rx napi when removing device
Unloading the mt7915e module with a MT7916 triggers multiples WARN in
__netif_napi_del_locked() and in page_pool_disable_direct_recycling()
because the driver does not disable the napi before destroying it.

This is troublesome since on MT7916 it is required to unload the module
and reinsert it with a different enable_6ghz parameter to change the
frequency.  The system generally becomes unstable after reinserting the
module.

Fix it by disabling rx napi inside mt7915e itself, even through napi rx is
enabled in the mt76 generic code.  Disabling it in the mt76 generic code
was previously attempted and reverted because napi was disabled too
late and rx handlers could access freed structures.  Note that the tx
side is enabled and disabled by the mt76 generic code.

It is disabled in mt7915_stop_hardware() since, unlike
mt7915_unregister_device(), is it also called in the probe path if an
error happens after rx napi is enabled.

Fixes: e57b790146 ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Signed-off-by: Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
Link: https://patch.msgid.link/20260810154923.32546-1-nicolas.cavallari@green-communications.fr
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Tao Gong
9c9e4e4c8b wifi: mt76: mt7996: fix struct mt7996_mcu_wed_rro_ba_delete_event layout
Correct the definition of struct mt7996_mcu_wed_rro_ba_delete_event to
match the 12-byte event record layout observed from firmware.

The event TLV sent by firmware is 12 bytes in length rather than 8 bytes.
It contains an additional 4 bytes that appear to be wlan_id and tid.
For example, a captured batch deletion of sessions 8, 9, and 10 (TIDs 6,
0, and 1) shows:

  00000000: 02 00 0c 00 08 00 01 00 06 00 00 00 02 00 0c 00
  00000010: 09 00 01 00 00 00 00 00 02 00 0c 00 0a 00 01 00
  00000020: 01 00 00 00

The previous 8-byte structure corrupts the parsing of subsequent TLVs,
leading to unhandled delete events and erroneous session deletions.
Consequently, clients that create and tear down BA sessions in batches
(such as Apple Wi-Fi clients) fail to properly clean up stale sessions,
causing HW_RRO to be lost upon subsequent reassociations.

Fixes: a5d028d668 ("wifi: mt76: mt7996: add wed rro delete session garbage collector")
Signed-off-by: Tao Gong <gongtao0607@gmail.com>
Link: https://patch.msgid.link/20260823053739.186748-1-gongtao0607@gmail.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Aaron Ma
8f9e580767 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: 69acd6d910 ("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>
2026-10-06 11:50:52 +02:00
Felix Fietkau
7c2e6b43c3 wifi: mt76: use ALTX queue for packets to disassociated stations
Running these packets through regular buffering queues could cause them
to hang, especially when the packets were for stations that in disassoc
state.

Fixes: dedf2ec30f ("wifi: mt76: fix queue assignment for deauth packets")
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260901092232.461379-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Felix Fietkau
752770d7a5 wifi: mt76: account non-AQL frames per peer rather than per link
The driver increments wcid->non_aql_packets when a frame goes to the
hardware queue. The completion path decrements the counter again.

For an MLO peer, the hardware reports the completion on the link that it
used for the transmission. This link can differ from the link that the
driver queued the frame on. In that case, the increment and the
decrement go to different link wcids, and the count drifts upwards until
it blocks the station.

Keep the count on the wcid of the primary link, like the other peer-wide
state.

Fixes: 86c051f2c4 ("wifi: mt76: mt7925: enabling MLO when the firmware supports it")
Link: https://patch.msgid.link/20260818125825.395538-5-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Felix Fietkau
0ec14f8c8c wifi: mt76: mt7996: take over connection monitoring
mt76 runs its own beacon monitor. mt76_beacon_mon_check() counts a miss
for each affiliated link of an MLD, and it stops the count while the phy
is off channel. mt7996 supplies it through mt76_rx_beacon(), but it does
not set CONNECTION_MONITOR. Therefore mac80211 also starts its legacy
monitor.

The legacy monitor knows one interface, not a set of links. It also
counts while the radio serves a different link. After seven beacon
intervals it removes an association that still carries traffic on the
other links.

Set the CONNECTION_MONITOR flag to disable the legacy monitor.

Fixes: 4df75606ec ("wifi: mt76: add per-link beacon monitoring for MLO")
Link: https://patch.msgid.link/20260818125825.395538-3-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-06 11:50:52 +02:00
Felix Fietkau
f5e0b20f6c wifi: mt76: mt7996: program a link again if the driver holds it
The firmware needs the driver to remove active links from the BSSINFO table
when it destroys the interface. A link therefore stays registered from its
first chanctx assignment until the interface goes away. If the driver holds
the link already, a second add does nothing.

mac80211 gives a non-AP MLD a new address each time it sets a link up. A link
that comes back after a failed attempt thus carries an address that the
hardware does not know, on a BSS that the driver never programs again. The
station then authenticates from an address that nothing answers. The failure
repeats until the driver tears the interface down for good.

Program the address and the BSS again. This is the pair that the initial add
sets up. For a station it does what mt7996_mcu_mld_link_oper() does for an AP.

Fixes: 08813703ac ("wifi: mt76: mt7996: Destroy vif active links in mt7996_remove_interface()")
Link: https://patch.msgid.link/20260818125825.395538-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-10-02 11:26:58 +02:00
Devin Wittmayer
7825de3f75 wifi: mt76: mt792x: fix NULL dereference in ACPI SAR init during probe
Some laptops carry a MediaTek power table in their firmware, and the
driver reads it to set a transmit limit for each frequency range.  It
only fills in the ranges themselves when it registers the device.

The startup step that does this existed already, but it never programmed
anything.  Two recent commits made it run a regulatory update instead,
which sets the limits on the way through, long before registration.

As a result, on a machine that has the table the driver reads through an
empty pointer and the interface never appears:

  BUG: kernel NULL pointer dereference, address: 0000000000000004
  RIP: 0010:mt792x_init_acpi_sar_power
  Call Trace:
   mt7921_set_tx_sar_pwr
   mt7921_mcu_regd_update
   mt7921_regd_update
   mt7921_run_firmware
   mt7921e_mcu_init
   mt7921_init_work

Skip it when the ranges are missing. They are applied again once the
device is up, which is where they came from before.

Reported-by: Klara Modin <klarasmodin@gmail.com>
Closes: https://lore.kernel.org/linux-wireless/aoyxqHYvSuaBeubf@soda.int.kasm.eu/
Fixes: 9b80bd9cab ("wifi: mt76: mt7921: add regulatory wiphy self manager support")
Fixes: e9f3f1cc13 ("wifi: mt76: mt7925: add regulatory wiphy self manager support")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Tested-by: David Gow <david@davidgow.net>
Tested-by: Klara Modin <klarasmodin@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-09-13 10:15:16 -07:00
Laxman Acharya Padhya
1a296bfd3e wifi: mt76: mt7921: skip unknown CLC firmware records
Treat an out-of-range CLC index as newer firmware rather than a
malformed image. linux-firmware 20260810 ships MT7922 records with
idx 3, and rejecting them made mt7921e fail to probe.

Keep the record-length checks, and report those as errors so a
truncated table is visible instead of a silent retry loop.

Fixes: 9417c5818a ("wifi: mt76: mt7921: validate CLC firmware records")
Reported-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Reviewed-by: Junjie Cao <junjie.cao@intel.com>
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-09-13 10:15:16 -07:00
Kees Cook
3a2c4d55e3 treewide: refresh kmalloc_obj() conversions
This is another run of the Coccinelle script for converting kmalloc()
family of allocations to kmalloc_obj() via the existing rules in
scripts/coccinelle/api/kmalloc_objs.cocci

This catches both the set of kmalloc() uses added since the first
kmalloc_obj() conversions in v7.0 and adds a large group missed in the
first pass due to Coccinelle not interacting well with the cleanup.h
scoped_...() family of macros[1]. I worked around this with spatch's
"--macro-file" argument to a file with all the scoped_...() macros mapped
to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control
flow indicator I could find.

Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc,
riscv, and s390 with no new warnings.

Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1]
Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2]
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
2026-09-04 21:37:00 -07:00
Jakub Kicinski
3da8c3c8b8 Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.2-rc8).

No conflicts.

Adjacent changes:

drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
  5f3a13e0bb ("net: ngbe: fix NULL pointer dereference in non-MSI-X interrupt enabling")
  d661abdc30 ("net: ngbe: correct misleading interrupt comment")

drivers/net/ipvlan/ipvlan_main.c
  e16e960d55 ("ipvlan: inherit needed_headroom and needed_tailroom from phy_dev")
  00a40d8092 ("ipvlan: Support per-netns netdev unregistration.")

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-08-13 11:00:14 -07:00
Mikhail Gavrilov
3aa1dcaa4f Revert "wifi: mt76: Disable napi when removing device"
This reverts commit 13b7e6a96a.

That commit made mt76_dma_cleanup() disable every RX NAPI instance before
deleting it, to silence WARNs in __netif_napi_del_locked() and
page_pool_disable_direct_recycling() seen when unloading mt7915e with an
MT7916.

On mt7921e and mt7925e the same instances are already disabled earlier,
in mt7921e_unregister_device() and mt7925e_unregister_device(), which
only afterwards call mt792x_dma_cleanup() -> mt76_dma_cleanup().  Each
instance is therefore disabled twice, and napi_disable() is not
idempotent: on return it leaves NAPIF_STATE_SCHED and NAPIF_STATE_NPSVC
set, so the second call spins in usleep_range() forever, waiting for bits
that nobody will clear.

mt7921_pci_shutdown() and mt7925_pci_shutdown() reuse the remove path, so
this is hit on every reboot, poweroff and module unload.  It is silent:
the stuck task keeps sleeping and rescheduling, so neither the hung task
detector nor the lockup detectors fire, and the last line on the console
is "systemd-shutdown[1]: Rebooting."

  task:modprobe        state:D stack:25720 pid:7954  tgid:7954
  Call Trace:
   <TASK>
   __schedule+0x11b8/0x26d0
   schedule+0xe7/0x2f0
   schedule_hrtimeout_range_clock+0x218/0x330
   usleep_range_state+0x133/0x1b0
   napi_disable_locked+0x37d/0x5f0
   napi_disable+0x43/0x80
   mt76_dma_cleanup+0x2b4/0x860 [mt76]
   mt7921_pci_remove+0x17f/0x350 [mt7921e]
   pci_device_remove+0xb6/0x1e0
   device_release_driver_internal+0x38d/0x540
   driver_detach+0xd0/0x1b0
   bus_remove_driver+0x127/0x2d0
   pci_unregister_driver+0x2a/0x280
   __do_sys_delete_module+0x36a/0x5b0
   do_syscall_64+0x11c/0x6d0
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
   </TASK>

Dropping the two driver-side loops instead was tried and rejected: with
them gone, the RX poll can reach mt76_token_release() via
PKT_TYPE_TXRX_NOTIFY and mt7921_mac_tx_free() while
mt76_connac2_tx_token_put() is running idr_destroy(&dev->token) outside
token_lock, which is a use-after-free rather than a hang [1].

Revert for now, so that reboot, poweroff and module unload work again.
The WARNs on mt7915e are a less severe problem than an unbootable
machine, and fixing them belongs in the drivers that delete the NAPI
instances, where each one can pick a point that is safe for its own
teardown order, rather than in the shared mt76_dma_cleanup().

[ This is the "landing soonish" known regression fix mentioned in the
  previous networking merge commit       - Linus ]

Reported-by: Bert Karwatzki <spasswolf@web.de>
Closes: https://lore.kernel.org/all/20260724151419.26014-1-spasswolf@web.de/
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221818
Link: https://lore.kernel.org/all/20260730050428.GA73812@sol/ [1]
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Acked-by: Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
Fixes: 13b7e6a96a ("wifi: mt76: Disable napi when removing device")
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-08-13 09:00:55 -07:00
Jose Ignacio Tornos Martinez
4df22710a7 wifi: mt76: mt7996: remove beacon_int_min_gcd from ADHOC interface combinations
The driver fails to register with error -22 (EINVAL) due to a cfg80211
validation failure in wiphy_verify_iface_combinations().

Commit 5ef0e8e265 ("wifi: mt76: mt7996: fix iface combination for
different chipsets") added beacon_int_min_gcd to if_comb_global and
if_comb_global_7992, but these combinations include ADHOC (IBSS)
interface type. This violates a cfg80211 rule from commit 56271da29c
("cfg80211: disallow beacon_int_min_gcd with IBSS") that explicitly
forbids combining ADHOC with beacon_int_min_gcd.

The restriction exists because beacon_int_min_gcd requires static,
predictable beacon intervals to coordinate multiple beaconing interfaces,
but ADHOC interfaces have dynamic beacon intervals that change when
joining different networks, making the GCD constraint unenforceable.

Remove beacon_int_min_gcd from the interface combinations that include
ADHOC because they are not necessary for ADHOC operation. The if_comb
combination (AP/MESH/STA only, without ADHOC) correctly retains
beacon_int_min_gcd for multi-AP coordination.

Fixes: 5ef0e8e265 ("wifi: mt76: mt7996: fix iface combination for different chipsets")
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Tested-by: Alex Gavin <alex.gavin@candelatech.com>
Link: https://patch.msgid.link/20260702104337.679536-1-jtornosm@redhat.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 17:55:26 +00:00
Devin Wittmayer
6f6c9800e5 wifi: mt76: mt792x: do not advertise active monitor
mt76_phy_init() sets NL80211_FEATURE_ACTIVE_MONITOR for every mt76 device,
but mt792x firmware does not honor it: entering active monitor mode stops
RX. Gate the feature behind a new per-phy no_active_monitor flag and set it
for mt792x.

Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Link: https://patch.msgid.link/20260722011302.113060-1-lucid_duck@justthetip.ca
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 17:55:25 +00:00
Felix Fietkau
4330a0ef9f wifi: mt76: mt7996: fix out-of-bounds link array access in mt7996_tx()
When mac80211 leaves the link unspecified, mt7996_tx() substitutes the
primary link id of the station or vif. That value is
IEEE80211_LINK_UNSPECIFIED (0xf) until the first link has been added,
and it is then used unchecked to index vif->link_conf[],
mvif->mt76.link[] and sta->link[], all of which hold
IEEE80211_MLD_MAX_NUM_LINKS (15) entries.

Clamp the primary link id to the default link before using it, and use
the clamped value for the link_sta fallback as well.

Fixes: 1609b014aa ("wifi: mt76: mt7996: Overwrite unspecified link_id in mt7996_tx()")
Link: https://patch.msgid.link/20260801145334.1166751-10-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
9ba744a28c wifi: mt76: reject out-of-range link ids in mt76_vif_link()
mt76_vif_link() indexes mvif->link[] without validating link_id, but
callers pass mvif->deflink_id / msta->deflink_id, which hold
IEEE80211_LINK_UNSPECIFIED (0xf) until the first link has been added.
Since IEEE80211_MLD_MAX_NUM_LINKS is 15, that reads one element past the
end of the array, aliasing mt76_vif_data.offchannel_link.

Reachable via mt7996_set_tsf()/mt7996_offset_tsf() and
mt7996_net_fill_forward_path(). Bounds check link_id and return NULL,
matching mt7996_sta_link() and mt7996_sta_link_protected().

Fixes: a9384b36a4 ("wifi: mt76: mt7996: rework set/get_tsf callabcks to support MLO")
Link: https://patch.msgid.link/20260801145334.1166751-9-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
0bbd6c52df wifi: mt76: mt7603: file buffered frames under the TID reported to mac80211
The PS queue filed redirected frames under the TID taken from the TXD,
while mac80211 was told about the TID taken from the QoS header, or TID 0
for anything that is not a QoS data frame. When the two disagree,
mt7603_release_buffered_frames() skips the frame because it does not
match the requested TIDs, so it stays in the PS queue until the station
wakes up. Buffered MMPDUs hit this whenever they were sent on a
non-zero TID.

Use one TID for both.

Link: https://patch.msgid.link/20260801145334.1166751-8-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
636a883e2f wifi: mt76: mt7603: restore hardware PS buffering after a service period
Releasing buffered frames has to turn off the PSE redirect for the
station, otherwise the released frames are looped straight back into the
driver PS queue. Nothing ever turns it back on: mt7603_sta_ps() only runs
on an observed PM bit transition, and MT_WCID_FLAG_PS keeps mt76 from
reporting the same state twice. After the first service period the
hardware therefore treats a dozing station as awake and transmits at it
directly, which is where the retry storms and the packet loss reported
against U-APSD clients come from.

Re-arm hardware buffering from mt7603_mac_work() for every station that
is still known to be asleep, once the PSD queue has drained and the
released frames have passed the redirect stage. Frames that are still
queued belong to the service period that was just served, so unlike on a
sleep transition they must not be pulled back with mt7603_filter_tx().

Track the sleep state separately from the WTBL state, so a station that
wakes up while the re-arm is pending is not put back to sleep.

Link: https://patch.msgid.link/20260801145334.1166751-7-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
d5001f493f wifi: mt76: mt7603: tell mac80211 when the PS queue has run empty
mt7603_rx_loopback_skb() marks a TID as buffered when the hardware
redirects a frame into the driver PS queue, but nothing ever clears that
state again. mac80211 therefore keeps the TIM bit set for the station and
keeps routing every service period to the driver, which also prevents it
from releasing frames it has buffered itself.

Clear the buffered state for every requested TID that has no frames left
in the PS queue.

Link: https://patch.msgid.link/20260801145334.1166751-6-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
697badc27a wifi: mt76: mt7603: fix U-APSD service period termination
Frames released from the driver PS queue were all tagged with MORE_DATA
and none of them ever carried the EOSP bit, so from the client's point of
view a U-APSD service period was started but never finished. Clients that
keep their receiver on until EOSP arrives stop sending trigger frames,
and all downlink traffic for that station stalls until they give up.
ieee80211_sta_eosp() only cleared the service period state inside
mac80211, which is why the mismatch went unnoticed.

Assign MORE_DATA per frame and set the wire EOSP bit on the last one. If
the last released frame is a bufferable MMPDU it has no QoS control field
to carry EOSP, so let mac80211 append a QoS-Null frame instead.

Also stop handing the remaining frame budget to
mt76_release_buffered_frames() once frames have been released from the PS
queue: both would signal the end of the same service period. Releasing
fewer frames than requested is allowed, and MORE_DATA tells the client to
trigger again.

Link: https://patch.msgid.link/20260801145334.1166751-5-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
0b8d252471 wifi: mt76: set the EOSP bit in the QoS header of the last released frame
When the driver implements .release_buffered_frames, mac80211 leaves the
U-APSD signalling entirely to the driver: "In this case it is also
responsible for setting the EOSP flag in the QoS header of the frames"
(include/net/mac80211.h). Only IEEE80211_TX_STATUS_EOSP was being set,
which merely ends the service period inside mac80211, so on air the
service period was never terminated. Clients that wait for EOSP before
going back to doze keep the SP open and stop triggering, which stalls all
downlink traffic for that station.

Set the wire EOSP bit on the last frame of a U-APSD service period.
EOSP has no meaning for a PS-Poll response, so pass the release reason
down and leave those frames alone.

Link: https://patch.msgid.link/20260801145334.1166751-4-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
2d16caccd2 wifi: mt76: mt7996: handle UNI PS sync events
Enable MT_DRV_HW_PS_BUFFERING and handle MCU_UNI_EVENT_PS_SYNC with
all three TLV formats (single client, multi-client packed entries,
and bitmap).

Link: https://patch.msgid.link/20260801145334.1166751-3-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
dc930cf883 wifi: mt76: mt7915: handle MCU PS sync events
Enable MT_DRV_HW_PS_BUFFERING and handle MCU_EXT_EVENT_PS_SYNC to
track station power-save state via firmware notifications.

Link: https://patch.msgid.link/20260801145334.1166751-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
Felix Fietkau
a547b414bf wifi: mt76: add PS buffering support for HW-managed TIM drivers
Add MT_DRV_HW_PS_BUFFERING flag for drivers where firmware controls
the TIM bit based on buffered frames. Instead of blocking all TX to
PS stations (which starves firmware and prevents TIM from being set),
allow limited frame delivery using AQL pending airtime as the
throttle. Replenish the firmware buffer on TX completion.

Add mt76_sta_ps_transition() helper for drivers to call from MCU
PS sync events.

Link: https://patch.msgid.link/20260801145334.1166751-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 15:22:41 +00:00
shengwei.lu
404c4e564f wifi: mt76: mt7925: Fix EHT Beamformee SS subfields to meet 802.11be minimum
Per IEEE 802.11be, the Beamformee SS <= 80/160/320 MHz 3-bit subfields
in the EHT PHY Capabilities are encoded as (Nss - 1) and are required
to be >= 3 (i.e. at least 4 SS receive capability) whenever SU
Beamformee is advertised.

MT7925 is a 2x2 STA (sts = 2), so directly filling (sts - 1) = 1
violates the spec minimum. Clamp the encoded value to 3 when sts <= 3,
otherwise use (sts - 1). This is applied consistently to the
BEAMFORMEE_SS <= 80 MHz (split across phy_cap_info[0]/[1]), <= 160 MHz
and <= 320 MHz (6 GHz only) subfields.

Fixes: c948b5da6b ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: shengwei.lu <shengwei.lu@mediatek.com>
Link: https://patch.msgid.link/20260723031108.2017653-1-jb.tsai@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Dmitry Antipov
f0be077b7b wifi: mt76: mt7915: simplify mt7915_sys_recovery_set()
Use convenient ' kstrtou16_from_user()'
to simplify 'mt7915_sys_recovery_set()'.

Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Link: https://patch.msgid.link/20260723180430.747789-1-dmantipov@yandex.ru
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Jeff Hsu
5f23b939a3 wifi: mt76: mt7925: skip DMA re-init selectively
Add a flag to skip it on chips that don't need it.

Signed-off-by: Jeff Hsu <Jeff.Hsu@mediatek.com>
Link: https://patch.msgid.link/20260706024306.47806-1-jb.tsai@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
fc7801b7f1 wifi: mt76: mt7925: fix infinite loop in UNI event TLV parsing
The event TLV loops accept a zero-length TLV, which advances neither the
cursor nor the remaining length, so a malformed event hangs the caller.
mt7925_mcu_uni_roc_event() additionally walked past the end of the skb,
since it never checked the declared length against the remainder.

Replace the five open-coded loops with a shared iterator that rejects
lengths below the TLV header and beyond the remaining buffer, and check
the per-tag payload sizes before dereferencing them.

While here, make the RSSI monitor event read from the current TLV rather
than from the start of the list.

Link: https://patch.msgid.link/20260727150434.1778520-15-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
StanleyYP Wang
d8eb7952fa wifi: mt76: mt7996: add scan dwell time hw cap
Add NL80211_EXT_FEATURE_SET_SCAN_DWELL support in driver.
This allows user to specify channel dwell time during scanning.

Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Link: https://patch.msgid.link/20260727150434.1778520-14-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
6613d2104f wifi: mt76: mt7915: update SKU power limits after changing antennas
Changing the antenna configuration updates the stream capabilities but
left the per-path SKU power limits and path delta compensation stale
until the next channel switch. Reapply the SKU table like mt7996
already does.

Link: https://patch.msgid.link/20260727150434.1778520-13-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Howard Hsu
de3afeafbc wifi: mt76: mt7996: reject iTWT setup requests from MLD stations
The firmware does not support individual TWT agreements with non-AP MLDs,
and the driver only tracks TWT flow state on the default link, which may
not be the link the agreement was negotiated on. Reject TWT setup
requests from MLD stations instead of programming an unsupported
configuration.

Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
Link: https://patch.msgid.link/20260727150434.1778520-12-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Peter Chiu
3999d15cfc wifi: mt76: fix queue assignment for disassoc packets
Like deauth, a disassoc frame sent to a client in powersave mode can get
stuck in a tx queue along with other buffered frames, filling up hardware
queues with frames that are only released after the WTBL slot is reused
for another client.

Move disassoc packets to the ALTX queue, matching the existing deauth
handling.

Fixes: dedf2ec30f ("wifi: mt76: fix queue assignment for deauth packets")
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Link: https://patch.msgid.link/20260727150434.1778520-11-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
StanleyYP Wang
d22f7f29c6 wifi: mt76: mt7996: remove repeater muar config
Repeater mode is not supported currently, so remove it.
get_omac_idx() only hands out HW_BSSID/EXT_BSSID indices, so the
omac_idx >= REPEATER_BSSID_START call sites are unreachable.

Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Link: https://patch.msgid.link/20260727150434.1778520-10-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
b53c44fe65 wifi: mt76: mt7915: report RX chain signal for all RX paths
status->chains was set from the antenna mask, which is derived from the
number of spatial streams, while the chain_signal array is filled from
all RCPI fields. On boards where the number of RX paths exceeds the
stream count, e.g. the 3T3R mt7916/mt7981 variant with 2 streams on the
5 GHz band, the RSSI of the extra chains was never reported.

Use the band local RX path chainmask instead.

Fixes: e57b790146 ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Link: https://patch.msgid.link/20260727150434.1778520-9-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
ea891799ec wifi: mt76: mt7915: fix chainmask handling for non-dbdc phys on band 1
On single-adie mt7986 the only phy is bound to band 1, but its chainmask
is stored unshifted, because dev->chainshift is still zero while the
eeprom is parsed for the main phy. mt7915_set_antenna() on the other
hand shifts by chainshift * band_idx, so the representation of the
chainmask changed as soon as the antenna configuration was touched.
Until then, mt7915_mcu_set_chan_info() passed rx_path = 0 to the
firmware, since shifting the unshifted mask down clears all bits.

Keep the unshifted form for that case and add helpers for the band local
chainmask, so that only the band 1 phy of a dbdc device uses the shifted
form.

Fixes: 3eb50cc905 ("wifi: mt76: mt7915: rely on band_idx of mt76_phy")
Link: https://patch.msgid.link/20260727150434.1778520-8-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
6a4cabff12 wifi: mt76: mt7996: do not leave state behind after a failed WED attach
mt7996_mmio_wed_init() set dev->mt76.hwrro_mode and rx_token_size while
building the WED configuration, before knowing whether the WED attach
can succeed. A failed attach left the enlarged rx_token_size behind and
reset hwrro_mode to MT76_HWRRO_OFF, clobbering the values that another
RX datapath owner may have configured earlier in probe: on Airoha
platforms with the wed_enable module parameter set, this broke the NPU
offload configuration set up by mt76_npu_init() (NPU offload requires
HW-RRO and a larger rx token space, and the attach always fails there
since no SoC has both an Airoha NPU and MTK WED).

Move both assignments after a successful attach, next to the existing
success-only dma_dev/irq assignments. This is safe for the regular WED
attach case: the first consumer of either field runs after probe
continues (mtk_wed_device_attach() only invokes the init_buf callback;
rx buffers are allocated via init_rx_buf from mtk_wed_start(), long
after mt7996_mmio_wed_init() has returned).

Within the WED configuration the HW-RRO checks were constant: the mode
was assigned unconditionally right before them, and the hif2 path is
only reachable after a successful main attach has set it. Resolve them
to their constant values and drop the dead branches.

Fixes: 377aa17d2a ("wifi: mt76: mt7996: Add NPU offload support to MT7996 driver")
Link: https://patch.msgid.link/20260727150434.1778520-7-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
7c1924332e wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed
If the WED attach for the primary PCIe function fails, the probe path
still attached wed_hif2 for the secondary function, leaving the device
in an inconsistent half-WED configuration that crashes later. The hif2
call also re-enabled hwrro_mode, which the failed primary attach had
just turned off.

Skip the hif2 WED setup when the primary WED device is not active.

Fixes: 83eafc9251 ("wifi: mt76: mt7996: add wed tx support")
Link: https://patch.msgid.link/20260727150434.1778520-6-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
StanleyYP Wang
eb906eeff2 wifi: mt76: mt7996: fix reg addr remap when addr is 0
When addr is less than the hardcoded threshold in __mt7996_reg_addr,
it indicates that remapping is unnecessary.
Currently, the flow remaps address 0x0 to MT_HIF_REMAP_BASE_L2,
which is incorrect.
To address this, modify __mt7996_reg_addr to return INVALID_REG_ADDR
if the address is not below the hardcoded value or is not present in
the mt7996_reg_map array.
Additionally, update the remap condition to check if addr is equal to
INVALID_REG_ADDR.

Fixes: 3687854d3e ("wifi: mt76: mt7996: add locking for accessing mapped registers")
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Link: https://patch.msgid.link/20260727150434.1778520-5-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
8370aebd26 wifi: mt76: mt7915: release hif2 reference on probe IRQ failure
The hif2 reference obtained by mt7915_pci_init_hif2() is only released on
error paths that key off dev->hif2, which is not assigned until after the
IRQ setup. If pci_alloc_irq_vectors() or the primary devm_request_irq()
fails, the reference leaks. Drop it explicitly on those paths via
mt7915_put_hif2().

Fixes: f68d67623d ("mt76: mt7915: add Wireless Ethernet Dispatch support")
Link: https://patch.msgid.link/20260727150434.1778520-4-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
15b960014f wifi: mt76: mt7915: fix ext PHY use-after-free on register error path
After mt7915_register_ext_phy() succeeded, a failure of the main PHY
mt7915_init_debugfs() or mt7915_coredump_register() unwound through
free_phy2, which called ieee80211_free_hw() on the ext PHY hw while it
was still registered with mac80211, since mt76_unregister_device() only
unregisters the main hw. Unregister the ext PHY (thermal + phy + hw)
first and skip the redundant free.

Fixes: 7b8e1ae886 ("mt76: mt7915: rework hardware/phy initialization")
Link: https://patch.msgid.link/20260727150434.1778520-3-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
3ae8ad277e wifi: mt76: mt7915: fix double hif2 init on the non-WED path
mt7915_pci_init_hif2() was called unconditionally and again inside the
WED-inactive branch. The helper increments the global hif_idx, writes the
PCIe RECOG_ID register and takes a get_device() reference via
mt7915_pci_get_hif2(), while removal only drops one reference. On non-WED
dual-hif hardware this double-incremented hif_idx, wrote RECOG_ID twice and
leaked a device reference. Only the call inside the WED-inactive branch is
correct; drop the unconditional one. hif2 is already initialised to NULL.

Fixes: cacdd67812 ("mt76: mt7915: add mt7915_mmio_probe() as a common probing function")
Link: https://patch.msgid.link/20260727150434.1778520-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:43 +00:00
Felix Fietkau
d0b750072a wifi: mt76: mt7996: fix MIB TX aggregation counter registers for mt7990
The MIB_TSCR0-7 counters read by mt7996_mac_update_stats() are
hardcoded at the mt7996/mt7992 offsets 0x6b0-0x6d0, but mt7990 moved
them to 0x750-0x770, so TX AMPDU statistics were read from unrelated
registers on that chip. Move the offsets into the per-chip register
tables.

Fixes: f6c87411d1 ("wifi: mt76: mt7996: rework register mapping for mt7990")
Link: https://patch.msgid.link/20260727150434.1778520-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:42 +00:00
Chad Monroe
a3da1f2a3e wifi: mt76: mt7996: hold dev->mutex in remove_interface teardown
mt7996_remove_interface() destroys the remaining vif links, clearing
omac_mask, vif_mask and mld_idx_mask, with only the wiphy mutex held.
Those masks are modified under dev->mutex everywhere else, so the
unlocked clears can race the scan-link teardown and the reset work
and lose updates.

Take dev->mutex around the link destroy loop, matching
mt7996_add_interface() and mt7915_remove_interface(). The mutex is
released before mt76_vif_cleanup(), which aborts a pending scan and
takes the mutex itself.

Signed-off-by: Chad Monroe <chad@monroe.io>
Link: https://patch.msgid.link/20260724124813.3961474-29-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:42 +00:00
Chad Monroe
4c3cf4a8b1 wifi: mt76: serialize scan-link teardown with dev->mutex
The offchannel scan link is allocated in mt76_hw_scan() under
dev->mutex, but torn down without it: mt76_scan_complete() runs from
mt76_scan_work() on the mac80211 workqueue, or from mt76_abort_scan(),
and calls mt76_put_vif_phy_link(), whose vif_link_remove clears the
per-phy omac_mask and the device-wide vif_mask/mld_idx_mask with plain
read-modify-write. A vif link add or remove for another interface,
running concurrently under dev->mutex, can interleave with these
unlocked writes and lose an update: a cleared bit belonging to a live
link gets handed out again (two links sharing an omac/bss/wcid index,
breaking own-MAC unicast RX for the first one), or a freed bit stays
set until reboot and eventually exhausts the index space.

Take dev->mutex around the scan completion, mirroring the ROC teardown
in mt76_roc_complete_work()/mt76_abort_roc(), and switch the channel
restore to __mt76_set_channel() since the caller now holds the lock.
mt76_abort_scan() keeps cancelling the scan work before taking the
mutex, so the work-vs-abort ordering is unchanged.

Signed-off-by: Chad Monroe <chad@monroe.io>
Link: https://patch.msgid.link/20260724124813.3961474-28-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:42 +00:00
Felix Fietkau
6ff1c217a0 wifi: mt76: set MT76_SCANNING when starting a hw scan
The scan state bit is cleared by mt76_scan_complete(), but nothing ever
sets it: mt76_sw_scan() is only called for drivers without hw scan
support. As a result, all MT76_SCANNING checks are inert for drivers
using mt76_hw_scan(), including the DFS state handling in
mt76_phy_dfs_state() and the guard against manually triggered radar
detection while scanning.

Set the bit when the scan request is accepted. Since every channel
programmed while scanning now evaluates the DFS state as disabled and
stops the radar detector, re-program the operating channel at scan
completion regardless of the off-channel state, after the scanning bit
has been cleared. Otherwise a scan whose last visited channel was the
operating channel, or one that returned to it early because of
associated stations, would leave radar detection stopped until the
next channel switch.

Fixes: 31083e3854 ("wifi: mt76: add code for emulating hardware scanning")
Link: https://patch.msgid.link/20260724124813.3961474-27-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2026-08-01 14:49:42 +00:00