Skip to content

Conversation

@danpawlik
Copy link
Contributor

Some Banana Pi BPI-R4 BE14 WiFi modules are shipped with zeroed tx_power fields in EEPROM (2G/5G/6G). This leads to low transmit power on affected bands.

Fallback to default values if invalid EEPROM content is detected.

Original patch was done in mt76 project [1].
Related to: #17489

[1] openwrt/mt76#954

@github-actions github-actions bot added the core packages pull request/issue for core (in-tree) packages label Jul 23, 2025
@danpawlik danpawlik force-pushed the port-eeprom-patch branch from 4ef19ef to 337a52b Compare July 23, 2025 15:25
Some Banana Pi BPI-R4 BE14 WiFi modules are shipped with zeroed
tx_power fields in EEPROM (2G/5G/6G). This leads to low transmit
power on affected bands.

Fallback to default values if invalid EEPROM content is detected.

Original patch was done in mt76 project [1].
Related to: openwrt#17489

[1] openwrt/mt76#954

Co-Authored-By: Yukari Yakumo <mistelinn@gmail.com>
Signed-off-by: Daniel Pawlik <pawlik.dan@gmail.com>
@danpawlik danpawlik force-pushed the port-eeprom-patch branch from 337a52b to 7c3448a Compare July 23, 2025 15:27
@danpawlik danpawlik changed the title Port patch from mt76 for "add tx_power check during eeprom loading" mediatek: port patch: add tx_power check during eeprom loading for BE14 Jul 23, 2025
@danpawlik
Copy link
Contributor Author

kindly ping @dangowrt what you think about that approach.

@leow149
Copy link

leow149 commented Jul 31, 2025

Any updates on this? @danpawlik @dangowrt

@danpawlik
Copy link
Contributor Author

danpawlik commented Aug 2, 2025

Kindly ping @nbd168
It's bad that we ping you directly - we know it. It is just a situation that many BE14 owners are just affected and we don't want to use custom builds to set properly tx power. Please understand us. Any feedback how it can be done better would be appreciated.

@KFOq
Copy link

KFOq commented Aug 10, 2025

@nbd168 @dangowrt @hauke
we appreciate your support to approve this patch

=====

thanks @danpawlik for following on this matter

@hauke hauke requested review from dangowrt and nbd168 August 10, 2025 18:44
@dangowrt
Copy link
Member

dangowrt commented Aug 10, 2025

Instead of creating a patch file in package/kernel/mt76/patches this patch should be sent upstream to the linux-wireless mailing list, merged into the wireless-next tree and then it can be picked into https://github.com/openwrt/mt76
Make sure to add Lorenzo and Felix in Cc, they are the maintainers of that driver and with their review this should go upstream.

@mhalano
Copy link
Contributor

mhalano commented Aug 10, 2025

@dangowrt I think that's why @danpawlik created a new patch for openwrt instead of the original one that was for mt76.
Since it's a problem caused by the manufacturer, I don't think the Linux kernel will accept since at kernel level there is not wrong, the same reason that mt76 mentioned.
But I think openwrt could accept since it's a problem that happens in the field.

@dangowrt
Copy link
Member

I don't think @nbd168 is willing to accept downstream patches on mt76. And as it is a "problem that happens in the field" that's a good argument for upstream Linux as well.

@mhalano
Copy link
Contributor

mhalano commented Aug 10, 2025

@dangowrt So maybe we could find a middle ground and keep it as a patch for OpenWrt directly as this PR is, without trying to get upstream on mt76 or the kernel?

@danpawlik
Copy link
Contributor Author

danpawlik commented Aug 10, 2025

@dangowrt there is also similar patch done in mt76 project -openwrt/mt76#968 - where in the commit message it seems it was sent to upstream already (or they mail in cc: Cc: stable@vger.kernel.org makes confusion), but can not find it. Also I don't see any commit in kernel, that I can assume it was merged.
What I mean here is, if the patch was sent to upstream already and it is not merged, don't believe any other would be approved.

