BPI-R4 (MT7996/BE14): per-band WiFi 7 LEDs now work — incl. MLO

Another one off the list: the 2.4 / 5 / 6 GHz front LEDs now each light and blink on their own band's traffic.

Previously only the 2.4 GHz LED worked — the 5/6 GHz LEDs stayed dark (a known long-standing thing on BE14 cards). Under the single-wiphy MLO model the secondary bands never got their LED classdev registered, and a WARN_ON() fired at probe.

Fixed with two small generic mt76 driver patches (not board-specific — any MT7996/BE14 benefits):

  • wifi: mt76: share the throughput LED trigger across bands
  • wifi: mt76: mt7996: register a LED classdev for every band

Verified on BPI-R4 with single-band and active MLO clients. Already shipping as part of my BPI-R4 deploy system — both the standard and Pro 8X (X8) builds:
https://github.com/woziwrt/bpi-r4-deploy/releases

Submitted to mainline (linux-wireless):
lore: https://lore.kernel.org/linux-wireless/[email protected]/
patchwork: https://patchwork.kernel.org/project/linux-wireless/list/?series=1117621

6 Likes

Oh,you got the leds working with mlo?

Or is only one led working for all bands?

Yes — genuinely per-band, not one LED mirroring all. All three band LEDs register as separate classdevs (mt76-phy0 / mt76-phy0_1 / mt76-phy0_2), and each blinks on its own band's traffic.

Single-wiphy MLO was exactly the catch: all bands share one ieee80211_hw, so two things broke it —

  1. the throughput LED trigger is one-per-ieee80211_hw, so ieee80211_create_tpt_led_trigger() warned and handed the secondary bands a NULL trigger;
  2. mt7996 assigned the LED brightness_set/blink_set callbacks only to the primary (2.4 GHz) PHY, so mt76_led_init() bailed for 5/6 GHz and never registered their classdevs.

The two patches fix both: every band registers its own classdev and they share the one trigger.

The HW path was already per-band — mt7996_led_set_config() indexes MT_LED_EN()/MT_LED_CTRL() by mphy->band_idx, with MT_LED_CTRL_BLINK_BAND_SEL for band1 — so per-band hardware blink works the moment the classdev exists.

Tested on BE14 with single-band clients (traffic on one band lights only that band's LED) and an MLO client (the bands it's actually using blink).

1 Like

If i want to include these patches in my image, do i put them in mt76/patches or somewhere else ?

And can this also be applied to vanilla OpenWRT?

1 Like

Good morning @wozi, another masterclass, if they end up hiring you.

By the way, help them improve their new software; what a load of garbage they’ve created. I know there are only Chinese and English speakers, and they can’t even add languages, and on top of that, they restrict installation; you have to do it through the terminal, and only what they want. So, nothing they show and promise is open source. What the Banana team has created is a complete mess.

Thanks for showing the Banana team where the flaws are. You expose and teach, while they hide things without official repositories, lest the competition copy their ideas.

I prefer to keep using everything you do rather than their crap job.

Thanks for showing us something new.

Where are you, Banana team?

You could read this kind of thread instead of giving us software and a new product that’s mass-produced by removing the 6G band.

Great progress! And they’ll mass-produce it, and who knows, they might even give it to us for free.

Thanks for the masterclass.

@LS3480 Your instinct is right — they go into the mt76 package’s patches directory.

  • On the MTK SDK feed layout (what I build with) that’s: .../autobuild/unified/filogic/mac80211/25.12/files/package/kernel/mt76/patches/
  • On plain OpenWrt it’s: package/kernel/mt76/patches/

Grab both patches from the mainline submission (the lore link in the first post) and drop the two files in there. Give them a high number so they apply after the existing mt76 patches, e.g. 9999-w-mt7996-per-band-leds.patch and 9999-w-mt76-share-tpt-led-trigger.patch. Then make package/kernel/mt76/{clean,compile} (or a full rebuild) picks them up. There’s nothing board-specific — they apply to any MT7996/BE14 build.

