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 19 static 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 */ 39 static 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 114 static int fw_ignore_section(struct wil6210_priv *wil, const void *data, 115 size_t size) 116 { 117 return 0; 118 } 119 120 static int 121 fw_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 143 static int 144 fw_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 = kzalloc_objs(struct wil_brd_info, max_num_ent); 164 if (!wil->brd_info) 165 return -ENOMEM; 166 167 for (i = 0; i < max_num_ent; i++) { 168 wil->brd_info[i].file_addr = 169 le32_to_cpu(rec->brd_info[i].base_addr); 170 wil->brd_info[i].file_max_size = 171 le32_to_cpu(rec->brd_info[i].max_size_bytes); 172 173 if (!wil->brd_info[i].file_addr) 174 break; 175 176 wil_dbg_fw(wil, 177 "brd info %d: file_addr 0x%x, file_max_size %d\n", 178 i, wil->brd_info[i].file_addr, 179 wil->brd_info[i].file_max_size); 180 } 181 182 wil->num_of_brd_entries = i; 183 if (wil->num_of_brd_entries == 0) { 184 kfree(wil->brd_info); 185 wil->brd_info = NULL; 186 wil_dbg_fw(wil, 187 "no valid brd info entries, using brd file addr\n"); 188 189 } else { 190 wil_dbg_fw(wil, "num of brd info entries %d\n", 191 wil->num_of_brd_entries); 192 } 193 194 return 0; 195 } 196 197 static int 198 fw_handle_concurrency(struct wil6210_priv *wil, const void *data, 199 size_t size) 200 { 201 const struct wil_fw_record_concurrency *rec = data; 202 const struct wil_fw_concurrency_combo *combo; 203 const struct wil_fw_concurrency_limit *limit; 204 size_t remain, lsize; 205 int i, n_combos; 206 207 if (size < sizeof(*rec)) { 208 wil_err_fw(wil, "concurrency record too short: %zu\n", size); 209 /* continue, let the FW load anyway */ 210 return 0; 211 } 212 213 n_combos = le16_to_cpu(rec->n_combos); 214 remain = size - sizeof(struct wil_fw_record_concurrency); 215 combo = (const struct wil_fw_concurrency_combo *)(rec + 1); 216 for (i = 0; i < n_combos; i++) { 217 if (remain < sizeof(*combo)) 218 goto out_short; 219 remain -= sizeof(*combo); 220 limit = combo->limits; 221 lsize = combo->n_limits * sizeof(*limit); 222 if (remain < lsize) 223 goto out_short; 224 remain -= lsize; 225 limit += combo->n_limits; 226 combo = (struct wil_fw_concurrency_combo *)limit; 227 } 228 229 return wil_cfg80211_iface_combinations_from_fw(wil, rec); 230 out_short: 231 wil_err_fw(wil, "concurrency record truncated\n"); 232 return 0; 233 } 234 235 static int 236 fw_handle_comment(struct wil6210_priv *wil, const void *data, 237 size_t size) 238 { 239 const struct wil_fw_record_comment_hdr *hdr = data; 240 u32 magic; 241 int rc = 0; 242 243 if (size < sizeof(*hdr)) 244 return 0; 245 246 magic = le32_to_cpu(hdr->magic); 247 248 switch (magic) { 249 case WIL_FW_CAPABILITIES_MAGIC: 250 wil_dbg_fw(wil, "magic is WIL_FW_CAPABILITIES_MAGIC\n"); 251 rc = fw_handle_capabilities(wil, data, size); 252 break; 253 case WIL_BRD_FILE_MAGIC: 254 wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n"); 255 rc = fw_handle_brd_file(wil, data, size); 256 break; 257 case WIL_FW_CONCURRENCY_MAGIC: 258 wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n"); 259 rc = fw_handle_concurrency(wil, data, size); 260 break; 261 default: 262 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, 263 data, size, true); 264 } 265 266 return rc; 267 } 268 269 static int __fw_handle_data(struct wil6210_priv *wil, const void *data, 270 size_t size, __le32 addr) 271 { 272 const struct wil_fw_record_data *d = data; 273 void __iomem *dst; 274 size_t s = size - sizeof(*d); 275 276 if (size < sizeof(*d) + sizeof(u32)) { 277 wil_err_fw(wil, "data record too short: %zu\n", size); 278 return -EINVAL; 279 } 280 281 if (!wil_fw_addr_check(wil, &dst, addr, s, "address")) 282 return -EINVAL; 283 wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s); 284 wil_memcpy_toio_32(dst, d->data, s); 285 wmb(); /* finish before processing next record */ 286 287 return 0; 288 } 289 290 static int fw_handle_data(struct wil6210_priv *wil, const void *data, 291 size_t size) 292 { 293 const struct wil_fw_record_data *d = data; 294 295 return __fw_handle_data(wil, data, size, d->addr); 296 } 297 298 static int fw_handle_fill(struct wil6210_priv *wil, const void *data, 299 size_t size) 300 { 301 const struct wil_fw_record_fill *d = data; 302 void __iomem *dst; 303 u32 v; 304 size_t s = (size_t)le32_to_cpu(d->size); 305 306 if (size != sizeof(*d)) { 307 wil_err_fw(wil, "bad size for fill record: %zu\n", size); 308 return -EINVAL; 309 } 310 311 if (s < sizeof(u32)) { 312 wil_err_fw(wil, "fill size too short: %zu\n", s); 313 return -EINVAL; 314 } 315 316 if (s % sizeof(u32)) { 317 wil_err_fw(wil, "fill size not aligned: %zu\n", s); 318 return -EINVAL; 319 } 320 321 if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address")) 322 return -EINVAL; 323 324 v = le32_to_cpu(d->value); 325 wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n", 326 le32_to_cpu(d->addr), v, s); 327 wil_memset_toio_32(dst, v, s); 328 wmb(); /* finish before processing next record */ 329 330 return 0; 331 } 332 333 static int fw_handle_file_header(struct wil6210_priv *wil, const void *data, 334 size_t size) 335 { 336 const struct wil_fw_record_file_header *d = data; 337 338 if (size != sizeof(*d)) { 339 wil_err_fw(wil, "file header length incorrect: %zu\n", size); 340 return -EINVAL; 341 } 342 343 wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n", 344 d->version, d->data_len); 345 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment, 346 sizeof(d->comment), true); 347 348 if (!memcmp(d->comment, WIL_FW_VERSION_PREFIX, 349 WIL_FW_VERSION_PREFIX_LEN)) 350 memcpy(wil->fw_version, 351 d->comment + WIL_FW_VERSION_PREFIX_LEN, 352 min(sizeof(d->comment) - WIL_FW_VERSION_PREFIX_LEN, 353 sizeof(wil->fw_version) - 1)); 354 355 return 0; 356 } 357 358 static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, 359 size_t size) 360 { 361 const struct wil_fw_record_direct_write *d = data; 362 const struct wil_fw_data_dwrite *block = d->data; 363 int n, i; 364 365 if (size % sizeof(*block)) { 366 wil_err_fw(wil, "record size not aligned on %zu: %zu\n", 367 sizeof(*block), size); 368 return -EINVAL; 369 } 370 n = size / sizeof(*block); 371 372 for (i = 0; i < n; i++) { 373 void __iomem *dst; 374 u32 m = le32_to_cpu(block[i].mask); 375 u32 v = le32_to_cpu(block[i].value); 376 u32 x, y; 377 378 if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address")) 379 return -EINVAL; 380 381 x = readl(dst); 382 y = (x & m) | (v & ~m); 383 wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x " 384 "(old 0x%08x val 0x%08x mask 0x%08x)\n", 385 le32_to_cpu(block[i].addr), y, x, v, m); 386 writel(y, dst); 387 wmb(); /* finish before processing next record */ 388 } 389 390 return 0; 391 } 392 393 static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr, 394 void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd, 395 u32 a) 396 { 397 unsigned delay = 0; 398 399 writel(a, gwa_addr); 400 writel(gw_cmd, gwa_cmd); 401 wmb(); /* finish before activate gw */ 402 403 writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ 404 do { 405 udelay(1); /* typical time is few usec */ 406 if (delay++ > 100) { 407 wil_err_fw(wil, "gw timeout\n"); 408 return -EINVAL; 409 } 410 } while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ 411 412 return 0; 413 } 414 415 static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, 416 size_t size) 417 { 418 const struct wil_fw_record_gateway_data *d = data; 419 const struct wil_fw_data_gw *block = d->data; 420 void __iomem *gwa_addr; 421 void __iomem *gwa_val; 422 void __iomem *gwa_cmd; 423 void __iomem *gwa_ctl; 424 u32 gw_cmd; 425 int n, i; 426 427 if (size < sizeof(*d) + sizeof(*block)) { 428 wil_err_fw(wil, "gateway record too short: %zu\n", size); 429 return -EINVAL; 430 } 431 432 if ((size - sizeof(*d)) % sizeof(*block)) { 433 wil_err_fw(wil, "gateway record data size" 434 " not aligned on %zu: %zu\n", 435 sizeof(*block), size - sizeof(*d)); 436 return -EINVAL; 437 } 438 n = (size - sizeof(*d)) / sizeof(*block); 439 440 gw_cmd = le32_to_cpu(d->command); 441 442 wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", 443 n, gw_cmd); 444 445 if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, 446 "gateway_addr_addr") || 447 !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0, 448 "gateway_value_addr") || 449 !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, 450 "gateway_cmd_addr") || 451 !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, 452 "gateway_ctrl_address")) 453 return -EINVAL; 454 455 wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x" 456 " cmd 0x%08x ctl 0x%08x\n", 457 le32_to_cpu(d->gateway_addr_addr), 458 le32_to_cpu(d->gateway_value_addr), 459 le32_to_cpu(d->gateway_cmd_addr), 460 le32_to_cpu(d->gateway_ctrl_address)); 461 462 for (i = 0; i < n; i++) { 463 int rc; 464 u32 a = le32_to_cpu(block[i].addr); 465 u32 v = le32_to_cpu(block[i].value); 466 467 wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n", 468 i, a, v); 469 470 writel(v, gwa_val); 471 rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); 472 if (rc) 473 return rc; 474 } 475 476 return 0; 477 } 478 479 static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, 480 size_t size) 481 { 482 const struct wil_fw_record_gateway_data4 *d = data; 483 const struct wil_fw_data_gw4 *block = d->data; 484 void __iomem *gwa_addr; 485 void __iomem *gwa_val[ARRAY_SIZE(block->value)]; 486 void __iomem *gwa_cmd; 487 void __iomem *gwa_ctl; 488 u32 gw_cmd; 489 int n, i, k; 490 491 if (size < sizeof(*d) + sizeof(*block)) { 492 wil_err_fw(wil, "gateway4 record too short: %zu\n", size); 493 return -EINVAL; 494 } 495 496 if ((size - sizeof(*d)) % sizeof(*block)) { 497 wil_err_fw(wil, "gateway4 record data size" 498 " not aligned on %zu: %zu\n", 499 sizeof(*block), size - sizeof(*d)); 500 return -EINVAL; 501 } 502 n = (size - sizeof(*d)) / sizeof(*block); 503 504 gw_cmd = le32_to_cpu(d->command); 505 506 wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", 507 n, gw_cmd); 508 509 if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0, 510 "gateway_addr_addr")) 511 return -EINVAL; 512 for (k = 0; k < ARRAY_SIZE(block->value); k++) 513 if (!wil_fw_addr_check(wil, &gwa_val[k], 514 d->gateway_value_addr[k], 515 0, "gateway_value_addr")) 516 return -EINVAL; 517 if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0, 518 "gateway_cmd_addr") || 519 !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0, 520 "gateway_ctrl_address")) 521 return -EINVAL; 522 523 wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n", 524 le32_to_cpu(d->gateway_addr_addr), 525 le32_to_cpu(d->gateway_cmd_addr), 526 le32_to_cpu(d->gateway_ctrl_address)); 527 wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4, 528 d->gateway_value_addr, sizeof(d->gateway_value_addr), 529 false); 530 531 for (i = 0; i < n; i++) { 532 int rc; 533 u32 a = le32_to_cpu(block[i].addr); 534 u32 v[ARRAY_SIZE(block->value)]; 535 536 for (k = 0; k < ARRAY_SIZE(block->value); k++) 537 v[k] = le32_to_cpu(block[i].value[k]); 538 539 wil_dbg_fw(wil, " gw4 write[%3d] [0x%08x] <==\n", i, a); 540 wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE, 16, 4, v, 541 sizeof(v), false); 542 543 for (k = 0; k < ARRAY_SIZE(block->value); k++) 544 writel(v[k], gwa_val[k]); 545 rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); 546 if (rc) 547 return rc; 548 } 549 550 return 0; 551 } 552 553 static const struct { 554 int type; 555 int (*load_handler)(struct wil6210_priv *wil, const void *data, 556 size_t size); 557 int (*parse_handler)(struct wil6210_priv *wil, const void *data, 558 size_t size); 559 } wil_fw_handlers[] = { 560 {wil_fw_type_comment, fw_handle_comment, fw_handle_comment}, 561 {wil_fw_type_data, fw_handle_data, fw_ignore_section}, 562 {wil_fw_type_fill, fw_handle_fill, fw_ignore_section}, 563 /* wil_fw_type_action */ 564 /* wil_fw_type_verify */ 565 {wil_fw_type_file_header, fw_handle_file_header, 566 fw_handle_file_header}, 567 {wil_fw_type_direct_write, fw_handle_direct_write, fw_ignore_section}, 568 {wil_fw_type_gateway_data, fw_handle_gateway_data, fw_ignore_section}, 569 {wil_fw_type_gateway_data4, fw_handle_gateway_data4, 570 fw_ignore_section}, 571 }; 572 573 static int wil_fw_handle_record(struct wil6210_priv *wil, int type, 574 const void *data, size_t size, bool load) 575 { 576 int i; 577 578 for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) 579 if (wil_fw_handlers[i].type == type) 580 return load ? 581 wil_fw_handlers[i].load_handler( 582 wil, data, size) : 583 wil_fw_handlers[i].parse_handler( 584 wil, data, size); 585 586 wil_err_fw(wil, "unknown record type: %d\n", type); 587 return -EINVAL; 588 } 589 590 /** 591 * wil_fw_process - process section from FW file 592 * if load is true: Load the FW and uCode code and data to the 593 * corresponding device memory regions, 594 * otherwise only parse and look for capabilities 595 * 596 * Return error code 597 */ 598 static int wil_fw_process(struct wil6210_priv *wil, const void *data, 599 size_t size, bool load) 600 { 601 int rc = 0; 602 const struct wil_fw_record_head *hdr; 603 size_t s, hdr_sz; 604 605 for (hdr = data;; hdr = (const void *)hdr + s, size -= s) { 606 if (size < sizeof(*hdr)) 607 break; 608 hdr_sz = le32_to_cpu(hdr->size); 609 s = sizeof(*hdr) + hdr_sz; 610 if (s > size) 611 break; 612 if (hdr_sz % 4) { 613 wil_err_fw(wil, "unaligned record size: %zu\n", 614 hdr_sz); 615 return -EINVAL; 616 } 617 rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type), 618 &hdr[1], hdr_sz, load); 619 if (rc) 620 return rc; 621 } 622 if (size) { 623 wil_err_fw(wil, "unprocessed bytes: %zu\n", size); 624 if (size >= sizeof(*hdr)) { 625 wil_err_fw(wil, "Stop at offset %ld" 626 " record type %d [%zd bytes]\n", 627 (long)((const void *)hdr - data), 628 le16_to_cpu(hdr->type), hdr_sz); 629 } 630 return -EINVAL; 631 } 632 633 return rc; 634 } 635 636 /** 637 * wil_request_firmware - Request firmware 638 * 639 * Request firmware image from the file 640 * If load is true, load firmware to device, otherwise 641 * only parse and extract capabilities 642 * 643 * Return error code 644 */ 645 int wil_request_firmware(struct wil6210_priv *wil, const char *name, 646 bool load) 647 { 648 int rc, rc1; 649 const struct firmware *fw; 650 size_t sz; 651 const void *d; 652 653 rc = request_firmware(&fw, name, wil_to_dev(wil)); 654 if (rc) { 655 wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc); 656 return rc; 657 } 658 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); 659 660 /* re-initialize board info params */ 661 wil->num_of_brd_entries = 0; 662 kfree(wil->brd_info); 663 wil->brd_info = NULL; 664 665 for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) { 666 rc1 = wil_fw_verify(wil, d, sz); 667 if (rc1 < 0) { 668 rc = rc1; 669 goto out; 670 } 671 rc = wil_fw_process(wil, d, rc1, load); 672 if (rc < 0) 673 goto out; 674 } 675 676 out: 677 release_firmware(fw); 678 if (rc) 679 wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); 680 return rc; 681 } 682 683 /** 684 * wil_brd_process - process section from BRD file 685 * 686 * Return error code 687 */ 688 static int wil_brd_process(struct wil6210_priv *wil, const void *data, 689 size_t size) 690 { 691 int rc = 0; 692 const struct wil_fw_record_head *hdr = data; 693 size_t s, hdr_sz = 0; 694 u16 type; 695 int i = 0; 696 697 /* Assuming the board file includes only one file header 698 * and one or several data records. 699 * Each record starts with wil_fw_record_head. 700 */ 701 if (size < sizeof(*hdr)) 702 return -EINVAL; 703 s = sizeof(*hdr) + le32_to_cpu(hdr->size); 704 if (s > size) 705 return -EINVAL; 706 707 /* Skip the header record and handle the data records */ 708 size -= s; 709 710 for (hdr = data + s;; hdr = (const void *)hdr + s, size -= s, i++) { 711 if (size < sizeof(*hdr)) 712 break; 713 714 if (i >= wil->num_of_brd_entries) { 715 wil_err_fw(wil, 716 "Too many brd records: %d, num of expected entries %d\n", 717 i, wil->num_of_brd_entries); 718 break; 719 } 720 721 hdr_sz = le32_to_cpu(hdr->size); 722 s = sizeof(*hdr) + hdr_sz; 723 if (wil->brd_info[i].file_max_size && 724 hdr_sz > wil->brd_info[i].file_max_size) 725 return -EINVAL; 726 if (sizeof(*hdr) + hdr_sz > size) 727 return -EINVAL; 728 if (hdr_sz % 4) { 729 wil_err_fw(wil, "unaligned record size: %zu\n", 730 hdr_sz); 731 return -EINVAL; 732 } 733 type = le16_to_cpu(hdr->type); 734 if (type != wil_fw_type_data) { 735 wil_err_fw(wil, 736 "invalid record type for board file: %d\n", 737 type); 738 return -EINVAL; 739 } 740 if (hdr_sz < sizeof(struct wil_fw_record_data)) { 741 wil_err_fw(wil, "data record too short: %zu\n", hdr_sz); 742 return -EINVAL; 743 } 744 745 wil_dbg_fw(wil, 746 "using info from fw file for record %d: addr[0x%08x], max size %d\n", 747 i, wil->brd_info[i].file_addr, 748 wil->brd_info[i].file_max_size); 749 750 rc = __fw_handle_data(wil, &hdr[1], hdr_sz, 751 cpu_to_le32(wil->brd_info[i].file_addr)); 752 if (rc) 753 return rc; 754 } 755 756 if (size) { 757 wil_err_fw(wil, "unprocessed bytes: %zu\n", size); 758 if (size >= sizeof(*hdr)) { 759 wil_err_fw(wil, 760 "Stop at offset %ld record type %d [%zd bytes]\n", 761 (long)((const void *)hdr - data), 762 le16_to_cpu(hdr->type), hdr_sz); 763 } 764 return -EINVAL; 765 } 766 767 return 0; 768 } 769 770 /** 771 * wil_request_board - Request board file 772 * 773 * Request board image from the file 774 * board file address and max size are read from FW file 775 * during initialization. 776 * brd file shall include one header and one data section. 777 * 778 * Return error code 779 */ 780 int wil_request_board(struct wil6210_priv *wil, const char *name) 781 { 782 int rc, dlen; 783 const struct firmware *brd; 784 785 rc = request_firmware(&brd, name, wil_to_dev(wil)); 786 if (rc) { 787 wil_err_fw(wil, "Failed to load brd %s\n", name); 788 return rc; 789 } 790 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, brd->size); 791 792 /* Verify the header */ 793 dlen = wil_fw_verify(wil, brd->data, brd->size); 794 if (dlen < 0) { 795 rc = dlen; 796 goto out; 797 } 798 799 /* Process the data records */ 800 rc = wil_brd_process(wil, brd->data, dlen); 801 802 out: 803 release_firmware(brd); 804 if (rc) 805 wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); 806 return rc; 807 } 808 809 /** 810 * wil_fw_verify_file_exists - checks if firmware file exist 811 * 812 * @wil: driver context 813 * @name: firmware file name 814 * 815 * return value - boolean, true for success, false for failure 816 */ 817 bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name) 818 { 819 const struct firmware *fw; 820 int rc; 821 822 rc = request_firmware(&fw, name, wil_to_dev(wil)); 823 if (!rc) 824 release_firmware(fw); 825 else 826 wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc); 827 return !rc; 828 } 829