@danpawlik
Copy link
Contributor Author

Kindly ping @yukariin as you are owner of that patch.
Also ping @im-0 as you have another patch proposed in mt76 project. May I ask if your patch was proposed to linux kernel?

@KFOq
Copy link

KFOq commented Aug 19, 2025

@yukariin @im-0. Please Your support

@danpawlik I believe we need to move from our side to get confirmation to add this patch

.....................
@dangowrt @nbd168 @hauke
Please your kindness support for this subject, based on my experience with Linux team is difficult to get their support on such things that has manufacturer fault

Im one of OpenWrt users who doesn't like to use customized build by other people ..I prefer the official one

Im sure the people are suffering from poor wifi performance on BPI-R4 because of this issue from long time , where the manufacturer left his hand and can't support or replace this defected wifi boards ...

In my humble opinion @openwrt team to add this patch under purposed file location for this device

This issue from 2024 until to now not solved and this patch will solve a huge issue..

Your support is highly appreciated by all members

@nbd168
Copy link
Member

nbd168 commented Sep 15, 2025

Sorry for not responding earlier. I believe this patch is incomplete, since the driver in those cases needs to merge data from flash or default bin with data from OTP. Also, I believe some support for external EEPROM may also be missing.
Once I have time to properly look into this, I will dig up the related patches from MTK's feed and upstream them.
Thank you for your patience.

@leow149
Copy link

leow149 commented Sep 15, 2025

Sorry for not responding earlier. I believe this patch is incomplete, since the driver in those cases needs to merge data from flash or default bin with data from OTP. Also, I believe some support for external EEPROM may also be missing.
Once I have time to properly look into this, I will dig up the related patches from MTK's feed and upstream them.
Thank you for your patience.

Great, thanks for looking into it :)

@pmarques
Copy link

Hi @nbd168 first of all thank you for all the amazing Openwrt work.

When you talk about External EEPROM, is that similar to this PR #20005 ?

I will dig up the related patches from MTK's feed and upstream them.

A few of us have been compiling the MTK Feed but we still need to hack / apply this patch to mt76 to make it work. The old mtk feed for Kernel 5.4 / Openwrt 21.04 seems to be using and mtd partition which is deprecated. Their doc also mentions a bin_file_name in the device tree but I don't think that's a available upstream #17489 (comment)

We may also be able to test a few things If you can share any pointers or guidance :)

@s09289728096
Copy link
Contributor

Ah, I shoulda make a upstream RP for it but I'm too busy to solve it.
Will be great if someone can give a hand.

@PancakeTAS
Copy link

I applied this patch to my kernel fork and while it did fix the limitation issue, it also slashed my speeds. Prior to patching I was able to get ~2100 Mbps on 6 GHz, and at the same time between 800 and 1600 Mbps on another device through 5 GHz. After the patch, the moment I start transfering from the second device, the 6 GHz device halves it's speed down to only 1000 Mbps and then both stay at that speed. That's a downgrade from ~3 Gbps to ~2 Gbps. I don't know how to properly debug this any further.

From what I understand this patch loads the default EEPROM from the firmware blob if the on-device EEPROM is filled with zeroes. I don't know what's stored on the EEPROM and I don't feel like it would be capable of slowing down operation. I did try artificially setting the 6 and 7 dB power limit back onto the 5 GHz band and 2.4 GHz band, but that didn't change anything.

Any ideas on what else could possibly cause this? I mean it makes no sense, right? These are two separate radios with two separate circuits and even processors, they shouldn't influence each other?

(I'll provide debug information when I find the time to)

@PancakeTAS
Copy link

I can't believe this dumb workaround actually works

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
index da3231c9a..406974c31 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
@@ -148,12 +148,23 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default)
 		goto out;
 	}
 
