1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2020 Xilinx, Inc. 4 * Copyright(c) 2009-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #if EFSYS_OPT_NVRAM 11 12 #if EFSYS_OPT_SIENA 13 14 static const efx_nvram_ops_t __efx_nvram_siena_ops = { 15 #if EFSYS_OPT_DIAG 16 siena_nvram_test, /* envo_test */ 17 #endif /* EFSYS_OPT_DIAG */ 18 siena_nvram_type_to_partn, /* envo_type_to_partn */ 19 siena_nvram_partn_info, /* envo_partn_info */ 20 siena_nvram_partn_rw_start, /* envo_partn_rw_start */ 21 siena_nvram_partn_read, /* envo_partn_read */ 22 siena_nvram_partn_read, /* envo_partn_read_backup */ 23 siena_nvram_partn_erase, /* envo_partn_erase */ 24 siena_nvram_partn_write, /* envo_partn_write */ 25 siena_nvram_partn_rw_finish, /* envo_partn_rw_finish */ 26 siena_nvram_partn_get_version, /* envo_partn_get_version */ 27 siena_nvram_partn_set_version, /* envo_partn_set_version */ 28 NULL, /* envo_partn_validate */ 29 }; 30 31 #endif /* EFSYS_OPT_SIENA */ 32 33 #if EFX_OPTS_EF10() 34 35 static const efx_nvram_ops_t __efx_nvram_ef10_ops = { 36 #if EFSYS_OPT_DIAG 37 ef10_nvram_test, /* envo_test */ 38 #endif /* EFSYS_OPT_DIAG */ 39 ef10_nvram_type_to_partn, /* envo_type_to_partn */ 40 ef10_nvram_partn_info, /* envo_partn_info */ 41 ef10_nvram_partn_rw_start, /* envo_partn_rw_start */ 42 ef10_nvram_partn_read, /* envo_partn_read */ 43 ef10_nvram_partn_read_backup, /* envo_partn_read_backup */ 44 ef10_nvram_partn_erase, /* envo_partn_erase */ 45 ef10_nvram_partn_write, /* envo_partn_write */ 46 ef10_nvram_partn_rw_finish, /* envo_partn_rw_finish */ 47 ef10_nvram_partn_get_version, /* envo_partn_get_version */ 48 ef10_nvram_partn_set_version, /* envo_partn_set_version */ 49 ef10_nvram_buffer_validate, /* envo_buffer_validate */ 50 }; 51 52 #endif /* EFX_OPTS_EF10() */ 53 54 __checkReturn efx_rc_t 55 efx_nvram_init( 56 __in efx_nic_t *enp) 57 { 58 const efx_nvram_ops_t *envop; 59 efx_rc_t rc; 60 61 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 62 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 63 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM)); 64 65 switch (enp->en_family) { 66 #if EFSYS_OPT_SIENA 67 case EFX_FAMILY_SIENA: 68 envop = &__efx_nvram_siena_ops; 69 break; 70 #endif /* EFSYS_OPT_SIENA */ 71 72 #if EFSYS_OPT_HUNTINGTON 73 case EFX_FAMILY_HUNTINGTON: 74 envop = &__efx_nvram_ef10_ops; 75 break; 76 #endif /* EFSYS_OPT_HUNTINGTON */ 77 78 #if EFSYS_OPT_MEDFORD 79 case EFX_FAMILY_MEDFORD: 80 envop = &__efx_nvram_ef10_ops; 81 break; 82 #endif /* EFSYS_OPT_MEDFORD */ 83 84 #if EFSYS_OPT_MEDFORD2 85 case EFX_FAMILY_MEDFORD2: 86 envop = &__efx_nvram_ef10_ops; 87 break; 88 #endif /* EFSYS_OPT_MEDFORD2 */ 89 90 default: 91 EFSYS_ASSERT(0); 92 rc = ENOTSUP; 93 goto fail1; 94 } 95 96 enp->en_envop = envop; 97 enp->en_mod_flags |= EFX_MOD_NVRAM; 98 99 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 100 101 return (0); 102 103 fail1: 104 EFSYS_PROBE1(fail1, efx_rc_t, rc); 105 106 return (rc); 107 } 108 109 #if EFSYS_OPT_DIAG 110 111 __checkReturn efx_rc_t 112 efx_nvram_test( 113 __in efx_nic_t *enp) 114 { 115 const efx_nvram_ops_t *envop = enp->en_envop; 116 efx_rc_t rc; 117 118 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 119 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 120 121 if ((rc = envop->envo_test(enp)) != 0) 122 goto fail1; 123 124 return (0); 125 126 fail1: 127 EFSYS_PROBE1(fail1, efx_rc_t, rc); 128 129 return (rc); 130 } 131 132 #endif /* EFSYS_OPT_DIAG */ 133 134 __checkReturn efx_rc_t 135 efx_nvram_size( 136 __in efx_nic_t *enp, 137 __in efx_nvram_type_t type, 138 __out size_t *sizep) 139 { 140 const efx_nvram_ops_t *envop = enp->en_envop; 141 efx_nvram_info_t eni = { 0 }; 142 uint32_t partn; 143 efx_rc_t rc; 144 145 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 146 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 147 148 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 149 goto fail1; 150 151 if ((rc = envop->envo_partn_info(enp, partn, &eni)) != 0) 152 goto fail2; 153 154 *sizep = eni.eni_partn_size; 155 156 return (0); 157 158 fail2: 159 EFSYS_PROBE(fail2); 160 fail1: 161 EFSYS_PROBE1(fail1, efx_rc_t, rc); 162 *sizep = 0; 163 164 return (rc); 165 } 166 167 extern __checkReturn efx_rc_t 168 efx_nvram_info( 169 __in efx_nic_t *enp, 170 __in efx_nvram_type_t type, 171 __out efx_nvram_info_t *enip) 172 { 173 const efx_nvram_ops_t *envop = enp->en_envop; 174 uint32_t partn; 175 efx_rc_t rc; 176 177 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 178 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 179 180 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 181 goto fail1; 182 183 if ((rc = envop->envo_partn_info(enp, partn, enip)) != 0) 184 goto fail2; 185 186 return (0); 187 188 fail2: 189 EFSYS_PROBE(fail2); 190 fail1: 191 EFSYS_PROBE1(fail1, efx_rc_t, rc); 192 193 return (rc); 194 } 195 196 197 __checkReturn efx_rc_t 198 efx_nvram_get_version( 199 __in efx_nic_t *enp, 200 __in efx_nvram_type_t type, 201 __out uint32_t *subtypep, 202 __out_ecount(4) uint16_t version[4]) 203 { 204 const efx_nvram_ops_t *envop = enp->en_envop; 205 uint32_t partn; 206 efx_rc_t rc; 207 208 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 209 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 210 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 211 212 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 213 goto fail1; 214 215 if ((rc = envop->envo_partn_get_version(enp, partn, 216 subtypep, version)) != 0) 217 goto fail2; 218 219 return (0); 220 221 fail2: 222 EFSYS_PROBE(fail2); 223 fail1: 224 EFSYS_PROBE1(fail1, efx_rc_t, rc); 225 226 return (rc); 227 } 228 229 __checkReturn efx_rc_t 230 efx_nvram_rw_start( 231 __in efx_nic_t *enp, 232 __in efx_nvram_type_t type, 233 __out_opt size_t *chunk_sizep) 234 { 235 const efx_nvram_ops_t *envop = enp->en_envop; 236 uint32_t partn; 237 efx_rc_t rc; 238 239 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 240 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 241 242 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 243 goto fail1; 244 245 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 246 247 if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0) 248 goto fail2; 249 250 enp->en_nvram_partn_locked = partn; 251 252 return (0); 253 254 fail2: 255 EFSYS_PROBE(fail2); 256 fail1: 257 EFSYS_PROBE1(fail1, efx_rc_t, rc); 258 259 return (rc); 260 } 261 262 __checkReturn efx_rc_t 263 efx_nvram_read_chunk( 264 __in efx_nic_t *enp, 265 __in efx_nvram_type_t type, 266 __in unsigned int offset, 267 __out_bcount(size) caddr_t data, 268 __in size_t size) 269 { 270 const efx_nvram_ops_t *envop = enp->en_envop; 271 uint32_t partn; 272 efx_rc_t rc; 273 274 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 275 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 276 277 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 278 goto fail1; 279 280 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 281 282 if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0) 283 goto fail2; 284 285 return (0); 286 287 fail2: 288 EFSYS_PROBE(fail2); 289 fail1: 290 EFSYS_PROBE1(fail1, efx_rc_t, rc); 291 292 return (rc); 293 } 294 295 /* 296 * Read from the backup (writeable) store of an A/B partition. 297 * For non A/B partitions, there is only a single store, and so this 298 * function has the same behaviour as efx_nvram_read_chunk(). 299 */ 300 __checkReturn efx_rc_t 301 efx_nvram_read_backup( 302 __in efx_nic_t *enp, 303 __in efx_nvram_type_t type, 304 __in unsigned int offset, 305 __out_bcount(size) caddr_t data, 306 __in size_t size) 307 { 308 const efx_nvram_ops_t *envop = enp->en_envop; 309 uint32_t partn; 310 efx_rc_t rc; 311 312 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 313 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 314 315 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 316 goto fail1; 317 318 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 319 320 if ((rc = envop->envo_partn_read_backup(enp, partn, offset, 321 data, size)) != 0) 322 goto fail2; 323 324 return (0); 325 326 fail2: 327 EFSYS_PROBE(fail2); 328 fail1: 329 EFSYS_PROBE1(fail1, efx_rc_t, rc); 330 331 return (rc); 332 } 333 334 __checkReturn efx_rc_t 335 efx_nvram_erase( 336 __in efx_nic_t *enp, 337 __in efx_nvram_type_t type) 338 { 339 const efx_nvram_ops_t *envop = enp->en_envop; 340 unsigned int offset = 0; 341 efx_nvram_info_t eni = { 0 }; 342 uint32_t partn; 343 efx_rc_t rc; 344 345 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 346 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 347 348 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 349 goto fail1; 350 351 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 352 353 if ((rc = envop->envo_partn_info(enp, partn, &eni)) != 0) 354 goto fail2; 355 356 if ((rc = envop->envo_partn_erase(enp, partn, offset, 357 eni.eni_partn_size)) != 0) 358 goto fail3; 359 360 return (0); 361 362 fail3: 363 EFSYS_PROBE(fail3); 364 fail2: 365 EFSYS_PROBE(fail2); 366 fail1: 367 EFSYS_PROBE1(fail1, efx_rc_t, rc); 368 369 return (rc); 370 } 371 372 __checkReturn efx_rc_t 373 efx_nvram_write_chunk( 374 __in efx_nic_t *enp, 375 __in efx_nvram_type_t type, 376 __in unsigned int offset, 377 __in_bcount(size) caddr_t data, 378 __in size_t size) 379 { 380 const efx_nvram_ops_t *envop = enp->en_envop; 381 uint32_t partn; 382 efx_rc_t rc; 383 384 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 385 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 386 387 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 388 goto fail1; 389 390 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 391 392 if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0) 393 goto fail2; 394 395 return (0); 396 397 fail2: 398 EFSYS_PROBE(fail2); 399 fail1: 400 EFSYS_PROBE1(fail1, efx_rc_t, rc); 401 402 return (rc); 403 } 404 405 __checkReturn efx_rc_t 406 efx_nvram_rw_finish( 407 __in efx_nic_t *enp, 408 __in efx_nvram_type_t type, 409 __out_opt uint32_t *verify_resultp) 410 { 411 const efx_nvram_ops_t *envop = enp->en_envop; 412 uint32_t partn; 413 uint32_t verify_result = 0; 414 efx_rc_t rc; 415 416 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 417 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 418 419 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 420 goto fail1; 421 422 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 423 424 if ((rc = envop->envo_partn_rw_finish(enp, partn, &verify_result)) != 0) 425 goto fail2; 426 427 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 428 429 if (verify_resultp != NULL) 430 *verify_resultp = verify_result; 431 432 return (0); 433 434 fail2: 435 EFSYS_PROBE(fail2); 436 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 437 438 fail1: 439 EFSYS_PROBE1(fail1, efx_rc_t, rc); 440 441 /* Always report verification result */ 442 if (verify_resultp != NULL) 443 *verify_resultp = verify_result; 444 445 return (rc); 446 } 447 448 __checkReturn efx_rc_t 449 efx_nvram_set_version( 450 __in efx_nic_t *enp, 451 __in efx_nvram_type_t type, 452 __in_ecount(4) uint16_t version[4]) 453 { 454 const efx_nvram_ops_t *envop = enp->en_envop; 455 uint32_t partn; 456 efx_rc_t rc; 457 458 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 459 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 460 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 461 462 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 463 goto fail1; 464 465 /* 466 * The Siena implementation of envo_set_version() will attempt to 467 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG partition. 468 * Therefore, you can't have already acquired the NVRAM_UPDATE lock. 469 */ 470 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 471 472 if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0) 473 goto fail2; 474 475 return (0); 476 477 fail2: 478 EFSYS_PROBE(fail2); 479 fail1: 480 EFSYS_PROBE1(fail1, efx_rc_t, rc); 481 482 return (rc); 483 } 484 485 /* Validate buffer contents (before writing to flash) */ 486 __checkReturn efx_rc_t 487 efx_nvram_validate( 488 __in efx_nic_t *enp, 489 __in efx_nvram_type_t type, 490 __in_bcount(partn_size) caddr_t partn_data, 491 __in size_t partn_size) 492 { 493 const efx_nvram_ops_t *envop = enp->en_envop; 494 uint32_t partn; 495 efx_rc_t rc; 496 497 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 498 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 499 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 500 501 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 502 goto fail1; 503 504 if (envop->envo_buffer_validate != NULL) { 505 if ((rc = envop->envo_buffer_validate(partn, 506 partn_data, partn_size)) != 0) 507 goto fail2; 508 } 509 510 return (0); 511 512 fail2: 513 EFSYS_PROBE(fail2); 514 fail1: 515 EFSYS_PROBE1(fail1, efx_rc_t, rc); 516 517 return (rc); 518 } 519 520 521 void 522 efx_nvram_fini( 523 __in efx_nic_t *enp) 524 { 525 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 526 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 527 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 528 529 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 530 531 enp->en_envop = NULL; 532 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 533 } 534 535 #endif /* EFSYS_OPT_NVRAM */ 536 537 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 538 539 /* 540 * Internal MCDI request handling 541 */ 542 543 __checkReturn efx_rc_t 544 efx_mcdi_nvram_partitions( 545 __in efx_nic_t *enp, 546 __out_bcount(size) caddr_t data, 547 __in size_t size, 548 __out unsigned int *npartnp) 549 { 550 efx_mcdi_req_t req; 551 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN, 552 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX); 553 unsigned int npartn; 554 efx_rc_t rc; 555 556 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 557 req.emr_in_buf = payload; 558 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 559 req.emr_out_buf = payload; 560 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 561 562 efx_mcdi_execute(enp, &req); 563 564 if (req.emr_rc != 0) { 565 rc = req.emr_rc; 566 goto fail1; 567 } 568 569 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 570 rc = EMSGSIZE; 571 goto fail2; 572 } 573 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 574 575 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 576 rc = ENOENT; 577 goto fail3; 578 } 579 580 if (size < npartn * sizeof (uint32_t)) { 581 rc = ENOSPC; 582 goto fail3; 583 } 584 585 *npartnp = npartn; 586 587 memcpy(data, 588 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 589 (npartn * sizeof (uint32_t))); 590 591 return (0); 592 593 fail3: 594 EFSYS_PROBE(fail3); 595 fail2: 596 EFSYS_PROBE(fail2); 597 fail1: 598 EFSYS_PROBE1(fail1, efx_rc_t, rc); 599 600 return (rc); 601 } 602 603 __checkReturn efx_rc_t 604 efx_mcdi_nvram_metadata( 605 __in efx_nic_t *enp, 606 __in uint32_t partn, 607 __out uint32_t *subtypep, 608 __out_ecount(4) uint16_t version[4], 609 __out_bcount_opt(size) char *descp, 610 __in size_t size) 611 { 612 efx_mcdi_req_t req; 613 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN, 614 MC_CMD_NVRAM_METADATA_OUT_LENMAX); 615 efx_rc_t rc; 616 617 req.emr_cmd = MC_CMD_NVRAM_METADATA; 618 req.emr_in_buf = payload; 619 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 620 req.emr_out_buf = payload; 621 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 622 623 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 624 625 efx_mcdi_execute_quiet(enp, &req); 626 627 if (req.emr_rc != 0) { 628 rc = req.emr_rc; 629 goto fail1; 630 } 631 632 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 633 rc = EMSGSIZE; 634 goto fail2; 635 } 636 637 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 638 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 639 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 640 } else { 641 *subtypep = 0; 642 } 643 644 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 645 NVRAM_METADATA_OUT_VERSION_VALID)) { 646 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 647 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 648 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 649 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 650 } else { 651 version[0] = version[1] = version[2] = version[3] = 0; 652 } 653 654 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 655 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 656 /* Return optional descrition string */ 657 if ((descp != NULL) && (size > 0)) { 658 size_t desclen; 659 660 descp[0] = '\0'; 661 desclen = (req.emr_out_length_used 662 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 663 664 EFSYS_ASSERT3U(desclen, <=, 665 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 666 667 if (size < desclen) { 668 rc = ENOSPC; 669 goto fail3; 670 } 671 672 memcpy(descp, MCDI_OUT2(req, char, 673 NVRAM_METADATA_OUT_DESCRIPTION), 674 desclen); 675 676 /* Ensure string is NUL terminated */ 677 descp[desclen] = '\0'; 678 } 679 } 680 681 return (0); 682 683 fail3: 684 EFSYS_PROBE(fail3); 685 fail2: 686 EFSYS_PROBE(fail2); 687 fail1: 688 EFSYS_PROBE1(fail1, efx_rc_t, rc); 689 690 return (rc); 691 } 692 693 __checkReturn efx_rc_t 694 efx_mcdi_nvram_info( 695 __in efx_nic_t *enp, 696 __in uint32_t partn, 697 __out efx_nvram_info_t *enip) 698 { 699 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN, 700 MC_CMD_NVRAM_INFO_V2_OUT_LEN); 701 efx_mcdi_req_t req; 702 efx_rc_t rc; 703 704 req.emr_cmd = MC_CMD_NVRAM_INFO; 705 req.emr_in_buf = payload; 706 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 707 req.emr_out_buf = payload; 708 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 709 710 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 711 712 efx_mcdi_execute_quiet(enp, &req); 713 714 if (req.emr_rc != 0) { 715 rc = req.emr_rc; 716 goto fail1; 717 } 718 719 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 720 rc = EMSGSIZE; 721 goto fail2; 722 } 723 724 enip->eni_partn_size = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 725 726 enip->eni_address = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 727 728 enip->eni_erase_size = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 729 730 enip->eni_write_size = 731 (req.emr_out_length_used < 732 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 733 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 734 735 enip->eni_flags = 0; 736 737 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_INFO_OUT_FLAGS, 738 NVRAM_INFO_OUT_PROTECTED)) 739 enip->eni_flags |= EFX_NVRAM_FLAG_READ_ONLY; 740 741 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_INFO_OUT_FLAGS, 742 NVRAM_INFO_OUT_READ_ONLY)) 743 enip->eni_flags |= EFX_NVRAM_FLAG_READ_ONLY; 744 745 return (0); 746 747 fail2: 748 EFSYS_PROBE(fail2); 749 fail1: 750 EFSYS_PROBE1(fail1, efx_rc_t, rc); 751 752 return (rc); 753 } 754 755 /* 756 * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified 757 * NVRAM updates. Older firmware will ignore the flags field in the request. 758 */ 759 __checkReturn efx_rc_t 760 efx_mcdi_nvram_update_start( 761 __in efx_nic_t *enp, 762 __in uint32_t partn) 763 { 764 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN, 765 MC_CMD_NVRAM_UPDATE_START_OUT_LEN); 766 efx_mcdi_req_t req; 767 efx_rc_t rc; 768 769 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 770 req.emr_in_buf = payload; 771 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN; 772 req.emr_out_buf = payload; 773 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 774 775 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn); 776 777 MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS, 778 NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); 779 780 efx_mcdi_execute(enp, &req); 781 782 if (req.emr_rc != 0) { 783 rc = req.emr_rc; 784 goto fail1; 785 } 786 787 return (0); 788 789 fail1: 790 EFSYS_PROBE1(fail1, efx_rc_t, rc); 791 792 return (rc); 793 } 794 795 __checkReturn efx_rc_t 796 efx_mcdi_nvram_read( 797 __in efx_nic_t *enp, 798 __in uint32_t partn, 799 __in uint32_t offset, 800 __out_bcount(size) caddr_t data, 801 __in size_t size, 802 __in uint32_t mode) 803 { 804 efx_mcdi_req_t req; 805 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN, 806 MC_CMD_NVRAM_READ_OUT_LENMAX); 807 efx_rc_t rc; 808 809 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 810 rc = EINVAL; 811 goto fail1; 812 } 813 814 req.emr_cmd = MC_CMD_NVRAM_READ; 815 req.emr_in_buf = payload; 816 req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN; 817 req.emr_out_buf = payload; 818 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 819 820 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn); 821 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset); 822 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size); 823 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode); 824 825 efx_mcdi_execute(enp, &req); 826 827 if (req.emr_rc != 0) { 828 rc = req.emr_rc; 829 goto fail1; 830 } 831 832 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 833 rc = EMSGSIZE; 834 goto fail2; 835 } 836 837 memcpy(data, 838 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 839 size); 840 841 return (0); 842 843 fail2: 844 EFSYS_PROBE(fail2); 845 fail1: 846 EFSYS_PROBE1(fail1, efx_rc_t, rc); 847 848 return (rc); 849 } 850 851 __checkReturn efx_rc_t 852 efx_mcdi_nvram_erase( 853 __in efx_nic_t *enp, 854 __in uint32_t partn, 855 __in uint32_t offset, 856 __in size_t size) 857 { 858 efx_mcdi_req_t req; 859 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN, 860 MC_CMD_NVRAM_ERASE_OUT_LEN); 861 efx_rc_t rc; 862 863 req.emr_cmd = MC_CMD_NVRAM_ERASE; 864 req.emr_in_buf = payload; 865 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 866 req.emr_out_buf = payload; 867 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 868 869 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 870 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 871 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 872 873 efx_mcdi_execute(enp, &req); 874 875 if (req.emr_rc != 0) { 876 rc = req.emr_rc; 877 goto fail1; 878 } 879 880 return (0); 881 882 fail1: 883 EFSYS_PROBE1(fail1, efx_rc_t, rc); 884 885 return (rc); 886 } 887 888 /* 889 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 890 * Sienna and EF10 based boards. However EF10 based boards support the use 891 * of this command with payloads up to the maximum MCDI V2 payload length. 892 */ 893 __checkReturn efx_rc_t 894 efx_mcdi_nvram_write( 895 __in efx_nic_t *enp, 896 __in uint32_t partn, 897 __in uint32_t offset, 898 __in_bcount(size) caddr_t data, 899 __in size_t size) 900 { 901 efx_mcdi_req_t req; 902 uint8_t *payload; 903 efx_rc_t rc; 904 size_t max_data_size; 905 size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length; 906 907 max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0); 908 EFSYS_ASSERT3U(payload_len, >, 0); 909 EFSYS_ASSERT3U(max_data_size, <, payload_len); 910 911 if (size > max_data_size) { 912 rc = EINVAL; 913 goto fail1; 914 } 915 916 EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload); 917 if (payload == NULL) { 918 rc = ENOMEM; 919 goto fail2; 920 } 921 922 (void) memset(payload, 0, payload_len); 923 req.emr_cmd = MC_CMD_NVRAM_WRITE; 924 req.emr_in_buf = payload; 925 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 926 req.emr_out_buf = payload; 927 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 928 929 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 930 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 931 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 932 933 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 934 data, size); 935 936 efx_mcdi_execute(enp, &req); 937 938 if (req.emr_rc != 0) { 939 rc = req.emr_rc; 940 goto fail3; 941 } 942 943 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 944 945 return (0); 946 947 fail3: 948 EFSYS_PROBE(fail3); 949 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 950 fail2: 951 EFSYS_PROBE(fail2); 952 fail1: 953 EFSYS_PROBE1(fail1, efx_rc_t, rc); 954 955 return (rc); 956 } 957 958 959 /* 960 * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified 961 * NVRAM updates. Older firmware will ignore the flags field in the request. 962 */ 963 __checkReturn efx_rc_t 964 efx_mcdi_nvram_update_finish( 965 __in efx_nic_t *enp, 966 __in uint32_t partn, 967 __in boolean_t reboot, 968 __in uint32_t flags, 969 __out_opt uint32_t *verify_resultp) 970 { 971 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 972 efx_mcdi_req_t req; 973 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN, 974 MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN); 975 uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 976 efx_rc_t rc = 0; 977 978 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 979 req.emr_in_buf = payload; 980 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN; 981 req.emr_out_buf = payload; 982 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN; 983 984 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn); 985 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot); 986 987 if (!encp->enc_nvram_update_poll_verify_result_supported) { 988 flags &= ~EFX_NVRAM_UPDATE_FLAGS_BACKGROUND; 989 flags &= ~EFX_NVRAM_UPDATE_FLAGS_POLL; 990 } 991 992 MCDI_IN_POPULATE_DWORD_3(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, 993 NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 994 1, 995 NVRAM_UPDATE_FINISH_V2_IN_FLAG_RUN_IN_BACKGROUND, 996 (flags & EFX_NVRAM_UPDATE_FLAGS_BACKGROUND) ? 1 : 0, 997 NVRAM_UPDATE_FINISH_V2_IN_FLAG_POLL_VERIFY_RESULT, 998 (flags & EFX_NVRAM_UPDATE_FLAGS_POLL) ? 1 : 0 999 ); 1000 1001 efx_mcdi_execute(enp, &req); 1002 1003 if (req.emr_rc != 0) { 1004 rc = req.emr_rc; 1005 goto fail1; 1006 } 1007 1008 if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { 1009 verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 1010 if (encp->enc_nvram_update_verify_result_supported) { 1011 /* Result of update verification is missing */ 1012 rc = EMSGSIZE; 1013 goto fail2; 1014 } 1015 } else { 1016 verify_result = 1017 MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); 1018 } 1019 1020 if (encp->enc_nvram_update_verify_result_supported) { 1021 if ((verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) && 1022 (verify_result != MC_CMD_NVRAM_VERIFY_RC_PENDING)) { 1023 /* Update verification failed */ 1024 rc = EINVAL; 1025 goto fail3; 1026 } 1027 } 1028 1029 if (verify_resultp != NULL) 1030 *verify_resultp = verify_result; 1031 1032 return (0); 1033 1034 fail3: 1035 EFSYS_PROBE(fail3); 1036 fail2: 1037 EFSYS_PROBE(fail2); 1038 fail1: 1039 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1040 1041 /* Always report verification result */ 1042 if (verify_resultp != NULL) 1043 *verify_resultp = verify_result; 1044 1045 return (rc); 1046 } 1047 1048 #if EFSYS_OPT_DIAG 1049 1050 __checkReturn efx_rc_t 1051 efx_mcdi_nvram_test( 1052 __in efx_nic_t *enp, 1053 __in uint32_t partn) 1054 { 1055 efx_mcdi_req_t req; 1056 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN, 1057 MC_CMD_NVRAM_TEST_OUT_LEN); 1058 int result; 1059 efx_rc_t rc; 1060 1061 req.emr_cmd = MC_CMD_NVRAM_TEST; 1062 req.emr_in_buf = payload; 1063 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 1064 req.emr_out_buf = payload; 1065 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 1066 1067 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 1068 1069 efx_mcdi_execute(enp, &req); 1070 1071 if (req.emr_rc != 0) { 1072 rc = req.emr_rc; 1073 goto fail1; 1074 } 1075 1076 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 1077 rc = EMSGSIZE; 1078 goto fail2; 1079 } 1080 1081 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 1082 if (result == MC_CMD_NVRAM_TEST_FAIL) { 1083 1084 EFSYS_PROBE1(nvram_test_failure, int, partn); 1085 1086 rc = (EINVAL); 1087 goto fail3; 1088 } 1089 1090 return (0); 1091 1092 fail3: 1093 EFSYS_PROBE(fail3); 1094 fail2: 1095 EFSYS_PROBE(fail2); 1096 fail1: 1097 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1098 1099 return (rc); 1100 } 1101 1102 #endif /* EFSYS_OPT_DIAG */ 1103 1104 1105 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 1106