On 1/4/2022 8:26 AM, Hector Martin wrote:
Apple platforms have firmware and config files identified with multiple dimensions. We want to be able to find the most specific firmware available for any given platform, progressively trying more general firmwares. First, add support for having multiple alternate firmware paths.
Reviewed-by: Arend van Spriel <arend.vanspriel@xxxxxxxxxxxx>
Acked-by: Linus Walleij <linus.walleij@xxxxxxxxxx> Signed-off-by: Hector Martin <marcan@xxxxxxxxx> --- .../broadcom/brcm80211/brcmfmac/firmware.c | 75 ++++++++++++++----- .../broadcom/brcm80211/brcmfmac/firmware.h | 2 + 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 0497b721136a..7570dbf22cdd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -427,6 +427,8 @@ void brcmf_fw_nvram_free(void *nvram) struct brcmf_fw { struct device *dev; struct brcmf_fw_request *req; + const char *alt_paths[BRCMF_FW_MAX_ALT_PATHS]; + int alt_index; u32 curpos; void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); }; @@ -592,14 +594,18 @@ static int brcmf_fw_complete_request(const struct firmware *fw, return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret; }-static char *brcm_alt_fw_path(const char *path, const char *board_type)+static int brcm_alt_fw_paths(const char *path, const char *board_type, + const char *alt_paths[BRCMF_FW_MAX_ALT_PATHS]) { char alt_path[BRCMF_FW_NAME_LEN]; const char *suffix;+ memset(alt_paths, 0, array_size(sizeof(*alt_paths),+ BRCMF_FW_MAX_ALT_PATHS)); + suffix = strrchr(path, '.'); if (!suffix || suffix == path) - return NULL; + return -EINVAL;/* strip extension at the end */strscpy(alt_path, path, BRCMF_FW_NAME_LEN); @@ -609,7 +615,18 @@ static char *brcm_alt_fw_path(const char *path, const char *board_type) strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN); strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN);- return kstrdup(alt_path, GFP_KERNEL);+ alt_paths[0] = kstrdup(alt_path, GFP_KERNEL); + + return 0; +} + +static void +brcm_free_alt_fw_paths(const char *alt_paths[BRCMF_FW_MAX_ALT_PATHS]) +{ + unsigned int i; + + for (i = 0; alt_paths[i]; i++) + kfree(alt_paths[i]); }static int brcmf_fw_request_firmware(const struct firmware **fw,@@ -617,19 +634,25 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, { struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos]; int ret; + unsigned int i;/* Files can be board-specific, first try a board-specific path */if (fwctx->req->board_type) { - char *alt_path; + const char *alt_paths[BRCMF_FW_MAX_ALT_PATHS];- alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type);- if (!alt_path) + if (brcm_alt_fw_paths(cur->path, fwctx->req->board_type, + alt_paths) != 0) goto fallback;- ret = request_firmware(fw, alt_path, fwctx->dev);- kfree(alt_path); - if (ret == 0) - return ret; + for (i = 0; i < BRCMF_FW_MAX_ALT_PATHS && alt_paths[i]; i++) { + ret = firmware_request_nowarn(fw, alt_paths[i], + fwctx->dev); + if (ret == 0) { + brcm_free_alt_fw_paths(alt_paths); + return ret; + } + } + brcm_free_alt_fw_paths(alt_paths); }fallback:@@ -641,6 +664,8 @@ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx) struct brcmf_fw *fwctx = ctx; int ret;+ brcm_free_alt_fw_paths(fwctx->alt_paths);+ ret = brcmf_fw_complete_request(fw, fwctx);while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {@@ -662,13 +687,27 @@ static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx) struct brcmf_fw_item *first = &fwctx->req->items[0]; int ret = 0;- /* Fall back to canonical path if board firmware not found */- if (!fw) + if (fw) { + brcmf_fw_request_done(fw, ctx); + return; + } + + fwctx->alt_index++; + if (fwctx->alt_index < BRCMF_FW_MAX_ALT_PATHS && + fwctx->alt_paths[fwctx->alt_index]) { + /* Try the next alt firmware */ + ret = request_firmware_nowait(THIS_MODULE, true, + fwctx->alt_paths[fwctx->alt_index], + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done_alt_path); + } else { + /* Fall back to canonical path if board firmware not found */ ret = request_firmware_nowait(THIS_MODULE, true, first->path, fwctx->dev, GFP_KERNEL, fwctx, brcmf_fw_request_done); + }- if (fw || ret < 0)+ if (ret < 0) brcmf_fw_request_done(fw, ctx); }@@ -693,7 +732,6 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,{ struct brcmf_fw_item *first = &req->items[0]; struct brcmf_fw *fwctx; - char *alt_path; int ret;brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));@@ -712,12 +750,13 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, fwctx->done = fw_cb;/* First try alternative board-specific path if any */- alt_path = brcm_alt_fw_path(first->path, fwctx->req->board_type); - if (alt_path) { - ret = request_firmware_nowait(THIS_MODULE, true, alt_path, + if (brcm_alt_fw_paths(first->path, req->board_type, + fwctx->alt_paths) == 0) { + fwctx->alt_index = 0; + ret = request_firmware_nowait(THIS_MODULE, true, + fwctx->alt_paths[0], fwctx->dev, GFP_KERNEL, fwctx, brcmf_fw_request_done_alt_path); - kfree(alt_path); } else { ret = request_firmware_nowait(THIS_MODULE, true, first->path, fwctx->dev, GFP_KERNEL, fwctx, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index e290dec9c53d..7f4e6e359c82 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -11,6 +11,8 @@#define BRCMF_FW_DEFAULT_PATH "brcm/" +#define BRCMF_FW_MAX_ALT_PATHS 8+
Any motivation to have 8 here today? In patch #9 I see a list of 6 paths in the commit message so you need 6 and rounded up here to power of 2?
/** * struct brcmf_firmware_mapping - Used to map chipid/revmask to firmware * filename and nvram filename. Each bus type implementation should create
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature