mac80211: backport brcmfmac firmware & clm_blob loading rework
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 327-v4.17-0008-brcmfmac-introduce-brcmf_fw_alloc_request-function.patch
diff --git a/package/kernel/mac80211/patches/327-v4.17-0008-brcmfmac-introduce-brcmf_fw_alloc_request-function.patch b/package/kernel/mac80211/patches/327-v4.17-0008-brcmfmac-introduce-brcmf_fw_alloc_request-function.patch
new file mode 100644 (file)
index 0000000..408154e
--- /dev/null
@@ -0,0 +1,328 @@
+From 2baa3aaee27f137b8db9a9224d0fe9b281d28e34 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:27 +0100
+Subject: [PATCH] brcmfmac: introduce brcmf_fw_alloc_request() function
+
+The function brcmf_fw_alloc_request() takes a list of required files
+and allocated the struct brcmf_fw_request instance accordingly. The
+request can be modified by the caller before being passed to the
+brcmf_fw_request_firmwares() function.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/firmware.c         | 58 ++++++++++++++++++++++
+ .../broadcom/brcm80211/brcmfmac/firmware.h         | 11 ++++
+ .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    | 58 ++++++++++++----------
+ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    | 38 ++++++++------
+ .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 42 +++++++++-------
+ 5 files changed, 147 insertions(+), 60 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -688,3 +688,61 @@ int brcmf_fw_map_chip_to_name(u32 chip,
+       return 0;
+ }
++struct brcmf_fw_request *
++brcmf_fw_alloc_request(u32 chip, u32 chiprev,
++                     struct brcmf_firmware_mapping mapping_table[],
++                     u32 table_size, struct brcmf_fw_name *fwnames,
++                     u32 n_fwnames)
++{
++      struct brcmf_fw_request *fwreq;
++      char chipname[12];
++      const char *mp_path;
++      u32 i, j;
++      char end;
++      size_t reqsz;
++
++      for (i = 0; i < table_size; i++) {
++              if (mapping_table[i].chipid == chip &&
++                  mapping_table[i].revmask & BIT(chiprev))
++                      break;
++      }
++
++      if (i == table_size) {
++              brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
++              return NULL;
++      }
++
++      reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
++      fwreq = kzalloc(reqsz, GFP_KERNEL);
++      if (!fwreq)
++              return NULL;
++
++      brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
++
++      brcmf_info("using %s for chip %s\n",
++                 mapping_table[i].fw_base, chipname);
++
++      mp_path = brcmf_mp_global.firmware_path;
++      end = mp_path[strlen(mp_path) - 1];
++      fwreq->n_items = n_fwnames;
++
++      for (j = 0; j < n_fwnames; j++) {
++              fwreq->items[j].path = fwnames[j].path;
++              /* check if firmware path is provided by module parameter */
++              if (brcmf_mp_global.firmware_path[0] != '\0') {
++                      strlcpy(fwnames[j].path, mp_path,
++                              BRCMF_FW_NAME_LEN);
++
++                      if (end != '/') {
++                              strlcat(fwnames[j].path, "/",
++                                      BRCMF_FW_NAME_LEN);
++                      }
++              }
++              brcmf_fw_get_full_name(fwnames[j].path,
++                                     mapping_table[i].fw_base,
++                                     fwnames[j].extension);
++              fwreq->items[j].path = fwnames[j].path;
++      }
++
++      return fwreq;
++}
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+@@ -77,6 +77,17 @@ struct brcmf_fw_request {
+       struct brcmf_fw_item items[0];
+ };
++struct brcmf_fw_name {
++      const char *extension;
++      char *path;
++};
++
++struct brcmf_fw_request *
++brcmf_fw_alloc_request(u32 chip, u32 chiprev,
++                     struct brcmf_firmware_mapping mapping_table[],
++                     u32 table_size, struct brcmf_fw_name *fwnames,
++                     u32 n_fwnames);
++
+ /*
+  * Request firmware(s) asynchronously. When the asynchronous request
+  * fails it will not use the callback, but call device_release_driver()
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1735,6 +1735,31 @@ fail:
+       device_release_driver(dev);
+ }
++static struct brcmf_fw_request *
++brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
++{
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ".bin", devinfo->fw_name },
++              { ".txt", devinfo->nvram_name },
++      };
++
++      fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
++                                     brcmf_pcie_fwnames,
++                                     ARRAY_SIZE(brcmf_pcie_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return NULL;
++
++      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->domain_nr = pci_domain_nr(devinfo->pdev->bus);
++      fwreq->bus_nr = devinfo->pdev->bus->number;
++
++      return fwreq;
++}
++
+ static int
+ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -1743,13 +1768,8 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
+       struct brcmf_pciedev_info *devinfo;
+       struct brcmf_pciedev *pcie_bus_dev;
+       struct brcmf_bus *bus;
+-      u16 domain_nr;
+-      u16 bus_nr;
+-      domain_nr = pci_domain_nr(pdev->bus) + 1;
+-      bus_nr = pdev->bus->number;
+-      brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
+-                domain_nr, bus_nr);
++      brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
+       ret = -ENOMEM;
+       devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
+@@ -1803,33 +1823,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
+       bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
+       dev_set_drvdata(&pdev->dev, bus);
+-      ret = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev,
+-                                      brcmf_pcie_fwnames,
+-                                      ARRAY_SIZE(brcmf_pcie_fwnames),
+-                                      devinfo->fw_name, devinfo->nvram_name);
+-      if (ret)
+-              goto fail_bus;
+-
+-      fwreq = kzalloc(sizeof(*fwreq) + 2 * sizeof(struct brcmf_fw_item),
+-                      GFP_KERNEL);
++      fwreq = brcmf_pcie_prepare_fw_request(devinfo);
+       if (!fwreq) {
+               ret = -ENOMEM;
+               goto fail_bus;
+       }
+-      fwreq->items[BRCMF_PCIE_FW_CODE].path = devinfo->fw_name;
+-      fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+-      fwreq->items[BRCMF_PCIE_FW_NVRAM].path = devinfo->nvram_name;
+-      fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+-      fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
+-      fwreq->n_items = 2;
+-      fwreq->domain_nr = domain_nr;
+-      fwreq->bus_nr = bus_nr;
+       ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup);
+-      if (ret == 0)
+-              return 0;
++      if (ret < 0) {
++              kfree(fwreq);
++              goto fail_bus;
++      }
++      return 0;
+-      kfree(fwreq);
+ fail_bus:
+       kfree(bus->msgbuf);
+       kfree(bus);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4155,6 +4155,28 @@ fail:
+       device_release_driver(dev);
+ }
++static struct brcmf_fw_request *
++brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
++{
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ".bin", bus->sdiodev->fw_name },
++              { ".txt", bus->sdiodev->nvram_name },
++      };
++
++      fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
++                                     brcmf_sdio_fwnames,
++                                     ARRAY_SIZE(brcmf_sdio_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return NULL;
++
++      fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
++      fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
++
++      return fwreq;
++}
++
+ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+ {
+       int ret;
+@@ -4244,26 +4266,12 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
+       brcmf_dbg(INFO, "completed!!\n");
+-      ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev,
+-                                      brcmf_sdio_fwnames,
+-                                      ARRAY_SIZE(brcmf_sdio_fwnames),
+-                                      sdiodev->fw_name, sdiodev->nvram_name);
+-      if (ret)
+-              goto fail;
+-
+-      fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item),
+-                      GFP_KERNEL);
++      fwreq = brcmf_sdio_prepare_fw_request(bus);
+       if (!fwreq) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+-      fwreq->items[BRCMF_SDIO_FW_CODE].path = sdiodev->fw_name;
+-      fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+-      fwreq->items[BRCMF_SDIO_FW_NVRAM].path = sdiodev->nvram_name;
+-      fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+-      fwreq->n_items = 2;
+-
+       ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
+                                    brcmf_sdio_firmware_callback);
+       if (ret != 0) {
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -1200,6 +1200,27 @@ error:
+       device_release_driver(dev);
+ }
++static struct brcmf_fw_request *
++brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
++{
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ".bin", devinfo->fw_name },
++      };
++
++      fwreq = brcmf_fw_alloc_request(devinfo->bus_pub.devid,
++                                     devinfo->bus_pub.chiprev,
++                                     brcmf_usb_fwnames,
++                                     ARRAY_SIZE(brcmf_usb_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return NULL;
++
++      fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
++
++      return fwreq;
++}
++
+ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
+ {
+       struct brcmf_bus *bus = NULL;
+@@ -1249,24 +1270,12 @@ static int brcmf_usb_probe_cb(struct brc
+       bus->chip = bus_pub->devid;
+       bus->chiprev = bus_pub->chiprev;
+-      ret = brcmf_fw_map_chip_to_name(bus_pub->devid, bus_pub->chiprev,
+-                                      brcmf_usb_fwnames,
+-                                      ARRAY_SIZE(brcmf_usb_fwnames),
+-                                      devinfo->fw_name, NULL);
+-      if (ret)
+-              goto fail;
+-
+-      fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
+-                      GFP_KERNEL);
++      fwreq = brcmf_usb_prepare_fw_request(devinfo);
+       if (!fwreq) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+-      fwreq->items[BRCMF_USB_FW_CODE].path = devinfo->fw_name;
+-      fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+-      fwreq->n_items = 1;
+-
+       /* request firmware here */
+       ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
+       if (ret) {
+@@ -1469,15 +1478,10 @@ static int brcmf_usb_reset_resume(struct
+       brcmf_dbg(USB, "Enter\n");
+-      fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
+-                      GFP_KERNEL);
++      fwreq = brcmf_usb_prepare_fw_request(devinfo);
+       if (!fwreq)
+               return -ENOMEM;
+-      fwreq->items[BRCMF_USB_FW_CODE].path = devinfo->fw_name;
+-      fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+-      fwreq->n_items = 1;
+-
+       ret = brcmf_fw_get_firmwares(&usb->dev, fwreq, brcmf_usb_probe_phase2);
+       if (ret < 0)
+               kfree(fwreq);