mac80211: brcmfmac: backport NVRAM loading improvements
authorRafał Miłecki <rafal@milecki.pl>
Wed, 7 Nov 2018 10:06:16 +0000 (11:06 +0100)
committerRafał Miłecki <rafal@milecki.pl>
Wed, 7 Nov 2018 10:11:08 +0000 (11:11 +0100)
This adds support for storing board specific NVRAM files as firmware.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
package/kernel/mac80211/patches/brcm/320-v4.21-0003-brcmfmac-Add-support-for-first-trying-to-get-a-board.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/320-v4.21-0004-brcmfmac-Set-board_type-used-for-nvram-file-selectio.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/320-v4.21-0005-brcmfmac-Set-board_type-from-DMI-on-x86-based-machin.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/320-v4.21-0006-brcmfmac-Cleanup-brcmf_fw_request_done.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/321-v4.21-0001-brcmfmac-Add-support-for-getting-nvram-contents-from.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/321-v4.21-0002-brcmfmac-Fix-ccode-from-EFI-nvram-when-necessary.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch
package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch

diff --git a/package/kernel/mac80211/patches/brcm/320-v4.21-0003-brcmfmac-Add-support-for-first-trying-to-get-a-board.patch b/package/kernel/mac80211/patches/brcm/320-v4.21-0003-brcmfmac-Add-support-for-first-trying-to-get-a-board.patch
new file mode 100644 (file)
index 0000000..727dcbe
--- /dev/null
@@ -0,0 +1,77 @@
+From eae8e50669e15002b195177212a6e25afbe7cf4d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../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];
+ };
diff --git a/package/kernel/mac80211/patches/brcm/320-v4.21-0004-brcmfmac-Set-board_type-used-for-nvram-file-selectio.patch b/package/kernel/mac80211/patches/brcm/320-v4.21-0004-brcmfmac-Set-board_type-used-for-nvram-file-selectio.patch
new file mode 100644 (file)
index 0000000..a33ceaa
--- /dev/null
@@ -0,0 +1,77 @@
+From 0ad4b55b2f29784f93875e6231bf57cd233624a2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ 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;
+ }
diff --git a/package/kernel/mac80211/patches/brcm/320-v4.21-0005-brcmfmac-Set-board_type-from-DMI-on-x86-based-machin.patch b/package/kernel/mac80211/patches/brcm/320-v4.21-0005-brcmfmac-Set-board_type-from-DMI-on-x86-based-machin.patch
new file mode 100644 (file)
index 0000000..25426e3
--- /dev/null
@@ -0,0 +1,179 @@
+From bd1e82bb420adf4ad7cd468d8a482cde622dd69d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../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 <hdegoede@redhat.com>
++ *
++ * 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;
++      }
++}
diff --git a/package/kernel/mac80211/patches/brcm/320-v4.21-0006-brcmfmac-Cleanup-brcmf_fw_request_done.patch b/package/kernel/mac80211/patches/brcm/320-v4.21-0006-brcmfmac-Cleanup-brcmf_fw_request_done.patch
new file mode 100644 (file)
index 0000000..211e9e4
--- /dev/null
@@ -0,0 +1,41 @@
+From 55e491edbf14b2da5419c2a319ea3b1d6368d9a2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ 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;
+       }
diff --git a/package/kernel/mac80211/patches/brcm/321-v4.21-0001-brcmfmac-Add-support-for-getting-nvram-contents-from.patch b/package/kernel/mac80211/patches/brcm/321-v4.21-0001-brcmfmac-Add-support-for-getting-nvram-contents-from.patch
new file mode 100644 (file)
index 0000000..88e5c67
--- /dev/null
@@ -0,0 +1,132 @@
+From ce2e6db554fad444fa0b3904fc3015336e0ef765 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../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;
diff --git a/package/kernel/mac80211/patches/brcm/321-v4.21-0002-brcmfmac-Fix-ccode-from-EFI-nvram-when-necessary.patch b/package/kernel/mac80211/patches/brcm/321-v4.21-0002-brcmfmac-Fix-ccode-from-EFI-nvram-when-necessary.patch
new file mode 100644 (file)
index 0000000..c2fd620
--- /dev/null
@@ -0,0 +1,97 @@
+From 29ec3394f0bd85c22674ab6693d92da5e2324610 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+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 <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../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);
index ed95e7a2407ba595eccc22ae7e3644124f559a75..574fcb40d773279c88f3ca0d68dc6220d17f016b 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
  }
 --- 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 <zajec5@gmail.com>
  };
  
  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 <zajec5@gmail.com>
        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 <zajec5@gmail.com>
        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 <zajec5@gmail.com>
  
        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);
  
index e7551c3a70368da98794e4d73869199c3d59e4dc..5bb701581083cf4f83b23158b9678438bc2a6950 100644 (file)
@@ -49,9 +49,9 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
  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);
 +