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