If it’s easier, my BPI-R4 deploy images already ship both patches: Releases · woziwrt/bpi-r4-deploy · GitHub

@avbohemen Yes. Both patches are generic mt76 driver changes — nothing board- or SDK-specific — and they’re in the mainline linux-wireless review process, so they apply to vanilla OpenWrt’s mt76 the same way: drop them in package/kernel/mt76/patches/ and rebuild. You may need a small offset fixup if vanilla’s mt76 version differs from the one I build against, but there’s no dependency on the MTK SDK for the LED fix itself.

One caveat so I don’t oversell it: this only fixes the LEDs. Getting the full MT7996/BE14 WiFi 7 + MLO stack running on vanilla OpenWrt is a separate, much bigger topic — but the LED patches themselves are vanilla-friendly.

@Xiaomi_ax3600 Thanks for the kind words, much appreciated — glad it’s useful to you! I’ll keep sharing what I find and posting the patches openly so anyone can build on them. :slightly_smiling_face:

@wozi It looks like I also need this one: wifi: mt76: pass LED define via ccflags-y in driver submodules by mbc07 · Pull Request #1090 · openwrt/mt76 · GitHub for the BE14 card in OpenWRT. CONFIG_MT76_LEDS needs to be enabled and that was not the case for mt7996 yet. I will test it asap.

Ok, I can confirm it is working in vanilla OpenWRT. At the moment I do not care about MLO, I just have 3 SSIDs, 1 for each band, and they are working just fine. I adapted the PR I linked to in my previous post to the following:

cat package/kernel/mt76/patches/997-config-mt76-leds-mt7996.patch
--- a/mt7996/Makefile
+++ b/mt7996/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: BSD-3-Clause-Clear

+ccflags-y += -DCONFIG_MT76_LEDS
 obj-$(CONFIG_MT7996E) += mt7996e.o

 mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \

After that, the LEDs are working by default, no config needed. However, it is possible to add it to /etc/config/system (via LuCI is also possible):

edit: the LED names in sysfs are different from what you might expect: 2g is mt76-phy0_2; 5g is mt76-phy0; 6g is mt76-phy0_1. I hope they are registered in the same sequence after a reboot…

config led
        option name 'wifi_2g'
        option sysfs 'mt76-phy0_2'
        option trigger 'netdev'
        option dev 'phy0.0-ap0'
        list mode 'link'
        list mode 'tx'
        list mode 'rx'

config led
        option name 'wifi_5g'
        option sysfs 'mt76-phy0'
        option trigger 'netdev'
        option dev 'phy0.1-ap0'
        list mode 'link'
        list mode 'tx'
        list mode 'rx'

config led
        option name 'wifi_6g'
        option sysfs 'mt76-phy0_1'
        option trigger 'netdev'
        option dev 'phy0.2-ap0'
        list mode 'link'
        list mode 'tx'
        list mode 'rx'

@avbohemen Nice work getting it up on vanilla — and thanks for tracking down the missing piece. That’s exactly the part my earlier reply glossed over: on vanilla the mt7996 driver isn’t compiled with LED support at all, so my two patches have nothing to attach to until CONFIG_MT76_LEDS is enabled for it. mbc07’s PR #1090 (or your local ccflags-y += -DCONFIG_MT76_LEDS in mt7996/Makefile) is the right fix.

So the full vanilla recipe is: enable MT76_LEDS for mt7996 + the two mt76 patches → per-band LEDs. On the MTK SDK build I use, MT76_LEDS is already on, which is why the two patches alone were enough on my side — good to have the vanilla path documented for others.

On the LED names: your mapping is safe to rely on. The sysfs suffix (mt76-phy0 / _1 / _2) follows the driver’s phy/band registration order, which is fixed by band_idx at init — nothing dynamic, so it comes up identically after every reboot. It just isn’t in 2.4/5/6 order because band_idx follows the MT7996 internal band numbering (the base mt76-phy0 is the primary band, 5 GHz on this chip), not frequency. So your 2g=mt76-phy0_2 / 5g=mt76-phy0 / 6g=mt76-phy0_1 will stay put across reboots.

1 Like