From 9d5d96f3b88287511a8db4b0899a0e85088d9842 Mon Sep 17 00:00:00 2001 From: Dean Ramsier Date: Fri, 17 Mar 2023 16:59:04 -0400 Subject: [PATCH 284/296] brcmfmac: Add CLM support to USB interface Upstream change to generic firmware blob implementation did not include USB. Signed-off-by: Dean Ramsier --- .../broadcom/brcm80211/brcmfmac/firmware.c | 48 +++++++++- .../broadcom/brcm80211/brcmfmac/firmware.h | 9 ++ .../broadcom/brcm80211/brcmfmac/usb.c | 91 ++++++++++++++++++- 3 files changed, 143 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 1c13137f2d1a..f35eaf3ea166 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -773,6 +773,50 @@ static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req) return true; } +int brcmf_fw_get_firmware_sync(struct device *dev, struct brcmf_fw_request *req, + void (*fw_cb)(struct device *dev, int err, + struct brcmf_fw_request *req)) +{ + struct brcmf_fw_item *first = &req->items[0]; + struct brcmf_fw *fwctx; + char *alt_path = NULL; + const struct firmware *fw; + int ret = -ENOENT; + + brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); + + if (!brcmf_fw_request_is_valid(req)) + return -EINVAL; + + if (req->n_items > 1) + return -EINVAL; + + fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL); + if (!fwctx) + return -ENOMEM; + + fwctx->dev = dev; + fwctx->req = req; + fwctx->done = fw_cb; + + /* First try alternative board-specific path if any */ + if (fwctx->req->board_types[0]) + alt_path = brcm_alt_fw_path(first->path, + fwctx->req->board_types[0]); + if (alt_path) { + /* Do not fallback to user-mode helper if file does not exist */ + ret = request_firmware_direct(&fw, alt_path, fwctx->dev); + kfree(alt_path); + } + + if (ret == -ENOENT) + ret = request_firmware(&fw, first->path, fwctx->dev); + + brcmf_fw_request_done(fw, fwctx); + + return ret; +} + 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)) @@ -804,8 +848,8 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, if (alt_path) { fwctx->board_index++; ret = request_firmware_nowait(THIS_MODULE, true, alt_path, - fwctx->dev, GFP_KERNEL, fwctx, - brcmf_fw_request_done_alt_path); + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done_alt_path); kfree(alt_path); } else { ret = request_firmware_nowait(THIS_MODULE, true, first->path, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index 2a74e4b00347..f1cc6296bea8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -111,4 +111,13 @@ 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)); +/** + * Request single firmware synchronously. + * Callback is called on a valid request + * whether it succeeds or not. + */ +int brcmf_fw_get_firmware_sync(struct device *dev, struct brcmf_fw_request *req, + void (*fw_cb)(struct device *dev, int err, + struct brcmf_fw_request *req)); + #endif /* BRCMFMAC_FIRMWARE_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index bb2d4d902f57..8251f1c4fe0c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -20,6 +20,7 @@ #include "common.h" #include "bcdc.h" #include "cfg80211.h" +#include "fwil.h" #define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000) @@ -148,6 +149,9 @@ struct brcmf_usbdev_info { const u8 *image; /* buffer for combine fw and nvram */ int image_len; + char clm_name[BRCMF_FW_NAME_LEN]; + const struct firmware *clm_fw; + struct usb_device *usbdev; struct device *dev; struct completion dev_init_done; @@ -168,6 +172,8 @@ struct brcmf_usbdev_info { struct brcmf_mp_device *settings; }; +static int brcmf_usb_get_clmblob(struct brcmf_usbdev_info *devinfo); + static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, struct brcmf_usbreq *req); @@ -677,6 +683,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) static int brcmf_usb_up(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + int ret; brcmf_dbg(USB, "Enter\n"); if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) @@ -704,7 +711,11 @@ static int brcmf_usb_up(struct device *dev) devinfo->ctl_read.wIndex = cpu_to_le16(devinfo->ifnum); } brcmf_usb_rx_fill_all(devinfo); - return 0; + + /* CLM blob needed after firmware download and re-attach has occurred */ + ret = brcmf_usb_get_clmblob(devinfo); + + return ret; } static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo) @@ -1162,8 +1173,21 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw, enum brcmf_blob_type type) { - /* No blobs for USB devices... */ - return -ENOENT; + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + + switch (type) { + case BRCMF_BLOB_CLM: + *fw = devinfo->clm_fw; + devinfo->clm_fw = NULL; + break; + default: + return -ENOENT; + } + + if (!*fw) + return -ENOENT; + + return 0; } static const struct brcmf_bus_ops brcmf_usb_bus_ops = { @@ -1177,6 +1201,9 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = { #define BRCMF_USB_FW_CODE 0 +/* Note - CLM blob file obtained separately from FW so also uses index 0 */ +#define BRCMF_USB_FW_CLM 0 + static void brcmf_usb_probe_phase2(struct device *dev, int ret, struct brcmf_fw_request *fwreq) { @@ -1560,12 +1587,70 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) return ret; } + +static void brcmf_usb_get_clmblob_complete(struct device *dev, int ret, + struct brcmf_fw_request *fwreq) +{ + struct brcmf_bus *bus = dev_get_drvdata(dev); + struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo; + + brcmf_dbg(USB, "Enter\n"); + + if (fwreq) { + devinfo->clm_fw = fwreq->items[BRCMF_USB_FW_CLM].binary; + kfree(fwreq); + } +} + +static int brcmf_usb_get_clmblob(struct brcmf_usbdev_info *devinfo) +{ + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ".clm_blob", devinfo->clm_name }, + }; + struct brcmf_bus *bus_if; + struct brcmf_if *ifp; + struct brcmf_rev_info_le revinfo; + int ret = -1; + + brcmf_dbg(USB, "Enter\n"); + + bus_if = dev_get_drvdata(devinfo->dev); + if (bus_if && bus_if->drvr) { + ifp = bus_if->drvr->iflist[0]; + ret = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, + &revinfo, sizeof(revinfo)); + } + + if (ret) { + brcmf_err("Unable to get version for CLM blob request!"); + goto error_return; + } + + fwreq = brcmf_fw_alloc_request(le32_to_cpu(revinfo.chipnum), + le32_to_cpu(revinfo.chiprev), + brcmf_usb_fwnames, + ARRAY_SIZE(brcmf_usb_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return -ENOMEM; + + fwreq->items[BRCMF_USB_FW_CLM].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_USB_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; + + ret = brcmf_fw_get_firmware_sync(devinfo->dev, fwreq, brcmf_usb_get_clmblob_complete); + +error_return: + return ret; +} + #define BRCMF_USB_DEVICE(dev_id) \ { \ USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id), \ .driver_info = BRCMF_FWVENDOR_WCC \ } + #define LINKSYS_USB_DEVICE(dev_id) \ { \ USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id), \ -- 2.25.1