Browse Source

mac80211: brcmfmac: backport NVRAM loading improvements

This adds support for storing board specific NVRAM files as firmware.

Signed-off-by: Rafał Miłecki <[email protected]>
Rafał Miłecki 7 years ago
parent
commit
3eab6b8275

+ 77 - 0
package/kernel/mac80211/patches/brcm/320-v4.21-0003-brcmfmac-Add-support-for-first-trying-to-get-a-board.patch

@@ -0,0 +1,77 @@
+From eae8e50669e15002b195177212a6e25afbe7cf4d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+Date: Wed, 10 Oct 2018 13:01:00 +0200
+Subject: [PATCH] brcmfmac: Add support for first trying to get a board
+ specific nvram file
+
+The nvram files which some brcmfmac chips need are board-specific. To be
+able to distribute these as part of linux-firmware, so that devices with
+such a wifi chip will work OOTB, multiple (one per board) versions must
+co-exist under /lib/firmware.
+
+This commit adds support for callers of the brcmfmac/firmware.c code to
+pass in a board_type parameter through the request structure.
+
+If that parameter is set then the code will first try to load
+chipmodel.board_type.txt before falling back to the old chipmodel.txt name.
+
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ .../broadcom/brcm80211/brcmfmac/firmware.c         | 27 +++++++++++++++++++++-
+ .../broadcom/brcm80211/brcmfmac/firmware.h         |  1 +
+ 2 files changed, 27 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -532,6 +532,31 @@ static int brcmf_fw_complete_request(con
+ 	return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
+ }
+ 
++static int brcmf_fw_request_firmware(const struct firmware **fw,
++				     struct brcmf_fw *fwctx)
++{
++	struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
++	int ret;
++
++	/* nvram files are board-specific, first try a board-specific path */
++	if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
++		char alt_path[BRCMF_FW_NAME_LEN];
++
++		strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN);
++		/* strip .txt at the end */
++		alt_path[strlen(alt_path) - 4] = 0;
++		strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
++		strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
++		strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
++
++		ret = request_firmware(fw, alt_path, fwctx->dev);
++		if (ret == 0)
++			return ret;
++	}
++
++	return request_firmware(fw, cur->path, fwctx->dev);
++}
++
+ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
+ {
+ 	struct brcmf_fw *fwctx = ctx;
+@@ -544,7 +569,7 @@ static void brcmf_fw_request_done(const
+ 
+ 	while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
+ 		cur = &fwctx->req->items[fwctx->curpos];
+-		request_firmware(&fw, cur->path, fwctx->dev);
++		brcmf_fw_request_firmware(&fw, fwctx);
+ 		ret = brcmf_fw_complete_request(fw, ctx);
+ 	}
+ 
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+@@ -70,6 +70,7 @@ struct brcmf_fw_request {
+ 	u16 domain_nr;
+ 	u16 bus_nr;
+ 	u32 n_items;
++	const char *board_type;
+ 	struct brcmf_fw_item items[0];
+ };
+ 

+ 77 - 0
package/kernel/mac80211/patches/brcm/320-v4.21-0004-brcmfmac-Set-board_type-used-for-nvram-file-selectio.patch

@@ -0,0 +1,77 @@
+From 0ad4b55b2f29784f93875e6231bf57cd233624a2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+Date: Wed, 10 Oct 2018 13:01:01 +0200
+Subject: [PATCH] brcmfmac: Set board_type used for nvram file selection to
+ machine-compatible
+
+For of/devicetree using machines, set the board_type used for nvram file
+selection to the first string listed in the top-level's node compatible
+string, aka the machine-compatible as used by of_machine_is_compatible().
+
+The board_type setting is used to load the board-specific nvram file with
+a board-specific name so that we can ship files for each supported board
+in linux-firmware.
+
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h |  1 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c     | 11 ++++++++++-
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c   |  1 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c   |  1 +
+ 4 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+@@ -59,6 +59,7 @@ struct brcmf_mp_device {
+ 	bool		iapp;
+ 	bool		ignore_probe_fail;
+ 	struct brcmfmac_pd_cc *country_codes;
++	const char	*board_type;
+ 	union {
+ 		struct brcmfmac_sdio_pd sdio;
+ 	} bus;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+@@ -27,11 +27,20 @@ void brcmf_of_probe(struct device *dev,
+ 		    struct brcmf_mp_device *settings)
+ {
+ 	struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
+-	struct device_node *np = dev->of_node;
++	struct device_node *root, *np = dev->of_node;
++	struct property *prop;
+ 	int irq;
+ 	u32 irqf;
+ 	u32 val;
+ 
++	/* Set board-type to the first string of the machine compatible prop */
++	root = of_find_node_by_path("/");
++	if (root) {
++		prop = of_find_property(root, "compatible", NULL);
++		settings->board_type = of_prop_next_string(prop, NULL);
++		of_node_put(root);
++	}
++
+ 	if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
+ 	    !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
+ 		return;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1785,6 +1785,7 @@ brcmf_pcie_prepare_fw_request(struct brc
+ 	fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+ 	fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+ 	fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
++	fwreq->board_type = devinfo->settings->board_type;
+ 	/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
+ 	fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
+ 	fwreq->bus_nr = devinfo->pdev->bus->number;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4174,6 +4174,7 @@ brcmf_sdio_prepare_fw_request(struct brc
+ 
+ 	fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+ 	fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
++	fwreq->board_type = bus->sdiodev->settings->board_type;
+ 
+ 	return fwreq;
+ }

+ 179 - 0
package/kernel/mac80211/patches/brcm/320-v4.21-0005-brcmfmac-Set-board_type-from-DMI-on-x86-based-machin.patch

@@ -0,0 +1,179 @@
+From bd1e82bb420adf4ad7cd468d8a482cde622dd69d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+Date: Wed, 10 Oct 2018 13:01:02 +0200
+Subject: [PATCH] brcmfmac: Set board_type from DMI on x86 based machines
+
+For x86 based machines, set the board_type used for nvram file selection
+based on the DMI sys-vendor and product-name strings.
+
+Since on some models these strings are too generic, this commit also adds
+a quirk table overriding the strings for models listed in that table.
+
+The board_type setting is used to load the board-specific nvram file with
+a board-specific name so that we can ship files for each supported board
+in linux-firmware.
+
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/Makefile  |   2 +
+ .../wireless/broadcom/brcm80211/brcmfmac/common.c  |   3 +-
+ .../wireless/broadcom/brcm80211/brcmfmac/common.h  |   7 ++
+ .../net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 116 +++++++++++++++++++++
+ 4 files changed, 127 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+@@ -54,3 +54,5 @@ brcmfmac-$(CPTCFG_BRCM_TRACING) += \
+ 		tracepoint.o
+ brcmfmac-$(CONFIG_OF) += \
+ 		of.o
++brcmfmac-$(CONFIG_DMI) += \
++		dmi.o
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+@@ -448,8 +448,9 @@ struct brcmf_mp_device *brcmf_get_module
+ 		}
+ 	}
+ 	if (!found) {
+-		/* No platform data for this device, try OF (Open Firwmare) */
++		/* No platform data for this device, try OF and DMI data */
+ 		brcmf_of_probe(dev, bus_type, settings);
++		brcmf_dmi_probe(settings, chip, chiprev);
+ 	}
+ 	return settings;
+ }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+@@ -75,4 +75,11 @@ void brcmf_release_module_param(struct b
+ /* Sets dongle media info (drv_version, mac address). */
+ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+ 
++#ifdef CONFIG_DMI
++void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev);
++#else
++static inline void
++brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
++#endif
++
+ #endif /* BRCMFMAC_COMMON_H */
+--- /dev/null
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright 2018 Hans de Goede <[email protected]>
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/dmi.h>
++#include <linux/mod_devicetable.h>
++#include "core.h"
++#include "common.h"
++#include "brcm_hw_ids.h"
++
++/* The DMI data never changes so we can use a static buf for this */
++static char dmi_board_type[128];
++
++struct brcmf_dmi_data {
++	u32 chip;
++	u32 chiprev;
++	const char *board_type;
++};
++
++/* NOTE: Please keep all entries sorted alphabetically */
++
++static const struct brcmf_dmi_data gpd_win_pocket_data = {
++	BRCM_CC_4356_CHIP_ID, 2, "gpd-win-pocket"
++};
++
++static const struct brcmf_dmi_data jumper_ezpad_mini3_data = {
++	BRCM_CC_43430_CHIP_ID, 0, "jumper-ezpad-mini3"
++};
++
++static const struct brcmf_dmi_data meegopad_t08_data = {
++	BRCM_CC_43340_CHIP_ID, 2, "meegopad-t08"
++};
++
++static const struct dmi_system_id dmi_platform_data[] = {
++	{
++		/* Match for the GPDwin which unfortunately uses somewhat
++		 * generic dmi strings, which is why we test for 4 strings.
++		 * Comparing against 23 other byt/cht boards, board_vendor
++		 * and board_name are unique to the GPDwin, where as only one
++		 * other board has the same board_serial and 3 others have
++		 * the same default product_name. Also the GPDwin is the
++		 * only device to have both board_ and product_name not set.
++		 */
++		.matches = {
++			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
++			DMI_MATCH(DMI_BOARD_NAME, "Default string"),
++			DMI_MATCH(DMI_BOARD_SERIAL, "Default string"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
++		},
++		.driver_data = (void *)&gpd_win_pocket_data,
++	},
++	{
++		/* Jumper EZpad mini3 */
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
++			/* jumperx.T87.KFBNEEA02 with the version-nr dropped */
++			DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
++		},
++		.driver_data = (void *)&jumper_ezpad_mini3_data,
++	},
++	{
++		/* Meegopad T08 */
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
++			DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
++			DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
++		},
++		.driver_data = (void *)&meegopad_t08_data,
++	},
++	{}
++};
++
++void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev)
++{
++	const struct dmi_system_id *match;
++	const struct brcmf_dmi_data *data;
++	const char *sys_vendor;
++	const char *product_name;
++
++	/* Some models have DMI strings which are too generic, e.g.
++	 * "Default string", we use a quirk table for these.
++	 */
++	for (match = dmi_first_match(dmi_platform_data);
++	     match;
++	     match = dmi_first_match(match + 1)) {
++		data = match->driver_data;
++
++		if (data->chip == chip && data->chiprev == chiprev) {
++			settings->board_type = data->board_type;
++			return;
++		}
++	}
++
++	/* Not found in the quirk-table, use sys_vendor-product_name */
++	sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
++	product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
++	if (sys_vendor && product_name) {
++		snprintf(dmi_board_type, sizeof(dmi_board_type), "%s-%s",
++			 sys_vendor, product_name);
++		settings->board_type = dmi_board_type;
++	}
++}

