Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2013 Broadcom Corporation
0004  */
0005 
0006 #include <linux/efi.h>
0007 #include <linux/kernel.h>
0008 #include <linux/slab.h>
0009 #include <linux/device.h>
0010 #include <linux/firmware.h>
0011 #include <linux/module.h>
0012 #include <linux/bcm47xx_nvram.h>
0013 
0014 #include "debug.h"
0015 #include "firmware.h"
0016 #include "core.h"
0017 #include "common.h"
0018 #include "chip.h"
0019 
0020 #define BRCMF_FW_MAX_NVRAM_SIZE         64000
0021 #define BRCMF_FW_NVRAM_DEVPATH_LEN      19  /* devpath0=pcie/1/4/ */
0022 #define BRCMF_FW_NVRAM_PCIEDEV_LEN      10  /* pcie/1/4/ + \0 */
0023 #define BRCMF_FW_DEFAULT_BOARDREV       "boardrev=0xff"
0024 
0025 enum nvram_parser_state {
0026     IDLE,
0027     KEY,
0028     VALUE,
0029     COMMENT,
0030     END
0031 };
0032 
0033 /**
0034  * struct nvram_parser - internal info for parser.
0035  *
0036  * @state: current parser state.
0037  * @data: input buffer being parsed.
0038  * @nvram: output buffer with parse result.
0039  * @nvram_len: length of parse result.
0040  * @line: current line.
0041  * @column: current column in line.
0042  * @pos: byte offset in input buffer.
0043  * @entry: start position of key,value entry.
0044  * @multi_dev_v1: detect pcie multi device v1 (compressed).
0045  * @multi_dev_v2: detect pcie multi device v2.
0046  * @boardrev_found: nvram contains boardrev information.
0047  */
0048 struct nvram_parser {
0049     enum nvram_parser_state state;
0050     const u8 *data;
0051     u8 *nvram;
0052     u32 nvram_len;
0053     u32 line;
0054     u32 column;
0055     u32 pos;
0056     u32 entry;
0057     bool multi_dev_v1;
0058     bool multi_dev_v2;
0059     bool boardrev_found;
0060 };
0061 
0062 /*
0063  * is_nvram_char() - check if char is a valid one for NVRAM entry
0064  *
0065  * It accepts all printable ASCII chars except for '#' which opens a comment.
0066  * Please note that ' ' (space) while accepted is not a valid key name char.
0067  */
0068 static bool is_nvram_char(char c)
0069 {
0070     /* comment marker excluded */
0071     if (c == '#')
0072         return false;
0073 
0074     /* key and value may have any other readable character */
0075     return (c >= 0x20 && c < 0x7f);
0076 }
0077 
0078 static bool is_whitespace(char c)
0079 {
0080     return (c == ' ' || c == '\r' || c == '\n' || c == '\t');
0081 }
0082 
0083 static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
0084 {
0085     char c;
0086 
0087     c = nvp->data[nvp->pos];
0088     if (c == '\n')
0089         return COMMENT;
0090     if (is_whitespace(c) || c == '\0')
0091         goto proceed;
0092     if (c == '#')
0093         return COMMENT;
0094     if (is_nvram_char(c)) {
0095         nvp->entry = nvp->pos;
0096         return KEY;
0097     }
0098     brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n",
0099           nvp->line, nvp->column);
0100 proceed:
0101     nvp->column++;
0102     nvp->pos++;
0103     return IDLE;
0104 }
0105 
0106 static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
0107 {
0108     enum nvram_parser_state st = nvp->state;
0109     char c;
0110 
0111     c = nvp->data[nvp->pos];
0112     if (c == '=') {
0113         /* ignore RAW1 by treating as comment */
0114         if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
0115             st = COMMENT;
0116         else
0117             st = VALUE;
0118         if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
0119             nvp->multi_dev_v1 = true;
0120         if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
0121             nvp->multi_dev_v2 = true;
0122         if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
0123             nvp->boardrev_found = true;
0124     } else if (!is_nvram_char(c) || c == ' ') {
0125         brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
0126               nvp->line, nvp->column);
0127         return COMMENT;
0128     }
0129 
0130     nvp->column++;
0131     nvp->pos++;
0132     return st;
0133 }
0134 
0135 static enum nvram_parser_state
0136 brcmf_nvram_handle_value(struct nvram_parser *nvp)
0137 {
0138     char c;
0139     char *skv;
0140     char *ekv;
0141     u32 cplen;
0142 
0143     c = nvp->data[nvp->pos];
0144     if (!is_nvram_char(c)) {
0145         /* key,value pair complete */
0146         ekv = (u8 *)&nvp->data[nvp->pos];
0147         skv = (u8 *)&nvp->data[nvp->entry];
0148         cplen = ekv - skv;
0149         if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
0150             return END;
0151         /* copy to output buffer */
0152         memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
0153         nvp->nvram_len += cplen;
0154         nvp->nvram[nvp->nvram_len] = '\0';
0155         nvp->nvram_len++;
0156         return IDLE;
0157     }
0158     nvp->pos++;
0159     nvp->column++;
0160     return VALUE;
0161 }
0162 
0163 static enum nvram_parser_state
0164 brcmf_nvram_handle_comment(struct nvram_parser *nvp)
0165 {
0166     char *eoc, *sol;
0167 
0168     sol = (char *)&nvp->data[nvp->pos];
0169     eoc = strchr(sol, '\n');
0170     if (!eoc) {
0171         eoc = strchr(sol, '\0');
0172         if (!eoc)
0173             return END;
0174     }
0175 
0176     /* eat all moving to next line */
0177     nvp->line++;
0178     nvp->column = 1;
0179     nvp->pos += (eoc - sol) + 1;
0180     return IDLE;
0181 }
0182 
0183 static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp)
0184 {
0185     /* final state */
0186     return END;
0187 }
0188 
0189 static enum nvram_parser_state
0190 (*nv_parser_states[])(struct nvram_parser *nvp) = {
0191     brcmf_nvram_handle_idle,
0192     brcmf_nvram_handle_key,
0193     brcmf_nvram_handle_value,
0194     brcmf_nvram_handle_comment,
0195     brcmf_nvram_handle_end
0196 };
0197 
0198 static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
0199                    const u8 *data, size_t data_len)
0200 {
0201     size_t size;
0202 
0203     memset(nvp, 0, sizeof(*nvp));
0204     nvp->data = data;
0205     /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
0206     if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
0207         size = BRCMF_FW_MAX_NVRAM_SIZE;
0208     else
0209         size = data_len;
0210     /* Add space for properties we may add */
0211     size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1;
0212     /* Alloc for extra 0 byte + roundup by 4 + length field */
0213     size += 1 + 3 + sizeof(u32);
0214     nvp->nvram = kzalloc(size, GFP_KERNEL);
0215     if (!nvp->nvram)
0216         return -ENOMEM;
0217 
0218     nvp->line = 1;
0219     nvp->column = 1;
0220     return 0;
0221 }
0222 
0223 /* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
0224  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
0225  * which data is to be returned. v1 is the version where nvram is stored
0226  * compressed and "devpath" maps to index for valid entries.
0227  */
0228 static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
0229                     u16 bus_nr)
0230 {
0231     /* Device path with a leading '=' key-value separator */
0232     char pci_path[] = "=pci/?/?";
0233     size_t pci_len;
0234     char pcie_path[] = "=pcie/?/?";
0235     size_t pcie_len;
0236 
0237     u32 i, j;
0238     bool found;
0239     u8 *nvram;
0240     u8 id;
0241 
0242     nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
0243     if (!nvram)
0244         goto fail;
0245 
0246     /* min length: devpath0=pcie/1/4/ + 0:x=y */
0247     if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
0248         goto fail;
0249 
0250     /* First search for the devpathX and see if it is the configuration
0251      * for domain_nr/bus_nr. Search complete nvp
0252      */
0253     snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
0254          bus_nr);
0255     pci_len = strlen(pci_path);
0256     snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
0257          bus_nr);
0258     pcie_len = strlen(pcie_path);
0259     found = false;
0260     i = 0;
0261     while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
0262         /* Format: devpathX=pcie/Y/Z/
0263          * Y = domain_nr, Z = bus_nr, X = virtual ID
0264          */
0265         if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
0266             (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
0267              !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
0268             id = nvp->nvram[i + 7] - '0';
0269             found = true;
0270             break;
0271         }
0272         while (nvp->nvram[i] != 0)
0273             i++;
0274         i++;
0275     }
0276     if (!found)
0277         goto fail;
0278 
0279     /* Now copy all valid entries, release old nvram and assign new one */
0280     i = 0;
0281     j = 0;
0282     while (i < nvp->nvram_len) {
0283         if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
0284             i += 2;
0285             if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
0286                 nvp->boardrev_found = true;
0287             while (nvp->nvram[i] != 0) {
0288                 nvram[j] = nvp->nvram[i];
0289                 i++;
0290                 j++;
0291             }
0292             nvram[j] = 0;
0293             j++;
0294         }
0295         while (nvp->nvram[i] != 0)
0296             i++;
0297         i++;
0298     }
0299     kfree(nvp->nvram);
0300     nvp->nvram = nvram;
0301     nvp->nvram_len = j;
0302     return;
0303 
0304 fail:
0305     kfree(nvram);
0306     nvp->nvram_len = 0;
0307 }
0308 
0309 /* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
0310  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
0311  * which data is to be returned. v2 is the version where nvram is stored
0312  * uncompressed, all relevant valid entries are identified by
0313  * pcie/domain_nr/bus_nr:
0314  */
0315 static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
0316                     u16 bus_nr)
0317 {
0318     char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
0319     size_t len;
0320     u32 i, j;
0321     u8 *nvram;
0322 
0323     nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
0324     if (!nvram) {
0325         nvp->nvram_len = 0;
0326         return;
0327     }
0328 
0329     /* Copy all valid entries, release old nvram and assign new one.
0330      * Valid entries are of type pcie/X/Y/ where X = domain_nr and
0331      * Y = bus_nr.
0332      */
0333     snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
0334     len = strlen(prefix);
0335     i = 0;
0336     j = 0;
0337     while (i < nvp->nvram_len - len) {
0338         if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
0339             i += len;
0340             if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
0341                 nvp->boardrev_found = true;
0342             while (nvp->nvram[i] != 0) {
0343                 nvram[j] = nvp->nvram[i];
0344                 i++;
0345                 j++;
0346             }
0347             nvram[j] = 0;
0348             j++;
0349         }
0350         while (nvp->nvram[i] != 0)
0351             i++;
0352         i++;
0353     }
0354     kfree(nvp->nvram);
0355     nvp->nvram = nvram;
0356     nvp->nvram_len = j;
0357 }
0358 
0359 static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
0360 {
0361     if (nvp->boardrev_found)
0362         return;
0363 
0364     memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
0365            strlen(BRCMF_FW_DEFAULT_BOARDREV));
0366     nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
0367     nvp->nvram[nvp->nvram_len] = '\0';
0368     nvp->nvram_len++;
0369 }
0370 
0371 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
0372  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
0373  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
0374  * End of buffer is completed with token identifying length of buffer.
0375  */
0376 static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
0377                   u32 *new_length, u16 domain_nr, u16 bus_nr)
0378 {
0379     struct nvram_parser nvp;
0380     u32 pad;
0381     u32 token;
0382     __le32 token_le;
0383 
0384     if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
0385         return NULL;
0386 
0387     while (nvp.pos < data_len) {
0388         nvp.state = nv_parser_states[nvp.state](&nvp);
0389         if (nvp.state == END)
0390             break;
0391     }
0392     if (nvp.multi_dev_v1) {
0393         nvp.boardrev_found = false;
0394         brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
0395     } else if (nvp.multi_dev_v2) {
0396         nvp.boardrev_found = false;
0397         brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
0398     }
0399 
0400     if (nvp.nvram_len == 0) {
0401         kfree(nvp.nvram);
0402         return NULL;
0403     }
0404 
0405     brcmf_fw_add_defaults(&nvp);
0406 
0407     pad = nvp.nvram_len;
0408     *new_length = roundup(nvp.nvram_len + 1, 4);
0409     while (pad != *new_length) {
0410         nvp.nvram[pad] = 0;
0411         pad++;
0412     }
0413 
0414     token = *new_length / 4;
0415     token = (~token << 16) | (token & 0x0000FFFF);
0416     token_le = cpu_to_le32(token);
0417 
0418     memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le));
0419     *new_length += sizeof(token_le);
0420 
0421     return nvp.nvram;
0422 }
0423 
0424 void brcmf_fw_nvram_free(void *nvram)
0425 {
0426     kfree(nvram);
0427 }
0428 
0429 struct brcmf_fw {
0430     struct device *dev;
0431     struct brcmf_fw_request *req;
0432     u32 curpos;
0433     void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
0434 };
0435 
0436 #ifdef CONFIG_EFI
0437 /* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV"
0438  * to specify "worldwide" compatible settings, but these 2 ccode-s do not work
0439  * properly. "ccode=ALL" causes channels 12 and 13 to not be available,
0440  * "ccode=XV" causes all 5GHz channels to not be available. So we replace both
0441  * with "ccode=X2" which allows channels 12+13 and 5Ghz channels in
0442  * no-Initiate-Radiation mode. This means that we will never send on these
0443  * channels without first having received valid wifi traffic on the channel.
0444  */
0445 static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
0446 {
0447     char *ccode;
0448 
0449     ccode = strnstr((char *)data, "ccode=ALL", data_len);
0450     if (!ccode)
0451         ccode = strnstr((char *)data, "ccode=XV\r", data_len);
0452     if (!ccode)
0453         return;
0454 
0455     ccode[6] = 'X';
0456     ccode[7] = '2';
0457     ccode[8] = '\r';
0458 }
0459 
0460 static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
0461 {
0462     efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f,
0463                    0x43, 0x26, 0x81, 0x23, 0xd1, 0x13);
0464     unsigned long data_len = 0;
0465     efi_status_t status;
0466     u8 *data = NULL;
0467 
0468     if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
0469         return NULL;
0470 
0471     status = efi.get_variable(L"nvram", &guid, NULL, &data_len, NULL);
0472     if (status != EFI_BUFFER_TOO_SMALL)
0473         goto fail;
0474 
0475     data = kmalloc(data_len, GFP_KERNEL);
0476     if (!data)
0477         goto fail;
0478 
0479     status = efi.get_variable(L"nvram", &guid, NULL, &data_len, data);
0480     if (status != EFI_SUCCESS)
0481         goto fail;
0482 
0483     brcmf_fw_fix_efi_nvram_ccode(data, data_len);
0484     brcmf_info("Using nvram EFI variable\n");
0485 
0486     *data_len_ret = data_len;
0487     return data;
0488 fail:
0489     kfree(data);
0490     return NULL;
0491 }
0492 #else
0493 static inline u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
0494 #endif
0495 
0496 static void brcmf_fw_free_request(struct brcmf_fw_request *req)
0497 {
0498     struct brcmf_fw_item *item;
0499     int i;
0500 
0501     for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
0502         if (item->type == BRCMF_FW_TYPE_BINARY)
0503             release_firmware(item->binary);
0504         else if (item->type == BRCMF_FW_TYPE_NVRAM)
0505             brcmf_fw_nvram_free(item->nv_data.data);
0506     }
0507     kfree(req);
0508 }
0509 
0510 static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
0511 {
0512     struct brcmf_fw *fwctx = ctx;
0513     struct brcmf_fw_item *cur;
0514     bool free_bcm47xx_nvram = false;
0515     bool kfree_nvram = false;
0516     u32 nvram_length = 0;
0517     void *nvram = NULL;
0518     u8 *data = NULL;
0519     size_t data_len;
0520 
0521     brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
0522 
0523     cur = &fwctx->req->items[fwctx->curpos];
0524 
0525     if (fw && fw->data) {
0526         data = (u8 *)fw->data;
0527         data_len = fw->size;
0528     } else {
0529         if ((data = bcm47xx_nvram_get_contents(&data_len)))
0530             free_bcm47xx_nvram = true;
0531         else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
0532             kfree_nvram = true;
0533         else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
0534             goto fail;
0535     }
0536 
0537     if (data)
0538         nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
0539                          fwctx->req->domain_nr,
0540                          fwctx->req->bus_nr);
0541 
0542     if (free_bcm47xx_nvram)
0543         bcm47xx_nvram_release_contents(data);
0544     if (kfree_nvram)
0545         kfree(data);
0546 
0547     release_firmware(fw);
0548     if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
0549         goto fail;
0550 
0551     brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
0552     cur->nv_data.data = nvram;
0553     cur->nv_data.len = nvram_length;
0554     return 0;
0555 
0556 fail:
0557     return -ENOENT;
0558 }
0559 
0560 static int brcmf_fw_complete_request(const struct firmware *fw,
0561                      struct brcmf_fw *fwctx)
0562 {
0563     struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
0564     int ret = 0;
0565 
0566     brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path, fw ? "" : "not ");
0567 
0568     switch (cur->type) {
0569     case BRCMF_FW_TYPE_NVRAM:
0570         ret = brcmf_fw_request_nvram_done(fw, fwctx);
0571         break;
0572     case BRCMF_FW_TYPE_BINARY:
0573         if (fw)
0574             cur->binary = fw;
0575         else
0576             ret = -ENOENT;
0577         break;
0578     default:
0579         /* something fishy here so bail out early */
0580         brcmf_err("unknown fw type: %d\n", cur->type);
0581         release_firmware(fw);
0582         ret = -EINVAL;
0583     }
0584 
0585     return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
0586 }
0587 
0588 static char *brcm_alt_fw_path(const char *path, const char *board_type)
0589 {
0590     char alt_path[BRCMF_FW_NAME_LEN];
0591     char suffix[5];
0592 
0593     strscpy(alt_path, path, BRCMF_FW_NAME_LEN);
0594     /* At least one character + suffix */
0595     if (strlen(alt_path) < 5)
0596         return NULL;
0597 
0598     /* strip .txt or .bin at the end */
0599     strscpy(suffix, alt_path + strlen(alt_path) - 4, 5);
0600     alt_path[strlen(alt_path) - 4] = 0;
0601     strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
0602     strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN);
0603     strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN);
0604 
0605     return kstrdup(alt_path, GFP_KERNEL);
0606 }
0607 
0608 static int brcmf_fw_request_firmware(const struct firmware **fw,
0609                      struct brcmf_fw *fwctx)
0610 {
0611     struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
0612     int ret;
0613 
0614     /* Files can be board-specific, first try a board-specific path */
0615     if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
0616         char *alt_path;
0617 
0618         alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type);
0619         if (!alt_path)
0620             goto fallback;
0621 
0622         ret = request_firmware(fw, alt_path, fwctx->dev);
0623         kfree(alt_path);
0624         if (ret == 0)
0625             return ret;
0626     }
0627 
0628 fallback:
0629     return request_firmware(fw, cur->path, fwctx->dev);
0630 }
0631 
0632 static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
0633 {
0634     struct brcmf_fw *fwctx = ctx;
0635     int ret;
0636 
0637     ret = brcmf_fw_complete_request(fw, fwctx);
0638 
0639     while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
0640         brcmf_fw_request_firmware(&fw, fwctx);
0641         ret = brcmf_fw_complete_request(fw, ctx);
0642     }
0643 
0644     if (ret) {
0645         brcmf_fw_free_request(fwctx->req);
0646         fwctx->req = NULL;
0647     }
0648     fwctx->done(fwctx->dev, ret, fwctx->req);
0649     kfree(fwctx);
0650 }
0651 
0652 static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx)
0653 {
0654     struct brcmf_fw *fwctx = ctx;
0655     struct brcmf_fw_item *first = &fwctx->req->items[0];
0656     int ret = 0;
0657 
0658     /* Fall back to canonical path if board firmware not found */
0659     if (!fw)
0660         ret = request_firmware_nowait(THIS_MODULE, true, first->path,
0661                           fwctx->dev, GFP_KERNEL, fwctx,
0662                           brcmf_fw_request_done);
0663 
0664     if (fw || ret < 0)
0665         brcmf_fw_request_done(fw, ctx);
0666 }
0667 
0668 static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
0669 {
0670     struct brcmf_fw_item *item;
0671     int i;
0672 
0673     if (!req->n_items)
0674         return false;
0675 
0676     for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
0677         if (!item->path)
0678             return false;
0679     }
0680     return true;
0681 }
0682 
0683 int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
0684                void (*fw_cb)(struct device *dev, int err,
0685                      struct brcmf_fw_request *req))
0686 {
0687     struct brcmf_fw_item *first = &req->items[0];
0688     struct brcmf_fw *fwctx;
0689     char *alt_path = NULL;
0690     int ret;
0691 
0692     brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
0693     if (!fw_cb)
0694         return -EINVAL;
0695 
0696     if (!brcmf_fw_request_is_valid(req))
0697         return -EINVAL;
0698 
0699     fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
0700     if (!fwctx)
0701         return -ENOMEM;
0702 
0703     fwctx->dev = dev;
0704     fwctx->req = req;
0705     fwctx->done = fw_cb;
0706 
0707     /* First try alternative board-specific path if any */
0708     if (fwctx->req->board_type)
0709         alt_path = brcm_alt_fw_path(first->path,
0710                         fwctx->req->board_type);
0711     if (alt_path) {
0712         ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
0713                           fwctx->dev, GFP_KERNEL, fwctx,
0714                           brcmf_fw_request_done_alt_path);
0715         kfree(alt_path);
0716     } else {
0717         ret = request_firmware_nowait(THIS_MODULE, true, first->path,
0718                           fwctx->dev, GFP_KERNEL, fwctx,
0719                           brcmf_fw_request_done);
0720     }
0721     if (ret < 0)
0722         brcmf_fw_request_done(NULL, fwctx);
0723 
0724     return 0;
0725 }
0726 
0727 struct brcmf_fw_request *
0728 brcmf_fw_alloc_request(u32 chip, u32 chiprev,
0729                const struct brcmf_firmware_mapping mapping_table[],
0730                u32 table_size, struct brcmf_fw_name *fwnames,
0731                u32 n_fwnames)
0732 {
0733     struct brcmf_fw_request *fwreq;
0734     char chipname[12];
0735     const char *mp_path;
0736     size_t mp_path_len;
0737     u32 i, j;
0738     char end = '\0';
0739 
0740     for (i = 0; i < table_size; i++) {
0741         if (mapping_table[i].chipid == chip &&
0742             mapping_table[i].revmask & BIT(chiprev))
0743             break;
0744     }
0745 
0746     brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
0747 
0748     if (i == table_size) {
0749         brcmf_err("Unknown chip %s\n", chipname);
0750         return NULL;
0751     }
0752 
0753     fwreq = kzalloc(struct_size(fwreq, items, n_fwnames), GFP_KERNEL);
0754     if (!fwreq)
0755         return NULL;
0756 
0757     brcmf_info("using %s for chip %s\n",
0758            mapping_table[i].fw_base, chipname);
0759 
0760     mp_path = brcmf_mp_global.firmware_path;
0761     mp_path_len = strnlen(mp_path, BRCMF_FW_ALTPATH_LEN);
0762     if (mp_path_len)
0763         end = mp_path[mp_path_len - 1];
0764 
0765     fwreq->n_items = n_fwnames;
0766 
0767     for (j = 0; j < n_fwnames; j++) {
0768         fwreq->items[j].path = fwnames[j].path;
0769         fwnames[j].path[0] = '\0';
0770         /* check if firmware path is provided by module parameter */
0771         if (brcmf_mp_global.firmware_path[0] != '\0') {
0772             strlcpy(fwnames[j].path, mp_path,
0773                 BRCMF_FW_NAME_LEN);
0774 
0775             if (end != '/') {
0776                 strlcat(fwnames[j].path, "/",
0777                     BRCMF_FW_NAME_LEN);
0778             }
0779         }
0780         strlcat(fwnames[j].path, mapping_table[i].fw_base,
0781             BRCMF_FW_NAME_LEN);
0782         strlcat(fwnames[j].path, fwnames[j].extension,
0783             BRCMF_FW_NAME_LEN);
0784         fwreq->items[j].path = fwnames[j].path;
0785     }
0786 
0787     return fwreq;
0788 }