wifi: brcmfmac: pcie/sdio/usb: Get CLM blob via standard firmware mechanism
authorHector Martin <marcan@marcan.st>
Fri, 16 Sep 2022 16:02:36 +0000 (17:02 +0100)
committerKalle Valo <kvalo@kernel.org>
Mon, 19 Sep 2022 09:59:33 +0000 (12:59 +0300)
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: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Hector Martin <marcan@marcan.st>
Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/E1oZDnY-0077aA-8f@rmk-PC.armlinux.org.uk
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c

index ae5af76e256840b4a96ac9c567eb5349db67439b..2208ab3aa79598b3d122333b2958c1acc5375f78 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef BRCMFMAC_BUS_H
 #define BRCMFMAC_BUS_H
 
+#include <linux/kernel.h>
+#include <linux/firmware.h>
 #include "debug.h"
 
 /* IDs of the 6 default common rings of msgbuf protocol */
@@ -34,6 +36,11 @@ enum brcmf_bus_protocol_type {
        BRCMF_PROTO_MSGBUF
 };
 
+/* Firmware blobs that may be available */
+enum brcmf_blob_type {
+       BRCMF_BLOB_CLM,
+};
+
 struct brcmf_mp_device;
 
 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
  * @get_ramsize: obtain size of device memory.
  * @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
  * bus specific driver. For control messages to common driver
@@ -77,8 +84,8 @@ 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, const char *ext,
-                         unsigned char *fw_name);
+       int (*get_blob)(struct device *dev, const struct firmware **fw,
+                       enum brcmf_blob_type type);
        void (*debugfs_create)(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)
 }
 
 static inline
-int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
-                        unsigned char *fw_name)
+int brcmf_bus_get_blob(struct brcmf_bus *bus, const struct firmware **fw,
+                      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
index 372deeb6947726c54b0b317e17a81e6019249286..74020fa100659e554574173d8ba77db7ff8b0de7 100644 (file)
@@ -123,7 +123,6 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
        struct brcmf_bus *bus = drvr->bus_if;
        struct brcmf_dload_data_le *chunk_buf;
        const struct firmware *clm = NULL;
-       u8 clm_name[BRCMF_FW_NAME_LEN];
        u32 chunk_len;
        u32 datalen;
        u32 cumulative_len;
@@ -133,15 +132,8 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       memset(clm_name, 0, sizeof(clm_name));
-       err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
-       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) {
+       err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM);
+       if (err || !clm) {
                brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
                           err);
                return 0;
index 97f0f13dfe505bec40d08784b191439516f6d560..ec73d2620ec9b00cde246af0cfb2b286d65620b7 100644 (file)
@@ -66,6 +66,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
 
 /* per-board firmware binaries */
 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[] = {
        BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
@@ -261,6 +262,8 @@ struct brcmf_pciedev_info {
        struct pci_dev *pdev;
        char fw_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 *tcm;
        u32 ram_base;
@@ -1382,23 +1385,25 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
        return 0;
 }
 
-static
-int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,
+                              enum brcmf_blob_type type)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       struct brcmf_fw_name fwnames[] = {
-               { ext, fw_name },
-       };
+       struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+       struct brcmf_pciedev_info *devinfo = buspub->devinfo;
 
-       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;
+       switch (type) {
+       case BRCMF_BLOB_CLM:
+               *fw = devinfo->clm_fw;
+               devinfo->clm_fw = NULL;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       if (!*fw)
+               return -ENOENT;
 
-       kfree(fwreq);
        return 0;
 }
 
@@ -1445,7 +1450,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
        .wowl_config = brcmf_pcie_wowl_config,
        .get_ramsize = brcmf_pcie_get_ramsize,
        .get_memdump = brcmf_pcie_get_memdump,
-       .get_fwname = brcmf_pcie_get_fwname,
+       .get_blob = brcmf_pcie_get_blob,
        .reset = brcmf_pcie_reset,
 };
 
@@ -1731,6 +1736,7 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
 
 #define BRCMF_PCIE_FW_CODE     0
 #define BRCMF_PCIE_FW_NVRAM    1
+#define BRCMF_PCIE_FW_CLM      2
 
 static void brcmf_pcie_setup(struct device *dev, int ret,
                             struct brcmf_fw_request *fwreq)
