Commit a1b5a902 authored by Hector Martin's avatar Hector Martin Committed by Kalle Valo

wifi: brcmfmac: pcie/sdio/usb: Get CLM blob via standard firmware mechanism

Now that the firmware fetcher can handle per-board CLM files, load the
CLM blob alongside the other firmware files and change the bus API to
just return the existing blob, instead of fetching the filename.

This enables per-board CLM blobs, which are required on Apple platforms.
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: default avatarHector Martin <marcan@marcan.st>
Reviewed-by: default avatarAlvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/E1oZDnY-0077aA-8f@rmk-PC.armlinux.org.uk
parent e263d722
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#ifndef BRCMFMAC_BUS_H #ifndef BRCMFMAC_BUS_H
#define BRCMFMAC_BUS_H #define BRCMFMAC_BUS_H
#include <linux/kernel.h>
#include <linux/firmware.h>
#include "debug.h" #include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */ /* IDs of the 6 default common rings of msgbuf protocol */
...@@ -34,6 +36,11 @@ enum brcmf_bus_protocol_type { ...@@ -34,6 +36,11 @@ enum brcmf_bus_protocol_type {
BRCMF_PROTO_MSGBUF BRCMF_PROTO_MSGBUF
}; };
/* Firmware blobs that may be available */
enum brcmf_blob_type {
BRCMF_BLOB_CLM,
};
struct brcmf_mp_device; struct brcmf_mp_device;
struct brcmf_bus_dcmd { struct brcmf_bus_dcmd {
...@@ -60,7 +67,7 @@ struct brcmf_bus_dcmd { ...@@ -60,7 +67,7 @@ struct brcmf_bus_dcmd {
* @wowl_config: specify if dongle is configured for wowl when going to suspend * @wowl_config: specify if dongle is configured for wowl when going to suspend
* @get_ramsize: obtain size of device memory. * @get_ramsize: obtain size of device memory.
* @get_memdump: obtain device memory dump in provided buffer. * @get_memdump: obtain device memory dump in provided buffer.
* @get_fwname: obtain firmware name. * @get_blob: obtain a firmware blob.
* *
* This structure provides an abstract interface towards the * This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver * bus specific driver. For control messages to common driver
...@@ -77,8 +84,8 @@ struct brcmf_bus_ops { ...@@ -77,8 +84,8 @@ struct brcmf_bus_ops {
void (*wowl_config)(struct device *dev, bool enabled); void (*wowl_config)(struct device *dev, bool enabled);
size_t (*get_ramsize)(struct device *dev); size_t (*get_ramsize)(struct device *dev);
int (*get_memdump)(struct device *dev, void *data, size_t len); int (*get_memdump)(struct device *dev, void *data, size_t len);
int (*get_fwname)(struct device *dev, const char *ext, int (*get_blob)(struct device *dev, const struct firmware **fw,
unsigned char *fw_name); enum brcmf_blob_type type);
void (*debugfs_create)(struct device *dev); void (*debugfs_create)(struct device *dev);
int (*reset)(struct device *dev); int (*reset)(struct device *dev);
}; };
...@@ -220,10 +227,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len) ...@@ -220,10 +227,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
} }
static inline static inline
int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext, int brcmf_bus_get_blob(struct brcmf_bus *bus, const struct firmware **fw,
unsigned char *fw_name) enum brcmf_blob_type type)
{ {
return bus->ops->get_fwname(bus->dev, ext, fw_name); return bus->ops->get_blob(bus->dev, fw, type);
} }
static inline static inline
......
...@@ -123,7 +123,6 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) ...@@ -123,7 +123,6 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
struct brcmf_bus *bus = drvr->bus_if; struct brcmf_bus *bus = drvr->bus_if;
struct brcmf_dload_data_le *chunk_buf; struct brcmf_dload_data_le *chunk_buf;
const struct firmware *clm = NULL; const struct firmware *clm = NULL;
u8 clm_name[BRCMF_FW_NAME_LEN];
u32 chunk_len; u32 chunk_len;
u32 datalen; u32 datalen;
u32 cumulative_len; u32 cumulative_len;
...@@ -133,15 +132,8 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) ...@@ -133,15 +132,8 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
memset(clm_name, 0, sizeof(clm_name)); err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM);
err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name); if (err || !clm) {
if (err) {
bphy_err(drvr, "get CLM blob file name failed (%d)\n", err);
return err;
}
err = firmware_request_nowarn(&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); err);
return 0; return 0;
......
...@@ -66,6 +66,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); ...@@ -66,6 +66,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
/* per-board firmware binaries */ /* per-board firmware binaries */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin"); MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin");
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob");
static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
...@@ -261,6 +262,8 @@ struct brcmf_pciedev_info { ...@@ -261,6 +262,8 @@ struct brcmf_pciedev_info {
struct pci_dev *pdev; struct pci_dev *pdev;
char fw_name[BRCMF_FW_NAME_LEN]; char fw_name[BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_NAME_LEN];
char clm_name[BRCMF_FW_NAME_LEN];
const struct firmware *clm_fw;
void __iomem *regs; void __iomem *regs;
void __iomem *tcm; void __iomem *tcm;
u32 ram_base; u32 ram_base;
...@@ -1382,23 +1385,25 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) ...@@ -1382,23 +1385,25 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
return 0; return 0;
} }
static static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,
int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name) enum brcmf_blob_type type)
{ {
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_fw_request *fwreq; struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
struct brcmf_fw_name fwnames[] = { struct brcmf_pciedev_info *devinfo = buspub->devinfo;
{ ext, fw_name },
};
fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, switch (type) {
brcmf_pcie_fwnames, case BRCMF_BLOB_CLM:
ARRAY_SIZE(brcmf_pcie_fwnames), *fw = devinfo->clm_fw;
fwnames, ARRAY_SIZE(fwnames)); devinfo->clm_fw = NULL;
if (!fwreq) break;
return -ENOMEM; default:
return -ENOENT;
}
if (!*fw)
return -ENOENT;
kfree(fwreq);
return 0; return 0;
} }
...@@ -1445,7 +1450,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { ...@@ -1445,7 +1450,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
.wowl_config = brcmf_pcie_wowl_config, .wowl_config = brcmf_pcie_wowl_config,
.get_ramsize = brcmf_pcie_get_ramsize, .get_ramsize = brcmf_pcie_get_ramsize,
.get_memdump = brcmf_pcie_get_memdump, .get_memdump = brcmf_pcie_get_memdump,
.get_fwname = brcmf_pcie_get_fwname, .get_blob = brcmf_pcie_get_blob,
.reset = brcmf_pcie_reset, .reset = brcmf_pcie_reset,
}; };
...@@ -1731,6 +1736,7 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { ...@@ -1731,6 +1736,7 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
#define BRCMF_PCIE_FW_CODE 0 #define BRCMF_PCIE_FW_CODE 0
#define BRCMF_PCIE_FW_NVRAM 1 #define BRCMF_PCIE_FW_NVRAM 1
#define BRCMF_PCIE_FW_CLM 2
static void brcmf_pcie_setup(struct device *dev, int ret, static void brcmf_pcie_setup(struct device *dev, int ret,
struct brcmf_fw_request *fwreq) struct brcmf_fw_request *fwreq)
...@@ -1755,6 +1761,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, ...@@ -1755,6 +1761,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary; fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data; nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len; nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
kfree(fwreq); kfree(fwreq);
ret = brcmf_chip_get_raminfo(devinfo->ci); ret = brcmf_chip_get_raminfo(devinfo->ci);
...@@ -1830,6 +1837,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) ...@@ -1830,6 +1837,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
struct brcmf_fw_name fwnames[] = { struct brcmf_fw_name fwnames[] = {
{ ".bin", devinfo->fw_name }, { ".bin", devinfo->fw_name },
{ ".txt", devinfo->nvram_name }, { ".txt", devinfo->nvram_name },
{ ".clm_blob", devinfo->clm_name },
}; };
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
...@@ -1842,6 +1850,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) ...@@ -1842,6 +1850,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; 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].type = BRCMF_FW_TYPE_NVRAM;
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
fwreq->board_type = devinfo->settings->board_type; fwreq->board_type = devinfo->settings->board_type;
/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */ /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
...@@ -1981,6 +1991,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) ...@@ -1981,6 +1991,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
brcmf_pcie_release_ringbuffers(devinfo); brcmf_pcie_release_ringbuffers(devinfo);
brcmf_pcie_reset_device(devinfo); brcmf_pcie_reset_device(devinfo);
brcmf_pcie_release_resource(devinfo); brcmf_pcie_release_resource(devinfo);
release_firmware(devinfo->clm_fw);
if (devinfo->ci) if (devinfo->ci)
brcmf_chip_detach(devinfo->ci); brcmf_chip_detach(devinfo->ci);
......
...@@ -4131,23 +4131,24 @@ brcmf_sdio_watchdog(struct timer_list *t) ...@@ -4131,23 +4131,24 @@ brcmf_sdio_watchdog(struct timer_list *t)
} }
} }
static static int brcmf_sdio_get_blob(struct device *dev, const struct firmware **fw,
int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name) enum brcmf_blob_type type)
{ {
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_fw_request *fwreq; struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_fw_name fwnames[] = {
{ ext, fw_name },
};
fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, switch (type) {
brcmf_sdio_fwnames, case BRCMF_BLOB_CLM:
ARRAY_SIZE(brcmf_sdio_fwnames), *fw = sdiodev->clm_fw;
fwnames, ARRAY_SIZE(fwnames)); sdiodev->clm_fw = NULL;
if (!fwreq) break;
return -ENOMEM; default:
return -ENOENT;
}
if (!*fw)
return -ENOENT;
kfree(fwreq);
return 0; return 0;
} }
...@@ -4182,13 +4183,14 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { ...@@ -4182,13 +4183,14 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.wowl_config = brcmf_sdio_wowl_config, .wowl_config = brcmf_sdio_wowl_config,
.get_ramsize = brcmf_sdio_bus_get_ramsize, .get_ramsize = brcmf_sdio_bus_get_ramsize,
.get_memdump = brcmf_sdio_bus_get_memdump, .get_memdump = brcmf_sdio_bus_get_memdump,
.get_fwname = brcmf_sdio_get_fwname, .get_blob = brcmf_sdio_get_blob,
.debugfs_create = brcmf_sdio_debugfs_create, .debugfs_create = brcmf_sdio_debugfs_create,
.reset = brcmf_sdio_bus_reset .reset = brcmf_sdio_bus_reset
}; };
#define BRCMF_SDIO_FW_CODE 0 #define BRCMF_SDIO_FW_CODE 0
#define BRCMF_SDIO_FW_NVRAM 1 #define BRCMF_SDIO_FW_NVRAM 1
#define BRCMF_SDIO_FW_CLM 2
static void brcmf_sdio_firmware_callback(struct device *dev, int err, static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq) struct brcmf_fw_request *fwreq)
...@@ -4211,6 +4213,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, ...@@ -4211,6 +4213,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
code = fwreq->items[BRCMF_SDIO_FW_CODE].binary; code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data; nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len; nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
sdiod->clm_fw = fwreq->items[BRCMF_SDIO_FW_CLM].binary;
kfree(fwreq); kfree(fwreq);
/* try to download image and nvram to the dongle */ /* try to download image and nvram to the dongle */
...@@ -4409,6 +4412,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) ...@@ -4409,6 +4412,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
struct brcmf_fw_name fwnames[] = { struct brcmf_fw_name fwnames[] = {
{ ".bin", bus->sdiodev->fw_name }, { ".bin", bus->sdiodev->fw_name },
{ ".txt", bus->sdiodev->nvram_name }, { ".txt", bus->sdiodev->nvram_name },
{ ".clm_blob", bus->sdiodev->clm_name },
}; };
fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
...@@ -4420,6 +4424,8 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) ...@@ -4420,6 +4424,8 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
fwreq->board_type = bus->sdiodev->settings->board_type; fwreq->board_type = bus->sdiodev->settings->board_type;
return fwreq; return fwreq;
...@@ -4576,6 +4582,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) ...@@ -4576,6 +4582,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
if (bus->sdiodev->settings) if (bus->sdiodev->settings)
brcmf_release_module_param(bus->sdiodev->settings); brcmf_release_module_param(bus->sdiodev->settings);
release_firmware(bus->sdiodev->clm_fw);
bus->sdiodev->clm_fw = NULL;
kfree(bus->rxbuf); kfree(bus->rxbuf);
kfree(bus->hdrbuf); kfree(bus->hdrbuf);
kfree(bus); kfree(bus);
......
...@@ -186,9 +186,11 @@ struct brcmf_sdio_dev { ...@@ -186,9 +186,11 @@ struct brcmf_sdio_dev {
struct sg_table sgtable; struct sg_table sgtable;
char fw_name[BRCMF_FW_NAME_LEN]; char fw_name[BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_NAME_LEN];
char clm_name[BRCMF_FW_NAME_LEN];
bool wowl_enabled; bool wowl_enabled;
enum brcmf_sdiod_state state; enum brcmf_sdiod_state state;
struct brcmf_sdiod_freezer *freezer; struct brcmf_sdiod_freezer *freezer;
const struct firmware *clm_fw;
}; };
/* sdio core registers */ /* sdio core registers */
......
...@@ -1154,24 +1154,11 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, ...@@ -1154,24 +1154,11 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
return NULL; return NULL;
} }
static static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) enum brcmf_blob_type type)
{ {
struct brcmf_bus *bus = dev_get_drvdata(dev); /* No blobs for USB devices... */
struct brcmf_fw_request *fwreq; return -ENOENT;
struct brcmf_fw_name fwnames[] = {
{ ext, fw_name },
};
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;
kfree(fwreq);
return 0;
} }
static const struct brcmf_bus_ops brcmf_usb_bus_ops = { static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
...@@ -1180,7 +1167,7 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = { ...@@ -1180,7 +1167,7 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx, .txdata = brcmf_usb_tx,
.txctl = brcmf_usb_tx_ctlpkt, .txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt, .rxctl = brcmf_usb_rx_ctlpkt,
.get_fwname = brcmf_usb_get_fwname, .get_blob = brcmf_usb_get_blob,
}; };
#define BRCMF_USB_FW_CODE 0 #define BRCMF_USB_FW_CODE 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment