|
@@ -0,0 +1,574 @@
|
|
|
+From d09ae51a4b676151edaf572bcd5f272b5532639f Mon Sep 17 00:00:00 2001
|
|
|
+From: Arend Van Spriel <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+Reviewed-by: Pieter-Paul Giesberts <[email protected]>
|
|
|
+Reviewed-by: Franky Lin <[email protected]>
|
|
|
+Signed-off-by: Arend van Spriel <[email protected]>
|
|
|
+Signed-off-by: Kalle Valo <[email protected]>
|
|
|
+---
|
|
|
+ .../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) \
|