2 * Copyright (c) 2013 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/device.h>
20 #include <linux/firmware.h>
21 #include <linux/module.h>
22 #include <linux/bcm47xx_nvram.h>
29 #define BRCMF_FW_MAX_NVRAM_SIZE 64000
30 #define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
31 #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
33 enum nvram_parser_state {
42 * struct nvram_parser - internal info for parser.
44 * @state: current parser state.
45 * @data: input buffer being parsed.
46 * @nvram: output buffer with parse result.
47 * @nvram_len: lenght of parse result.
48 * @line: current line.
49 * @column: current column in line.
50 * @pos: byte offset in input buffer.
51 * @entry: start position of key,value entry.
52 * @multi_dev_v1: detect pcie multi device v1 (compressed).
53 * @multi_dev_v2: detect pcie multi device v2.
56 enum nvram_parser_state state;
69 * is_nvram_char() - check if char is a valid one for NVRAM entry
71 * It accepts all printable ASCII chars except for '#' which opens a comment.
72 * Please note that ' ' (space) while accepted is not a valid key name char.
74 static bool is_nvram_char(char c)
76 /* comment marker excluded */
80 /* key and value may have any other readable character */
81 return (c >= 0x20 && c < 0x7f);
84 static bool is_whitespace(char c)
86 return (c == ' ' || c == '\r' || c == '\n' || c == '\t');
89 static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
93 c = nvp->data[nvp->pos];
100 if (is_nvram_char(c)) {
101 nvp->entry = nvp->pos;
104 brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n",
105 nvp->line, nvp->column);
112 static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
114 enum nvram_parser_state st = nvp->state;
117 c = nvp->data[nvp->pos];
119 /* ignore RAW1 by treating as comment */
120 if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
124 if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
125 nvp->multi_dev_v1 = true;
126 if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
127 nvp->multi_dev_v2 = true;
128 } else if (!is_nvram_char(c) || c == ' ') {
129 brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
130 nvp->line, nvp->column);
139 static enum nvram_parser_state
140 brcmf_nvram_handle_value(struct nvram_parser *nvp)
147 c = nvp->data[nvp->pos];
148 if (!is_nvram_char(c)) {
149 /* key,value pair complete */
150 ekv = (u8 *)&nvp->data[nvp->pos];
151 skv = (u8 *)&nvp->data[nvp->entry];
153 if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
155 /* copy to output buffer */
156 memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
157 nvp->nvram_len += cplen;
158 nvp->nvram[nvp->nvram_len] = '\0';
167 static enum nvram_parser_state
168 brcmf_nvram_handle_comment(struct nvram_parser *nvp)
172 sol = (char *)&nvp->data[nvp->pos];
173 eoc = strchr(sol, '\n');
175 eoc = strchr(sol, '\0');
180 /* eat all moving to next line */
183 nvp->pos += (eoc - sol) + 1;
187 static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp)
193 static enum nvram_parser_state
194 (*nv_parser_states[])(struct nvram_parser *nvp) = {
195 brcmf_nvram_handle_idle,
196 brcmf_nvram_handle_key,
197 brcmf_nvram_handle_value,
198 brcmf_nvram_handle_comment,
199 brcmf_nvram_handle_end
202 static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
203 const u8 *data, size_t data_len)
207 memset(nvp, 0, sizeof(*nvp));
209 /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
210 if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
211 size = BRCMF_FW_MAX_NVRAM_SIZE;
214 /* Alloc for extra 0 byte + roundup by 4 + length field */
215 size += 1 + 3 + sizeof(u32);
216 nvp->nvram = kzalloc(size, GFP_KERNEL);
225 /* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
226 * devices. Strip it down for one device, use domain_nr/bus_nr to determine
227 * which data is to be returned. v1 is the version where nvram is stored
228 * compressed and "devpath" maps to index for valid entries.
230 static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
233 /* Device path with a leading '=' key-value separator */
234 char pci_path[] = "=pci/?/?";
236 char pcie_path[] = "=pcie/?/?";
244 nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
248 /* min length: devpath0=pcie/1/4/ + 0:x=y */
249 if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
252 /* First search for the devpathX and see if it is the configuration
253 * for domain_nr/bus_nr. Search complete nvp
255 snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
257 pci_len = strlen(pci_path);
258 snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
260 pcie_len = strlen(pcie_path);
263 while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
264 /* Format: devpathX=pcie/Y/Z/
265 * Y = domain_nr, Z = bus_nr, X = virtual ID
267 if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
268 (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
269 !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
270 id = nvp->nvram[i + 7] - '0';
274 while (nvp->nvram[i] != 0)
281 /* Now copy all valid entries, release old nvram and assign new one */
284 while (i < nvp->nvram_len) {
285 if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
287 while (nvp->nvram[i] != 0) {
288 nvram[j] = nvp->nvram[i];
295 while (nvp->nvram[i] != 0)
309 /* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
310 * devices. Strip it down for one device, use domain_nr/bus_nr to determine
311 * which data is to be returned. v2 is the version where nvram is stored
312 * uncompressed, all relevant valid entries are identified by
313 * pcie/domain_nr/bus_nr:
315 static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
318 char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
323 nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
327 /* Copy all valid entries, release old nvram and assign new one.
328 * Valid entries are of type pcie/X/Y/ where X = domain_nr and
331 snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
332 len = strlen(prefix);
335 while (i < nvp->nvram_len - len) {
336 if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
338 while (nvp->nvram[i] != 0) {
339 nvram[j] = nvp->nvram[i];
346 while (nvp->nvram[i] != 0)
359 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
360 * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
361 * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
362 * End of buffer is completed with token identifying length of buffer.
364 static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
365 u32 *new_length, u16 domain_nr, u16 bus_nr)
367 struct nvram_parser nvp;
372 if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
375 while (nvp.pos < data_len) {
376 nvp.state = nv_parser_states[nvp.state](&nvp);
377 if (nvp.state == END)
380 if (nvp.multi_dev_v1)
381 brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
382 else if (nvp.multi_dev_v2)
383 brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
385 if (nvp.nvram_len == 0) {
391 *new_length = roundup(nvp.nvram_len + 1, 4);
392 while (pad != *new_length) {
397 token = *new_length / 4;
398 token = (~token << 16) | (token & 0x0000FFFF);
399 token_le = cpu_to_le32(token);
401 memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le));
402 *new_length += sizeof(token_le);
407 void brcmf_fw_nvram_free(void *nvram)
415 const struct firmware *code;
416 const char *nvram_name;
419 void (*done)(struct device *dev, const struct firmware *fw,
420 void *nvram_image, u32 nvram_len);
423 static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
425 struct brcmf_fw *fwctx = ctx;
426 u32 nvram_length = 0;
432 brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
433 if (fw && fw->data) {
434 data = (u8 *)fw->data;
438 data = bcm47xx_nvram_get_contents(&data_len);
439 if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
445 nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
446 fwctx->domain_nr, fwctx->bus_nr);
449 bcm47xx_nvram_release_contents(data);
450 release_firmware(fw);
451 if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
454 fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length);
459 brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
460 release_firmware(fwctx->code);
461 device_release_driver(fwctx->dev);
465 static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
467 struct brcmf_fw *fwctx = ctx;
470 brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
474 /* only requested code so done here */
475 if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) {
476 fwctx->done(fwctx->dev, fw, NULL, 0);
481 ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
482 fwctx->dev, GFP_KERNEL, fwctx,
483 brcmf_fw_request_nvram_done);
488 brcmf_fw_request_nvram_done(NULL, fwctx);
492 brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
493 device_release_driver(fwctx->dev);
497 int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
498 const char *code, const char *nvram,
499 void (*fw_cb)(struct device *dev,
500 const struct firmware *fw,
501 void *nvram_image, u32 nvram_len),
502 u16 domain_nr, u16 bus_nr)
504 struct brcmf_fw *fwctx;
506 brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
510 if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
513 fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
518 fwctx->flags = flags;
520 if (flags & BRCMF_FW_REQUEST_NVRAM)
521 fwctx->nvram_name = nvram;
522 fwctx->domain_nr = domain_nr;
523 fwctx->bus_nr = bus_nr;
525 return request_firmware_nowait(THIS_MODULE, true, code, dev,
527 brcmf_fw_request_code_done);
530 int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
531 const char *code, const char *nvram,
532 void (*fw_cb)(struct device *dev,
533 const struct firmware *fw,
534 void *nvram_image, u32 nvram_len))
536 return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
540 int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
541 struct brcmf_firmware_mapping mapping_table[],
542 u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
543 char nvram_name[BRCMF_FW_NAME_LEN])
548 for (i = 0; i < table_size; i++) {
549 if (mapping_table[i].chipid == chip &&
550 mapping_table[i].revmask & BIT(chiprev))
554 if (i == table_size) {
555 brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
559 /* check if firmware path is provided by module parameter */
560 if (brcmf_mp_global.firmware_path[0] != '\0') {
561 strlcpy(fw_name, brcmf_mp_global.firmware_path,
563 if ((nvram_name) && (mapping_table[i].nvram))
564 strlcpy(nvram_name, brcmf_mp_global.firmware_path,
567 end = brcmf_mp_global.firmware_path[
568 strlen(brcmf_mp_global.firmware_path) - 1];
570 strlcat(fw_name, "/", BRCMF_FW_NAME_LEN);
571 if ((nvram_name) && (mapping_table[i].nvram))
572 strlcat(nvram_name, "/", BRCMF_FW_NAME_LEN);
575 strlcat(fw_name, mapping_table[i].fw, BRCMF_FW_NAME_LEN);
576 if ((nvram_name) && (mapping_table[i].nvram))
577 strlcat(nvram_name, mapping_table[i].nvram, BRCMF_FW_NAME_LEN);