117 lines
3.9 KiB
Diff
117 lines
3.9 KiB
Diff
|
After some crashes in the 3D engine (!) on the Samsung GT-I8530
|
||
|
it turns out that the main firmware file can be device dependent,
|
||
|
something that was previously only handled for the NVRAM
|
||
|
parameter file.
|
||
|
|
||
|
Rewrite the code a bit so we can a per-board suffixed firmware
|
||
|
binary as well, if this does not exist we fall back to the
|
||
|
canonical firmware name.
|
||
|
|
||
|
Example: a 4330 device with the OF board compatible is
|
||
|
"samsung,gavini". We will first try
|
||
|
"brcmfmac4330-sdio.samsung,gavini.bin" then "brcmfmac4330-sdio.bin"
|
||
|
if that does not work.
|
||
|
|
||
|
Cc: phone-devel@vger.kernel.org
|
||
|
Cc: newbyte@disroot.org
|
||
|
Cc: Stephan Gerhold <stephan@gerhold.net>
|
||
|
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
|
||
|
---
|
||
|
.../broadcom/brcm80211/brcmfmac/firmware.c | 53 +++++++++++++++----
|
||
|
1 file changed, 42 insertions(+), 11 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||
|
index d40104b8df55..adfdfc654b10 100644
|
||
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||
|
@@ -594,28 +594,47 @@ 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)
|
||
|
+{
|
||
|
+ char alt_path[BRCMF_FW_NAME_LEN];
|
||
|
+ char suffix[5];
|
||
|
+
|
||
|
+ strscpy(alt_path, path, BRCMF_FW_NAME_LEN);
|
||
|
+ /* At least one character + suffix */
|
||
|
+ if (strlen(alt_path) < 5)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ /* strip .txt or .bin at the end */
|
||
|
+ strscpy(suffix, alt_path + strlen(alt_path) - 4, 5);
|
||
|
+ alt_path[strlen(alt_path) - 4] = 0;
|
||
|
+ strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
|
||
|
+ strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN);
|
||
|
+ strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN);
|
||
|
+
|
||
|
+ return kstrdup(alt_path, GFP_KERNEL);
|
||
|
+}
|
||
|
+
|
||
|
static int brcmf_fw_request_firmware(const struct firmware **fw,
|
||
|
struct brcmf_fw *fwctx)
|
||
|
{
|
||
|
struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
|
||
|
int ret;
|
||
|
|
||
|
- /* nvram files are board-specific, first try a board-specific path */
|
||
|
+ /* Files can be board-specific, first try a board-specific path */
|
||
|
if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
|
||
|
- char alt_path[BRCMF_FW_NAME_LEN];
|
||
|
+ char *alt_path;
|
||
|
|
||
|
- strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN);
|
||
|
- /* strip .txt at the end */
|
||
|
- alt_path[strlen(alt_path) - 4] = 0;
|
||
|
- strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
|
||
|
- strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
|
||
|
- strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
|
||
|
+ alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type);
|
||
|
+ if (!alt_path)
|
||
|
+ goto fallback;
|
||
|
|
||
|
ret = request_firmware(fw, alt_path, fwctx->dev);
|
||
|
+ kfree(alt_path);
|
||
|
if (ret == 0)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+fallback:
|
||
|
return request_firmware(fw, cur->path, fwctx->dev);
|
||
|
}
|
||
|
|
||
|
@@ -660,6 +679,7 @@ 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));
|
||
|
@@ -677,9 +697,20 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
|
||
|
fwctx->req = req;
|
||
|
fwctx->done = fw_cb;
|
||
|
|
||
|
- ret = request_firmware_nowait(THIS_MODULE, true, first->path,
|
||
|
- fwctx->dev, GFP_KERNEL, fwctx,
|
||
|
- brcmf_fw_request_done);
|
||
|
+ /* 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,
|
||
|
+ fwctx->dev, GFP_KERNEL, fwctx,
|
||
|
+ brcmf_fw_request_done);
|
||
|
+ kfree(alt_path);
|
||
|
+ }
|
||
|
+ /* Else try canonical path */
|
||
|
+ if (ret) {
|
||
|
+ ret = request_firmware_nowait(THIS_MODULE, true, first->path,
|
||
|
+ fwctx->dev, GFP_KERNEL, fwctx,
|
||
|
+ brcmf_fw_request_done);
|
||
|
+ }
|
||
|
if (ret < 0)
|
||
|
brcmf_fw_request_done(NULL, fwctx);
|
||
|
|
||
|
--
|
||
|
2.31.1
|