1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
7 /* Algorithmic part of the firmware download.
8 * To be included in the container file providing framework
11 #define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
12 #define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
13 #define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \
14 groupsize, buf, len, ascii) \
15 print_hex_dump_debug("DBG[ FW ]" prefix_str, \
16 prefix_type, rowsize, \
17 groupsize, buf, len, ascii)
19 static bool wil_fw_addr_check(struct wil6210_priv
*wil
,
20 void __iomem
**ioaddr
, __le32 val
,
21 u32 size
, const char *msg
)
23 *ioaddr
= wmi_buffer_block(wil
, val
, size
);
25 wil_err_fw(wil
, "bad %s: 0x%08x\n", msg
, le32_to_cpu(val
));
32 * wil_fw_verify - verify firmware file validity
34 * perform various checks for the firmware file header.
35 * records are not validated.
37 * Return file size or negative error
39 static int wil_fw_verify(struct wil6210_priv
*wil
, const u8
*data
, size_t size
)
41 const struct wil_fw_record_head
*hdr
= (const void *)data
;
42 struct wil_fw_record_file_header fh
;
43 const struct wil_fw_record_file_header
*fh_
;
48 wil_err_fw(wil
, "image size not aligned: %zu\n", size
);
51 /* have enough data for the file header? */
52 if (size
< sizeof(*hdr
) + sizeof(fh
)) {
53 wil_err_fw(wil
, "file too short: %zu bytes\n", size
);
57 /* start with the file header? */
58 if (le16_to_cpu(hdr
->type
) != wil_fw_type_file_header
) {
59 wil_err_fw(wil
, "no file header\n");
64 fh_
= (struct wil_fw_record_file_header
*)&hdr
[1];
65 dlen
= le32_to_cpu(fh_
->data_len
);
67 wil_err_fw(wil
, "data length not aligned: %lu\n", (ulong
)dlen
);
71 wil_err_fw(wil
, "file truncated at %zu/%lu\n",
75 if (dlen
< sizeof(*hdr
) + sizeof(fh
)) {
76 wil_err_fw(wil
, "data length too short: %lu\n", (ulong
)dlen
);
81 if (le32_to_cpu(fh_
->signature
) != WIL_FW_SIGNATURE
) {
82 wil_err_fw(wil
, "bad header signature: 0x%08x\n",
83 le32_to_cpu(fh_
->signature
));
88 if (le32_to_cpu(fh_
->version
) > WIL_FW_FMT_VERSION
) {
89 wil_err_fw(wil
, "unsupported header version: %d\n",
90 le32_to_cpu(fh_
->version
));
94 /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
98 crc
= crc32_le(~0, (unsigned char const *)hdr
, sizeof(*hdr
));
99 crc
= crc32_le(crc
, (unsigned char const *)&fh
, sizeof(fh
));
100 crc
= crc32_le(crc
, (unsigned char const *)&fh_
[1],
101 dlen
- sizeof(*hdr
) - sizeof(fh
));
104 if (crc
!= le32_to_cpu(fh_
->crc
)) {
105 wil_err_fw(wil
, "checksum mismatch:"
106 " calculated for %lu bytes 0x%08x != 0x%08x\n",
107 (ulong
)dlen
, crc
, le32_to_cpu(fh_
->crc
));
114 static int fw_ignore_section(struct wil6210_priv
*wil
, const void *data
,
121 fw_handle_capabilities(struct wil6210_priv
*wil
, const void *data
,
124 const struct wil_fw_record_capabilities
*rec
= data
;
127 if (size
< sizeof(*rec
)) {
128 wil_err_fw(wil
, "capabilities record too short: %zu\n", size
);
129 /* let the FW load anyway */
133 capa_size
= size
- offsetof(struct wil_fw_record_capabilities
,
135 bitmap_zero(wil
->fw_capabilities
, WMI_FW_CAPABILITY_MAX
);
136 memcpy(wil
->fw_capabilities
, rec
->capabilities
,
137 min_t(size_t, sizeof(wil
->fw_capabilities
), capa_size
));
138 wil_hex_dump_fw("CAPA", DUMP_PREFIX_OFFSET
, 16, 1,
139 rec
->capabilities
, capa_size
, false);
144 fw_handle_brd_file(struct wil6210_priv
*wil
, const void *data
,
147 const struct wil_fw_record_brd_file
*rec
= data
;
148 u32 max_num_ent
, i
, ent_size
;
150 if (size
<= offsetof(struct wil_fw_record_brd_file
, brd_info
)) {
151 wil_err(wil
, "board record too short, size %zu\n", size
);
155 ent_size
= size
- offsetof(struct wil_fw_record_brd_file
, brd_info
);
156 max_num_ent
= ent_size
/ sizeof(struct brd_info
);
159 wil_err(wil
, "brd info entries are missing\n");
163 wil
->brd_info
= kcalloc(max_num_ent
, sizeof(struct wil_brd_info
),
168 for (i
= 0; i
< max_num_ent
; i
++) {
169 wil
->brd_info
[i
].file_addr
=
170 le32_to_cpu(rec
->brd_info
[i
].base_addr
);
171 wil
->brd_info
[i
].file_max_size
=
172 le32_to_cpu(rec
->brd_info
[i
].max_size_bytes
);
174 if (!wil
->brd_info
[i
].file_addr
)
178 "brd info %d: file_addr 0x%x, file_max_size %d\n",
179 i
, wil
->brd_info
[i
].file_addr
,
180 wil
->brd_info
[i
].file_max_size
);
183 wil
->num_of_brd_entries
= i
;
184 if (wil
->num_of_brd_entries
== 0) {
185 kfree(wil
->brd_info
);
186 wil
->brd_info
= NULL
;
188 "no valid brd info entries, using brd file addr\n");
191 wil_dbg_fw(wil
, "num of brd info entries %d\n",
192 wil
->num_of_brd_entries
);
199 fw_handle_concurrency(struct wil6210_priv
*wil
, const void *data
,
202 const struct wil_fw_record_concurrency
*rec
= data
;
203 const struct wil_fw_concurrency_combo
*combo
;
204 const struct wil_fw_concurrency_limit
*limit
;
205 size_t remain
, lsize
;
208 if (size
< sizeof(*rec
)) {
209 wil_err_fw(wil
, "concurrency record too short: %zu\n", size
);
210 /* continue, let the FW load anyway */
214 n_combos
= le16_to_cpu(rec
->n_combos
);
215 remain
= size
- offsetof(struct wil_fw_record_concurrency
, combos
);
217 for (i
= 0; i
< n_combos
; i
++) {
218 if (remain
< sizeof(*combo
))
220 remain
-= sizeof(*combo
);
221 limit
= combo
->limits
;
222 lsize
= combo
->n_limits
* sizeof(*limit
);
226 limit
+= combo
->n_limits
;
227 combo
= (struct wil_fw_concurrency_combo
*)limit
;
230 return wil_cfg80211_iface_combinations_from_fw(wil
, rec
);
232 wil_err_fw(wil
, "concurrency record truncated\n");
237 fw_handle_comment(struct wil6210_priv
*wil
, const void *data
,
240 const struct wil_fw_record_comment_hdr
*hdr
= data
;
244 if (size
< sizeof(*hdr
))
247 magic
= le32_to_cpu(hdr
->magic
);
250 case WIL_FW_CAPABILITIES_MAGIC
:
251 wil_dbg_fw(wil
, "magic is WIL_FW_CAPABILITIES_MAGIC\n");
252 rc
= fw_handle_capabilities(wil
, data
, size
);
254 case WIL_BRD_FILE_MAGIC
:
255 wil_dbg_fw(wil
, "magic is WIL_BRD_FILE_MAGIC\n");
256 rc
= fw_handle_brd_file(wil
, data
, size
);
258 case WIL_FW_CONCURRENCY_MAGIC
:
259 wil_dbg_fw(wil
, "magic is WIL_FW_CONCURRENCY_MAGIC\n");
260 rc
= fw_handle_concurrency(wil
, data
, size
);
263 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET
, 16, 1,
270 static int __fw_handle_data(struct wil6210_priv
*wil
, const void *data
,
271 size_t size
, __le32 addr
)
273 const struct wil_fw_record_data
*d
= data
;
275 size_t s
= size
- sizeof(*d
);
277 if (size
< sizeof(*d
) + sizeof(u32
)) {
278 wil_err_fw(wil
, "data record too short: %zu\n", size
);
282 if (!wil_fw_addr_check(wil
, &dst
, addr
, s
, "address"))
284 wil_dbg_fw(wil
, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr
), s
);
285 wil_memcpy_toio_32(dst
, d
->data
, s
);
286 wmb(); /* finish before processing next record */
291 static int fw_handle_data(struct wil6210_priv
*wil
, const void *data
,
294 const struct wil_fw_record_data
*d
= data
;
296 return __fw_handle_data(wil
, data
, size
, d
->addr
);
299 static int fw_handle_fill(struct wil6210_priv
*wil
, const void *data
,
302 const struct wil_fw_record_fill
*d
= data
;
305 size_t s
= (size_t)le32_to_cpu(d
->size
);
307 if (size
!= sizeof(*d
)) {
308 wil_err_fw(wil
, "bad size for fill record: %zu\n", size
);
312 if (s
< sizeof(u32
)) {
313 wil_err_fw(wil
, "fill size too short: %zu\n", s
);
317 if (s
% sizeof(u32
)) {
318 wil_err_fw(wil
, "fill size not aligned: %zu\n", s
);
322 if (!wil_fw_addr_check(wil
, &dst
, d
->addr
, s
, "address"))
325 v
= le32_to_cpu(d
->value
);
326 wil_dbg_fw(wil
, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
327 le32_to_cpu(d
->addr
), v
, s
);
328 wil_memset_toio_32(dst
, v
, s
);
329 wmb(); /* finish before processing next record */
334 static int fw_handle_file_header(struct wil6210_priv
*wil
, const void *data
,
337 const struct wil_fw_record_file_header
*d
= data
;
339 if (size
!= sizeof(*d
)) {
340 wil_err_fw(wil
, "file header length incorrect: %zu\n", size
);
344 wil_dbg_fw(wil
, "new file, ver. %d, %i bytes\n",
345 d
->version
, d
->data_len
);
346 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET
, 16, 1, d
->comment
,
347 sizeof(d
->comment
), true);
349 if (!memcmp(d
->comment
, WIL_FW_VERSION_PREFIX
,
350 WIL_FW_VERSION_PREFIX_LEN
))
351 memcpy(wil
->fw_version
,
352 d
->comment
+ WIL_FW_VERSION_PREFIX_LEN
,
353 min(sizeof(d
->comment
) - WIL_FW_VERSION_PREFIX_LEN
,
354 sizeof(wil
->fw_version
) - 1));
359 static int fw_handle_direct_write(struct wil6210_priv
*wil
, const void *data
,
362 const struct wil_fw_record_direct_write
*d
= data
;
363 const struct wil_fw_data_dwrite
*block
= d
->data
;
366 if (size
% sizeof(*block
)) {
367 wil_err_fw(wil
, "record size not aligned on %zu: %zu\n",
368 sizeof(*block
), size
);
371 n
= size
/ sizeof(*block
);
373 for (i
= 0; i
< n
; i
++) {
375 u32 m
= le32_to_cpu(block
[i
].mask
);
376 u32 v
= le32_to_cpu(block
[i
].value
);
379 if (!wil_fw_addr_check(wil
, &dst
, block
[i
].addr
, 0, "address"))
383 y
= (x
& m
) | (v
& ~m
);
384 wil_dbg_fw(wil
, "write [0x%08x] <== 0x%08x "
385 "(old 0x%08x val 0x%08x mask 0x%08x)\n",
386 le32_to_cpu(block
[i
].addr
), y
, x
, v
, m
);
388 wmb(); /* finish before processing next record */
394 static int gw_write(struct wil6210_priv
*wil
, void __iomem
*gwa_addr
,
395 void __iomem
*gwa_cmd
, void __iomem
*gwa_ctl
, u32 gw_cmd
,
401 writel(gw_cmd
, gwa_cmd
);
402 wmb(); /* finish before activate gw */
404 writel(WIL_FW_GW_CTL_RUN
, gwa_ctl
); /* activate gw */
406 udelay(1); /* typical time is few usec */
408 wil_err_fw(wil
, "gw timeout\n");
411 } while (readl(gwa_ctl
) & WIL_FW_GW_CTL_BUSY
); /* gw done? */
416 static int fw_handle_gateway_data(struct wil6210_priv
*wil
, const void *data
,
419 const struct wil_fw_record_gateway_data
*d
= data
;
420 const struct wil_fw_data_gw
*block
= d
->data
;
421 void __iomem
*gwa_addr
;
422 void __iomem
*gwa_val
;
423 void __iomem
*gwa_cmd
;
424 void __iomem
*gwa_ctl
;
428 if (size
< sizeof(*d
) + sizeof(*block
)) {
429 wil_err_fw(wil
, "gateway record too short: %zu\n", size
);
433 if ((size
- sizeof(*d
)) % sizeof(*block
)) {
434 wil_err_fw(wil
, "gateway record data size"
435 " not aligned on %zu: %zu\n",
436 sizeof(*block
), size
- sizeof(*d
));
439 n
= (size
- sizeof(*d
)) / sizeof(*block
);
441 gw_cmd
= le32_to_cpu(d
->command
);
443 wil_dbg_fw(wil
, "gw write record [%3d] blocks, cmd 0x%08x\n",
446 if (!wil_fw_addr_check(wil
, &gwa_addr
, d
->gateway_addr_addr
, 0,
447 "gateway_addr_addr") ||
448 !wil_fw_addr_check(wil
, &gwa_val
, d
->gateway_value_addr
, 0,
449 "gateway_value_addr") ||
450 !wil_fw_addr_check(wil
, &gwa_cmd
, d
->gateway_cmd_addr
, 0,
451 "gateway_cmd_addr") ||
452 !wil_fw_addr_check(wil
, &gwa_ctl
, d
->gateway_ctrl_address
, 0,
453 "gateway_ctrl_address"))
456 wil_dbg_fw(wil
, "gw addresses: addr 0x%08x val 0x%08x"
457 " cmd 0x%08x ctl 0x%08x\n",
458 le32_to_cpu(d
->gateway_addr_addr
),
459 le32_to_cpu(d
->gateway_value_addr
),
460 le32_to_cpu(d
->gateway_cmd_addr
),
461 le32_to_cpu(d
->gateway_ctrl_address
));
463 for (i
= 0; i
< n
; i
++) {
465 u32 a
= le32_to_cpu(block
[i
].addr
);
466 u32 v
= le32_to_cpu(block
[i
].value
);
468 wil_dbg_fw(wil
, " gw write[%3d] [0x%08x] <== 0x%08x\n",
472 rc
= gw_write(wil
, gwa_addr
, gwa_cmd
, gwa_ctl
, gw_cmd
, a
);
480 static int fw_handle_gateway_data4(struct wil6210_priv
*wil
, const void *data
,
483 const struct wil_fw_record_gateway_data4
*d
= data
;
484 const struct wil_fw_data_gw4
*block
= d
->data
;
485 void __iomem
*gwa_addr
;
486 void __iomem
*gwa_val
[ARRAY_SIZE(block
->value
)];
487 void __iomem
*gwa_cmd
;
488 void __iomem
*gwa_ctl
;
492 if (size
< sizeof(*d
) + sizeof(*block
)) {
493 wil_err_fw(wil
, "gateway4 record too short: %zu\n", size
);
497 if ((size
- sizeof(*d
)) % sizeof(*block
)) {
498 wil_err_fw(wil
, "gateway4 record data size"
499 " not aligned on %zu: %zu\n",
500 sizeof(*block
), size
- sizeof(*d
));
503 n
= (size
- sizeof(*d
)) / sizeof(*block
);
505 gw_cmd
= le32_to_cpu(d
->command
);
507 wil_dbg_fw(wil
, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
510 if (!wil_fw_addr_check(wil
, &gwa_addr
, d
->gateway_addr_addr
, 0,
511 "gateway_addr_addr"))
513 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
514 if (!wil_fw_addr_check(wil
, &gwa_val
[k
],
515 d
->gateway_value_addr
[k
],
516 0, "gateway_value_addr"))
518 if (!wil_fw_addr_check(wil
, &gwa_cmd
, d
->gateway_cmd_addr
, 0,
519 "gateway_cmd_addr") ||
520 !wil_fw_addr_check(wil
, &gwa_ctl
, d
->gateway_ctrl_address
, 0,
521 "gateway_ctrl_address"))
524 wil_dbg_fw(wil
, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
525 le32_to_cpu(d
->gateway_addr_addr
),
526 le32_to_cpu(d
->gateway_cmd_addr
),
527 le32_to_cpu(d
->gateway_ctrl_address
));
528 wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE
, 16, 4,
529 d
->gateway_value_addr
, sizeof(d
->gateway_value_addr
),
532 for (i
= 0; i
< n
; i
++) {
534 u32 a
= le32_to_cpu(block
[i
].addr
);
535 u32 v
[ARRAY_SIZE(block
->value
)];
537 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
538 v
[k
] = le32_to_cpu(block
[i
].value
[k
]);
540 wil_dbg_fw(wil
, " gw4 write[%3d] [0x%08x] <==\n", i
, a
);
541 wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE
, 16, 4, v
,
544 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
545 writel(v
[k
], gwa_val
[k
]);
546 rc
= gw_write(wil
, gwa_addr
, gwa_cmd
, gwa_ctl
, gw_cmd
, a
);
554 static const struct {
556 int (*load_handler
)(struct wil6210_priv
*wil
, const void *data
,
558 int (*parse_handler
)(struct wil6210_priv
*wil
, const void *data
,
560 } wil_fw_handlers
[] = {
561 {wil_fw_type_comment
, fw_handle_comment
, fw_handle_comment
},
562 {wil_fw_type_data
, fw_handle_data
, fw_ignore_section
},
563 {wil_fw_type_fill
, fw_handle_fill
, fw_ignore_section
},
564 /* wil_fw_type_action */
565 /* wil_fw_type_verify */
566 {wil_fw_type_file_header
, fw_handle_file_header
,
567 fw_handle_file_header
},
568 {wil_fw_type_direct_write
, fw_handle_direct_write
, fw_ignore_section
},
569 {wil_fw_type_gateway_data
, fw_handle_gateway_data
, fw_ignore_section
},
570 {wil_fw_type_gateway_data4
, fw_handle_gateway_data4
,
574 static int wil_fw_handle_record(struct wil6210_priv
*wil
, int type
,
575 const void *data
, size_t size
, bool load
)
579 for (i
= 0; i
< ARRAY_SIZE(wil_fw_handlers
); i
++)
580 if (wil_fw_handlers
[i
].type
== type
)
582 wil_fw_handlers
[i
].load_handler(
584 wil_fw_handlers
[i
].parse_handler(
587 wil_err_fw(wil
, "unknown record type: %d\n", type
);
592 * wil_fw_process - process section from FW file
593 * if load is true: Load the FW and uCode code and data to the
594 * corresponding device memory regions,
595 * otherwise only parse and look for capabilities
599 static int wil_fw_process(struct wil6210_priv
*wil
, const void *data
,
600 size_t size
, bool load
)
603 const struct wil_fw_record_head
*hdr
;
606 for (hdr
= data
;; hdr
= (const void *)hdr
+ s
, size
-= s
) {
607 if (size
< sizeof(*hdr
))
609 hdr_sz
= le32_to_cpu(hdr
->size
);
610 s
= sizeof(*hdr
) + hdr_sz
;
614 wil_err_fw(wil
, "unaligned record size: %zu\n",
618 rc
= wil_fw_handle_record(wil
, le16_to_cpu(hdr
->type
),
619 &hdr
[1], hdr_sz
, load
);
624 wil_err_fw(wil
, "unprocessed bytes: %zu\n", size
);
625 if (size
>= sizeof(*hdr
)) {
626 wil_err_fw(wil
, "Stop at offset %ld"
627 " record type %d [%zd bytes]\n",
628 (long)((const void *)hdr
- data
),
629 le16_to_cpu(hdr
->type
), hdr_sz
);
638 * wil_request_firmware - Request firmware
640 * Request firmware image from the file
641 * If load is true, load firmware to device, otherwise
642 * only parse and extract capabilities
646 int wil_request_firmware(struct wil6210_priv
*wil
, const char *name
,
650 const struct firmware
*fw
;
654 rc
= request_firmware(&fw
, name
, wil_to_dev(wil
));
656 wil_err_fw(wil
, "Failed to load firmware %s rc %d\n", name
, rc
);
659 wil_dbg_fw(wil
, "Loading <%s>, %zu bytes\n", name
, fw
->size
);
661 /* re-initialize board info params */
662 wil
->num_of_brd_entries
= 0;
663 kfree(wil
->brd_info
);
664 wil
->brd_info
= NULL
;
666 for (sz
= fw
->size
, d
= fw
->data
; sz
; sz
-= rc1
, d
+= rc1
) {
667 rc1
= wil_fw_verify(wil
, d
, sz
);
672 rc
= wil_fw_process(wil
, d
, rc1
, load
);
678 release_firmware(fw
);
680 wil_err_fw(wil
, "Loading <%s> failed, rc %d\n", name
, rc
);
685 * wil_brd_process - process section from BRD file
689 static int wil_brd_process(struct wil6210_priv
*wil
, const void *data
,
693 const struct wil_fw_record_head
*hdr
= data
;
694 size_t s
, hdr_sz
= 0;
698 /* Assuming the board file includes only one file header
699 * and one or several data records.
700 * Each record starts with wil_fw_record_head.
702 if (size
< sizeof(*hdr
))
704 s
= sizeof(*hdr
) + le32_to_cpu(hdr
->size
);
708 /* Skip the header record and handle the data records */
711 for (hdr
= data
+ s
;; hdr
= (const void *)hdr
+ s
, size
-= s
, i
++) {
712 if (size
< sizeof(*hdr
))
715 if (i
>= wil
->num_of_brd_entries
) {
717 "Too many brd records: %d, num of expected entries %d\n",
718 i
, wil
->num_of_brd_entries
);
722 hdr_sz
= le32_to_cpu(hdr
->size
);
723 s
= sizeof(*hdr
) + hdr_sz
;
724 if (wil
->brd_info
[i
].file_max_size
&&
725 hdr_sz
> wil
->brd_info
[i
].file_max_size
)
727 if (sizeof(*hdr
) + hdr_sz
> size
)
730 wil_err_fw(wil
, "unaligned record size: %zu\n",
734 type
= le16_to_cpu(hdr
->type
);
735 if (type
!= wil_fw_type_data
) {
737 "invalid record type for board file: %d\n",
741 if (hdr_sz
< sizeof(struct wil_fw_record_data
)) {
742 wil_err_fw(wil
, "data record too short: %zu\n", hdr_sz
);
747 "using info from fw file for record %d: addr[0x%08x], max size %d\n",
748 i
, wil
->brd_info
[i
].file_addr
,
749 wil
->brd_info
[i
].file_max_size
);
751 rc
= __fw_handle_data(wil
, &hdr
[1], hdr_sz
,
752 cpu_to_le32(wil
->brd_info
[i
].file_addr
));
758 wil_err_fw(wil
, "unprocessed bytes: %zu\n", size
);
759 if (size
>= sizeof(*hdr
)) {
761 "Stop at offset %ld record type %d [%zd bytes]\n",
762 (long)((const void *)hdr
- data
),
763 le16_to_cpu(hdr
->type
), hdr_sz
);
772 * wil_request_board - Request board file
774 * Request board image from the file
775 * board file address and max size are read from FW file
776 * during initialization.
777 * brd file shall include one header and one data section.
781 int wil_request_board(struct wil6210_priv
*wil
, const char *name
)
784 const struct firmware
*brd
;
786 rc
= request_firmware(&brd
, name
, wil_to_dev(wil
));
788 wil_err_fw(wil
, "Failed to load brd %s\n", name
);
791 wil_dbg_fw(wil
, "Loading <%s>, %zu bytes\n", name
, brd
->size
);
793 /* Verify the header */
794 dlen
= wil_fw_verify(wil
, brd
->data
, brd
->size
);
800 /* Process the data records */
801 rc
= wil_brd_process(wil
, brd
->data
, dlen
);
804 release_firmware(brd
);
806 wil_err_fw(wil
, "Loading <%s> failed, rc %d\n", name
, rc
);
811 * wil_fw_verify_file_exists - checks if firmware file exist
813 * @wil: driver context
814 * @name: firmware file name
816 * return value - boolean, true for success, false for failure
818 bool wil_fw_verify_file_exists(struct wil6210_priv
*wil
, const char *name
)
820 const struct firmware
*fw
;
823 rc
= request_firmware(&fw
, name
, wil_to_dev(wil
));
825 release_firmware(fw
);
827 wil_dbg_fw(wil
, "<%s> not available: %d\n", name
, rc
);