@@ -1755,6 +1761,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
        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;
+       devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
        kfree(fwreq);
 
        ret = brcmf_chip_get_raminfo(devinfo->ci);
@@ -1830,6 +1837,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
        struct brcmf_fw_name fwnames[] = {
                { ".bin", devinfo->fw_name },
                { ".txt", devinfo->nvram_name },
+               { ".clm_blob", devinfo->clm_name },
        };
 
        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)
        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->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;
        /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
        fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
@@ -1981,6 +1991,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
        brcmf_pcie_release_ringbuffers(devinfo);
        brcmf_pcie_reset_device(devinfo);
        brcmf_pcie_release_resource(devinfo);
+       release_firmware(devinfo->clm_fw);
 
        if (devinfo->ci)
                brcmf_chip_detach(devinfo->ci);
index d7072009c47f188eb1ef085afde59207355e7c50..5eb9b3138f09fae1876e219fe6475da4dd6776a8 100644 (file)
@@ -4131,23 +4131,24 @@ brcmf_sdio_watchdog(struct timer_list *t)
        }
 }
 
-static
-int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_sdio_get_blob(struct device *dev, const struct firmware **fw,
+                              enum brcmf_blob_type type)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       struct brcmf_fw_name fwnames[] = {
-               { ext, fw_name },
-       };
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
-       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;
+       switch (type) {
+       case BRCMF_BLOB_CLM:
+               *fw = sdiodev->clm_fw;
+               sdiodev->clm_fw = NULL;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       if (!*fw)
+               return -ENOENT;
 
-       kfree(fwreq);
        return 0;
 }
 
@@ -4182,13 +4183,14 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
        .wowl_config = brcmf_sdio_wowl_config,
        .get_ramsize = brcmf_sdio_bus_get_ramsize,
        .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,
        .reset = brcmf_sdio_bus_reset
 };
 
 #define BRCMF_SDIO_FW_CODE     0
 #define BRCMF_SDIO_FW_NVRAM    1
+#define BRCMF_SDIO_FW_CLM      2
 
 static void brcmf_sdio_firmware_callback(struct device *dev, int err,
                                         struct brcmf_fw_request *fwreq)
@@ -4211,6 +4213,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
        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;
+       sdiod->clm_fw = fwreq->items[BRCMF_SDIO_FW_CLM].binary;
        kfree(fwreq);
 
        /* try to download image and nvram to the dongle */
@@ -4409,6 +4412,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
        struct brcmf_fw_name fwnames[] = {
                { ".bin", bus->sdiodev->fw_name },
                { ".txt", bus->sdiodev->nvram_name },
+               { ".clm_blob", bus->sdiodev->clm_name },
        };
 
        fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
@@ -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_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;
 
        return fwreq;
@@ -4576,6 +4582,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
                if (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->hdrbuf);
                kfree(bus);
index 47351ff458cab234652b891843de07d0ce0e9119..b76d34d36bde6435f11390a3c10e3f5ccb243acd 100644 (file)
@@ -186,9 +186,11 @@ struct brcmf_sdio_dev {
        struct sg_table sgtable;
        char fw_name[BRCMF_FW_NAME_LEN];
        char nvram_name[BRCMF_FW_NAME_LEN];
+       char clm_name[BRCMF_FW_NAME_LEN];
        bool wowl_enabled;
        enum brcmf_sdiod_state state;
        struct brcmf_sdiod_freezer *freezer;
+       const struct firmware *clm_fw;
 };
 
 /* sdio core registers */
index 9fb68c2dc7e39cec6d1ef547115b5d89aa4dfddd..85e18fb9c497a0ebced73f25bb89735838a4d5f8 100644 (file)
@@ -1154,24 +1154,11 @@ error:
        return NULL;
 }
 
-static
-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
+                             enum brcmf_blob_type type)
 {
-       struct brcmf_bus *bus = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       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;
+       /* No blobs for USB devices... */
+       return -ENOENT;
 }
 
 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,
        .txctl = brcmf_usb_tx_ctlpkt,
        .rxctl = brcmf_usb_rx_ctlpkt,
-       .get_fwname = brcmf_usb_get_fwname,
+       .get_blob = brcmf_usb_get_blob,
 };
 
 #define BRCMF_USB_FW_CODE      0