1 /*- 2 * Copyright 2008-2009 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include "efsys.h" 30 #include "efx.h" 31 #include "efx_types.h" 32 #include "efx_regs.h" 33 #include "efx_regs_mcdi.h" 34 #include "efx_impl.h" 35 36 #if EFSYS_OPT_MCDI 37 38 /* 39 * A reboot/assertion causes the MCDI status word to be set after the 40 * command word is set or a REBOOT event is sent. If we notice a reboot 41 * via these mechanisms then wait 10ms for the status word to be set. 42 */ 43 #define MCDI_STATUS_SLEEP_US 10000 44 45 void 46 efx_mcdi_request_start( 47 __in efx_nic_t *enp, 48 __in efx_mcdi_req_t *emrp, 49 __in boolean_t ev_cpl) 50 { 51 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 52 efx_dword_t dword; 53 unsigned int seq; 54 unsigned int xflags; 55 unsigned int pdur; 56 unsigned int dbr; 57 unsigned int pos; 58 int state; 59 60 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 61 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 62 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 63 64 switch (emip->emi_port) { 65 case 1: 66 pdur = MC_SMEM_P0_PDU_OFST >> 2; 67 dbr = MC_SMEM_P0_DOORBELL_OFST >> 2; 68 break; 69 case 2: 70 pdur = MC_SMEM_P1_PDU_OFST >> 2; 71 dbr = MC_SMEM_P1_DOORBELL_OFST >> 2; 72 break; 73 default: 74 EFSYS_ASSERT(0); 75 pdur = dbr = 0; 76 }; 77 78 /* 79 * efx_mcdi_request_start() is naturally serialised against both 80 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), 81 * by virtue of there only being one outstanding MCDI request. 82 * Unfortunately, upper layers may also call efx_mcdi_request_abort() 83 * at any time, to timeout a pending mcdi request, That request may 84 * then subsequently complete, meaning efx_mcdi_ev_cpl() or 85 * efx_mcdi_ev_death() may end up running in parallel with 86 * efx_mcdi_request_start(). This race is handled by ensuring that 87 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the 88 * en_eslp lock. 89 */ 90 EFSYS_LOCK(enp->en_eslp, state); 91 EFSYS_ASSERT(emip->emi_pending_req == NULL); 92 emip->emi_pending_req = emrp; 93 emip->emi_ev_cpl = ev_cpl; 94 emip->emi_poll_cnt = 0; 95 seq = emip->emi_seq++ & 0xf; 96 EFSYS_UNLOCK(enp->en_eslp, state); 97 98 xflags = 0; 99 if (ev_cpl) 100 xflags |= MCDI_HEADER_XFLAGS_EVREQ; 101 102 /* Construct the header in shared memory */ 103 EFX_POPULATE_DWORD_6(dword, 104 MCDI_HEADER_CODE, emrp->emr_cmd, 105 MCDI_HEADER_RESYNC, 1, 106 MCDI_HEADER_DATALEN, emrp->emr_in_length, 107 MCDI_HEADER_SEQ, seq, 108 MCDI_HEADER_RESPONSE, 0, 109 MCDI_HEADER_XFLAGS, xflags); 110 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE); 111 112 for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { 113 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), 114 MIN(sizeof (dword), emrp->emr_in_length - pos)); 115 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, 116 pdur + 1 + (pos >> 2), &dword, B_FALSE); 117 } 118 119 /* Ring the doorbell */ 120 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11); 121 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE); 122 } 123 124 static void 125 efx_mcdi_request_copyout( 126 __in efx_nic_t *enp, 127 __in efx_mcdi_req_t *emrp) 128 { 129 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 130 unsigned int pos; 131 unsigned int pdur; 132 efx_dword_t data; 133 134 pdur = (emip->emi_port == 1) 135 ? MC_SMEM_P0_PDU_OFST >> 2 136 : MC_SMEM_P1_PDU_OFST >> 2; 137 138 /* Copy payload out if caller supplied buffer */ 139 if (emrp->emr_out_buf != NULL) { 140 size_t bytes = MIN(emrp->emr_out_length_used, 141 emrp->emr_out_length); 142 for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) { 143 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, 144 pdur + 1 + (pos >> 2), &data, B_FALSE); 145 memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data, 146 MIN(sizeof (data), bytes - pos)); 147 } 148 } 149 } 150 151 static int 152 efx_mcdi_request_errcode( 153 __in unsigned int err) 154 { 155 156 switch (err) { 157 case MC_CMD_ERR_ENOENT: 158 return (ENOENT); 159 case MC_CMD_ERR_EINTR: 160 return (EINTR); 161 case MC_CMD_ERR_EACCES: 162 return (EACCES); 163 case MC_CMD_ERR_EBUSY: 164 return (EBUSY); 165 case MC_CMD_ERR_EINVAL: 166 return (EINVAL); 167 case MC_CMD_ERR_EDEADLK: 168 return (EDEADLK); 169 case MC_CMD_ERR_ENOSYS: 170 return (ENOTSUP); 171 case MC_CMD_ERR_ETIME: 172 return (ETIMEDOUT); 173 #ifdef WITH_MCDI_V2 174 case MC_CMD_ERR_EAGAIN: 175 return (EAGAIN); 176 case MC_CMD_ERR_ENOSPC: 177 return (ENOSPC); 178 #endif 179 default: 180 EFSYS_PROBE1(mc_pcol_error, int, err); 181 return (EIO); 182 } 183 } 184 185 static void 186 efx_mcdi_raise_exception( 187 __in efx_nic_t *enp, 188 __in_opt efx_mcdi_req_t *emrp, 189 __in int rc) 190 { 191 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 192 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 193 efx_mcdi_exception_t exception; 194 195 /* Reboot or Assertion failure only */ 196 EFSYS_ASSERT(rc == EIO || rc == EINTR); 197 198 /* 199 * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 200 * then the EIO is not worthy of an exception. 201 */ 202 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 203 return; 204 205 exception = (rc == EIO) 206 ? EFX_MCDI_EXCEPTION_MC_REBOOT 207 : EFX_MCDI_EXCEPTION_MC_BADASSERT; 208 209 emtp->emt_exception(emtp->emt_context, exception); 210 } 211 212 static int 213 efx_mcdi_poll_reboot( 214 __in efx_nic_t *enp) 215 { 216 #ifndef EFX_GRACEFUL_MC_REBOOT 217 /* 218 * This function is not being used properly. 219 * Until its callers are fixed, it should always return 0. 220 */ 221 _NOTE(ARGUNUSED(enp)) 222 return (0); 223 #else 224 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 225 unsigned int rebootr; 226 efx_dword_t dword; 227 uint32_t value; 228 229 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 230 rebootr = ((emip->emi_port == 1) 231 ? MC_SMEM_P0_STATUS_OFST >> 2 232 : MC_SMEM_P1_STATUS_OFST >> 2); 233 234 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 235 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 236 237 if (value == 0) 238 return (0); 239 240 EFX_ZERO_DWORD(dword); 241 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 242 243 if (value == MC_STATUS_DWORD_ASSERT) 244 return (EINTR); 245 else 246 return (EIO); 247 #endif 248 } 249 250 __checkReturn boolean_t 251 efx_mcdi_request_poll( 252 __in efx_nic_t *enp) 253 { 254 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 255 efx_mcdi_req_t *emrp; 256 efx_dword_t dword; 257 unsigned int pdur; 258 unsigned int seq; 259 unsigned int length; 260 int state; 261 int rc; 262 263 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 264 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 265 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 266 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 267 268 /* Serialise against post-watchdog efx_mcdi_ev* */ 269 EFSYS_LOCK(enp->en_eslp, state); 270 271 EFSYS_ASSERT(emip->emi_pending_req != NULL); 272 EFSYS_ASSERT(!emip->emi_ev_cpl); 273 emrp = emip->emi_pending_req; 274 275 /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 276 if (emip->emi_poll_cnt++ == 0) { 277 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 278 emip->emi_pending_req = NULL; 279 EFSYS_UNLOCK(enp->en_eslp, state); 280 281 goto fail1; 282 } 283 } 284 285 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 286 pdur = (emip->emi_port == 1) 287 ? MC_SMEM_P0_PDU_OFST >> 2 288 : MC_SMEM_P1_PDU_OFST >> 2; 289 290 /* Read the command header */ 291 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_FALSE); 292 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) { 293 EFSYS_UNLOCK(enp->en_eslp, state); 294 return (B_FALSE); 295 } 296 297 /* Request complete */ 298 emip->emi_pending_req = NULL; 299 seq = (emip->emi_seq - 1) & 0xf; 300 301 /* Check for synchronous reboot */ 302 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && 303 EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN) == 0) { 304 /* Consume status word */ 305 EFSYS_SPIN(MCDI_STATUS_SLEEP_US); 306 efx_mcdi_poll_reboot(enp); 307 EFSYS_UNLOCK(enp->en_eslp, state); 308 rc = EIO; 309 goto fail2; 310 } 311 312 EFSYS_UNLOCK(enp->en_eslp, state); 313 314 /* Check that the returned data is consistent */ 315 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) != emrp->emr_cmd || 316 EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) { 317 /* Response is for a different request */ 318 rc = EIO; 319 goto fail3; 320 } 321 322 length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN); 323 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) { 324 efx_dword_t errdword; 325 int errcode; 326 327 EFSYS_ASSERT3U(length, ==, 4); 328 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, 329 pdur + 1 + (MC_CMD_ERR_CODE_OFST >> 2), 330 &errdword, B_FALSE); 331 errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0); 332 rc = efx_mcdi_request_errcode(errcode); 333 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, int, errcode); 334 goto fail4; 335 336 } else { 337 emrp->emr_out_length_used = length; 338 emrp->emr_rc = 0; 339 efx_mcdi_request_copyout(enp, emrp); 340 } 341 342 goto out; 343 344 fail4: 345 EFSYS_PROBE(fail4); 346 fail3: 347 EFSYS_PROBE(fail3); 348 fail2: 349 EFSYS_PROBE(fail2); 350 fail1: 351 EFSYS_PROBE1(fail1, int, rc); 352 353 /* Fill out error state */ 354 emrp->emr_rc = rc; 355 emrp->emr_out_length_used = 0; 356 357 /* Reboot/Assertion */ 358 if (rc == EIO || rc == EINTR) 359 efx_mcdi_raise_exception(enp, emrp, rc); 360 361 out: 362 return (B_TRUE); 363 } 364 365 void 366 efx_mcdi_execute( 367 __in efx_nic_t *enp, 368 __in efx_mcdi_req_t *emrp) 369 { 370 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 371 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 372 373 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 374 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 375 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 376 377 emtp->emt_execute(emtp->emt_context, emrp); 378 } 379 380 void 381 efx_mcdi_ev_cpl( 382 __in efx_nic_t *enp, 383 __in unsigned int seq, 384 __in unsigned int outlen, 385 __in int errcode) 386 { 387 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 388 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 389 efx_mcdi_req_t *emrp; 390 int state; 391 392 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 393 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 394 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 395 396 /* 397 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 398 * when we're completing an aborted request. 399 */ 400 EFSYS_LOCK(enp->en_eslp, state); 401 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 402 (seq != ((emip->emi_seq - 1) & 0xf))) { 403 EFSYS_ASSERT(emip->emi_aborted > 0); 404 if (emip->emi_aborted > 0) 405 --emip->emi_aborted; 406 EFSYS_UNLOCK(enp->en_eslp, state); 407 return; 408 } 409 410 emrp = emip->emi_pending_req; 411 emip->emi_pending_req = NULL; 412 EFSYS_UNLOCK(enp->en_eslp, state); 413 414 /* 415 * Fill out the remaining hdr fields, and copyout the payload 416 * if the user supplied an output buffer. 417 */ 418 if (errcode != 0) { 419 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 420 int, errcode); 421 emrp->emr_out_length_used = 0; 422 emrp->emr_rc = efx_mcdi_request_errcode(errcode); 423 } else { 424 emrp->emr_out_length_used = outlen; 425 emrp->emr_rc = 0; 426 efx_mcdi_request_copyout(enp, emrp); 427 } 428 429 emtp->emt_ev_cpl(emtp->emt_context); 430 } 431 432 void 433 efx_mcdi_ev_death( 434 __in efx_nic_t *enp, 435 __in int rc) 436 { 437 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 438 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 439 efx_mcdi_req_t *emrp = NULL; 440 boolean_t ev_cpl; 441 int state; 442 443 /* 444 * The MCDI request (if there is one) has been terminated, either 445 * by a BADASSERT or REBOOT event. 446 * 447 * If there is an outstanding event-completed MCDI operation, then we 448 * will never receive the completion event (because both MCDI 449 * completions and BADASSERT events are sent to the same evq). So 450 * complete this MCDI op. 451 * 452 * This function might run in parallel with efx_mcdi_request_poll() 453 * for poll completed mcdi requests, and also with 454 * efx_mcdi_request_start() for post-watchdog completions. 455 */ 456 EFSYS_LOCK(enp->en_eslp, state); 457 emrp = emip->emi_pending_req; 458 ev_cpl = emip->emi_ev_cpl; 459 if (emrp != NULL && emip->emi_ev_cpl) { 460 emip->emi_pending_req = NULL; 461 462 emrp->emr_out_length_used = 0; 463 emrp->emr_rc = rc; 464 ++emip->emi_aborted; 465 } 466 467 /* 468 * Since we're running in parallel with a request, consume the 469 * status word before dropping the lock. 470 */ 471 if (rc == EIO || rc == EINTR) { 472 EFSYS_SPIN(MCDI_STATUS_SLEEP_US); 473 (void) efx_mcdi_poll_reboot(enp); 474 } 475 476 EFSYS_UNLOCK(enp->en_eslp, state); 477 478 efx_mcdi_raise_exception(enp, emrp, rc); 479 480 if (emrp != NULL && ev_cpl) 481 emtp->emt_ev_cpl(emtp->emt_context); 482 } 483 484 __checkReturn int 485 efx_mcdi_version( 486 __in efx_nic_t *enp, 487 __out_ecount_opt(4) uint16_t versionp[4], 488 __out_opt uint32_t *buildp, 489 __out_opt efx_mcdi_boot_t *statusp) 490 { 491 uint8_t outbuf[MAX(MC_CMD_GET_VERSION_OUT_LEN, 492 MC_CMD_GET_BOOT_STATUS_OUT_LEN)]; 493 efx_mcdi_req_t req; 494 efx_word_t *ver_words; 495 uint16_t version[4]; 496 uint32_t build; 497 efx_mcdi_boot_t status; 498 int rc; 499 500 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 501 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 502 503 EFX_STATIC_ASSERT(MC_CMD_GET_VERSION_IN_LEN == 0); 504 req.emr_cmd = MC_CMD_GET_VERSION; 505 req.emr_in_buf = NULL; 506 req.emr_in_length = 0; 507 req.emr_out_buf = outbuf; 508 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 509 510 efx_mcdi_execute(enp, &req); 511 512 if (req.emr_rc != 0) { 513 rc = req.emr_rc; 514 goto fail1; 515 } 516 517 /* bootrom support */ 518 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 519 version[0] = version[1] = version[2] = version[3] = 0; 520 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 521 522 goto version; 523 } 524 525 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 526 rc = EMSGSIZE; 527 goto fail2; 528 } 529 530 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 531 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 532 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 533 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 534 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 535 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 536 537 version: 538 /* The bootrom doesn't understand BOOT_STATUS */ 539 if (build == MC_CMD_GET_VERSION_OUT_FIRMWARE_SIENA_BOOTROM) { 540 status = EFX_MCDI_BOOT_ROM; 541 goto out; 542 } 543 544 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 545 EFX_STATIC_ASSERT(MC_CMD_GET_BOOT_STATUS_IN_LEN == 0); 546 req.emr_in_buf = NULL; 547 req.emr_in_length = 0; 548 req.emr_out_buf = outbuf; 549 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 550 551 efx_mcdi_execute(enp, &req); 552 553 if (req.emr_rc != 0) { 554 rc = req.emr_rc; 555 goto fail3; 556 } 557 558 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 559 rc = EMSGSIZE; 560 goto fail4; 561 } 562 563 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 564 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 565 status = EFX_MCDI_BOOT_PRIMARY; 566 else 567 status = EFX_MCDI_BOOT_SECONDARY; 568 569 out: 570 if (versionp != NULL) 571 memcpy(versionp, version, sizeof (version)); 572 if (buildp != NULL) 573 *buildp = build; 574 if (statusp != NULL) 575 *statusp = status; 576 577 return (0); 578 579 fail4: 580 EFSYS_PROBE(fail4); 581 fail3: 582 EFSYS_PROBE(fail3); 583 fail2: 584 EFSYS_PROBE(fail2); 585 fail1: 586 EFSYS_PROBE1(fail1, int, rc); 587 588 return (rc); 589 } 590 591 __checkReturn int 592 efx_mcdi_init( 593 __in efx_nic_t *enp, 594 __in const efx_mcdi_transport_t *mtp) 595 { 596 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 597 efx_oword_t oword; 598 unsigned int portnum; 599 int rc; 600 601 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 602 enp->en_mod_flags |= EFX_MOD_MCDI; 603 604 if (enp->en_family == EFX_FAMILY_FALCON) 605 return (0); 606 607 emip->emi_mtp = mtp; 608 609 /* Determine the port number to use for MCDI */ 610 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword); 611 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 612 613 if (portnum == 0) { 614 /* Presumably booted from ROM; only MCDI port 1 will work */ 615 emip->emi_port = 1; 616 } else if (portnum <= 2) { 617 emip->emi_port = portnum; 618 } else { 619 rc = EINVAL; 620 goto fail1; 621 } 622 623 /* 624 * Wipe the atomic reboot status so subsequent MCDI requests succeed. 625 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the 626 * assertion handler. 627 */ 628 (void) efx_mcdi_poll_reboot(enp); 629 630 return (0); 631 632 fail1: 633 EFSYS_PROBE1(fail1, int, rc); 634 635 enp->en_mod_flags &= ~EFX_MOD_MCDI; 636 637 return (rc); 638 } 639 640 641 __checkReturn int 642 efx_mcdi_reboot( 643 __in efx_nic_t *enp) 644 { 645 uint8_t payload[MC_CMD_REBOOT_IN_LEN]; 646 efx_mcdi_req_t req; 647 int rc; 648 649 /* 650 * We could require the caller to have caused en_mod_flags=0 to 651 * call this function. This doesn't help the other port though, 652 * who's about to get the MC ripped out from underneath them. 653 * Since they have to cope with the subsequent fallout of MCDI 654 * failures, we should as well. 655 */ 656 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 657 658 req.emr_cmd = MC_CMD_REBOOT; 659 req.emr_in_buf = payload; 660 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 661 req.emr_out_buf = NULL; 662 req.emr_out_length = 0; 663 664 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 0); 665 666 efx_mcdi_execute(enp, &req); 667 668 /* Invert EIO */ 669 if (req.emr_rc != EIO) { 670 rc = EIO; 671 goto fail1; 672 } 673 674 return (0); 675 676 fail1: 677 EFSYS_PROBE1(fail1, int, rc); 678 679 return (rc); 680 } 681 682 __checkReturn boolean_t 683 efx_mcdi_request_abort( 684 __in efx_nic_t *enp) 685 { 686 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 687 efx_mcdi_req_t *emrp; 688 boolean_t aborted; 689 int state; 690 691 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 692 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 693 694 /* 695 * efx_mcdi_ev_* may have already completed this event, and be 696 * spinning/blocked on the upper layer lock. So it *is* legitimate 697 * to for emi_pending_req to be NULL. If there is a pending event 698 * completed request, then provide a "credit" to allow 699 * efx_mcdi_ev_cpl() to accept a single spurious completion. 700 */ 701 EFSYS_LOCK(enp->en_eslp, state); 702 emrp = emip->emi_pending_req; 703 aborted = (emrp != NULL); 704 if (aborted) { 705 emip->emi_pending_req = NULL; 706 707 /* Error the request */ 708 emrp->emr_out_length_used = 0; 709 emrp->emr_rc = ETIMEDOUT; 710 711 /* Provide a credit for seqno/emr_pending_req mismatches */ 712 if (emip->emi_ev_cpl) 713 ++emip->emi_aborted; 714 715 /* 716 * The upper layer has called us, so we don't 717 * need to complete the request. 718 */ 719 } 720 EFSYS_UNLOCK(enp->en_eslp, state); 721 722 return (aborted); 723 } 724 725 void 726 efx_mcdi_fini( 727 __in efx_nic_t *enp) 728 { 729 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 730 731 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); 732 enp->en_mod_flags &= ~EFX_MOD_MCDI; 733 734 if (~(enp->en_features) & EFX_FEATURE_MCDI) 735 return; 736 737 emip->emi_mtp = NULL; 738 emip->emi_port = 0; 739 emip->emi_aborted = 0; 740 } 741 742 #endif /* EFSYS_OPT_MCDI */ 743