321-v5.0-0001-brcmfmac-Add-support-for-getting-nvram-contents-from.patch 3.7 KB

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