-	if (!use_default && mt7996_eeprom_variant_valid(dev, fw->data))
-		goto out;
-
-	dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
-	memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
-	dev->flash_mode = true;
+	// always use default tx power, regardless of use_default
+	eeprom[MT_EE_TX0_POWER_2G] = fw->data[MT_EE_TX0_POWER_2G];
+	eeprom[MT_EE_TX0_POWER_2G+1] = fw->data[MT_EE_TX0_POWER_2G+1];
+	eeprom[MT_EE_TX0_POWER_2G+2] = fw->data[MT_EE_TX0_POWER_2G+2];
+	eeprom[MT_EE_TX0_POWER_2G+3] = fw->data[MT_EE_TX0_POWER_2G+3];
+	eeprom[MT_EE_TX0_POWER_2G+4] = fw->data[MT_EE_TX0_POWER_2G+4];
+	eeprom[MT_EE_TX0_POWER_5G] = fw->data[MT_EE_TX0_POWER_5G];
+	eeprom[MT_EE_TX0_POWER_5G+1] = fw->data[MT_EE_TX0_POWER_5G+1];
+	eeprom[MT_EE_TX0_POWER_5G+2] = fw->data[MT_EE_TX0_POWER_5G+2];
+	eeprom[MT_EE_TX0_POWER_5G+3] = fw->data[MT_EE_TX0_POWER_5G+3];
+	eeprom[MT_EE_TX0_POWER_5G+4] = fw->data[MT_EE_TX0_POWER_5G+4];
+	eeprom[MT_EE_TX0_POWER_6G] = fw->data[MT_EE_TX0_POWER_6G];
+	eeprom[MT_EE_TX0_POWER_6G+1] = fw->data[MT_EE_TX0_POWER_6G+1];
+	eeprom[MT_EE_TX0_POWER_6G+2] = fw->data[MT_EE_TX0_POWER_6G+2];
+	eeprom[MT_EE_TX0_POWER_6G+3] = fw->data[MT_EE_TX0_POWER_6G+3];
+	eeprom[MT_EE_TX0_POWER_6G+4] = fw->data[MT_EE_TX0_POWER_6G+4];
 
 out:
 	release_firmware(fw);

Copies the transmit power, but nothing else. Seems to not slow down my network anymore. Someone who actually knows what the code does should probably take a look at this, not me.

@mhalano
Copy link
Contributor

mhalano commented Oct 13, 2025

Nice. I will try this patch as soon as possible. It seems not the best code, but if works...

@andreabravetti
Copy link

andreabravetti commented Oct 13, 2025

Copies the transmit power, but nothing else. Seems to not slow down my network anymore. Someone who actually knows what the code does should probably take a look at this, not me.

Isn't it like openwrt/mt76#968? are ranges correct? +4 for 5G and +8 for 6G? and 2G?

@Gilly1970
Copy link

@andreabravetti iwinfo confirms the correct power levels after adjusting, which does point to a different issue.

@mhalano
Copy link
Contributor

mhalano commented Oct 25, 2025

@Gilly1970 what is the difference between your patch and the original one from this PR? Which cases yours cover that the original don't?

@Gilly1970
Copy link

@mhalano The same code and logic from this PR is in this new patch, it's the second part of the fix that is a little different from the original.

This patch replaces tx_power zeros with default values from firmware
files while keeping the rest of the EEPROM data intact (including valid
6 GHz tx_power table).

The key differences, when it detects the zeros on the physical card, it sets use_default = true. This forces the driver to:

  1. Load the entire board "Default board-specific eeprom bin" file (mt7996_eeprom_233_2i5i6i.bin) into memory.
  2. Copy that entire file over the card's data into memory using memcpy.
  3. Run the fixup function, which then only modifies the 6GHz power values within that copied data, replacing them with the defaults from the main firmware.

So, the final state is: All data (antenna settings, calibration, 2.4/5GHz power) comes from the default firmware mt7996_eeprom_233_2i5i6i.bin, but the 6GHz power values are specifically corrected by the fixup function.

@mhalano
Copy link
Contributor

mhalano commented Oct 26, 2025

3. replacing them with the defaults from the main firmware.

