From 29ec3394f0bd85c22674ab6693d92da5e2324610 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 11 Oct 2018 11:51:07 +0200 Subject: [PATCH] brcmfmac: Fix ccode from EFI nvram when necessary In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV" to specify "worldwide" compatible settings, but these 2 ccode-s do not work properly. I've tested the different known "worldwide" ccode-s used in various nvram sources with the latest firmwares from linux-firmware for various brcmfmac models, here is a simplified (*) table with what each setting results in: ALL: 12-14 disab, U-NII-1, U-NII-2 no-IR/radar, U-NII-3 XV: 12-14 no-IR, disables all 5G channels XY: 12-13 enab, 14 disab, U-NII-1 enab, U-NII-2 no-IR/radar, U-NII-3 disab X2: 12-13 no-IR, 14 dis, U-NII-1 no-IR, U-NII-2 no-IR/radar, U-NII-3 no-IR Where 12,13,14 are 2.4G channels 12-14 and U-NII-1/2/3 are the 3 different 5G channel groups. no-IR is no-Initiate-Radiation, we will never send on these channels without first having received valid wifi traffic there. This immediately shows that both ALL and XV are not as worldwide as we want them to be. ALL causes channels 12 and 13 to not be available and XV causes all 5GHz channels to not be available. Also ALL unconditionally enables the U-NII-1 and U-NII-3 5G groups, while we really should be using no-IR for these. This commit replace XV and ALL with X2, which allows usage of chan 12-13 and 5G channels, but only after receiving valid wifi traffic there first. Note that this configure the firmware's channel limits, the kernels own regulatory restrictions based on e.g. regulatory info received from the access-point, will be applied on top of this. This fixes channels 12+13 not working on the Asus T200TA and the Lenovo Mixx 2 8 and 5G channels not working on the Asus T100HA. This has been tested on the following models: Acer Iconia Tab8 w1-810, Acer One 10, Asus T100CHI, Asus T100HA, Asus T100TA, Asus T200TA and a Lenovo Mixx 2 8. *) There are some exceptions to this table: 1) On really old firmware e.g. linux-firmware's 2011 brcmfmac4330-sdio.bin ALL really means all, unconditionally enabling everything 2) The exact meaning might be influenced by setting the regrev nvram var. Specifically using ccode=XV + regrev=1 on brcmfmac43241b4 leads to: 12-14 no-ir, U-NII-1 no-ir, U-NII-2 no-ir/radar, U-NII-3 no-ir But only on the brcmfmac43241b4 and not on e.g. the brcmfmac43340 Tested-by: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/firmware.c | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -447,6 +447,29 @@ struct brcmf_fw { static void brcmf_fw_request_done(const struct firmware *fw, void *ctx); #ifdef CONFIG_EFI +/* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV" + * to specify "worldwide" compatible settings, but these 2 ccode-s do not work + * properly. "ccode=ALL" causes channels 12 and 13 to not be available, + * "ccode=XV" causes all 5GHz channels to not be available. So we replace both + * with "ccode=X2" which allows channels 12+13 and 5Ghz channels in + * no-Initiate-Radiation mode. This means that we will never send on these + * channels without first having received valid wifi traffic on the channel. + */ +static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len) +{ + char *ccode; + + ccode = strnstr((char *)data, "ccode=ALL", data_len); + if (!ccode) + ccode = strnstr((char *)data, "ccode=XV\r", data_len); + if (!ccode) + return; + + ccode[6] = 'X'; + ccode[7] = '2'; + ccode[8] = '\r'; +} + static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret) { const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 }; @@ -476,6 +499,7 @@ static u8 *brcmf_fw_nvram_from_efi(size_ if (err) goto fail; + brcmf_fw_fix_efi_nvram_ccode(data, data_len); brcmf_info("Using nvram EFI variable\n"); kfree(nvram_efivar);