1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2012-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #if EFX_OPTS_EF10() 11 12 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 13 14 #include "ef10_tlv_layout.h" 15 16 /* Cursor for TLV partition format */ 17 typedef struct tlv_cursor_s { 18 uint32_t *block; /* Base of data block */ 19 uint32_t *current; /* Cursor position */ 20 uint32_t *end; /* End tag position */ 21 uint32_t *limit; /* Last dword of data block */ 22 } tlv_cursor_t; 23 24 typedef struct nvram_partition_s { 25 uint16_t type; 26 uint8_t chip_select; 27 uint8_t flags; 28 /* 29 * The full length of the NVRAM partition. 30 * This is different from tlv_partition_header.total_length, 31 * which can be smaller. 32 */ 33 uint32_t length; 34 uint32_t erase_size; 35 uint32_t *data; 36 tlv_cursor_t tlv_cursor; 37 } nvram_partition_t; 38 39 40 static __checkReturn efx_rc_t 41 tlv_validate_state( 42 __inout tlv_cursor_t *cursor); 43 44 45 static void 46 tlv_init_block( 47 __out uint32_t *block) 48 { 49 *block = __CPU_TO_LE_32(TLV_TAG_END); 50 } 51 52 static uint32_t 53 tlv_tag( 54 __in tlv_cursor_t *cursor) 55 { 56 uint32_t dword, tag; 57 58 dword = cursor->current[0]; 59 tag = __LE_TO_CPU_32(dword); 60 61 return (tag); 62 } 63 64 static size_t 65 tlv_length( 66 __in tlv_cursor_t *cursor) 67 { 68 uint32_t dword, length; 69 70 if (tlv_tag(cursor) == TLV_TAG_END) 71 return (0); 72 73 dword = cursor->current[1]; 74 length = __LE_TO_CPU_32(dword); 75 76 return ((size_t)length); 77 } 78 79 static uint8_t * 80 tlv_value( 81 __in tlv_cursor_t *cursor) 82 { 83 if (tlv_tag(cursor) == TLV_TAG_END) 84 return (NULL); 85 86 return ((uint8_t *)(&cursor->current[2])); 87 } 88 89 static uint8_t * 90 tlv_item( 91 __in tlv_cursor_t *cursor) 92 { 93 if (tlv_tag(cursor) == TLV_TAG_END) 94 return (NULL); 95 96 return ((uint8_t *)cursor->current); 97 } 98 99 /* 100 * TLV item DWORD length is tag + length + value (rounded up to DWORD) 101 * equivalent to tlv_n_words_for_len in mc-comms tlv.c 102 */ 103 #define TLV_DWORD_COUNT(length) \ 104 (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t))) 105 106 107 static uint32_t * 108 tlv_next_item_ptr( 109 __in tlv_cursor_t *cursor) 110 { 111 uint32_t length; 112 113 length = tlv_length(cursor); 114 115 return (cursor->current + TLV_DWORD_COUNT(length)); 116 } 117 118 static __checkReturn efx_rc_t 119 tlv_advance( 120 __inout tlv_cursor_t *cursor) 121 { 122 efx_rc_t rc; 123 124 if ((rc = tlv_validate_state(cursor)) != 0) 125 goto fail1; 126 127 if (cursor->current == cursor->end) { 128 /* No more tags after END tag */ 129 cursor->current = NULL; 130 rc = ENOENT; 131 goto fail2; 132 } 133 134 /* Advance to next item and validate */ 135 cursor->current = tlv_next_item_ptr(cursor); 136 137 if ((rc = tlv_validate_state(cursor)) != 0) 138 goto fail3; 139 140 return (0); 141 142 fail3: 143 EFSYS_PROBE(fail3); 144 fail2: 145 EFSYS_PROBE(fail2); 146 fail1: 147 EFSYS_PROBE1(fail1, efx_rc_t, rc); 148 149 return (rc); 150 } 151 152 static efx_rc_t 153 tlv_rewind( 154 __in tlv_cursor_t *cursor) 155 { 156 efx_rc_t rc; 157 158 cursor->current = cursor->block; 159 160 if ((rc = tlv_validate_state(cursor)) != 0) 161 goto fail1; 162 163 return (0); 164 165 fail1: 166 EFSYS_PROBE1(fail1, efx_rc_t, rc); 167 168 return (rc); 169 } 170 171 static efx_rc_t 172 tlv_find( 173 __inout tlv_cursor_t *cursor, 174 __in uint32_t tag) 175 { 176 efx_rc_t rc; 177 178 rc = tlv_rewind(cursor); 179 while (rc == 0) { 180 if (tlv_tag(cursor) == tag) 181 break; 182 183 rc = tlv_advance(cursor); 184 } 185 return (rc); 186 } 187 188 static __checkReturn efx_rc_t 189 tlv_validate_state( 190 __inout tlv_cursor_t *cursor) 191 { 192 efx_rc_t rc; 193 194 /* Check cursor position */ 195 if (cursor->current < cursor->block) { 196 rc = EINVAL; 197 goto fail1; 198 } 199 if (cursor->current > cursor->limit) { 200 rc = EINVAL; 201 goto fail2; 202 } 203 204 if (tlv_tag(cursor) != TLV_TAG_END) { 205 /* Check current item has space for tag and length */ 206 if (cursor->current > (cursor->limit - 1)) { 207 cursor->current = NULL; 208 rc = EFAULT; 209 goto fail3; 210 } 211 212 /* Check we have value data for current item and an END tag */ 213 if (tlv_next_item_ptr(cursor) > cursor->limit) { 214 cursor->current = NULL; 215 rc = EFAULT; 216 goto fail4; 217 } 218 } 219 220 return (0); 221 222 fail4: 223 EFSYS_PROBE(fail4); 224 fail3: 225 EFSYS_PROBE(fail3); 226 fail2: 227 EFSYS_PROBE(fail2); 228 fail1: 229 EFSYS_PROBE1(fail1, efx_rc_t, rc); 230 231 return (rc); 232 } 233 234 static efx_rc_t 235 tlv_init_cursor( 236 __out tlv_cursor_t *cursor, 237 __in uint32_t *block, 238 __in uint32_t *limit, 239 __in uint32_t *current) 240 { 241 cursor->block = block; 242 cursor->limit = limit; 243 244 cursor->current = current; 245 cursor->end = NULL; 246 247 return (tlv_validate_state(cursor)); 248 } 249 250 static __checkReturn efx_rc_t 251 tlv_init_cursor_from_size( 252 __out tlv_cursor_t *cursor, 253 __in_bcount(size) 254 uint8_t *block, 255 __in size_t size) 256 { 257 uint32_t *limit; 258 limit = (uint32_t *)(block + size - sizeof (uint32_t)); 259 return (tlv_init_cursor(cursor, (uint32_t *)block, 260 limit, (uint32_t *)block)); 261 } 262 263 static __checkReturn efx_rc_t 264 tlv_init_cursor_at_offset( 265 __out tlv_cursor_t *cursor, 266 __in_bcount(size) 267 uint8_t *block, 268 __in size_t size, 269 __in size_t offset) 270 { 271 uint32_t *limit; 272 uint32_t *current; 273 limit = (uint32_t *)(block + size - sizeof (uint32_t)); 274 current = (uint32_t *)(block + offset); 275 return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current)); 276 } 277 278 static __checkReturn efx_rc_t 279 tlv_require_end( 280 __inout tlv_cursor_t *cursor) 281 { 282 uint32_t *pos; 283 efx_rc_t rc; 284 285 if (cursor->end == NULL) { 286 pos = cursor->current; 287 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0) 288 goto fail1; 289 290 cursor->end = cursor->current; 291 cursor->current = pos; 292 } 293 294 return (0); 295 296 fail1: 297 EFSYS_PROBE1(fail1, efx_rc_t, rc); 298 299 return (rc); 300 } 301 302 static size_t 303 tlv_block_length_used( 304 __inout tlv_cursor_t *cursor) 305 { 306 efx_rc_t rc; 307 308 if ((rc = tlv_validate_state(cursor)) != 0) 309 goto fail1; 310 311 if ((rc = tlv_require_end(cursor)) != 0) 312 goto fail2; 313 314 /* Return space used (including the END tag) */ 315 return (cursor->end + 1 - cursor->block) * sizeof (uint32_t); 316 317 fail2: 318 EFSYS_PROBE(fail2); 319 fail1: 320 EFSYS_PROBE1(fail1, efx_rc_t, rc); 321 322 return (0); 323 } 324 325 static uint32_t * 326 tlv_last_segment_end( 327 __in tlv_cursor_t *cursor) 328 { 329 tlv_cursor_t segment_cursor; 330 uint32_t *last_segment_end = cursor->block; 331 uint32_t *segment_start = cursor->block; 332 333 /* 334 * Go through each segment and check that it has an end tag. If there 335 * is no end tag then the previous segment was the last valid one, 336 * so return the pointer to its end tag. 337 */ 338 for (;;) { 339 if (tlv_init_cursor(&segment_cursor, segment_start, 340 cursor->limit, segment_start) != 0) 341 break; 342 if (tlv_require_end(&segment_cursor) != 0) 343 break; 344 last_segment_end = segment_cursor.end; 345 segment_start = segment_cursor.end + 1; 346 } 347 348 return (last_segment_end); 349 } 350 351 352 static uint32_t * 353 tlv_write( 354 __in tlv_cursor_t *cursor, 355 __in uint32_t tag, 356 __in_bcount(size) uint8_t *data, 357 __in size_t size) 358 { 359 uint32_t len = size; 360 uint32_t *ptr; 361 362 ptr = cursor->current; 363 364 *ptr++ = __CPU_TO_LE_32(tag); 365 *ptr++ = __CPU_TO_LE_32(len); 366 367 if (len > 0) { 368 ptr[(len - 1) / sizeof (uint32_t)] = 0; 369 memcpy(ptr, data, len); 370 ptr += EFX_P2ROUNDUP(uint32_t, len, 371 sizeof (uint32_t)) / sizeof (*ptr); 372 } 373 374 return (ptr); 375 } 376 377 static __checkReturn efx_rc_t 378 tlv_insert( 379 __inout tlv_cursor_t *cursor, 380 __in uint32_t tag, 381 __in_bcount(size) 382 uint8_t *data, 383 __in size_t size) 384 { 385 unsigned int delta; 386 uint32_t *last_segment_end; 387 efx_rc_t rc; 388 389 if ((rc = tlv_validate_state(cursor)) != 0) 390 goto fail1; 391 392 if ((rc = tlv_require_end(cursor)) != 0) 393 goto fail2; 394 395 if (tag == TLV_TAG_END) { 396 rc = EINVAL; 397 goto fail3; 398 } 399 400 last_segment_end = tlv_last_segment_end(cursor); 401 402 delta = TLV_DWORD_COUNT(size); 403 if (last_segment_end + 1 + delta > cursor->limit) { 404 rc = ENOSPC; 405 goto fail4; 406 } 407 408 /* Move data up: new space at cursor->current */ 409 memmove(cursor->current + delta, cursor->current, 410 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 411 412 /* Adjust the end pointer */ 413 cursor->end += delta; 414 415 /* Write new TLV item */ 416 tlv_write(cursor, tag, data, size); 417 418 return (0); 419 420 fail4: 421 EFSYS_PROBE(fail4); 422 fail3: 423 EFSYS_PROBE(fail3); 424 fail2: 425 EFSYS_PROBE(fail2); 426 fail1: 427 EFSYS_PROBE1(fail1, efx_rc_t, rc); 428 429 return (rc); 430 } 431 432 static __checkReturn efx_rc_t 433 tlv_delete( 434 __inout tlv_cursor_t *cursor) 435 { 436 unsigned int delta; 437 uint32_t *last_segment_end; 438 efx_rc_t rc; 439 440 if ((rc = tlv_validate_state(cursor)) != 0) 441 goto fail1; 442 443 if (tlv_tag(cursor) == TLV_TAG_END) { 444 rc = EINVAL; 445 goto fail2; 446 } 447 448 delta = TLV_DWORD_COUNT(tlv_length(cursor)); 449 450 if ((rc = tlv_require_end(cursor)) != 0) 451 goto fail3; 452 453 last_segment_end = tlv_last_segment_end(cursor); 454 455 /* Shuffle things down, destroying the item at cursor->current */ 456 memmove(cursor->current, cursor->current + delta, 457 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 458 /* Zero the new space at the end of the TLV chain */ 459 memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t)); 460 /* Adjust the end pointer */ 461 cursor->end -= delta; 462 463 return (0); 464 465 fail3: 466 EFSYS_PROBE(fail3); 467 fail2: 468 EFSYS_PROBE(fail2); 469 fail1: 470 EFSYS_PROBE1(fail1, efx_rc_t, rc); 471 472 return (rc); 473 } 474 475 static __checkReturn efx_rc_t 476 tlv_modify( 477 __inout tlv_cursor_t *cursor, 478 __in uint32_t tag, 479 __in_bcount(size) 480 uint8_t *data, 481 __in size_t size) 482 { 483 uint32_t *pos; 484 unsigned int old_ndwords; 485 unsigned int new_ndwords; 486 unsigned int delta; 487 uint32_t *last_segment_end; 488 efx_rc_t rc; 489 490 if ((rc = tlv_validate_state(cursor)) != 0) 491 goto fail1; 492 493 if (tlv_tag(cursor) == TLV_TAG_END) { 494 rc = EINVAL; 495 goto fail2; 496 } 497 if (tlv_tag(cursor) != tag) { 498 rc = EINVAL; 499 goto fail3; 500 } 501 502 old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor)); 503 new_ndwords = TLV_DWORD_COUNT(size); 504 505 if ((rc = tlv_require_end(cursor)) != 0) 506 goto fail4; 507 508 last_segment_end = tlv_last_segment_end(cursor); 509 510 if (new_ndwords > old_ndwords) { 511 /* Expand space used for TLV item */ 512 delta = new_ndwords - old_ndwords; 513 pos = cursor->current + old_ndwords; 514 515 if (last_segment_end + 1 + delta > cursor->limit) { 516 rc = ENOSPC; 517 goto fail5; 518 } 519 520 /* Move up: new space at (cursor->current + old_ndwords) */ 521 memmove(pos + delta, pos, 522 (last_segment_end + 1 - pos) * sizeof (uint32_t)); 523 524 /* Adjust the end pointer */ 525 cursor->end += delta; 526 527 } else if (new_ndwords < old_ndwords) { 528 /* Shrink space used for TLV item */ 529 delta = old_ndwords - new_ndwords; 530 pos = cursor->current + new_ndwords; 531 532 /* Move down: remove words at (cursor->current + new_ndwords) */ 533 memmove(pos, pos + delta, 534 (last_segment_end + 1 - pos) * sizeof (uint32_t)); 535 536 /* Zero the new space at the end of the TLV chain */ 537 memset(last_segment_end + 1 - delta, 0, 538 delta * sizeof (uint32_t)); 539 540 /* Adjust the end pointer */ 541 cursor->end -= delta; 542 } 543 544 /* Write new data */ 545 tlv_write(cursor, tag, data, size); 546 547 return (0); 548 549 fail5: 550 EFSYS_PROBE(fail5); 551 fail4: 552 EFSYS_PROBE(fail4); 553 fail3: 554 EFSYS_PROBE(fail3); 555 fail2: 556 EFSYS_PROBE(fail2); 557 fail1: 558 EFSYS_PROBE1(fail1, efx_rc_t, rc); 559 560 return (rc); 561 } 562 563 static uint32_t checksum_tlv_partition( 564 __in nvram_partition_t *partition) 565 { 566 tlv_cursor_t *cursor; 567 uint32_t *ptr; 568 uint32_t *end; 569 uint32_t csum; 570 size_t len; 571 572 cursor = &partition->tlv_cursor; 573 len = tlv_block_length_used(cursor); 574 EFSYS_ASSERT3U((len & 3), ==, 0); 575 576 csum = 0; 577 ptr = partition->data; 578 end = &ptr[len >> 2]; 579 580 while (ptr < end) 581 csum += __LE_TO_CPU_32(*ptr++); 582 583 return (csum); 584 } 585 586 static __checkReturn efx_rc_t 587 tlv_update_partition_len_and_cks( 588 __in tlv_cursor_t *cursor) 589 { 590 efx_rc_t rc; 591 nvram_partition_t partition; 592 struct tlv_partition_header *header; 593 struct tlv_partition_trailer *trailer; 594 size_t new_len; 595 596 /* 597 * We just modified the partition, so the total length may not be 598 * valid. Don't use tlv_find(), which performs some sanity checks 599 * that may fail here. 600 */ 601 partition.data = cursor->block; 602 memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor)); 603 header = (struct tlv_partition_header *)partition.data; 604 /* Sanity check. */ 605 if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) { 606 rc = EFAULT; 607 goto fail1; 608 } 609 new_len = tlv_block_length_used(&partition.tlv_cursor); 610 if (new_len == 0) { 611 rc = EFAULT; 612 goto fail2; 613 } 614 header->total_length = __CPU_TO_LE_32(new_len); 615 /* Ensure the modified partition always has a new generation count. */ 616 header->generation = __CPU_TO_LE_32( 617 __LE_TO_CPU_32(header->generation) + 1); 618 619 trailer = (struct tlv_partition_trailer *)((uint8_t *)header + 620 new_len - sizeof (*trailer) - sizeof (uint32_t)); 621 trailer->generation = header->generation; 622 trailer->checksum = __CPU_TO_LE_32( 623 __LE_TO_CPU_32(trailer->checksum) - 624 checksum_tlv_partition(&partition)); 625 626 return (0); 627 628 fail2: 629 EFSYS_PROBE(fail2); 630 fail1: 631 EFSYS_PROBE1(fail1, efx_rc_t, rc); 632 633 return (rc); 634 } 635 636 /* Validate buffer contents (before writing to flash) */ 637 __checkReturn efx_rc_t 638 ef10_nvram_buffer_validate( 639 __in uint32_t partn, 640 __in_bcount(partn_size) caddr_t partn_data, 641 __in size_t partn_size) 642 { 643 tlv_cursor_t cursor; 644 struct tlv_partition_header *header; 645 struct tlv_partition_trailer *trailer; 646 size_t total_length; 647 uint32_t cksum; 648 int pos; 649 efx_rc_t rc; 650 651 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 652 653 if ((partn_data == NULL) || (partn_size == 0)) { 654 rc = EINVAL; 655 goto fail1; 656 } 657 658 /* The partition header must be the first item (at offset zero) */ 659 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, 660 partn_size)) != 0) { 661 rc = EFAULT; 662 goto fail2; 663 } 664 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 665 rc = EINVAL; 666 goto fail3; 667 } 668 header = (struct tlv_partition_header *)tlv_item(&cursor); 669 670 /* Check TLV partition length (includes the END tag) */ 671 total_length = __LE_TO_CPU_32(header->total_length); 672 if (total_length > partn_size) { 673 rc = EFBIG; 674 goto fail4; 675 } 676 677 /* Check partition header matches partn */ 678 if (__LE_TO_CPU_16(header->type_id) != partn) { 679 rc = EINVAL; 680 goto fail5; 681 } 682 683 /* Check partition ends with PARTITION_TRAILER and END tags */ 684 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 685 rc = EINVAL; 686 goto fail6; 687 } 688 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 689 690 if ((rc = tlv_advance(&cursor)) != 0) { 691 rc = EINVAL; 692 goto fail7; 693 } 694 if (tlv_tag(&cursor) != TLV_TAG_END) { 695 rc = EINVAL; 696 goto fail8; 697 } 698 699 /* Check generation counts are consistent */ 700 if (trailer->generation != header->generation) { 701 rc = EINVAL; 702 goto fail9; 703 } 704 705 /* Verify partition checksum */ 706 cksum = 0; 707 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 708 cksum += *((uint32_t *)(partn_data + pos)); 709 } 710 if (cksum != 0) { 711 rc = EINVAL; 712 goto fail10; 713 } 714 715 return (0); 716 717 fail10: 718 EFSYS_PROBE(fail10); 719 fail9: 720 EFSYS_PROBE(fail9); 721 fail8: 722 EFSYS_PROBE(fail8); 723 fail7: 724 EFSYS_PROBE(fail7); 725 fail6: 726 EFSYS_PROBE(fail6); 727 fail5: 728 EFSYS_PROBE(fail5); 729 fail4: 730 EFSYS_PROBE(fail4); 731 fail3: 732 EFSYS_PROBE(fail3); 733 fail2: 734 EFSYS_PROBE(fail2); 735 fail1: 736 EFSYS_PROBE1(fail1, efx_rc_t, rc); 737 738 return (rc); 739 } 740 741 void 742 ef10_nvram_buffer_init( 743 __out_bcount(buffer_size) 744 caddr_t bufferp, 745 __in size_t buffer_size) 746 { 747 uint32_t *buf = (uint32_t *)bufferp; 748 749 memset(buf, 0xff, buffer_size); 750 751 tlv_init_block(buf); 752 } 753 754 __checkReturn efx_rc_t 755 ef10_nvram_buffer_create( 756 __in uint32_t partn_type, 757 __out_bcount(partn_size) 758 caddr_t partn_data, 759 __in size_t partn_size) 760 { 761 uint32_t *buf = (uint32_t *)partn_data; 762 efx_rc_t rc; 763 tlv_cursor_t cursor; 764 struct tlv_partition_header header; 765 struct tlv_partition_trailer trailer; 766 767 unsigned int min_buf_size = sizeof (struct tlv_partition_header) + 768 sizeof (struct tlv_partition_trailer); 769 if (partn_size < min_buf_size) { 770 rc = EINVAL; 771 goto fail1; 772 } 773 774 ef10_nvram_buffer_init(partn_data, partn_size); 775 776 if ((rc = tlv_init_cursor(&cursor, buf, 777 (uint32_t *)((uint8_t *)buf + partn_size), 778 buf)) != 0) { 779 goto fail2; 780 } 781 782 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); 783 header.length = __CPU_TO_LE_32(sizeof (header) - 8); 784 header.type_id = __CPU_TO_LE_16(partn_type); 785 header.preset = 0; 786 header.generation = __CPU_TO_LE_32(1); 787 header.total_length = 0; /* This will be fixed below. */ 788 if ((rc = tlv_insert( 789 &cursor, TLV_TAG_PARTITION_HEADER, 790 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) 791 goto fail3; 792 if ((rc = tlv_advance(&cursor)) != 0) 793 goto fail4; 794 795 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); 796 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); 797 trailer.generation = header.generation; 798 trailer.checksum = 0; /* This will be fixed below. */ 799 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, 800 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) 801 goto fail5; 802 803 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 804 goto fail6; 805 806 /* Check that the partition is valid. */ 807 if ((rc = ef10_nvram_buffer_validate(partn_type, 808 partn_data, partn_size)) != 0) 809 goto fail7; 810 811 return (0); 812 813 fail7: 814 EFSYS_PROBE(fail7); 815 fail6: 816 EFSYS_PROBE(fail6); 817 fail5: 818 EFSYS_PROBE(fail5); 819 fail4: 820 EFSYS_PROBE(fail4); 821 fail3: 822 EFSYS_PROBE(fail3); 823 fail2: 824 EFSYS_PROBE(fail2); 825 fail1: 826 EFSYS_PROBE1(fail1, efx_rc_t, rc); 827 828 return (rc); 829 } 830 831 static uint32_t 832 byte_offset( 833 __in uint32_t *position, 834 __in uint32_t *base) 835 { 836 return (uint32_t)((uint8_t *)position - (uint8_t *)base); 837 } 838 839 __checkReturn efx_rc_t 840 ef10_nvram_buffer_find_item_start( 841 __in_bcount(buffer_size) 842 caddr_t bufferp, 843 __in size_t buffer_size, 844 __out uint32_t *startp) 845 { 846 /* Read past partition header to find start address of the first key */ 847 tlv_cursor_t cursor; 848 efx_rc_t rc; 849 850 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 851 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 852 buffer_size)) != 0) { 853 rc = EFAULT; 854 goto fail1; 855 } 856 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 857 rc = EINVAL; 858 goto fail2; 859 } 860 861 if ((rc = tlv_advance(&cursor)) != 0) { 862 rc = EINVAL; 863 goto fail3; 864 } 865 *startp = byte_offset(cursor.current, cursor.block); 866 867 if ((rc = tlv_require_end(&cursor)) != 0) 868 goto fail4; 869 870 return (0); 871 872 fail4: 873 EFSYS_PROBE(fail4); 874 fail3: 875 EFSYS_PROBE(fail3); 876 fail2: 877 EFSYS_PROBE(fail2); 878 fail1: 879 EFSYS_PROBE1(fail1, efx_rc_t, rc); 880 881 return (rc); 882 } 883 884 __checkReturn efx_rc_t 885 ef10_nvram_buffer_find_end( 886 __in_bcount(buffer_size) 887 caddr_t bufferp, 888 __in size_t buffer_size, 889 __in uint32_t offset, 890 __out uint32_t *endp) 891 { 892 /* Read to end of partition */ 893 tlv_cursor_t cursor; 894 efx_rc_t rc; 895 uint32_t *segment_used; 896 897 _NOTE(ARGUNUSED(offset)) 898 899 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 900 buffer_size)) != 0) { 901 rc = EFAULT; 902 goto fail1; 903 } 904 905 segment_used = cursor.block; 906 907 /* 908 * Go through each segment and check that it has an end tag. If there 909 * is no end tag then the previous segment was the last valid one, 910 * so return the used space including that end tag. 911 */ 912 while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 913 if (tlv_require_end(&cursor) != 0) { 914 if (segment_used == cursor.block) { 915 /* 916 * First segment is corrupt, so there is 917 * no valid data in partition. 918 */ 919 rc = EINVAL; 920 goto fail2; 921 } 922 break; 923 } 924 segment_used = cursor.end + 1; 925 926 cursor.current = segment_used; 927 } 928 /* Return space used (including the END tag) */ 929 *endp = (segment_used - cursor.block) * sizeof (uint32_t); 930 931 return (0); 932 933 fail2: 934 EFSYS_PROBE(fail2); 935 fail1: 936 EFSYS_PROBE1(fail1, efx_rc_t, rc); 937 938 return (rc); 939 } 940 941 __checkReturn __success(return != B_FALSE) boolean_t 942 ef10_nvram_buffer_find_item( 943 __in_bcount(buffer_size) 944 caddr_t bufferp, 945 __in size_t buffer_size, 946 __in uint32_t offset, 947 __out uint32_t *startp, 948 __out uint32_t *lengthp) 949 { 950 /* Find TLV at offset and return key start and length */ 951 tlv_cursor_t cursor; 952 uint8_t *key; 953 uint32_t tag; 954 955 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 956 buffer_size, offset) != 0) { 957 return (B_FALSE); 958 } 959 960 while ((key = tlv_item(&cursor)) != NULL) { 961 tag = tlv_tag(&cursor); 962 if (tag == TLV_TAG_PARTITION_HEADER || 963 tag == TLV_TAG_PARTITION_TRAILER) { 964 if (tlv_advance(&cursor) != 0) { 965 break; 966 } 967 continue; 968 } 969 *startp = byte_offset(cursor.current, cursor.block); 970 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 971 cursor.current); 972 return (B_TRUE); 973 } 974 975 return (B_FALSE); 976 } 977 978 __checkReturn efx_rc_t 979 ef10_nvram_buffer_peek_item( 980 __in_bcount(buffer_size) 981 caddr_t bufferp, 982 __in size_t buffer_size, 983 __in uint32_t offset, 984 __out uint32_t *tagp, 985 __out uint32_t *lengthp, 986 __out uint32_t *value_offsetp) 987 { 988 efx_rc_t rc; 989 tlv_cursor_t cursor; 990 uint32_t tag; 991 992 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 993 buffer_size, offset)) != 0) { 994 goto fail1; 995 } 996 997 tag = tlv_tag(&cursor); 998 *tagp = tag; 999 if (tag == TLV_TAG_END) { 1000 /* 1001 * To allow stepping over the END tag, report the full tag 1002 * length and a zero length value. 1003 */ 1004 *lengthp = sizeof (tag); 1005 *value_offsetp = sizeof (tag); 1006 } else { 1007 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1008 cursor.current); 1009 *value_offsetp = byte_offset((uint32_t *)tlv_value(&cursor), 1010 cursor.current); 1011 } 1012 return (0); 1013 1014 fail1: 1015 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1016 1017 return (rc); 1018 } 1019 1020 __checkReturn efx_rc_t 1021 ef10_nvram_buffer_get_item( 1022 __in_bcount(buffer_size) 1023 caddr_t bufferp, 1024 __in size_t buffer_size, 1025 __in uint32_t offset, 1026 __in uint32_t length, 1027 __out uint32_t *tagp, 1028 __out_bcount_part(value_max_size, *lengthp) 1029 caddr_t valuep, 1030 __in size_t value_max_size, 1031 __out uint32_t *lengthp) 1032 { 1033 efx_rc_t rc; 1034 tlv_cursor_t cursor; 1035 uint32_t value_length; 1036 1037 if (buffer_size < (offset + length)) { 1038 rc = ENOSPC; 1039 goto fail1; 1040 } 1041 1042 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1043 buffer_size, offset)) != 0) { 1044 goto fail2; 1045 } 1046 1047 value_length = tlv_length(&cursor); 1048 if (value_max_size < value_length) { 1049 rc = ENOSPC; 1050 goto fail3; 1051 } 1052 memcpy(valuep, tlv_value(&cursor), value_length); 1053 1054 *tagp = tlv_tag(&cursor); 1055 *lengthp = value_length; 1056 1057 return (0); 1058 1059 fail3: 1060 EFSYS_PROBE(fail3); 1061 fail2: 1062 EFSYS_PROBE(fail2); 1063 fail1: 1064 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1065 1066 return (rc); 1067 } 1068 1069 __checkReturn efx_rc_t 1070 ef10_nvram_buffer_insert_item( 1071 __in_bcount(buffer_size) 1072 caddr_t bufferp, 1073 __in size_t buffer_size, 1074 __in uint32_t offset, 1075 __in uint32_t tag, 1076 __in_bcount(length) caddr_t valuep, 1077 __in uint32_t length, 1078 __out uint32_t *lengthp) 1079 { 1080 efx_rc_t rc; 1081 tlv_cursor_t cursor; 1082 1083 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1084 buffer_size, offset)) != 0) { 1085 goto fail1; 1086 } 1087 1088 rc = tlv_insert(&cursor, tag, (uint8_t *)valuep, length); 1089 1090 if (rc != 0) 1091 goto fail2; 1092 1093 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1094 cursor.current); 1095 1096 return (0); 1097 1098 fail2: 1099 EFSYS_PROBE(fail2); 1100 fail1: 1101 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1102 1103 return (rc); 1104 } 1105 1106 __checkReturn efx_rc_t 1107 ef10_nvram_buffer_modify_item( 1108 __in_bcount(buffer_size) 1109 caddr_t bufferp, 1110 __in size_t buffer_size, 1111 __in uint32_t offset, 1112 __in uint32_t tag, 1113 __in_bcount(length) caddr_t valuep, 1114 __in uint32_t length, 1115 __out uint32_t *lengthp) 1116 { 1117 efx_rc_t rc; 1118 tlv_cursor_t cursor; 1119 1120 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1121 buffer_size, offset)) != 0) { 1122 goto fail1; 1123 } 1124 1125 rc = tlv_modify(&cursor, tag, (uint8_t *)valuep, length); 1126 1127 if (rc != 0) { 1128 goto fail2; 1129 } 1130 1131 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1132 cursor.current); 1133 1134 return (0); 1135 1136 fail2: 1137 EFSYS_PROBE(fail2); 1138 fail1: 1139 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1140 1141 return (rc); 1142 } 1143 1144 1145 __checkReturn efx_rc_t 1146 ef10_nvram_buffer_delete_item( 1147 __in_bcount(buffer_size) 1148 caddr_t bufferp, 1149 __in size_t buffer_size, 1150 __in uint32_t offset, 1151 __in uint32_t length, 1152 __in uint32_t end) 1153 { 1154 efx_rc_t rc; 1155 tlv_cursor_t cursor; 1156 1157 _NOTE(ARGUNUSED(length, end)) 1158 1159 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1160 buffer_size, offset)) != 0) { 1161 goto fail1; 1162 } 1163 1164 if ((rc = tlv_delete(&cursor)) != 0) 1165 goto fail2; 1166 1167 return (0); 1168 1169 fail2: 1170 EFSYS_PROBE(fail2); 1171 fail1: 1172 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1173 1174 return (rc); 1175 } 1176 1177 __checkReturn efx_rc_t 1178 ef10_nvram_buffer_finish( 1179 __in_bcount(buffer_size) 1180 caddr_t bufferp, 1181 __in size_t buffer_size) 1182 { 1183 efx_rc_t rc; 1184 tlv_cursor_t cursor; 1185 1186 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 1187 buffer_size)) != 0) { 1188 rc = EFAULT; 1189 goto fail1; 1190 } 1191 1192 if ((rc = tlv_require_end(&cursor)) != 0) 1193 goto fail2; 1194 1195 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 1196 goto fail3; 1197 1198 return (0); 1199 1200 fail3: 1201 EFSYS_PROBE(fail3); 1202 fail2: 1203 EFSYS_PROBE(fail2); 1204 fail1: 1205 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1206 1207 return (rc); 1208 } 1209 1210 1211 1212 /* 1213 * Read and validate a segment from a partition. A segment is a complete 1214 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may 1215 * be multiple segments in a partition, so seg_offset allows segments 1216 * beyond the first to be read. 1217 */ 1218 static __checkReturn efx_rc_t 1219 ef10_nvram_read_tlv_segment( 1220 __in efx_nic_t *enp, 1221 __in uint32_t partn, 1222 __in size_t seg_offset, 1223 __in_bcount(max_seg_size) caddr_t seg_data, 1224 __in size_t max_seg_size) 1225 { 1226 tlv_cursor_t cursor; 1227 struct tlv_partition_header *header; 1228 struct tlv_partition_trailer *trailer; 1229 size_t total_length; 1230 uint32_t cksum; 1231 int pos; 1232 efx_rc_t rc; 1233 1234 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 1235 1236 if ((seg_data == NULL) || (max_seg_size == 0)) { 1237 rc = EINVAL; 1238 goto fail1; 1239 } 1240 1241 /* Read initial chunk of the segment, starting at offset */ 1242 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, 1243 EF10_NVRAM_CHUNK, 1244 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { 1245 goto fail2; 1246 } 1247 1248 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1249 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1250 max_seg_size)) != 0) { 1251 rc = EFAULT; 1252 goto fail3; 1253 } 1254 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1255 rc = EINVAL; 1256 goto fail4; 1257 } 1258 header = (struct tlv_partition_header *)tlv_item(&cursor); 1259 1260 /* Check TLV segment length (includes the END tag) */ 1261 total_length = __LE_TO_CPU_32(header->total_length); 1262 if (total_length > max_seg_size) { 1263 rc = EFBIG; 1264 goto fail5; 1265 } 1266 1267 /* Read the remaining segment content */ 1268 if (total_length > EF10_NVRAM_CHUNK) { 1269 if ((rc = ef10_nvram_partn_read_mode(enp, partn, 1270 seg_offset + EF10_NVRAM_CHUNK, 1271 seg_data + EF10_NVRAM_CHUNK, 1272 total_length - EF10_NVRAM_CHUNK, 1273 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) 1274 goto fail6; 1275 } 1276 1277 /* Check segment ends with PARTITION_TRAILER and END tags */ 1278 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1279 rc = EINVAL; 1280 goto fail7; 1281 } 1282 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1283 1284 if ((rc = tlv_advance(&cursor)) != 0) { 1285 rc = EINVAL; 1286 goto fail8; 1287 } 1288 if (tlv_tag(&cursor) != TLV_TAG_END) { 1289 rc = EINVAL; 1290 goto fail9; 1291 } 1292 1293 /* Check data read from segment is consistent */ 1294 if (trailer->generation != header->generation) { 1295 /* 1296 * The partition data may have been modified between successive 1297 * MCDI NVRAM_READ requests by the MC or another PCI function. 1298 * 1299 * The caller must retry to obtain consistent partition data. 1300 */ 1301 rc = EAGAIN; 1302 goto fail10; 1303 } 1304 1305 /* Verify segment checksum */ 1306 cksum = 0; 1307 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 1308 cksum += *((uint32_t *)(seg_data + pos)); 1309 } 1310 if (cksum != 0) { 1311 rc = EINVAL; 1312 goto fail11; 1313 } 1314 1315 return (0); 1316 1317 fail11: 1318 EFSYS_PROBE(fail11); 1319 fail10: 1320 EFSYS_PROBE(fail10); 1321 fail9: 1322 EFSYS_PROBE(fail9); 1323 fail8: 1324 EFSYS_PROBE(fail8); 1325 fail7: 1326 EFSYS_PROBE(fail7); 1327 fail6: 1328 EFSYS_PROBE(fail6); 1329 fail5: 1330 EFSYS_PROBE(fail5); 1331 fail4: 1332 EFSYS_PROBE(fail4); 1333 fail3: 1334 EFSYS_PROBE(fail3); 1335 fail2: 1336 EFSYS_PROBE(fail2); 1337 fail1: 1338 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1339 1340 return (rc); 1341 } 1342 1343 /* 1344 * Read a single TLV item from a host memory 1345 * buffer containing a TLV formatted segment. 1346 */ 1347 __checkReturn efx_rc_t 1348 ef10_nvram_buf_read_tlv( 1349 __in efx_nic_t *enp, 1350 __in_bcount(max_seg_size) caddr_t seg_data, 1351 __in size_t max_seg_size, 1352 __in uint32_t tag, 1353 __deref_out_bcount_opt(*sizep) caddr_t *datap, 1354 __out size_t *sizep) 1355 { 1356 tlv_cursor_t cursor; 1357 caddr_t data; 1358 size_t length; 1359 caddr_t value; 1360 efx_rc_t rc; 1361 1362 _NOTE(ARGUNUSED(enp)) 1363 1364 if ((seg_data == NULL) || (max_seg_size == 0)) { 1365 rc = EINVAL; 1366 goto fail1; 1367 } 1368 1369 /* Find requested TLV tag in segment data */ 1370 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1371 max_seg_size)) != 0) { 1372 rc = EFAULT; 1373 goto fail2; 1374 } 1375 if ((rc = tlv_find(&cursor, tag)) != 0) { 1376 rc = ENOENT; 1377 goto fail3; 1378 } 1379 value = (caddr_t)tlv_value(&cursor); 1380 length = tlv_length(&cursor); 1381 1382 if (length == 0) 1383 data = NULL; 1384 else { 1385 /* Copy out data from TLV item */ 1386 EFSYS_KMEM_ALLOC(enp->en_esip, length, data); 1387 if (data == NULL) { 1388 rc = ENOMEM; 1389 goto fail4; 1390 } 1391 memcpy(data, value, length); 1392 } 1393 1394 *datap = data; 1395 *sizep = length; 1396 1397 return (0); 1398 1399 fail4: 1400 EFSYS_PROBE(fail4); 1401 fail3: 1402 EFSYS_PROBE(fail3); 1403 fail2: 1404 EFSYS_PROBE(fail2); 1405 fail1: 1406 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1407 1408 return (rc); 1409 } 1410 1411 /* Read a single TLV item from the first segment in a TLV formatted partition */ 1412 __checkReturn efx_rc_t 1413 ef10_nvram_partn_read_tlv( 1414 __in efx_nic_t *enp, 1415 __in uint32_t partn, 1416 __in uint32_t tag, 1417 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, 1418 __out size_t *seg_sizep) 1419 { 1420 caddr_t seg_data = NULL; 1421 size_t partn_size = 0; 1422 size_t length; 1423 caddr_t data; 1424 int retry; 1425 efx_rc_t rc; 1426 1427 /* Allocate sufficient memory for the entire partition */ 1428 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1429 goto fail1; 1430 1431 if (partn_size == 0) { 1432 rc = ENOENT; 1433 goto fail2; 1434 } 1435 1436 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); 1437 if (seg_data == NULL) { 1438 rc = ENOMEM; 1439 goto fail3; 1440 } 1441 1442 /* 1443 * Read the first segment in a TLV partition. Retry until consistent 1444 * segment contents are returned. Inconsistent data may be read if: 1445 * a) the segment contents are invalid 1446 * b) the MC has rebooted while we were reading the partition 1447 * c) the partition has been modified while we were reading it 1448 * Limit retry attempts to ensure forward progress. 1449 */ 1450 retry = 10; 1451 do { 1452 if ((rc = ef10_nvram_read_tlv_segment(enp, partn, 0, 1453 seg_data, partn_size)) != 0) 1454 --retry; 1455 } while ((rc == EAGAIN) && (retry > 0)); 1456 1457 if (rc != 0) { 1458 /* Failed to obtain consistent segment data */ 1459 if (rc == EAGAIN) 1460 rc = EIO; 1461 1462 goto fail4; 1463 } 1464 1465 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, 1466 tag, &data, &length)) != 0) 1467 goto fail5; 1468 1469 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1470 1471 *seg_datap = data; 1472 *seg_sizep = length; 1473 1474 return (0); 1475 1476 fail5: 1477 EFSYS_PROBE(fail5); 1478 fail4: 1479 EFSYS_PROBE(fail4); 1480 1481 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1482 fail3: 1483 EFSYS_PROBE(fail3); 1484 fail2: 1485 EFSYS_PROBE(fail2); 1486 fail1: 1487 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1488 1489 return (rc); 1490 } 1491 1492 /* Compute the size of a segment. */ 1493 static __checkReturn efx_rc_t 1494 ef10_nvram_buf_segment_size( 1495 __in caddr_t seg_data, 1496 __in size_t max_seg_size, 1497 __out size_t *seg_sizep) 1498 { 1499 efx_rc_t rc; 1500 tlv_cursor_t cursor; 1501 struct tlv_partition_header *header; 1502 uint32_t cksum; 1503 int pos; 1504 uint32_t *end_tag_position; 1505 uint32_t segment_length; 1506 1507 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1508 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1509 max_seg_size)) != 0) { 1510 rc = EFAULT; 1511 goto fail1; 1512 } 1513 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1514 rc = EINVAL; 1515 goto fail2; 1516 } 1517 header = (struct tlv_partition_header *)tlv_item(&cursor); 1518 1519 /* Check TLV segment length (includes the END tag) */ 1520 *seg_sizep = __LE_TO_CPU_32(header->total_length); 1521 if (*seg_sizep > max_seg_size) { 1522 rc = EFBIG; 1523 goto fail3; 1524 } 1525 1526 /* Check segment ends with PARTITION_TRAILER and END tags */ 1527 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1528 rc = EINVAL; 1529 goto fail4; 1530 } 1531 1532 if ((rc = tlv_advance(&cursor)) != 0) { 1533 rc = EINVAL; 1534 goto fail5; 1535 } 1536 if (tlv_tag(&cursor) != TLV_TAG_END) { 1537 rc = EINVAL; 1538 goto fail6; 1539 } 1540 end_tag_position = cursor.current; 1541 1542 /* Verify segment checksum */ 1543 cksum = 0; 1544 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { 1545 cksum += *((uint32_t *)(seg_data + pos)); 1546 } 1547 if (cksum != 0) { 1548 rc = EINVAL; 1549 goto fail7; 1550 } 1551 1552 /* 1553 * Calculate total length from HEADER to END tags and compare to 1554 * max_seg_size and the total_length field in the HEADER tag. 1555 */ 1556 segment_length = tlv_block_length_used(&cursor); 1557 1558 if (segment_length > max_seg_size) { 1559 rc = EINVAL; 1560 goto fail8; 1561 } 1562 1563 if (segment_length != *seg_sizep) { 1564 rc = EINVAL; 1565 goto fail9; 1566 } 1567 1568 /* Skip over the first HEADER tag. */ 1569 rc = tlv_rewind(&cursor); 1570 rc = tlv_advance(&cursor); 1571 1572 while (rc == 0) { 1573 if (tlv_tag(&cursor) == TLV_TAG_END) { 1574 /* Check that the END tag is the one found earlier. */ 1575 if (cursor.current != end_tag_position) 1576 goto fail10; 1577 break; 1578 } 1579 /* Check for duplicate HEADER tags before the END tag. */ 1580 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 1581 rc = EINVAL; 1582 goto fail11; 1583 } 1584 1585 rc = tlv_advance(&cursor); 1586 } 1587 if (rc != 0) 1588 goto fail12; 1589 1590 return (0); 1591 1592 fail12: 1593 EFSYS_PROBE(fail12); 1594 fail11: 1595 EFSYS_PROBE(fail11); 1596 fail10: 1597 EFSYS_PROBE(fail10); 1598 fail9: 1599 EFSYS_PROBE(fail9); 1600 fail8: 1601 EFSYS_PROBE(fail8); 1602 fail7: 1603 EFSYS_PROBE(fail7); 1604 fail6: 1605 EFSYS_PROBE(fail6); 1606 fail5: 1607 EFSYS_PROBE(fail5); 1608 fail4: 1609 EFSYS_PROBE(fail4); 1610 fail3: 1611 EFSYS_PROBE(fail3); 1612 fail2: 1613 EFSYS_PROBE(fail2); 1614 fail1: 1615 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1616 1617 return (rc); 1618 } 1619 1620 /* 1621 * Add or update a single TLV item in a host memory buffer containing a TLV 1622 * formatted segment. Historically partitions consisted of only one segment. 1623 */ 1624 __checkReturn efx_rc_t 1625 ef10_nvram_buf_write_tlv( 1626 __inout_bcount(max_seg_size) caddr_t seg_data, 1627 __in size_t max_seg_size, 1628 __in uint32_t tag, 1629 __in_bcount(tag_size) caddr_t tag_data, 1630 __in size_t tag_size, 1631 __out size_t *total_lengthp) 1632 { 1633 tlv_cursor_t cursor; 1634 struct tlv_partition_header *header; 1635 struct tlv_partition_trailer *trailer; 1636 uint32_t generation; 1637 uint32_t cksum; 1638 int pos; 1639 efx_rc_t rc; 1640 1641 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 1642 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1643 max_seg_size)) != 0) { 1644 rc = EFAULT; 1645 goto fail1; 1646 } 1647 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1648 rc = EINVAL; 1649 goto fail2; 1650 } 1651 header = (struct tlv_partition_header *)tlv_item(&cursor); 1652 1653 /* Update the TLV chain to contain the new data */ 1654 if ((rc = tlv_find(&cursor, tag)) == 0) { 1655 /* Modify existing TLV item */ 1656 if ((rc = tlv_modify(&cursor, tag, 1657 (uint8_t *)tag_data, tag_size)) != 0) 1658 goto fail3; 1659 } else { 1660 /* Insert a new TLV item before the PARTITION_TRAILER */ 1661 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); 1662 if (rc != 0) { 1663 rc = EINVAL; 1664 goto fail4; 1665 } 1666 if ((rc = tlv_insert(&cursor, tag, 1667 (uint8_t *)tag_data, tag_size)) != 0) { 1668 rc = EINVAL; 1669 goto fail5; 1670 } 1671 } 1672 1673 /* Find the trailer tag */ 1674 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1675 rc = EINVAL; 1676 goto fail6; 1677 } 1678 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1679 1680 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ 1681 *total_lengthp = tlv_block_length_used(&cursor); 1682 if (*total_lengthp > max_seg_size) { 1683 rc = ENOSPC; 1684 goto fail7; 1685 } 1686 generation = __LE_TO_CPU_32(header->generation) + 1; 1687 1688 header->total_length = __CPU_TO_LE_32(*total_lengthp); 1689 header->generation = __CPU_TO_LE_32(generation); 1690 trailer->generation = __CPU_TO_LE_32(generation); 1691 1692 /* Recompute PARTITION_TRAILER checksum */ 1693 trailer->checksum = 0; 1694 cksum = 0; 1695 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { 1696 cksum += *((uint32_t *)(seg_data + pos)); 1697 } 1698 trailer->checksum = ~cksum + 1; 1699 1700 return (0); 1701 1702 fail7: 1703 EFSYS_PROBE(fail7); 1704 fail6: 1705 EFSYS_PROBE(fail6); 1706 fail5: 1707 EFSYS_PROBE(fail5); 1708 fail4: 1709 EFSYS_PROBE(fail4); 1710 fail3: 1711 EFSYS_PROBE(fail3); 1712 fail2: 1713 EFSYS_PROBE(fail2); 1714 fail1: 1715 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1716 1717 return (rc); 1718 } 1719 1720 /* 1721 * Add or update a single TLV item in the first segment of a TLV formatted 1722 * dynamic config partition. The first segment is the current active 1723 * configuration. 1724 */ 1725 __checkReturn efx_rc_t 1726 ef10_nvram_partn_write_tlv( 1727 __in efx_nic_t *enp, 1728 __in uint32_t partn, 1729 __in uint32_t tag, 1730 __in_bcount(size) caddr_t data, 1731 __in size_t size) 1732 { 1733 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, 1734 size, B_FALSE); 1735 } 1736 1737 /* 1738 * Read a segment from nvram at the given offset into a buffer (segment_data) 1739 * and optionally write a new tag to it. 1740 */ 1741 static __checkReturn efx_rc_t 1742 ef10_nvram_segment_write_tlv( 1743 __in efx_nic_t *enp, 1744 __in uint32_t partn, 1745 __in uint32_t tag, 1746 __in_bcount(size) caddr_t data, 1747 __in size_t size, 1748 __inout caddr_t *seg_datap, 1749 __inout size_t *partn_offsetp, 1750 __inout size_t *src_remain_lenp, 1751 __inout size_t *dest_remain_lenp, 1752 __in boolean_t write) 1753 { 1754 efx_rc_t rc; 1755 efx_rc_t status; 1756 size_t original_segment_size; 1757 size_t modified_segment_size; 1758 1759 /* 1760 * Read the segment from NVRAM into the segment_data buffer and validate 1761 * it, returning if it does not validate. This is not a failure unless 1762 * this is the first segment in a partition. In this case the caller 1763 * must propagate the error. 1764 */ 1765 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, 1766 *seg_datap, *src_remain_lenp); 1767 if (status != 0) { 1768 rc = EINVAL; 1769 goto fail1; 1770 } 1771 1772 status = ef10_nvram_buf_segment_size(*seg_datap, 1773 *src_remain_lenp, &original_segment_size); 1774 if (status != 0) { 1775 rc = EINVAL; 1776 goto fail2; 1777 } 1778 1779 if (write) { 1780 /* Update the contents of the segment in the buffer */ 1781 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, 1782 *dest_remain_lenp, tag, data, size, 1783 &modified_segment_size)) != 0) { 1784 goto fail3; 1785 } 1786 *dest_remain_lenp -= modified_segment_size; 1787 *seg_datap += modified_segment_size; 1788 } else { 1789 /* 1790 * We won't modify this segment, but still need to update the 1791 * remaining lengths and pointers. 1792 */ 1793 *dest_remain_lenp -= original_segment_size; 1794 *seg_datap += original_segment_size; 1795 } 1796 1797 *partn_offsetp += original_segment_size; 1798 *src_remain_lenp -= original_segment_size; 1799 1800 return (0); 1801 1802 fail3: 1803 EFSYS_PROBE(fail3); 1804 fail2: 1805 EFSYS_PROBE(fail2); 1806 fail1: 1807 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1808 1809 return (rc); 1810 } 1811 1812 /* 1813 * Add or update a single TLV item in either the first segment or in all 1814 * segments in a TLV formatted dynamic config partition. Dynamic config 1815 * partitions on boards that support RFID are divided into a number of segments, 1816 * each formatted like a partition, with header, trailer and end tags. The first 1817 * segment is the current active configuration. 1818 * 1819 * The segments are initialised by manftest and each contain a different 1820 * configuration e.g. firmware variant. The firmware can be instructed 1821 * via RFID to copy a segment to replace the first segment, hence changing the 1822 * active configuration. This allows ops to change the configuration of a board 1823 * prior to shipment using RFID. 1824 * 1825 * Changes to the dynamic config may need to be written to all segments (e.g. 1826 * firmware versions) or just the first segment (changes to the active 1827 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". 1828 * If only the first segment is written the code still needs to be aware of the 1829 * possible presence of subsequent segments as writing to a segment may cause 1830 * its size to increase, which would overwrite the subsequent segments and 1831 * invalidate them. 1832 */ 1833 __checkReturn efx_rc_t 1834 ef10_nvram_partn_write_segment_tlv( 1835 __in efx_nic_t *enp, 1836 __in uint32_t partn, 1837 __in uint32_t tag, 1838 __in_bcount(size) caddr_t data, 1839 __in size_t size, 1840 __in boolean_t all_segments) 1841 { 1842 size_t partn_size = 0; 1843 caddr_t partn_data; 1844 size_t total_length = 0; 1845 efx_rc_t rc; 1846 size_t current_offset = 0; 1847 size_t remaining_original_length; 1848 size_t remaining_modified_length; 1849 caddr_t segment_data; 1850 1851 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); 1852 1853 /* Allocate sufficient memory for the entire partition */ 1854 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1855 goto fail1; 1856 1857 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); 1858 if (partn_data == NULL) { 1859 rc = ENOMEM; 1860 goto fail2; 1861 } 1862 1863 remaining_original_length = partn_size; 1864 remaining_modified_length = partn_size; 1865 segment_data = partn_data; 1866 1867 /* Lock the partition */ 1868 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 1869 goto fail3; 1870 1871 /* Iterate over each (potential) segment to update it. */ 1872 do { 1873 boolean_t write = all_segments || current_offset == 0; 1874 1875 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, 1876 &segment_data, ¤t_offset, &remaining_original_length, 1877 &remaining_modified_length, write); 1878 if (rc != 0) { 1879 if (current_offset == 0) { 1880 /* 1881 * If no data has been read then the first 1882 * segment is invalid, which is an error. 1883 */ 1884 goto fail4; 1885 } 1886 break; 1887 } 1888 } while (current_offset < partn_size); 1889 1890 total_length = segment_data - partn_data; 1891 1892 /* 1893 * We've run out of space. This should actually be dealt with by 1894 * ef10_nvram_buf_write_tlv returning ENOSPC. 1895 */ 1896 if (total_length > partn_size) { 1897 rc = ENOSPC; 1898 goto fail5; 1899 } 1900 1901 /* Erase the whole partition in NVRAM */ 1902 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) 1903 goto fail6; 1904 1905 /* Write new partition contents from the buffer to NVRAM */ 1906 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, 1907 total_length)) != 0) 1908 goto fail7; 1909 1910 /* Unlock the partition */ 1911 (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1912 1913 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1914 1915 return (0); 1916 1917 fail7: 1918 EFSYS_PROBE(fail7); 1919 fail6: 1920 EFSYS_PROBE(fail6); 1921 fail5: 1922 EFSYS_PROBE(fail5); 1923 fail4: 1924 EFSYS_PROBE(fail4); 1925 1926 (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1927 fail3: 1928 EFSYS_PROBE(fail3); 1929 1930 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1931 fail2: 1932 EFSYS_PROBE(fail2); 1933 fail1: 1934 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1935 1936 return (rc); 1937 } 1938 1939 /* 1940 * Get the size of a NVRAM partition. This is the total size allocated in nvram, 1941 * not the data used by the segments in the partition. 1942 */ 1943 __checkReturn efx_rc_t 1944 ef10_nvram_partn_size( 1945 __in efx_nic_t *enp, 1946 __in uint32_t partn, 1947 __out size_t *sizep) 1948 { 1949 efx_rc_t rc; 1950 efx_nvram_info_t eni = { 0 }; 1951 1952 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0) 1953 goto fail1; 1954 1955 *sizep = eni.eni_partn_size; 1956 1957 return (0); 1958 1959 fail1: 1960 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1961 1962 return (rc); 1963 } 1964 1965 __checkReturn efx_rc_t 1966 ef10_nvram_partn_info( 1967 __in efx_nic_t *enp, 1968 __in uint32_t partn, 1969 __out efx_nvram_info_t *enip) 1970 { 1971 efx_rc_t rc; 1972 1973 if ((rc = efx_mcdi_nvram_info(enp, partn, enip)) != 0) 1974 goto fail1; 1975 1976 if (enip->eni_write_size == 0) 1977 enip->eni_write_size = EF10_NVRAM_CHUNK; 1978 1979 return (0); 1980 1981 fail1: 1982 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1983 1984 return (rc); 1985 } 1986 1987 1988 __checkReturn efx_rc_t 1989 ef10_nvram_partn_lock( 1990 __in efx_nic_t *enp, 1991 __in uint32_t partn) 1992 { 1993 efx_rc_t rc; 1994 1995 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) 1996 goto fail1; 1997 1998 return (0); 1999 2000 fail1: 2001 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2002 2003 return (rc); 2004 } 2005 2006 __checkReturn efx_rc_t 2007 ef10_nvram_partn_read_mode( 2008 __in efx_nic_t *enp, 2009 __in uint32_t partn, 2010 __in unsigned int offset, 2011 __out_bcount(size) caddr_t data, 2012 __in size_t size, 2013 __in uint32_t mode) 2014 { 2015 size_t chunk; 2016 efx_rc_t rc; 2017 2018 while (size > 0) { 2019 chunk = MIN(size, EF10_NVRAM_CHUNK); 2020 2021 if ((rc = efx_mcdi_nvram_read(enp, partn, offset, 2022 data, chunk, mode)) != 0) { 2023 goto fail1; 2024 } 2025 2026 size -= chunk; 2027 data += chunk; 2028 offset += chunk; 2029 } 2030 2031 return (0); 2032 2033 fail1: 2034 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2035 2036 return (rc); 2037 } 2038 2039 __checkReturn efx_rc_t 2040 ef10_nvram_partn_read( 2041 __in efx_nic_t *enp, 2042 __in uint32_t partn, 2043 __in unsigned int offset, 2044 __out_bcount(size) caddr_t data, 2045 __in size_t size) 2046 { 2047 /* 2048 * An A/B partition has two data stores (current and backup). 2049 * Read requests which come in through the EFX API expect to read the 2050 * current, active store of an A/B partition. For non A/B partitions, 2051 * there is only a single store and so the mode param is ignored. 2052 */ 2053 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 2054 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); 2055 } 2056 2057 __checkReturn efx_rc_t 2058 ef10_nvram_partn_read_backup( 2059 __in efx_nic_t *enp, 2060 __in uint32_t partn, 2061 __in unsigned int offset, 2062 __out_bcount(size) caddr_t data, 2063 __in size_t size) 2064 { 2065 /* 2066 * An A/B partition has two data stores (current and backup). 2067 * Read the backup store of an A/B partition (i.e. the store currently 2068 * being written to if the partition is locked). 2069 * 2070 * This is needed when comparing the existing partition content to avoid 2071 * unnecessary writes, or to read back what has been written to check 2072 * that the writes have succeeded. 2073 */ 2074 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 2075 MC_CMD_NVRAM_READ_IN_V2_TARGET_BACKUP); 2076 } 2077 2078 __checkReturn efx_rc_t 2079 ef10_nvram_partn_erase( 2080 __in efx_nic_t *enp, 2081 __in uint32_t partn, 2082 __in unsigned int offset, 2083 __in size_t size) 2084 { 2085 efx_rc_t rc; 2086 efx_nvram_info_t eni = { 0 }; 2087 uint32_t erase_size; 2088 2089 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0) 2090 goto fail1; 2091 2092 erase_size = eni.eni_erase_size; 2093 2094 if (erase_size == 0) { 2095 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) 2096 goto fail2; 2097 } else { 2098 if (size % erase_size != 0) { 2099 rc = EINVAL; 2100 goto fail3; 2101 } 2102 while (size > 0) { 2103 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, 2104 erase_size)) != 0) 2105 goto fail4; 2106 offset += erase_size; 2107 size -= erase_size; 2108 } 2109 } 2110 2111 return (0); 2112 2113 fail4: 2114 EFSYS_PROBE(fail4); 2115 fail3: 2116 EFSYS_PROBE(fail3); 2117 fail2: 2118 EFSYS_PROBE(fail2); 2119 fail1: 2120 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2121 2122 return (rc); 2123 } 2124 2125 __checkReturn efx_rc_t 2126 ef10_nvram_partn_write( 2127 __in efx_nic_t *enp, 2128 __in uint32_t partn, 2129 __in unsigned int offset, 2130 __in_bcount(size) caddr_t data, 2131 __in size_t size) 2132 { 2133 size_t chunk; 2134 efx_nvram_info_t eni = { 0 }; 2135 uint32_t write_size; 2136 efx_rc_t rc; 2137 2138 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0) 2139 goto fail1; 2140 2141 write_size = eni.eni_write_size; 2142 2143 if (write_size != 0) { 2144 /* 2145 * Check that the size is a multiple of the write chunk size if 2146 * the write chunk size is available. 2147 */ 2148 if (size % write_size != 0) { 2149 rc = EINVAL; 2150 goto fail2; 2151 } 2152 } else { 2153 write_size = EF10_NVRAM_CHUNK; 2154 } 2155 2156 while (size > 0) { 2157 chunk = MIN(size, write_size); 2158 2159 if ((rc = efx_mcdi_nvram_write(enp, partn, offset, 2160 data, chunk)) != 0) { 2161 goto fail3; 2162 } 2163 2164 size -= chunk; 2165 data += chunk; 2166 offset += chunk; 2167 } 2168 2169 return (0); 2170 2171 fail3: 2172 EFSYS_PROBE(fail3); 2173 fail2: 2174 EFSYS_PROBE(fail2); 2175 fail1: 2176 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2177 2178 return (rc); 2179 } 2180 2181 #define EF10_NVRAM_INITIAL_POLL_DELAY_US 10000 2182 #define EF10_NVRAM_MAX_POLL_DELAY_US 1000000 2183 #define EF10_NVRAM_POLL_RETRIES 100 2184 2185 __checkReturn efx_rc_t 2186 ef10_nvram_partn_unlock( 2187 __in efx_nic_t *enp, 2188 __in uint32_t partn, 2189 __out_opt uint32_t *verify_resultp) 2190 { 2191 boolean_t reboot = B_FALSE; 2192 uint32_t poll_delay_us = EF10_NVRAM_INITIAL_POLL_DELAY_US; 2193 uint32_t poll_retry = 0; 2194 uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 2195 efx_rc_t rc; 2196 2197 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, 2198 EFX_NVRAM_UPDATE_FLAGS_BACKGROUND, &verify_result); 2199 2200 /* 2201 * NVRAM updates can take a long time (e.g. up to 1 minute for bundle 2202 * images). Polling for NVRAM update completion ensures that other MCDI 2203 * commands can be issued before the background NVRAM update completes. 2204 * 2205 * Without polling, other MCDI commands can only be issued before the 2206 * NVRAM update completes if the MCDI transport and the firmware 2207 * support the Asynchronous MCDI protocol extensions in SF-116575-PS. 2208 * 2209 * The initial call either completes the update synchronously, or 2210 * returns RC_PENDING to indicate processing is continuing. In the 2211 * latter case, we poll for at least 1 minute, at increasing intervals 2212 * (10ms, 100ms, 1s). 2213 */ 2214 while (verify_result == MC_CMD_NVRAM_VERIFY_RC_PENDING) { 2215 2216 if (poll_retry > EF10_NVRAM_POLL_RETRIES) { 2217 rc = ETIMEDOUT; 2218 goto fail1; 2219 } 2220 poll_retry++; 2221 2222 EFSYS_SLEEP(poll_delay_us); 2223 if (poll_delay_us < EF10_NVRAM_MAX_POLL_DELAY_US) 2224 poll_delay_us *= 10; 2225 2226 /* Poll for completion of background NVRAM update. */ 2227 verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 2228 2229 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, 2230 EFX_NVRAM_UPDATE_FLAGS_POLL, &verify_result); 2231 if (rc != 0) { 2232 /* Poll failed, so assume NVRAM update failed. */ 2233 goto fail2; 2234 } 2235 } 2236 2237 if (verify_resultp != NULL) 2238 *verify_resultp = verify_result; 2239 2240 return (0); 2241 2242 fail2: 2243 EFSYS_PROBE(fail2); 2244 fail1: 2245 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2246 2247 return (rc); 2248 } 2249 2250 __checkReturn efx_rc_t 2251 ef10_nvram_partn_set_version( 2252 __in efx_nic_t *enp, 2253 __in uint32_t partn, 2254 __in_ecount(4) uint16_t version[4]) 2255 { 2256 struct tlv_partition_version partn_version; 2257 size_t size; 2258 efx_rc_t rc; 2259 2260 /* Add or modify partition version TLV item */ 2261 partn_version.version_w = __CPU_TO_LE_16(version[0]); 2262 partn_version.version_x = __CPU_TO_LE_16(version[1]); 2263 partn_version.version_y = __CPU_TO_LE_16(version[2]); 2264 partn_version.version_z = __CPU_TO_LE_16(version[3]); 2265 2266 size = sizeof (partn_version) - (2 * sizeof (uint32_t)); 2267 2268 /* Write the version number to all segments in the partition */ 2269 if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 2270 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2271 TLV_TAG_PARTITION_VERSION(partn), 2272 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) 2273 goto fail1; 2274 2275 return (0); 2276 2277 fail1: 2278 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2279 2280 return (rc); 2281 } 2282 2283 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 2284 2285 #if EFSYS_OPT_NVRAM 2286 2287 typedef struct ef10_parttbl_entry_s { 2288 unsigned int partn; 2289 unsigned int port_mask; 2290 efx_nvram_type_t nvtype; 2291 } ef10_parttbl_entry_t; 2292 2293 /* Port mask values */ 2294 #define PORT_1 (1u << 1) 2295 #define PORT_2 (1u << 2) 2296 #define PORT_3 (1u << 3) 2297 #define PORT_4 (1u << 4) 2298 #define PORT_ALL (0xffffffffu) 2299 2300 #define PARTN_MAP_ENTRY(partn, port_mask, nvtype) \ 2301 { (NVRAM_PARTITION_TYPE_##partn), (PORT_##port_mask), (EFX_NVRAM_##nvtype) } 2302 2303 /* Translate EFX NVRAM types to firmware partition types */ 2304 static ef10_parttbl_entry_t hunt_parttbl[] = { 2305 /* partn ports nvtype */ 2306 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2307 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2308 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2309 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT0, 1, BOOTROM_CFG), 2310 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT1, 2, BOOTROM_CFG), 2311 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT2, 3, BOOTROM_CFG), 2312 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT3, 4, BOOTROM_CFG), 2313 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2314 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2315 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2316 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2317 }; 2318 2319 static ef10_parttbl_entry_t medford_parttbl[] = { 2320 /* partn ports nvtype */ 2321 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2322 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2323 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2324 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG), 2325 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2326 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2327 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2328 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2329 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM), 2330 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE), 2331 }; 2332 2333 static ef10_parttbl_entry_t medford2_parttbl[] = { 2334 /* partn ports nvtype */ 2335 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2336 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2337 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2338 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG), 2339 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2340 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2341 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2342 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2343 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM), 2344 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE), 2345 PARTN_MAP_ENTRY(DYNCONFIG_DEFAULTS, ALL, DYNCONFIG_DEFAULTS), 2346 PARTN_MAP_ENTRY(ROMCONFIG_DEFAULTS, ALL, ROMCONFIG_DEFAULTS), 2347 PARTN_MAP_ENTRY(BUNDLE, ALL, BUNDLE), 2348 PARTN_MAP_ENTRY(BUNDLE_METADATA, ALL, BUNDLE_METADATA), 2349 }; 2350 2351 static __checkReturn efx_rc_t 2352 ef10_parttbl_get( 2353 __in efx_nic_t *enp, 2354 __out ef10_parttbl_entry_t **parttblp, 2355 __out size_t *parttbl_rowsp) 2356 { 2357 switch (enp->en_family) { 2358 case EFX_FAMILY_HUNTINGTON: 2359 *parttblp = hunt_parttbl; 2360 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); 2361 break; 2362 2363 case EFX_FAMILY_MEDFORD: 2364 *parttblp = medford_parttbl; 2365 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); 2366 break; 2367 2368 case EFX_FAMILY_MEDFORD2: 2369 *parttblp = medford2_parttbl; 2370 *parttbl_rowsp = EFX_ARRAY_SIZE(medford2_parttbl); 2371 break; 2372 2373 default: 2374 EFSYS_ASSERT(B_FALSE); 2375 return (EINVAL); 2376 } 2377 return (0); 2378 } 2379 2380 __checkReturn efx_rc_t 2381 ef10_nvram_type_to_partn( 2382 __in efx_nic_t *enp, 2383 __in efx_nvram_type_t type, 2384 __out uint32_t *partnp) 2385 { 2386 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2387 ef10_parttbl_entry_t *parttbl = NULL; 2388 size_t parttbl_rows = 0; 2389 unsigned int i; 2390 2391 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 2392 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 2393 EFSYS_ASSERT(partnp != NULL); 2394 2395 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2396 for (i = 0; i < parttbl_rows; i++) { 2397 ef10_parttbl_entry_t *entry = &parttbl[i]; 2398 2399 if ((entry->nvtype == type) && 2400 (entry->port_mask & (1u << emip->emi_port))) { 2401 *partnp = entry->partn; 2402 return (0); 2403 } 2404 } 2405 } 2406 2407 return (ENOTSUP); 2408 } 2409 2410 #if EFSYS_OPT_DIAG 2411 2412 static __checkReturn efx_rc_t 2413 ef10_nvram_partn_to_type( 2414 __in efx_nic_t *enp, 2415 __in uint32_t partn, 2416 __out efx_nvram_type_t *typep) 2417 { 2418 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2419 ef10_parttbl_entry_t *parttbl = NULL; 2420 size_t parttbl_rows = 0; 2421 unsigned int i; 2422 2423 EFSYS_ASSERT(typep != NULL); 2424 2425 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2426 for (i = 0; i < parttbl_rows; i++) { 2427 ef10_parttbl_entry_t *entry = &parttbl[i]; 2428 2429 if ((entry->partn == partn) && 2430 (entry->port_mask & (1u << emip->emi_port))) { 2431 *typep = entry->nvtype; 2432 return (0); 2433 } 2434 } 2435 } 2436 2437 return (ENOTSUP); 2438 } 2439 2440 __checkReturn efx_rc_t 2441 ef10_nvram_test( 2442 __in efx_nic_t *enp) 2443 { 2444 efx_nvram_type_t type; 2445 unsigned int npartns = 0; 2446 uint32_t *partns = NULL; 2447 size_t size; 2448 unsigned int i; 2449 efx_rc_t rc; 2450 2451 /* Read available partitions from NVRAM partition map */ 2452 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); 2453 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); 2454 if (partns == NULL) { 2455 rc = ENOMEM; 2456 goto fail1; 2457 } 2458 2459 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, 2460 &npartns)) != 0) { 2461 goto fail2; 2462 } 2463 2464 for (i = 0; i < npartns; i++) { 2465 /* Check if the partition is supported for this port */ 2466 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) 2467 continue; 2468 2469 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) 2470 goto fail3; 2471 } 2472 2473 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2474 return (0); 2475 2476 fail3: 2477 EFSYS_PROBE(fail3); 2478 fail2: 2479 EFSYS_PROBE(fail2); 2480 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2481 fail1: 2482 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2483 return (rc); 2484 } 2485 2486 #endif /* EFSYS_OPT_DIAG */ 2487 2488 __checkReturn efx_rc_t 2489 ef10_nvram_partn_get_version( 2490 __in efx_nic_t *enp, 2491 __in uint32_t partn, 2492 __out uint32_t *subtypep, 2493 __out_ecount(4) uint16_t version[4]) 2494 { 2495 efx_rc_t rc; 2496 2497 /* FIXME: get highest partn version from all ports */ 2498 /* FIXME: return partn description if available */ 2499 2500 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, 2501 version, NULL, 0)) != 0) 2502 goto fail1; 2503 2504 return (0); 2505 2506 fail1: 2507 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2508 2509 return (rc); 2510 } 2511 2512 __checkReturn efx_rc_t 2513 ef10_nvram_partn_rw_start( 2514 __in efx_nic_t *enp, 2515 __in uint32_t partn, 2516 __out size_t *chunk_sizep) 2517 { 2518 efx_nvram_info_t eni = { 0 }; 2519 efx_rc_t rc; 2520 2521 if ((rc = ef10_nvram_partn_info(enp, partn, &eni)) != 0) 2522 goto fail1; 2523 2524 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 2525 goto fail2; 2526 2527 if (chunk_sizep != NULL) 2528 *chunk_sizep = eni.eni_write_size; 2529 2530 return (0); 2531 2532 fail2: 2533 EFSYS_PROBE(fail2); 2534 fail1: 2535 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2536 2537 return (rc); 2538 } 2539 2540 __checkReturn efx_rc_t 2541 ef10_nvram_partn_rw_finish( 2542 __in efx_nic_t *enp, 2543 __in uint32_t partn, 2544 __out_opt uint32_t *verify_resultp) 2545 { 2546 efx_rc_t rc; 2547 2548 if ((rc = ef10_nvram_partn_unlock(enp, partn, verify_resultp)) != 0) 2549 goto fail1; 2550 2551 return (0); 2552 2553 fail1: 2554 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2555 2556 return (rc); 2557 } 2558 2559 #endif /* EFSYS_OPT_NVRAM */ 2560 2561 #endif /* EFX_OPTS_EF10() */ 2562