88e5c67735b63d990ffbe66d46867eb02e9f832d
[oweals/openwrt.git] /
1 From ce2e6db554fad444fa0b3904fc3015336e0ef765 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Thu, 11 Oct 2018 11:51:06 +0200
4 Subject: [PATCH] brcmfmac: Add support for getting nvram contents from EFI
5  variables
6
7 Various X86 laptops with a SDIO attached brcmfmac wifi chip, store the
8 nvram contents in a special EFI variable. This commit adds support for
9 getting nvram directly from this EFI variable, without the user needing
10 to manually copy it.
11
12 This makes Wifi / Bluetooth work out of the box on these devices instead of
13 requiring manual setup.
14
15 This has been tested on the following models: Acer Iconia Tab8 w1-810,
16 Acer One 10, Asus T100CHI, Asus T100HA, Asus T100TA, Asus T200TA and a
17 Lenovo Mixx 2 8.
18
19 Tested-by: Hans de Goede <hdegoede@redhat.com>
20 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
21 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
22 ---
23  .../broadcom/brcm80211/brcmfmac/firmware.c         | 63 +++++++++++++++++++---
24  1 file changed, 57 insertions(+), 6 deletions(-)
25
26 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
27 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
28 @@ -14,6 +14,7 @@
29   * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30   */
31  
32 +#include <linux/efi.h>
33  #include <linux/kernel.h>
34  #include <linux/slab.h>
35  #include <linux/device.h>
36 @@ -445,6 +446,51 @@ struct brcmf_fw {
37  
38  static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
39  
40 +#ifdef CONFIG_EFI
41 +static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
42 +{
43 +       const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
44 +       struct efivar_entry *nvram_efivar;
45 +       unsigned long data_len = 0;
46 +       u8 *data = NULL;
47 +       int err;
48 +
49 +       nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
50 +       if (!nvram_efivar)
51 +               return NULL;
52 +
53 +       memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
54 +       nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
55 +                                               0xb5, 0x1f, 0x43, 0x26,
56 +                                               0x81, 0x23, 0xd1, 0x13);
57 +
58 +       err = efivar_entry_size(nvram_efivar, &data_len);
59 +       if (err)
60 +               goto fail;
61 +
62 +       data = kmalloc(data_len, GFP_KERNEL);
63 +       if (!data)
64 +               goto fail;
65 +
66 +       err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
67 +       if (err)
68 +               goto fail;
69 +
70 +       brcmf_info("Using nvram EFI variable\n");
71 +
72 +       kfree(nvram_efivar);
73 +       *data_len_ret = data_len;
74 +       return data;
75 +
76 +fail:
77 +       kfree(data);
78 +       kfree(nvram_efivar);
79 +       return NULL;
80 +}
81 +#else
82 +static u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
83 +#endif
84 +
85  static void brcmf_fw_free_request(struct brcmf_fw_request *req)
86  {
87         struct brcmf_fw_item *item;
88 @@ -463,11 +509,12 @@ static int brcmf_fw_request_nvram_done(c
89  {
90         struct brcmf_fw *fwctx = ctx;
91         struct brcmf_fw_item *cur;
92 +       bool free_bcm47xx_nvram = false;
93 +       bool kfree_nvram = false;
94         u32 nvram_length = 0;
95         void *nvram = NULL;
96         u8 *data = NULL;
97         size_t data_len;
98 -       bool raw_nvram;
99  
100         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
101  
102 @@ -476,12 +523,13 @@ static int brcmf_fw_request_nvram_done(c
103         if (fw && fw->data) {
104                 data = (u8 *)fw->data;
105                 data_len = fw->size;
106 -               raw_nvram = false;
107         } else {
108 -               data = bcm47xx_nvram_get_contents(&data_len);
109 -               if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
110 +               if ((data = bcm47xx_nvram_get_contents(&data_len)))
111 +                       free_bcm47xx_nvram = true;
112 +               else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
113 +                       kfree_nvram = true;
114 +               else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
115                         goto fail;
116 -               raw_nvram = true;
117         }
118  
119         if (data)
120 @@ -489,8 +537,11 @@ static int brcmf_fw_request_nvram_done(c
121                                              fwctx->req->domain_nr,
122                                              fwctx->req->bus_nr);
123  
124 -       if (raw_nvram)
125 +       if (free_bcm47xx_nvram)
126                 bcm47xx_nvram_release_contents(data);
127 +       if (kfree_nvram)
128 +               kfree(data);
129 +
130         release_firmware(fw);
131         if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
132                 goto fail;