fw_inc.c (21597B)
1// SPDX-License-Identifier: ISC 2/* 3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 4 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. 5 */ 6 7/* Algorithmic part of the firmware download. 8 * To be included in the container file providing framework 9 */ 10 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) 18 19static bool wil_fw_addr_check(struct wil6210_priv *wil, 20 void __iomem **ioaddr, __le32 val, 21 u32 size, const char *msg) 22{ 23 *ioaddr = wmi_buffer_block(wil, val, size); 24 if (!(*ioaddr)) { 25 wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val)); 26 return false; 27 } 28 return true; 29} 30 31/** 32 * wil_fw_verify - verify firmware file validity 33 * 34 * perform various checks for the firmware file header. 35 * records are not validated. 36 * 37 * Return file size or negative error 38 */ 39static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size) 40{ 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_; 44 u32 crc; 45 u32 dlen; 46 47 if (size % 4) { 48 wil_err_fw(wil, "image size not aligned: %zu\n", size); 49 return -EINVAL; 50 } 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); 54 return -EINVAL; 55 } 56 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"); 60 return -EINVAL; 61 } 62 63 /* data_len */ 64 fh_ = (struct wil_fw_record_file_header *)&hdr[1]; 65 dlen = le32_to_cpu(fh_->data_len); 66 if (dlen % 4) { 67 wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen); 68 return -EINVAL; 69 } 70 if (size < dlen) { 71 wil_err_fw(wil, "file truncated at %zu/%lu\n", 72 size, (ulong)dlen); 73 return -EINVAL; 74 } 75 if (dlen < sizeof(*hdr) + sizeof(fh)) { 76 wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen); 77 return -EINVAL; 78 } 79 80 /* signature */ 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)); 84 return -EINVAL; 85 } 86 87 /* version */ 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)); 91 return -EINVAL; 92 } 93 94 /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/ 95 fh = *fh_; 96 fh.crc = 0; 97 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)); 102 crc = ~crc; 103 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)); 108 return -EINVAL; 109 } 110 111 return (int)dlen; 112} 113 114static int fw_ignore_section(struct wil6210_priv *wil, const void *data, 115 size_t size) 116{ 117 return 0; 118} 119 120static int 121fw_handle_capabilities(struct wil6210_priv *wil, const void *data, 122 size_t size) 123{ 124 const struct wil_fw_record_capabilities *rec = data; 125 size_t capa_size; 126 127 if (size < sizeof(*rec)) { 128 wil_err_fw(wil, "capabilities record too short: %zu\n", size); 129 /* let the FW load anyway */ 130 return 0; 131 } 132 133 capa_size = size - offsetof(struct wil_fw_record_capabilities, 134 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); 140 return 0; 141} 142 143static int 144fw_handle_brd_file(struct wil6210_priv *wil, const void *data, 145 size_t size) 146{ 147 const struct wil_fw_record_brd_file *rec = data; 148 u32 max_num_ent, i, ent_size; 149 150 if (size <= offsetof(struct wil_fw_record_brd_file, brd_info)) { 151 wil_err(wil, "board record too short, size %zu\n", size); 152 return -EINVAL; 153 } 154 155 ent_size = size - offsetof(struct wil_fw_record_brd_file, brd_info); 156 max_num_ent = ent_size / sizeof(struct brd_info); 157 158 if (!max_num_ent) { 159 wil_err(wil, "brd info entries are missing\n"); 160 return -EINVAL; 161 } 162 163 wil->brd_info = kcalloc(max_num_ent, sizeof(struct wil_brd_info), 164 GFP_KERNEL); 165 if (!wil->brd_info) 166 return -ENOMEM; 167 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); 173 174 if (!wil->brd_info[i].file_addr) 175 break; 176 177 wil_dbg_fw(wil, 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); 181 } 182 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; 187 wil_dbg_fw(wil, 188 "no valid brd info entries, using brd file addr\n"); 189 190 } else { 191 wil_dbg_fw(wil, "num of brd info entries %d\n", 192 wil->num_of_brd_entries); 193 } 194 195 return 0; 196} 197 198static int 199fw_handle_concurrency(struct wil6210_priv *wil, const void *data, 200 size_t size) 201{ 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; 206 int i, n_combos; 207 208 if (size < sizeof(*rec)) { 209 wil_err_fw(wil, "concurrency record too short: %zu\n", size); 210 /* continue, let the FW load anyway */ 211 return 0; 212 } 213 214 n_combos = le16_to_cpu(rec->n_combos); 215 remain = size - offsetof(struct wil_fw_record_concurrency, combos); 216 combo = rec->combos; 217 for (i = 0; i < n_combos; i++) { 218 if (remain < sizeof(*combo)) 219 goto out_short; 220 remain -= sizeof(*combo); 221 limit = combo->limits; 222 lsize = combo->n_limits * sizeof(*limit); 223 if (remain < lsize) 224 goto out_short; 225 remain -= lsize; 226 limit += combo->n_limits; 227 combo = (struct wil_fw_concurrency_combo *)limit; 228 } 229 230 return wil_cfg80211_iface_combinations_from_fw(wil, rec); 231out_short: 232 wil_err_fw(wil, "concurrency record truncated\n"); 233 return 0; 234} 235 236static int 237fw_handle_comment(struct wil6210_priv *wil, const void *data, 238 size_t size) 239{ 240 const struct wil_fw_record_comment_hdr *hdr = data; 241 u32 magic; 242 int rc = 0; 243 244 if (size < sizeof(*hdr)) 245 return 0; 246 247 magic = le32_to_cpu(hdr->magic); 248 249 switch (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); 253 break; 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); 257 break; 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); 261 break; 262 default: 263 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, 264 data, size, true); 265 } 266 267 return rc; 268} 269 270static int __fw_handle_data(struct wil6210_priv *wil, const void *data, 271 size_t size, __le32 addr) 272{ 273 const struct wil_fw_record_data *d = data; 274 void __iomem *dst; 275 size_t s = size - sizeof(*d); 276 277 if (size < sizeof(*d) + sizeof(u32)) { 278 wil_err_fw(wil, "data record too short: %zu\n", size); 279 return -EINVAL; 280 } 281 282 if (!wil_fw_addr_check(wil, &dst, addr, s, "address")) 283 return -EINVAL; 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 */ 287 288 return 0; 289} 290 291static int fw_handle_data(struct wil6210_priv *wil, const void *data, 292 size_t size) 293{ 294 const struct wil_fw_record_data *d = data; 295 296 return __fw_handle_data(wil, data, size, d->addr); 297} 298 299static int fw_handle_fill(struct wil6210_priv *wil, const void *data, 300 size_t size) 301{ 302 const struct wil_fw_record_fill *d = data; 303 void __iomem *dst; 304 u32 v; 305 size_t s = (size_t)le32_to_cpu(d->size); 306 307 if (size != sizeof(*d)) { 308 wil_err_fw(wil, "bad size for fill record: %zu\n", size); 309 return -EINVAL; 310 } 311 312 if (s < sizeof(u32)) { 313 wil_err_fw(wil, "fill size too short: %zu\n", s); 314 return -EINVAL; 315 } 316 317 if (s % sizeof(u32)) { 318 wil_err_fw(wil, "fill size not aligned: %zu\n", s); 319 return -EINVAL; 320 } 321 322 if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) 323 return -EINVAL; 324 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 */ 330 331 return 0; 332} 333 334static int fw_handle_file_header(struct wil6210_priv *wil, const void *data, 335 size_t size) 336{ 337 const struct wil_fw_record_file_header *d = data; 338 339 if (size != sizeof(*d)) { 340 wil_err_fw(wil, "file header length incorrect: %zu\n", size); 341 return -EINVAL; 342 } 343 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); 348 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)); 355 356 return 0; 357} 358 359static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, 360 size_t size) 361{ 362 const struct wil_fw_record_direct_write *d = data; 363 const struct wil_fw_data_dwrite *block = d->data; 364 int n, i; 365 366 if (size % sizeof(*block)) { 367 wil_err_fw(wil, "record size not aligned on %zu: %zu\n", 368 sizeof(*block), size); 369 return -EINVAL; 370 } 371 n = size / sizeof(*block); 372 373 for (i = 0; i < n; i++) { 374 void __iomem *dst; 375 u32 m = le32_to_cpu(block[i].mask); 376 u32 v = le32_to_cpu(block[i].value); 377 u32 x, y; 378 379 if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address")) 380 return -EINVAL; 381 382 x = readl(dst); 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); 387 writel(y, dst); 388 wmb(); /* finish before processing next record */ 389 } 390 391 return 0; 392} 393 394static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr, 395 void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd, 396 u32 a) 397{ 398 unsigned delay = 0; 399 400 writel(a, gwa_addr); 401 writel(gw_cmd, gwa_cmd); 402 wmb(); /* finish before activate gw */ 403 404 writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ 405 do { 406 udelay(1); /* typical time is few usec */ 407 if (delay++ > 100) { 408 wil_err_fw(wil, "gw timeout\n"); 409 return -EINVAL; 410 } 411 } while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ 412 413 return 0; 414} 415 416static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, 417 size_t size) 418{ 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; 425 u32 gw_cmd; 426 int n, i; 427 428 if (size < sizeof(*d) + sizeof(*block)) { 429 wil_err_fw(wil, "gateway record too short: %zu\n", size); 430 return -EINVAL; 431 } 432 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)); 437 return -EINVAL; 438 } 439 n = (size - sizeof(*d)) / sizeof(*block); 440 441 gw_cmd = le32_to_cpu(d->command); 442 443 wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", 444 n, gw_cmd); 445 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")) 454 return -EINVAL; 455 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)); 462 463 for (i = 0; i < n; i++) { 464 int rc; 465 u32 a = le32_to_cpu(block[i].addr); 466 u32 v = le32_to_cpu(block[i].value); 467 468 wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n", 469 i, a, v); 470 471 writel(v, gwa_val); 472 rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); 473 if (rc) 474 return rc; 475 } 476 477 return 0; 478} 479 480static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, 481 size_t size) 482{ 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; 489 u32 gw_cmd; 490 int n, i, k; 491 492 if (size < sizeof(*d) + sizeof(*block)) { 493 wil_err_fw(wil, "gateway4 record too short: %zu\n", size); 494 return -EINVAL; 495 } 496 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)); 501 return -EINVAL; 502 } 503 n = (size - sizeof(*d)) / sizeof(*block); 504 505 gw_cmd = le32_to_cpu(d->command); 506 507 wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", 508 n, gw_cmd); 509 510 if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, 511 "gateway_addr_addr")) 512 return -EINVAL; 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")) 517 return -EINVAL; 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")) 522 return -EINVAL; 523 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), 530 false); 531 532 for (i = 0; i < n; i++) { 533 int rc; 534 u32 a = le32_to_cpu(block[i].addr); 535 u32 v[ARRAY_SIZE(block->value)]; 536 537 for (k = 0; k < ARRAY_SIZE(block->value); k++) 538 v[k] = le32_to_cpu(block[i].value[k]); 539 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, 542 sizeof(v), false); 543 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); 547 if (rc) 548 return rc; 549 } 550 551 return 0; 552} 553 554static const struct { 555 int type; 556 int (*load_handler)(struct wil6210_priv *wil, const void *data, 557 size_t size); 558 int (*parse_handler)(struct wil6210_priv *wil, const void *data, 559 size_t size); 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, 571 fw_ignore_section}, 572}; 573 574static int wil_fw_handle_record(struct wil6210_priv *wil, int type, 575 const void *data, size_t size, bool load) 576{ 577 int i; 578 579 for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) 580 if (wil_fw_handlers[i].type == type) 581 return load ? 582 wil_fw_handlers[i].load_handler( 583 wil, data, size) : 584 wil_fw_handlers[i].parse_handler( 585 wil, data, size); 586 587 wil_err_fw(wil, "unknown record type: %d\n", type); 588 return -EINVAL; 589} 590 591/** 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 596 * 597 * Return error code 598 */ 599static int wil_fw_process(struct wil6210_priv *wil, const void *data, 600 size_t size, bool load) 601{ 602 int rc = 0; 603 const struct wil_fw_record_head *hdr; 604 size_t s, hdr_sz; 605 606 for (hdr = data;; hdr = (const void *)hdr + s, size -= s) { 607 if (size < sizeof(*hdr)) 608 break; 609 hdr_sz = le32_to_cpu(hdr->size); 610 s = sizeof(*hdr) + hdr_sz; 611 if (s > size) 612 break; 613 if (hdr_sz % 4) { 614 wil_err_fw(wil, "unaligned record size: %zu\n", 615 hdr_sz); 616 return -EINVAL; 617 } 618 rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type), 619 &hdr[1], hdr_sz, load); 620 if (rc) 621 return rc; 622 } 623 if (size) { 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); 630 } 631 return -EINVAL; 632 } 633 634 return rc; 635} 636 637/** 638 * wil_request_firmware - Request firmware 639 * 640 * Request firmware image from the file 641 * If load is true, load firmware to device, otherwise 642 * only parse and extract capabilities 643 * 644 * Return error code 645 */ 646int wil_request_firmware(struct wil6210_priv *wil, const char *name, 647 bool load) 648{ 649 int rc, rc1; 650 const struct firmware *fw; 651 size_t sz; 652 const void *d; 653 654 rc = request_firmware(&fw, name, wil_to_dev(wil)); 655 if (rc) { 656 wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc); 657 return rc; 658 } 659 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); 660 661 /* re-initialize board info params */ 662 wil->num_of_brd_entries = 0; 663 kfree(wil->brd_info); 664 wil->brd_info = NULL; 665 666 for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) { 667 rc1 = wil_fw_verify(wil, d, sz); 668 if (rc1 < 0) { 669 rc = rc1; 670 goto out; 671 } 672 rc = wil_fw_process(wil, d, rc1, load); 673 if (rc < 0) 674 goto out; 675 } 676 677out: 678 release_firmware(fw); 679 if (rc) 680 wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); 681 return rc; 682} 683 684/** 685 * wil_brd_process - process section from BRD file 686 * 687 * Return error code 688 */ 689static int wil_brd_process(struct wil6210_priv *wil, const void *data, 690 size_t size) 691{ 692 int rc = 0; 693 const struct wil_fw_record_head *hdr = data; 694 size_t s, hdr_sz = 0; 695 u16 type; 696 int i = 0; 697 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. 701 */ 702 if (size < sizeof(*hdr)) 703 return -EINVAL; 704 s = sizeof(*hdr) + le32_to_cpu(hdr->size); 705 if (s > size) 706 return -EINVAL; 707 708 /* Skip the header record and handle the data records */ 709 size -= s; 710 711 for (hdr = data + s;; hdr = (const void *)hdr + s, size -= s, i++) { 712 if (size < sizeof(*hdr)) 713 break; 714 715 if (i >= wil->num_of_brd_entries) { 716 wil_err_fw(wil, 717 "Too many brd records: %d, num of expected entries %d\n", 718 i, wil->num_of_brd_entries); 719 break; 720 } 721 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) 726 return -EINVAL; 727 if (sizeof(*hdr) + hdr_sz > size) 728 return -EINVAL; 729 if (hdr_sz % 4) { 730 wil_err_fw(wil, "unaligned record size: %zu\n", 731 hdr_sz); 732 return -EINVAL; 733 } 734 type = le16_to_cpu(hdr->type); 735 if (type != wil_fw_type_data) { 736 wil_err_fw(wil, 737 "invalid record type for board file: %d\n", 738 type); 739 return -EINVAL; 740 } 741 if (hdr_sz < sizeof(struct wil_fw_record_data)) { 742 wil_err_fw(wil, "data record too short: %zu\n", hdr_sz); 743 return -EINVAL; 744 } 745 746 wil_dbg_fw(wil, 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); 750 751 rc = __fw_handle_data(wil, &hdr[1], hdr_sz, 752 cpu_to_le32(wil->brd_info[i].file_addr)); 753 if (rc) 754 return rc; 755 } 756 757 if (size) { 758 wil_err_fw(wil, "unprocessed bytes: %zu\n", size); 759 if (size >= sizeof(*hdr)) { 760 wil_err_fw(wil, 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); 764 } 765 return -EINVAL; 766 } 767 768 return 0; 769} 770 771/** 772 * wil_request_board - Request board file 773 * 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. 778 * 779 * Return error code 780 */ 781int wil_request_board(struct wil6210_priv *wil, const char *name) 782{ 783 int rc, dlen; 784 const struct firmware *brd; 785 786 rc = request_firmware(&brd, name, wil_to_dev(wil)); 787 if (rc) { 788 wil_err_fw(wil, "Failed to load brd %s\n", name); 789 return rc; 790 } 791 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, brd->size); 792 793 /* Verify the header */ 794 dlen = wil_fw_verify(wil, brd->data, brd->size); 795 if (dlen < 0) { 796 rc = dlen; 797 goto out; 798 } 799 800 /* Process the data records */ 801 rc = wil_brd_process(wil, brd->data, dlen); 802 803out: 804 release_firmware(brd); 805 if (rc) 806 wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); 807 return rc; 808} 809 810/** 811 * wil_fw_verify_file_exists - checks if firmware file exist 812 * 813 * @wil: driver context 814 * @name: firmware file name 815 * 816 * return value - boolean, true for success, false for failure 817 */ 818bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name) 819{ 820 const struct firmware *fw; 821 int rc; 822 823 rc = request_firmware(&fw, name, wil_to_dev(wil)); 824 if (!rc) 825 release_firmware(fw); 826 else 827 wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc); 828 return !rc; 829}