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 */