What do you mean with "main firmware"? Did you mean the original eeprom? In my eeprom, you can see just the data for 2.4 and 5 GHz is zeroed, but for the 6GHz is present, and even it's the same as the default firmware (the .bin file you mentioned).

@Gilly1970
Copy link

Okay, When I say "main firmware," I'm referring to the core operational firmware for the Wi-Fi chip itself (e.g. files like mt7996_wa.bin, mt7996_wa_233.bin, mt7996_wm.bin or mt7996_wm__233.bin loaded by the kernel driver). This isn't one of the small mt7996_eeprom_233_2i5i6i.bin files. This is the actual operating system or microcode that runs on the Wi-Fi chip. It contains the driver logic and, crucially, compiled-in default calibration tables provided by MediaTek engineers. This is the source of truth for how the chip should behave and where the fix for 6GHz is coming from.

@mhalano
Copy link
Contributor

mhalano commented Oct 27, 2025

Why the values for 6GHz from mt7996_eeprom_233_2i5i6i.bin would be worse than the ones from files like mt7996_wa.bin, mt7996_wa_233.bin, mt7996_wm.bin or mt7996_wm__233.bin if all the files should come from MTK?
Did you compare the values?

@Gilly1970
Copy link

We know they must be different the patch's logic relies on comparing the EEPROM values to the internal defaults (def) and only performs the override if they differ. Since the override is happening (patch restore tx power control), the internal defaults must different from the values we are seeing.

Did you compare the values?

No, the internal default tables are a lot more complex. Without knowing the exact tables and not possessing the revers engineering skills needed, I only have the patch's logic 🗝️

@mhalano
Copy link
Contributor

mhalano commented Oct 27, 2025

As I see, we first overwrite all the eeprom from the board when we are using use_default = true, which will select the proper *eeprom*.bin file that should be used, and again in the fixup function against def, but I think, please prove me wrong, that def is already applied when we set use_default = true. Am I wrong?

Also, could you please clarify what you mean with "patch restore tx power control"? As far as I know, that's another problem where we cannot change the tx power for real, just in the CLI/GUI.

