133 lines
3.7 KiB
Diff
133 lines
3.7 KiB
Diff
|
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;
|