From: Rafał Miłecki Date: Mon, 18 Jun 2018 05:09:14 +0000 (+0200) Subject: mac80211: backport brcmfmac firmware & clm_blob loading rework X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=7e8eb7f309a802ba10a13ddb807c6a31fecc9183;p=openwrt%2Fstaging%2Fxback.git mac80211: backport brcmfmac firmware & clm_blob loading rework It backports remaining brcmfmac changes from 4.17. Signed-off-by: Rafał Miłecki --- 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 index 0000000000..a75465a893 --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0007-brcmfmac-pass-struct-in-brcmf_fw_get_firmwares.patch @@ -0,0 +1,574 @@ +From d09ae51a4b676151edaf572bcd5f272b5532639f Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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 index 0000000000..408154ef0f --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0008-brcmfmac-introduce-brcmf_fw_alloc_request-function.patch @@ -0,0 +1,328 @@ +From 2baa3aaee27f137b8db9a9224d0fe9b281d28e34 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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 index 0000000000..391229a865 --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0009-brcmfmac-add-extension-to-.get_fwname-callbacks.patch @@ -0,0 +1,231 @@ +From bf7a7b37f6ef5090a2bae7e7ae23cd26b741cca4 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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 index 0000000000..becf7cf3fb --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0010-brcmfmac-get-rid-of-brcmf_fw_map_chip_to_name.patch @@ -0,0 +1,92 @@ +From 18c2b20e276e04476a3350b4a92c1dfad725d45d Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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 index 0000000000..d831f44fcd --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0011-brcmfmac-get-rid-of-brcmf_fw_get_full_name.patch @@ -0,0 +1,44 @@ +From bf291b7247e53f52a4236c0b55a5df046d6177df Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Signed-off-by: Kalle Valo +--- + .../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 index 0000000000..1c9c99599f --- /dev/null +++ b/package/kernel/mac80211/patches/327-v4.17-0012-brcmfmac-add-kerneldoc-for-struct-brcmf_bus-msgbuf.patch @@ -0,0 +1,23 @@ +From 48eaee3f272a5bfe6986d07c51f6975d3c2f74d1 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Signed-off-by: Kalle Valo +--- + 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 index 0000000000..cd2279dd65 --- /dev/null +++ b/package/kernel/mac80211/patches/328-v4.17-0001-brcmfmac-fix-firmware-request-processing-if-nvram-lo.patch @@ -0,0 +1,81 @@ +From 0b5c0305e57ca940713bcb2b202fd2b412c62f31 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +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 +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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; diff --git a/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch index 63849f48db..3afffc0fc4 100644 --- a/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/860-brcmfmac-register-wiphy-s-during-module_init.patch @@ -23,66 +23,44 @@ Signed-off-by: Rafał Miłecki } --- 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,