+ 41 - 0
package/kernel/mac80211/patches/brcm/320-v4.21-0006-brcmfmac-Cleanup-brcmf_fw_request_done.patch

@@ -0,0 +1,41 @@
+From 55e491edbf14b2da5419c2a319ea3b1d6368d9a2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+Date: Wed, 10 Oct 2018 13:01:03 +0200
+Subject: [PATCH] brcmfmac: Cleanup brcmf_fw_request_done()
+
+The "cur" variable is now only used for a debug print and we already
+print the same info from brcmf_fw_complete_request(), so the debug print
+does not provide any extra info and we can remove it.
+
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -560,22 +560,16 @@ static int brcmf_fw_request_firmware(con
+ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
+ {
+ 	struct brcmf_fw *fwctx = ctx;
+-	struct brcmf_fw_item *cur;
+-	int ret = 0;
+-
+-	cur = &fwctx->req->items[fwctx->curpos];
++	int ret;
+ 
+ 	ret = brcmf_fw_complete_request(fw, fwctx);
+ 
+ 	while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
+-		cur = &fwctx->req->items[fwctx->curpos];
+ 		brcmf_fw_request_firmware(&fw, fwctx);
+ 		ret = brcmf_fw_complete_request(fw, ctx);
+ 	}
+ 
+ 	if (ret) {
+-		brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
+-			  dev_name(fwctx->dev), cur->path);
+ 		brcmf_fw_free_request(fwctx->req);
+ 		fwctx->req = NULL;
+ 	}

