mac80211: backport brcmfmac firmware & clm_blob loading rework
authorRafał Miłecki <rafal@milecki.pl>
Mon, 18 Jun 2018 05:09:14 +0000 (07:09 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Mon, 18 Jun 2018 05:41:40 +0000 (07:41 +0200)
It backports remaining brcmfmac changes from 4.17.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
package/kernel/mac80211/patches/327-v4.17-0007-brcmfmac-pass-struct-in-brcmf_fw_get_firmwares.patch [new file with mode: 0644]
package/kernel/mac80211/patches/327-v4.17-0008-brcmfmac-introduce-brcmf_fw_alloc_request-function.patch [new file with mode: 0644]
package/kernel/mac80211/patches/327-v4.17-0009-brcmfmac-add-extension-to-.get_fwname-callbacks.patch [new file with mode: 0644]
package/kernel/mac80211/patches/327-v4.17-0010-brcmfmac-get-rid-of-brcmf_fw_map_chip_to_name.patch [new file with mode: 0644]
package/kernel/mac80211/patches/327-v4.17-0011-brcmfmac-get-rid-of-brcmf_fw_get_full_name.patch [new file with mode: 0644]
package/kernel/mac80211/patches/327-v4.17-0012-brcmfmac-add-kerneldoc-for-struct-brcmf_bus-msgbuf.patch [new file with mode: 0644]
package/kernel/mac80211/patches/328-v4.17-0001-brcmfmac-fix-firmware-request-processing-if-nvram-lo.patch [new file with mode: 0644]
package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch

diff --git a/package/kernel/mac80211/patches/327-v4.17-0007-brcmfmac-pass-struct-in-brcmf_fw_get_firmwares.patch b/package/kernel/mac80211/patches/327-v4.17-0007-brcmfmac-pass-struct-in-brcmf_fw_get_firmwares.patch
new file mode 100644 (file)
index 0000000..a75465a
--- /dev/null
@@ -0,0 +1,574 @@
+From d09ae51a4b676151edaf572bcd5f272b5532639f Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:26 +0100
+Subject: [PATCH] brcmfmac: pass struct in brcmf_fw_get_firmwares()
+
+Make the function brcmf_fw_get_firmwares() a bit more easy to extend
+using a structure to pass the request parameters.
+
+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         | 175 ++++++++++++++-------
+ .../broadcom/brcm80211/brcmfmac/firmware.h         |  43 +++--
+ .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  38 ++++-
+ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  32 +++-
+ .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  43 ++++-
+ 5 files changed, 245 insertions(+), 86 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -438,18 +438,31 @@ void brcmf_fw_nvram_free(void *nvram)
+ struct brcmf_fw {
+       struct device *dev;
+-      u16 flags;
+-      const struct firmware *code;
+-      const char *nvram_name;
+-      u16 domain_nr;
+-      u16 bus_nr;
+-      void (*done)(struct device *dev, int err, const struct firmware *fw,
+-                   void *nvram_image, u32 nvram_len);
++      struct brcmf_fw_request *req;
++      u32 curpos;
++      void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
+ };
++static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
++
++static void brcmf_fw_free_request(struct brcmf_fw_request *req)
++{
++      struct brcmf_fw_item *item;
++      int i;
++
++      for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
++              if (item->type == BRCMF_FW_TYPE_BINARY)
++                      release_firmware(item->binary);
++              else if (item->type == BRCMF_FW_TYPE_NVRAM)
++                      brcmf_fw_nvram_free(item->nv_data.data);
++      }
++      kfree(req);
++}
++
+ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
+ {
+       struct brcmf_fw *fwctx = ctx;
++      struct brcmf_fw_item *cur;
+       u32 nvram_length = 0;
+       void *nvram = NULL;
+       u8 *data = NULL;
+@@ -457,83 +470,150 @@ static void brcmf_fw_request_nvram_done(
+       bool raw_nvram;
+       brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
++
++      cur = &fwctx->req->items[fwctx->curpos];
++
+       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 && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
++              if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+                       goto fail;
+               raw_nvram = true;
+       }
+       if (data)
+               nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
+-                                           fwctx->domain_nr, fwctx->bus_nr);
++                                           fwctx->req->domain_nr,
++                                           fwctx->req->bus_nr);
+       if (raw_nvram)
+               bcm47xx_nvram_release_contents(data);
+       release_firmware(fw);
+-      if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
++      if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+               goto fail;
+-      fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length);
+-      kfree(fwctx);
++      brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
++      cur->nv_data.data = nvram;
++      cur->nv_data.len = nvram_length;
+       return;
+ fail:
+       brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
+-      release_firmware(fwctx->code);
+-      fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0);
++      fwctx->done(fwctx->dev, -ENOENT, NULL);
++      brcmf_fw_free_request(fwctx->req);
+       kfree(fwctx);
+ }
+-static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
++static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
++{
++      struct brcmf_fw_item *cur;
++      const struct firmware *fw = NULL;
++      int ret;
++
++      cur = &fwctx->req->items[fwctx->curpos];
++
++      brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "",
++                cur->path);
++
++      if (async)
++              ret = request_firmware_nowait(THIS_MODULE, true, cur->path,
++                                            fwctx->dev, GFP_KERNEL, fwctx,
++                                            brcmf_fw_request_done);
++      else
++              ret = request_firmware(&fw, cur->path, fwctx->dev);
++
++      if (ret < 0) {
++              brcmf_fw_request_done(NULL, fwctx);
++      } else if (!async && fw) {
++              brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path,
++                        fw ? "" : "not ");
++              if (cur->type == BRCMF_FW_TYPE_BINARY)
++                      cur->binary = fw;
++              else if (cur->type == BRCMF_FW_TYPE_NVRAM)
++                      brcmf_fw_request_nvram_done(fw, fwctx);
++              else
++                      release_firmware(fw);
++
++              return -EAGAIN;
++      }
++      return 0;
++}
++
++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;
+-      brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
+-      if (!fw) {
++      cur = &fwctx->req->items[fwctx->curpos];
++
++      brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
++                fw ? "" : "not ");
++
++      if (fw) {
++              if (cur->type == BRCMF_FW_TYPE_BINARY)
++                      cur->binary = fw;
++              else if (cur->type == BRCMF_FW_TYPE_NVRAM)
++                      brcmf_fw_request_nvram_done(fw, fwctx);
++              else
++                      release_firmware(fw);
++      } else if (cur->type == BRCMF_FW_TYPE_NVRAM) {
++              brcmf_fw_request_nvram_done(NULL, fwctx);
++      } else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) {
+               ret = -ENOENT;
+               goto fail;
+       }
+-      /* only requested code so done here */
+-      if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM))
+-              goto done;
+-
+-      fwctx->code = fw;
+-      ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
+-                                    fwctx->dev, GFP_KERNEL, fwctx,
+-                                    brcmf_fw_request_nvram_done);
+-      /* pass NULL to nvram callback for bcm47xx fallback */
+-      if (ret)
+-              brcmf_fw_request_nvram_done(NULL, fwctx);
++      do {
++              if (++fwctx->curpos == fwctx->req->n_items) {
++                      ret = 0;
++                      goto done;
++              }
++
++              ret = brcmf_fw_request_next_item(fwctx, false);
++      } while (ret == -EAGAIN);
++
+       return;
+ fail:
+-      brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
++      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;
+ done:
+-      fwctx->done(fwctx->dev, ret, fw, NULL, 0);
++      fwctx->done(fwctx->dev, ret, fwctx->req);
+       kfree(fwctx);
+ }
+-int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+-                              const char *code, const char *nvram,
+-                              void (*fw_cb)(struct device *dev, int err,
+-                                            const struct firmware *fw,
+-                                            void *nvram_image, u32 nvram_len),
+-                              u16 domain_nr, u16 bus_nr)
++static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
++{
++      struct brcmf_fw_item *item;
++      int i;
++
++      if (!req->n_items)
++              return false;
++
++      for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
++              if (!item->path)
++                      return false;
++      }
++      return true;
++}
++
++int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
++                         void (*fw_cb)(struct device *dev, int err,
++                                       struct brcmf_fw_request *req))
+ {
+       struct brcmf_fw *fwctx;
+       brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
+-      if (!fw_cb || !code)
++      if (!fw_cb)
+               return -EINVAL;
+-      if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
++      if (!brcmf_fw_request_is_valid(req))
+               return -EINVAL;
+       fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
+@@ -541,26 +621,11 @@ int brcmf_fw_get_firmwares_pcie(struct d
+               return -ENOMEM;
+       fwctx->dev = dev;
+-      fwctx->flags = flags;
++      fwctx->req = req;
+       fwctx->done = fw_cb;
+-      if (flags & BRCMF_FW_REQUEST_NVRAM)
+-              fwctx->nvram_name = nvram;
+-      fwctx->domain_nr = domain_nr;
+-      fwctx->bus_nr = bus_nr;
+-
+-      return request_firmware_nowait(THIS_MODULE, true, code, dev,
+-                                     GFP_KERNEL, fwctx,
+-                                     brcmf_fw_request_code_done);
+-}
+-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
+-                         const char *code, const char *nvram,
+-                         void (*fw_cb)(struct device *dev, int err,
+-                                       const struct firmware *fw,
+-                                       void *nvram_image, u32 nvram_len))
+-{
+-      return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
+-                                         0);
++      brcmf_fw_request_next_item(fwctx, true);
++      return 0;
+ }
+ static void brcmf_fw_get_full_name(char fw_name[BRCMF_FW_NAME_LEN],
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+@@ -16,10 +16,7 @@
+ #ifndef BRCMFMAC_FIRMWARE_H
+ #define BRCMFMAC_FIRMWARE_H
+-#define BRCMF_FW_REQUEST              0x000F
+-#define  BRCMF_FW_REQUEST_NVRAM               0x0001
+-#define BRCMF_FW_REQ_FLAGS            0x00F0
+-#define  BRCMF_FW_REQ_NV_OPTIONAL     0x0010
++#define BRCMF_FW_REQF_OPTIONAL                0x0001
+ #define       BRCMF_FW_NAME_LEN               320
+@@ -54,21 +51,39 @@ int brcmf_fw_map_chip_to_name(u32 chip,
+                             u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
+                             char nvram_name[BRCMF_FW_NAME_LEN]);
+ void brcmf_fw_nvram_free(void *nvram);
++
++enum brcmf_fw_type {
++      BRCMF_FW_TYPE_BINARY,
++      BRCMF_FW_TYPE_NVRAM
++};
++
++struct brcmf_fw_item {
++      const char *path;
++      enum brcmf_fw_type type;
++      u16 flags;
++      union {
++              const struct firmware *binary;
++              struct {
++                      void *data;
++                      u32 len;
++              } nv_data;
++      };
++};
++
++struct brcmf_fw_request {
++      u16 domain_nr;
++      u16 bus_nr;
++      u32 n_items;
++      struct brcmf_fw_item items[0];
++};
++
+ /*
+  * Request firmware(s) asynchronously. When the asynchronous request
+  * fails it will not use the callback, but call device_release_driver()
+  * instead which will call the driver .remove() callback.
+  */
+-int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+-                              const char *code, const char *nvram,
+-                              void (*fw_cb)(struct device *dev, int err,
+-                                            const struct firmware *fw,
+-                                            void *nvram_image, u32 nvram_len),
+-                              u16 domain_nr, u16 bus_nr);
+-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
+-                         const char *code, const char *nvram,
++int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
+                          void (*fw_cb)(struct device *dev, int err,
+-                                       const struct firmware *fw,
+-                                       void *nvram_image, u32 nvram_len));
++                                       struct brcmf_fw_request *req));
+ #endif /* BRCMFMAC_FIRMWARE_H */
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1651,15 +1651,19 @@ static const struct brcmf_buscore_ops br
+       .write32 = brcmf_pcie_buscore_write32,
+ };
++#define BRCMF_PCIE_FW_CODE    0
++#define BRCMF_PCIE_FW_NVRAM   1
++
+ static void brcmf_pcie_setup(struct device *dev, int ret,
+-                           const struct firmware *fw,
+-                           void *nvram, u32 nvram_len)
++                           struct brcmf_fw_request *fwreq)
+ {
++      const struct firmware *fw;
++      void *nvram;
+       struct brcmf_bus *bus;
+       struct brcmf_pciedev *pcie_bus_dev;
+       struct brcmf_pciedev_info *devinfo;
+       struct brcmf_commonring **flowrings;
+-      u32 i;
++      u32 i, nvram_len;
+       /* check firmware loading result */
+       if (ret)
+@@ -1670,6 +1674,11 @@ static void brcmf_pcie_setup(struct devi
+       devinfo = pcie_bus_dev->devinfo;
+       brcmf_pcie_attach(devinfo);
++      fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
++      nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
++      nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
++      kfree(fwreq);
++
+       /* Some of the firmwares have the size of the memory of the device
+        * defined inside the firmware. This is because part of the memory in
+        * the device is shared and the devision is determined by FW. Parse
+@@ -1730,6 +1739,7 @@ static int
+ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+       int ret;
++      struct brcmf_fw_request *fwreq;
+       struct brcmf_pciedev_info *devinfo;
+       struct brcmf_pciedev *pcie_bus_dev;
+       struct brcmf_bus *bus;
+@@ -1800,12 +1810,26 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
+       if (ret)
+               goto fail_bus;
+-      ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
+-                                                  BRCMF_FW_REQ_NV_OPTIONAL,
+-                                        devinfo->fw_name, devinfo->nvram_name,
+-                                        brcmf_pcie_setup, domain_nr, bus_nr);
++      fwreq = kzalloc(sizeof(*fwreq) + 2 * sizeof(struct brcmf_fw_item),
++                      GFP_KERNEL);
++      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;
++
++      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
+@@ -4031,14 +4031,19 @@ static const struct brcmf_bus_ops brcmf_
+       .get_fwname = brcmf_sdio_get_fwname,
+ };
++#define BRCMF_SDIO_FW_CODE    0
++#define BRCMF_SDIO_FW_NVRAM   1
++
+ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
+-                                       const struct firmware *code,
+-                                       void *nvram, u32 nvram_len)
++                                       struct brcmf_fw_request *fwreq)
+ {
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
+       struct brcmf_sdio *bus = sdiod->bus;
+       struct brcmf_core *core = bus->sdio_core;
++      const struct firmware *code;
++      void *nvram;
++      u32 nvram_len;
+       u8 saveclk;
+       brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
+@@ -4046,6 +4051,11 @@ static void brcmf_sdio_firmware_callback
+       if (err)
+               goto fail;
++      code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
++      nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
++      nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
++      kfree(fwreq);
++
+       /* try to download image and nvram to the dongle */
+       bus->alp_only = true;
+       err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
+@@ -4150,6 +4160,7 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
+       int ret;
+       struct brcmf_sdio *bus;
+       struct workqueue_struct *wq;
++      struct brcmf_fw_request *fwreq;
+       brcmf_dbg(TRACE, "Enter\n");
+@@ -4240,11 +4251,24 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
+       if (ret)
+               goto fail;
+-      ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
+-                                   sdiodev->fw_name, sdiodev->nvram_name,
++      fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item),
++                      GFP_KERNEL);
++      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) {
+               brcmf_err("async firmware request failed: %d\n", ret);
++              kfree(fwreq);
+               goto fail;
+       }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -1155,18 +1155,23 @@ static const struct brcmf_bus_ops brcmf_
+       .get_fwname = brcmf_usb_get_fwname,
+ };
++#define BRCMF_USB_FW_CODE     0
++
+ static void brcmf_usb_probe_phase2(struct device *dev, int ret,
+-                                 const struct firmware *fw,
+-                                 void *nvram, u32 nvlen)
++                                 struct brcmf_fw_request *fwreq)
+ {
+       struct brcmf_bus *bus = dev_get_drvdata(dev);
+       struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
++      const struct firmware *fw;
+       if (ret)
+               goto error;
+       brcmf_dbg(USB, "Start fw downloading\n");
++      fw = fwreq->items[BRCMF_USB_FW_CODE].binary;
++      kfree(fwreq);
++
+       ret = check_file(fw->data);
+       if (ret < 0) {
+               brcmf_err("invalid firmware\n");
+@@ -1200,6 +1205,7 @@ static int brcmf_usb_probe_cb(struct brc
+       struct brcmf_bus *bus = NULL;
+       struct brcmf_usbdev *bus_pub = NULL;
+       struct device *dev = devinfo->dev;
++      struct brcmf_fw_request *fwreq;
+       int ret;
+       brcmf_dbg(USB, "Enter\n");
+@@ -1250,11 +1256,22 @@ static int brcmf_usb_probe_cb(struct brc
+       if (ret)
+               goto fail;
++      fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
++                      GFP_KERNEL);
++      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, 0, devinfo->fw_name, NULL,
+-                                   brcmf_usb_probe_phase2);
++      ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
+       if (ret) {
+               brcmf_err("firmware request failed: %d\n", ret);
++              kfree(fwreq);
+               goto fail;
+       }
+@@ -1447,11 +1464,25 @@ static int brcmf_usb_reset_resume(struct
+ {
+       struct usb_device *usb = interface_to_usbdev(intf);
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
++      struct brcmf_fw_request *fwreq;
++      int ret;
+       brcmf_dbg(USB, "Enter\n");
+-      return brcmf_fw_get_firmwares(&usb->dev, 0, devinfo->fw_name, NULL,
+-                                    brcmf_usb_probe_phase2);
++      fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
++                      GFP_KERNEL);
++      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);
++
++      return ret;
+ }
+ #define BRCMF_USB_DEVICE(dev_id)      \
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);
diff --git a/package/kernel/mac80211/patches/327-v4.17-0009-brcmfmac-add-extension-to-.get_fwname-callbacks.patch b/package/kernel/mac80211/patches/327-v4.17-0009-brcmfmac-add-extension-to-.get_fwname-callbacks.patch
new file mode 100644 (file)
index 0000000..391229a
--- /dev/null
@@ -0,0 +1,231 @@
+From bf7a7b37f6ef5090a2bae7e7ae23cd26b741cca4 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:28 +0100
+Subject: [PATCH] brcmfmac: add extension to .get_fwname() callbacks
+
+This changes the bus layer api by having the caller provide an
+extension. With this the callback can use brcmf_fw_alloc_request()
+to get the needed firmware name.
+
+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>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  6 +--
+ .../wireless/broadcom/brcm80211/brcmfmac/common.c  | 43 +++-------------------
+ .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    | 27 +++++++-------
+ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    | 26 +++++++------
+ .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 27 ++++++++------
+ 5 files changed, 51 insertions(+), 78 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+@@ -88,7 +88,7 @@ struct brcmf_bus_ops {
+       void (*wowl_config)(struct device *dev, bool enabled);
+       size_t (*get_ramsize)(struct device *dev);
+       int (*get_memdump)(struct device *dev, void *data, size_t len);
+-      int (*get_fwname)(struct device *dev, uint chip, uint chiprev,
++      int (*get_fwname)(struct device *dev, const char *ext,
+                         unsigned char *fw_name);
+ };
+@@ -228,10 +228,10 @@ int brcmf_bus_get_memdump(struct brcmf_b
+ }
+ static inline
+-int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
++int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
+                        unsigned char *fw_name)
+ {
+-      return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
++      return bus->ops->get_fwname(bus->dev, ext, fw_name);
+ }
+ /*
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+@@ -129,42 +129,9 @@ static int brcmf_c_download(struct brcmf
+       return err;
+ }
+-static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name)
+-{
+-      struct brcmf_bus *bus = ifp->drvr->bus_if;
+-      u8 fw_name[BRCMF_FW_NAME_LEN];
+-      u8 *ptr;
+-      size_t len;
+-      s32 err;
+-
+-      memset(fw_name, 0, BRCMF_FW_NAME_LEN);
+-      err = brcmf_bus_get_fwname(bus, bus->chip, bus->chiprev, fw_name);
+-      if (err) {
+-              brcmf_err("get firmware name failed (%d)\n", err);
+-              goto done;
+-      }
+-
+-      /* generate CLM blob file name */
+-      ptr = strrchr(fw_name, '.');
+-      if (!ptr) {
+-              err = -ENOENT;
+-              goto done;
+-      }
+-
+-      len = ptr - fw_name + 1;
+-      if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) {
+-              err = -E2BIG;
+-      } else {
+-              strlcpy(clm_name, fw_name, len);
+-              strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN);
+-      }
+-done:
+-      return err;
+-}
+-
+ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
+ {
+-      struct device *dev = ifp->drvr->bus_if->dev;
++      struct brcmf_bus *bus = ifp->drvr->bus_if;
+       struct brcmf_dload_data_le *chunk_buf;
+       const struct firmware *clm = NULL;
+       u8 clm_name[BRCMF_FW_NAME_LEN];
+@@ -177,16 +144,16 @@ static int brcmf_c_process_clm_blob(stru
+       brcmf_dbg(TRACE, "Enter\n");
+-      memset(clm_name, 0, BRCMF_FW_NAME_LEN);
+-      err = brcmf_c_get_clm_name(ifp, clm_name);
++      memset(clm_name, 0, sizeof(clm_name));
++      err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
+       if (err) {
+               brcmf_err("get CLM blob file name failed (%d)\n", err);
+               return err;
+       }
+-      err = request_firmware(&clm, clm_name, dev);
++      err = request_firmware(&clm, clm_name, bus->dev);
+       if (err) {
+-              brcmf_info("no clm_blob available(err=%d), device may have limited channels available\n",
++              brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
+                          err);
+               return 0;
+       }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1350,23 +1350,24 @@ static int brcmf_pcie_get_memdump(struct
+       return 0;
+ }
+-static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+-                               u8 *fw_name)
++static
++int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+ {
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+-      struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+-      struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+-      int ret = 0;
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ext, fw_name },
++      };
+-      if (devinfo->fw_name[0] != '\0')
+-              strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+-      else
+-              ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+-                                              brcmf_pcie_fwnames,
+-                                              ARRAY_SIZE(brcmf_pcie_fwnames),
+-                                              fw_name, NULL);
++      fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
++                                     brcmf_pcie_fwnames,
++                                     ARRAY_SIZE(brcmf_pcie_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return -ENOMEM;
+-      return ret;
++      kfree(fwreq);
++      return 0;
+ }
+ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4000,22 +4000,24 @@ brcmf_sdio_watchdog(unsigned long data)
+       }
+ }
+-static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+-                               u8 *fw_name)
++static
++int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+ {
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+-      struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+-      int ret = 0;
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ext, fw_name },
++      };
+-      if (sdiodev->fw_name[0] != '\0')
+-              strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN);
+-      else
+-              ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+-                                              brcmf_sdio_fwnames,
+-                                              ARRAY_SIZE(brcmf_sdio_fwnames),
+-                                              fw_name, NULL);
++      fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
++                                     brcmf_sdio_fwnames,
++                                     ARRAY_SIZE(brcmf_sdio_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return -ENOMEM;
+-      return ret;
++      kfree(fwreq);
++      return 0;
+ }
+ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -1128,21 +1128,24 @@ static void brcmf_usb_wowl_config(struct
+               device_set_wakeup_enable(devinfo->dev, false);
+ }
+-static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+-                              u8 *fw_name)
++static
++int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+ {
+-      struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+-      int ret = 0;
++      struct brcmf_bus *bus = dev_get_drvdata(dev);
++      struct brcmf_fw_request *fwreq;
++      struct brcmf_fw_name fwnames[] = {
++              { ext, fw_name },
++      };
+-      if (devinfo->fw_name[0] != '\0')
+-              strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+-      else
+-              ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+-                                              brcmf_usb_fwnames,
+-                                              ARRAY_SIZE(brcmf_usb_fwnames),
+-                                              fw_name, NULL);
++      fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
++                                     brcmf_usb_fwnames,
++                                     ARRAY_SIZE(brcmf_usb_fwnames),
++                                     fwnames, ARRAY_SIZE(fwnames));
++      if (!fwreq)
++              return -ENOMEM;
+-      return ret;
++      kfree(fwreq);
++      return 0;
+ }
+ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
diff --git a/package/kernel/mac80211/patches/327-v4.17-0010-brcmfmac-get-rid-of-brcmf_fw_map_chip_to_name.patch b/package/kernel/mac80211/patches/327-v4.17-0010-brcmfmac-get-rid-of-brcmf_fw_map_chip_to_name.patch
new file mode 100644 (file)
index 0000000..becf7cf
--- /dev/null
@@ -0,0 +1,92 @@
+From 18c2b20e276e04476a3350b4a92c1dfad725d45d Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:29 +0100
+Subject: [PATCH] brcmfmac: get rid of brcmf_fw_map_chip_to_name()
+
+The function is no longer used so removing it.
+
+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         | 53 ----------------------
+ .../broadcom/brcm80211/brcmfmac/firmware.h         |  4 --
+ 2 files changed, 57 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -635,59 +635,6 @@ static void brcmf_fw_get_full_name(char
+       strlcat(fw_name, extension, BRCMF_FW_NAME_LEN);
+ }
+-int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
+-                            struct brcmf_firmware_mapping mapping_table[],
+-                            u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
+-                            char nvram_name[BRCMF_FW_NAME_LEN])
+-{
+-      char chipname[12];
+-      u32 i;
+-      char end;
+-
+-      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 -ENODEV;
+-      }
+-
+-      brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
+-
+-      /* check if firmware path is provided by module parameter */
+-      if (brcmf_mp_global.firmware_path[0] != '\0') {
+-              if (fw_name)
+-                      strlcpy(fw_name, brcmf_mp_global.firmware_path,
+-                              BRCMF_FW_NAME_LEN);
+-              if (nvram_name)
+-                      strlcpy(nvram_name, brcmf_mp_global.firmware_path,
+-                              BRCMF_FW_NAME_LEN);
+-
+-              end = brcmf_mp_global.firmware_path[
+-                              strlen(brcmf_mp_global.firmware_path) - 1];
+-              if (end != '/') {
+-                      if (fw_name)
+-                              strlcat(fw_name, "/", BRCMF_FW_NAME_LEN);
+-                      if (nvram_name)
+-                              strlcat(nvram_name, "/", BRCMF_FW_NAME_LEN);
+-              }
+-      }
+-
+-      brcmf_info("using %s for chip %s\n",
+-                 mapping_table[i].fw_base, chipname);
+-      if (fw_name)
+-              brcmf_fw_get_full_name(fw_name,
+-                                     mapping_table[i].fw_base, ".bin");
+-      if (nvram_name)
+-              brcmf_fw_get_full_name(nvram_name,
+-                                     mapping_table[i].fw_base, ".txt");
+-
+-      return 0;
+-}
+-
+ struct brcmf_fw_request *
+ brcmf_fw_alloc_request(u32 chip, u32 chiprev,
+                      struct brcmf_firmware_mapping mapping_table[],
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+@@ -46,10 +46,6 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw
+ #define BRCMF_FW_ENTRY(chipid, mask, name) \
+       { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME }
+-int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
+-                            struct brcmf_firmware_mapping mapping_table[],
+-                            u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
+-                            char nvram_name[BRCMF_FW_NAME_LEN]);
+ void brcmf_fw_nvram_free(void *nvram);
+ enum brcmf_fw_type {
diff --git a/package/kernel/mac80211/patches/327-v4.17-0011-brcmfmac-get-rid-of-brcmf_fw_get_full_name.patch b/package/kernel/mac80211/patches/327-v4.17-0011-brcmfmac-get-rid-of-brcmf_fw_get_full_name.patch
new file mode 100644 (file)
index 0000000..d831f44
--- /dev/null
@@ -0,0 +1,44 @@
+From bf291b7247e53f52a4236c0b55a5df046d6177df Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:30 +0100
+Subject: [PATCH] brcmfmac: get rid of brcmf_fw_get_full_name()
+
+The function was pretty minimal and now it is called only from one
+place so just get rid of it.
+
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/firmware.c    | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -628,13 +628,6 @@ int brcmf_fw_get_firmwares(struct device
+       return 0;
+ }
+-static void brcmf_fw_get_full_name(char fw_name[BRCMF_FW_NAME_LEN],
+-                                 const char *fw_base, const char *extension)
+-{
+-      strlcat(fw_name, fw_base, BRCMF_FW_NAME_LEN);
+-      strlcat(fw_name, extension, BRCMF_FW_NAME_LEN);
+-}
+-
+ struct brcmf_fw_request *
+ brcmf_fw_alloc_request(u32 chip, u32 chiprev,
+                      struct brcmf_firmware_mapping mapping_table[],
+@@ -685,9 +678,10 @@ brcmf_fw_alloc_request(u32 chip, u32 chi
+                                       BRCMF_FW_NAME_LEN);
+                       }
+               }
+-              brcmf_fw_get_full_name(fwnames[j].path,
+-                                     mapping_table[i].fw_base,
+-                                     fwnames[j].extension);
++              strlcat(fwnames[j].path, mapping_table[i].fw_base,
++                      BRCMF_FW_NAME_LEN);
++              strlcat(fwnames[j].path, fwnames[j].extension,
++                      BRCMF_FW_NAME_LEN);
+               fwreq->items[j].path = fwnames[j].path;
+       }
diff --git a/package/kernel/mac80211/patches/327-v4.17-0012-brcmfmac-add-kerneldoc-for-struct-brcmf_bus-msgbuf.patch b/package/kernel/mac80211/patches/327-v4.17-0012-brcmfmac-add-kerneldoc-for-struct-brcmf_bus-msgbuf.patch
new file mode 100644 (file)
index 0000000..1c9c995
--- /dev/null
@@ -0,0 +1,23 @@
+From 48eaee3f272a5bfe6986d07c51f6975d3c2f74d1 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 22 Mar 2018 21:28:31 +0100
+Subject: [PATCH] brcmfmac: add kerneldoc for struct brcmf_bus::msgbuf
+
+This field did not have kerneldoc description so adding it now.
+
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+@@ -140,6 +140,7 @@ struct brcmf_bus_stats {
+  * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
+  * @wowl_supported: is wowl supported by bus driver.
+  * @chiprev: revision of the dongle chip.
++ * @msgbuf: msgbuf protocol parameters provided by bus layer.
+  */
+ struct brcmf_bus {
+       union {
diff --git a/package/kernel/mac80211/patches/328-v4.17-0001-brcmfmac-fix-firmware-request-processing-if-nvram-lo.patch b/package/kernel/mac80211/patches/328-v4.17-0001-brcmfmac-fix-firmware-request-processing-if-nvram-lo.patch
new file mode 100644 (file)
index 0000000..cd2279d
--- /dev/null
@@ -0,0 +1,81 @@
+From 0b5c0305e57ca940713bcb2b202fd2b412c62f31 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Tue, 3 Apr 2018 10:18:15 +0200
+Subject: [PATCH] brcmfmac: fix firmware request processing if nvram load fails
+
+When nvram loading fails a double free occurred. Fix this and reorg the
+code a little.
+
+Fixes: d09ae51a4b67 ("brcmfmac: pass struct in brcmf_fw_get_firmwares()")
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/firmware.c         | 36 ++++++++++++----------
+ 1 file changed, 20 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -459,7 +459,7 @@ static void brcmf_fw_free_request(struct
+       kfree(req);
+ }
+-static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
++static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
+ {
+       struct brcmf_fw *fwctx = ctx;
+       struct brcmf_fw_item *cur;
+@@ -498,13 +498,10 @@ static void brcmf_fw_request_nvram_done(
+       brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
+       cur->nv_data.data = nvram;
+       cur->nv_data.len = nvram_length;
+-      return;
++      return 0;
+ fail:
+-      brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
+-      fwctx->done(fwctx->dev, -ENOENT, NULL);
+-      brcmf_fw_free_request(fwctx->req);
+-      kfree(fwctx);
++      return -ENOENT;
+ }
+ static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
+@@ -553,20 +550,27 @@ static void brcmf_fw_request_done(const
+       brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
+                 fw ? "" : "not ");
+-      if (fw) {
+-              if (cur->type == BRCMF_FW_TYPE_BINARY)
+-                      cur->binary = fw;
+-              else if (cur->type == BRCMF_FW_TYPE_NVRAM)
+-                      brcmf_fw_request_nvram_done(fw, fwctx);
+-              else
+-                      release_firmware(fw);
+-      } else if (cur->type == BRCMF_FW_TYPE_NVRAM) {
+-              brcmf_fw_request_nvram_done(NULL, fwctx);
+-      } else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) {
++      if (!fw)
+               ret = -ENOENT;
++
++      switch (cur->type) {
++      case BRCMF_FW_TYPE_NVRAM:
++              ret = brcmf_fw_request_nvram_done(fw, fwctx);
++              break;
++      case BRCMF_FW_TYPE_BINARY:
++              cur->binary = fw;
++              break;
++      default:
++              /* something fishy here so bail out early */
++              brcmf_err("unknown fw type: %d\n", cur->type);
++              release_firmware(fw);
++              ret = -EINVAL;
+               goto fail;
+       }
++      if (ret < 0 && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
++              goto fail;
++
+       do {
+               if (++fwctx->curpos == fwctx->req->n_items) {
+                       ret = 0;
index 63849f48dbd01863effd9e11ad5a767a88657442..3afffc0fc4e152c751acc0ab8edddcd18bf70c87 100644 (file)
@@ -23,66 +23,44 @@ 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
-@@ -445,6 +445,7 @@ struct brcmf_fw {
-       u16 bus_nr;
-       void (*done)(struct device *dev, int err, const struct firmware *fw,
-                    void *nvram_image, u32 nvram_len);
+@@ -441,6 +441,7 @@ struct brcmf_fw {
+       struct brcmf_fw_request *req;
+       u32 curpos;
+       void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
 +      struct completion *completion;
  };
  
- static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
-@@ -479,6 +480,8 @@ static void brcmf_fw_request_nvram_done(
-               goto fail;
-       fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length);
-+      if (fwctx->completion)
-+              complete(fwctx->completion);
-       kfree(fwctx);
-       return;
-@@ -486,6 +489,8 @@ fail:
-       brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
-       release_firmware(fwctx->code);
-       fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0);
-+      if (fwctx->completion)
-+              complete(fwctx->completion);
-       kfree(fwctx);
- }
-@@ -517,6 +522,8 @@ fail:
-       brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
+ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
+@@ -589,6 +590,8 @@ fail:
+       fwctx->req = NULL;
  done:
-       fwctx->done(fwctx->dev, ret, fw, NULL, 0);
+       fwctx->done(fwctx->dev, ret, fwctx->req);
 +      if (fwctx->completion)
 +              complete(fwctx->completion);
        kfree(fwctx);
  }
  
-@@ -528,6 +535,8 @@ int brcmf_fw_get_firmwares_pcie(struct d
-                               u16 domain_nr, u16 bus_nr)
+@@ -612,6 +615,8 @@ int brcmf_fw_get_firmwares(struct device
+                                        struct brcmf_fw_request *req))
  {
        struct brcmf_fw *fwctx;
 +      struct completion completion;
 +      int err;
  
        brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
-       if (!fw_cb || !code)
-@@ -548,9 +557,17 @@ int brcmf_fw_get_firmwares_pcie(struct d
-       fwctx->domain_nr = domain_nr;
-       fwctx->bus_nr = bus_nr;
+       if (!fw_cb)
+@@ -628,7 +633,14 @@ int brcmf_fw_get_firmwares(struct device
+       fwctx->req = req;
+       fwctx->done = fw_cb;
  
--      return request_firmware_nowait(THIS_MODULE, true, code, dev,
 +      init_completion(&completion);
 +      fwctx->completion = &completion;
 +
-+      err = request_firmware_nowait(THIS_MODULE, true, code, dev,
-                                      GFP_KERNEL, fwctx,
-                                      brcmf_fw_request_code_done);
-+      if (!err)
-+              wait_for_completion_timeout(fwctx->completion,
-+                                          msecs_to_jiffies(5000));
+       brcmf_fw_request_next_item(fwctx, true);
++
++      wait_for_completion_timeout(fwctx->completion, msecs_to_jiffies(5000));
 +      fwctx->completion = NULL;
-+      return err;
++
+       return 0;
  }
  
- int brcmf_fw_get_firmwares(struct device *dev, u16 flags,