EDIT: Let me add more code in my comment.
First, the function mt7996_eeprom_load is called. There, we use content from dev->mt76.eeprom.data, which is the eeprom from the board, to check if any definition of TX power is empty.
If yes, we set use_default to true and then go to out, and then call another function, mt7996_eeprom_check_or_use_default, and that calls your function mt7996_eeprom_fixup_tx_power, which receives the content of the firmware (I don't know what file specifically), and uses default values.
Then the function runs and writes the data in the "eeprom" (the memory, not the chip).
But now you are back to `mt7996_eeprom_check_or_use_default``, and there exists an if condition:

        if (!use_default && mt7996_eeprom_variant_valid(dev, fw->data))
                goto out;

Since use_default it stills true, it won't go to out, and the next step is to write the default eeprom all over everything:

        dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
        memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
        dev->flash_mode = true;

What I think is that in your function you had trouble writing some values, but after that, everything will be verwritten.

What do you think?

@pmarques
Copy link

Not sure if you came around this but there are 2 versions of the patch for the TX power limitation which I believe are very similar to what you are discussing although I may be missing some context.

@mhalano
Copy link
Contributor

mhalano commented Oct 27, 2025

@pmarques The first one is the same as the one from this PR. The second one doesn't work as should because it just adds the correct values for TX power, but the signal strength is weak.
We are trying to create something that works 100%, but I think we should use the patch from this PR, and then look why we can't change the TX power correctly.

@Gilly1970
Copy link

@mhalano Can you please show me your debug where this patch is actually failing?

I'm just not getting the same results as you but that's most likely because I'm actually using a stable MTK build for confirmation this fix works, using the latest snapshot which has more bugs than my local bait store isn't the best test case.

@mhalano
Copy link
Contributor

mhalano commented Oct 28, 2025

@Gilly1970 Besides can't reducing the TX power, which I think it's another problem, it's ok, but I think technically there is no difference between your patch and the one from the PR, since the fixup function is overwritten in the end.

@Gilly1970
Copy link

Gilly1970 commented Oct 28, 2025

I think technically there is no difference between your patch and the one from the PR, since the fixup function is overwritten in the end.

If that's the case then you don't need my patch or me. I've put the two original patches together for you to save you the time doing it your self, which according to you is technically exactly the same. You technically should have the same outcome as my patch. 9999-original-EEPROM-0s.patch

For anyone that wants an actual working patch you will find it in my repo which I will keep up to date until we get an official one.

@mhalano
Copy link
Contributor

mhalano commented Oct 28, 2025

@Gilly1970 You are very helpful, but about these patches, they are alternatives, so should use either one or the other, not both at the same time because they do the same in different ways.
My problem is just using both patches together since they are not complementary in nature.
Together we find a lot of new informations, like the TX power control not working at all, the values for the eeprom and also the firmwares... We should keep working together, but I don't think a merge between both patches would be a valid patch to indicate others to use. Got it? It's not personal, just a technical matter.

@mhalano
Copy link
Contributor

mhalano commented Oct 28, 2025

One thing that could work, and I will try later, is adding dev->flash_mode = true; to the fixup function.
The fixup function changes the values, but they are not being used, and remove the use_default=true part. The idea is just rewrite the bits that are empty, and not the whole eeprom.
The problem with the previous patch that does that is the signal strength is very weak, even the reported values are correct.
And that's the other problem about can't change the tx power for real.

@Critter74
Copy link

When will this patch finally be integrated? It can't be that difficult to just press the merge button, can it?

@lexfrei
Copy link

lexfrei commented Jan 2, 2026

@Critter74 don't be rude. The problem is not the code. The problem is the architecture. There is no place for this code in openwork's upstream. If you need this patch — feel free to use ImmortalWRT

@mhalano
Copy link
Contributor

mhalano commented Jan 2, 2026

@lexfrei What is a good place to put the code? It can't be added upstream because the problem is with the vendor, but for some reason OpenWrt also doesn't want to add it.

@Critter74
Copy link

Critter74 commented Jan 2, 2026

Yeah, sorry, but I just can't understand it. I'm guessing the maintainers don't have the BL14 hardware and therefore have no reason to press the merge button.

Yes, okay, it's a workaround. But these aren't uncommon. Just look at those buggy x86 processors, especially the Intel ones. Even though Intel and AMD fixed the firmware, there are also patches in the Linux kernel. Nobody told you to buy a CPU that doesn't have this bug.

That's why I can't understand this approach. This patch doesn't harm users who have a Wi-Fi module that doesn't have these errors.

By the way, the patch included with ImmortalWrt is different. This one doesn't work. I already tried it with OpenWrt. You can set a higher Wi-Fi bandwidth, but in practice, it doesn't increase the Wi-Fi performance.

@lexfrei
Copy link

lexfrei commented Jan 2, 2026

Let me summarize why this patch doesn't belong in upstream (neither OpenWrt, mt76, nor the Linux kernel):

1. This is defective hardware, not a driver bug

The mt76 driver works correctly — it reads EEPROM data as designed. The problem is that SinoVoip/Banana Pi shipped boards with empty or garbage EEPROM. This is a manufacturing defect: the calibration data that should be burned into the chip at the factory is either missing (zeros) or corrupted. The Linux kernel and OpenWrt shouldn't accumulate vendor-specific workarounds for every piece of defective hardware that makes it to market.

2. The patch is incomplete

As @nbd168 noted, proper handling requires merging OTP data with flash/default bin, plus external EEPROM support. The current patch is a sledgehammer that either blindly replaces zeros or unconditionally overwrites 6GHz values — neither approach is architecturally correct.

3. Regulatory concerns

Hardcoding TX power values from a generic firmware blob, regardless of actual hardware calibration, can result in non-compliant transmission power levels. Upstream maintainers are rightfully cautious about accepting patches with regulatory implications.

4. The proper solution hasn't materialized

@nbd168 mentioned willingness to upstream correct patches from MTK's feed, but that was months ago and nothing has happened. PR #968 in mt76 remains open since March 2025. This is understandable — maintainers are volunteers with limited time — but it means the "wait for proper upstream fix" path has no concrete timeline.


@mhalano

What is a good place to put the code?

For vendor-specific hardware workarounds that don't meet upstream standards, the options are:

  1. Downstream distributions like ImmortalWRT, which explicitly carry such patches
  2. Local builds with patches in package/kernel/mt76/patches/
  3. Vendor SDK builds (MTK feed) where this reportedly works better

The upstream path (linux-wireless → wireless-next → mt76 → OpenWrt) exists, but requires a proper implementation — not a sledgehammer fix for defective EEPROM.


@Critter74

Just look at those buggy x86 processors, especially the Intel ones. Even though Intel and AMD fixed the firmware, there are also patches in the Linux kernel.

This comparison doesn't hold:

  1. Intel/AMD microcode updates are official vendor fixes for security vulnerabilities (Spectre, Meltdown, etc.) affecting hundreds of millions of systems. Intel provides these through official channels. The kernel just loads them.

  2. This is not a chip bug — it's defective EEPROM data. The MT7996 chip works fine. The problem is that the factory didn't properly burn calibration data into the EEPROM. Intel microcode fixes actual silicon errata; this patch works around missing factory calibration.

  3. Scale matters: CPU security bugs affect critical infrastructure worldwide. A batch of BE14 cards with bad EEPROM affects a small group of hobbyists.

  4. No vendor acknowledgment: Intel publishes microcode updates. SinoVoip/Banana Pi hasn't acknowledged the EEPROM issue or provided a fix.

  5. The patch is incomplete and has regulatory implications: Blindly loading generic TX power values without proper calibration can result in non-compliant transmission levels.


Regarding ImmortalWRT patch not working for you — that's actually proving the point. There are multiple patch variants floating around (zeros-only fix, unconditional 6GHz override, full EEPROM replacement), each with different trade-offs and failure modes. This fragmentation exists precisely because nobody has done the proper architectural work that @nbd168 outlined.

@mhalano
Copy link
Contributor

mhalano commented Jan 2, 2026

@lexfrei What do you think a non-sladgehammer approach like this patch? https://github.com/openwrt/mt76/pull/968/files
It replaces just the empty values. The problem is patch isn't working as should because it doesn't write the eeprom that was changed, so even it starts appearing the correct values on LuCi, the TX power doesn't increase, I as could measure.
Here is a comment I made about it: #19503 (comment)
If you want, I can create a PR that creates a .patch file, so no upstream changes, and does this approach just replacing the values that are empty.

@mhalano
Copy link
Contributor

mhalano commented Jan 2, 2026

@danpawlik Why did you close the PR?

@lexfrei
Copy link

lexfrei commented Jan 2, 2026

@mhalano I don't have any authority here — I'm not an OpenWrt or mt76 maintainer. I just tried to explain why this isn't a simple "press merge" situation.

As a maintainer of other projects, the "just press the button, how hard can it be?" attitude hits close to home. That's why I felt the need to respond.

I don't even own this hardware — I was just helping a friend set up her router. We ended up using ImmortalWRT with the patch, and that's how I got subscribed to these upstream PRs/issues.

For the technical questions about PR #968 and why patched values don't affect actual TX power — that's for @nbd168 or someone who understands mt76 internals.

@danpawlik
Copy link
Contributor Author

danpawlik commented Jan 2, 2026

@mhalano that's a good question - I did not close it. I even can not reopen it.

EDIT:
I was cleaning up my repository, so by mistake I remove the branch. Trying to restore...

@danpawlik danpawlik restored the port-eeprom-patch branch January 2, 2026 17:19
@danpawlik danpawlik reopened this Jan 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core packages pull request/issue for core (in-tree) packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.