+ 132 - 0
package/kernel/mac80211/patches/brcm/321-v4.21-0001-brcmfmac-Add-support-for-getting-nvram-contents-from.patch

@@ -0,0 +1,132 @@
+From ce2e6db554fad444fa0b3904fc3015336e0ef765 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+Date: Thu, 11 Oct 2018 11:51:06 +0200
+Subject: [PATCH] brcmfmac: Add support for getting nvram contents from EFI
+ variables
+
+Various X86 laptops with a SDIO attached brcmfmac wifi chip, store the
+nvram contents in a special EFI variable. This commit adds support for
+getting nvram directly from this EFI variable, without the user needing
+to manually copy it.
+
+This makes Wifi / Bluetooth work out of the box on these devices instead of
+requiring manual setup.
+
+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.
+
+Tested-by: Hans de Goede <[email protected]>
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ .../broadcom/brcm80211/brcmfmac/firmware.c         | 63 +++++++++++++++++++---
+ 1 file changed, 57 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -14,6 +14,7 @@
+  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  */
+ 
++#include <linux/efi.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/device.h>
+@@ -445,6 +446,51 @@ struct brcmf_fw {
+ 
+ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
+ 
++#ifdef CONFIG_EFI
++static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
++{
++	const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
++	struct efivar_entry *nvram_efivar;
++	unsigned long data_len = 0;
++	u8 *data = NULL;
++	int err;
++
++	nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
++	if (!nvram_efivar)
++		return NULL;
++
++	memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
++	nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
++						0xb5, 0x1f, 0x43, 0x26,
++						0x81, 0x23, 0xd1, 0x13);
++
++	err = efivar_entry_size(nvram_efivar, &data_len);
++	if (err)
++		goto fail;
++
++	data = kmalloc(data_len, GFP_KERNEL);
++	if (!data)
++		goto fail;
++
++	err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
++	if (err)
++		goto fail;
++
++	brcmf_info("Using nvram EFI variable\n");
++
++	kfree(nvram_efivar);
++	*data_len_ret = data_len;
++	return data;
++
++fail:
++	kfree(data);
++	kfree(nvram_efivar);
++	return NULL;
++}
++#else
++static u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
++#endif
++
+ static void brcmf_fw_free_request(struct brcmf_fw_request *req)
+ {
+ 	struct brcmf_fw_item *item;
+@@ -463,11 +509,12 @@ static int brcmf_fw_request_nvram_done(c
+ {
+ 	struct brcmf_fw *fwctx = ctx;
+ 	struct brcmf_fw_item *cur;
++	bool free_bcm47xx_nvram = false;
++	bool kfree_nvram = false;
+ 	u32 nvram_length = 0;
+ 	void *nvram = NULL;
+ 	u8 *data = NULL;
+ 	size_t data_len;
+-	bool raw_nvram;
+ 
+ 	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
+ 
+@@ -476,12 +523,13 @@ static int brcmf_fw_request_nvram_done(c
+ 	if (fw && fw->data) {
+ 		data = (u8 *)fw->data;
+ 		data_len = fw->size;
+-		raw_nvram = false;
+ 	} else {
+-		data = bcm47xx_nvram_get_contents(&data_len);
+-		if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
++		if ((data = bcm47xx_nvram_get_contents(&data_len)))
++			free_bcm47xx_nvram = true;
++		else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
++			kfree_nvram = true;
++		else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+ 			goto fail;
+-		raw_nvram = true;
+ 	}
+ 
+ 	if (data)
+@@ -489,8 +537,11 @@ static int brcmf_fw_request_nvram_done(c
+ 					     fwctx->req->domain_nr,
+ 					     fwctx->req->bus_nr);
+ 
+-	if (raw_nvram)
++	if (free_bcm47xx_nvram)
+ 		bcm47xx_nvram_release_contents(data);
++	if (kfree_nvram)
++		kfree(data);
++
+ 	release_firmware(fw);
+ 	if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+ 		goto fail;

+ 97 - 0
package/kernel/mac80211/patches/brcm/321-v4.21-0002-brcmfmac-Fix-ccode-from-EFI-nvram-when-necessary.patch

@@ -0,0 +1,97 @@
+From 29ec3394f0bd85c22674ab6693d92da5e2324610 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <[email protected]>
+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 <[email protected]>
+Signed-off-by: Hans de Goede <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+ .../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);

+ 5 - 5
package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch

@@ -23,7 +23,7 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  }
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-@@ -441,6 +441,7 @@ struct brcmf_fw {
+@@ -442,6 +442,7 @@ struct brcmf_fw {
  	struct brcmf_fw_request *req;
  	u32 curpos;
  	void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
@@ -31,7 +31,7 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  };
  
  static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
-@@ -555,6 +556,8 @@ static void brcmf_fw_request_done(const
+@@ -649,6 +650,8 @@ static void brcmf_fw_request_done(const
  		fwctx->req = NULL;
  	}
  	fwctx->done(fwctx->dev, ret, fwctx->req);
@@ -40,7 +40,7 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  	kfree(fwctx);
  }
  
-@@ -579,6 +582,7 @@ int brcmf_fw_get_firmwares(struct device
+@@ -673,6 +676,7 @@ int brcmf_fw_get_firmwares(struct device
  {
  	struct brcmf_fw_item *first = &req->items[0];
  	struct brcmf_fw *fwctx;
@@ -48,7 +48,7 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  	int ret;
  
  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
-@@ -595,6 +599,9 @@ int brcmf_fw_get_firmwares(struct device
+@@ -689,6 +693,9 @@ int brcmf_fw_get_firmwares(struct device
  	fwctx->dev = dev;
  	fwctx->req = req;
  	fwctx->done = fw_cb;
@@ -58,7 +58,7 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  
  	ret = request_firmware_nowait(THIS_MODULE, true, first->path,
  				      fwctx->dev, GFP_KERNEL, fwctx,
-@@ -602,6 +609,9 @@ int brcmf_fw_get_firmwares(struct device
+@@ -696,6 +703,9 @@ int brcmf_fw_get_firmwares(struct device
  	if (ret < 0)
  		brcmf_fw_request_done(NULL, fwctx);
  

+ 3 - 3
package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch

@@ -49,9 +49,9 @@ Signed-off-by: Rafał Miłecki <[email protected]>
  void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
  		    struct brcmf_mp_device *settings)
  {
-@@ -32,6 +62,8 @@ void brcmf_of_probe(struct device *dev,
- 	u32 irqf;
- 	u32 val;
+@@ -41,6 +71,8 @@ void brcmf_of_probe(struct device *dev,
+ 		of_node_put(root);
+ 	}
  
 +	brcmf_of_probe_cc(dev, settings);
 +