ef10_mcdi.c revision 291588
1283514Sarybchik/*- 2283514Sarybchik * Copyright (c) 2012-2015 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_mcdi.c 291588 2015-12-01 15:38:39Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efsys.h" 35283514Sarybchik#include "efx.h" 36283514Sarybchik#include "efx_impl.h" 37283514Sarybchik 38283514Sarybchik 39283514Sarybchik#if EFSYS_OPT_HUNTINGTON 40283514Sarybchik 41283514Sarybchik#if EFSYS_OPT_MCDI 42283514Sarybchik 43283514Sarybchik#ifndef WITH_MCDI_V2 44283514Sarybchik#error "WITH_MCDI_V2 required for Huntington MCDIv2 commands." 45283514Sarybchik#endif 46283514Sarybchik 47283514Sarybchiktypedef enum efx_mcdi_header_type_e { 48283514Sarybchik EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */ 49283514Sarybchik EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */ 50283514Sarybchik} efx_mcdi_header_type_t; 51283514Sarybchik 52283514Sarybchik/* 53283514Sarybchik * Return the header format to use for sending an MCDI request. 54283514Sarybchik * 55283514Sarybchik * An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the 56283514Sarybchik * request input buffer or response output buffer are too large for the MCDIv1 57283514Sarybchik * format. An MCDIv2 command must always be sent using MCDIv2 encapsulation. 58283514Sarybchik */ 59283514Sarybchik#define EFX_MCDI_HEADER_TYPE(_cmd, _length) \ 60283514Sarybchik ((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) || \ 61283514Sarybchik ((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN))) ? \ 62283514Sarybchik EFX_MCDI_HEADER_TYPE_V2 : EFX_MCDI_HEADER_TYPE_V1) 63283514Sarybchik 64283514Sarybchik 65283514Sarybchik/* 66283514Sarybchik * MCDI Header NOT_EPOCH flag 67283514Sarybchik * ========================== 68283514Sarybchik * A new epoch begins at initial startup or after an MC reboot, and defines when 69283514Sarybchik * the MC should reject stale MCDI requests. 70283514Sarybchik * 71283514Sarybchik * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all 72283514Sarybchik * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1. 73283514Sarybchik * 74283514Sarybchik * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a 75283514Sarybchik * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0. 76283514Sarybchik */ 77283514Sarybchik 78283514Sarybchik 79291436Sarybchik __checkReturn efx_rc_t 80283514Sarybchikhunt_mcdi_init( 81283514Sarybchik __in efx_nic_t *enp, 82283514Sarybchik __in const efx_mcdi_transport_t *emtp) 83283514Sarybchik{ 84283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 85283514Sarybchik efx_dword_t dword; 86291436Sarybchik efx_rc_t rc; 87283514Sarybchik 88283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 89283514Sarybchik EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); 90283514Sarybchik 91283514Sarybchik /* A host DMA buffer is required for Huntington MCDI */ 92283514Sarybchik if (esmp == NULL) { 93283514Sarybchik rc = EINVAL; 94283514Sarybchik goto fail1; 95283514Sarybchik } 96283514Sarybchik 97283514Sarybchik /* 98283514Sarybchik * Ensure that the MC doorbell is in a known state before issuing MCDI 99283514Sarybchik * commands. The recovery algorithm requires that the MC command buffer 100283514Sarybchik * must be 256 byte aligned. See bug24769. 101283514Sarybchik */ 102283514Sarybchik if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { 103283514Sarybchik rc = EINVAL; 104283514Sarybchik goto fail2; 105283514Sarybchik } 106283514Sarybchik EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); 107283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 108283514Sarybchik 109283514Sarybchik /* Save initial MC reboot status */ 110283514Sarybchik (void) hunt_mcdi_poll_reboot(enp); 111283514Sarybchik 112283514Sarybchik /* Start a new epoch (allow fresh MCDI requests to succeed) */ 113283514Sarybchik efx_mcdi_new_epoch(enp); 114283514Sarybchik 115283514Sarybchik return (0); 116283514Sarybchik 117283514Sarybchikfail2: 118283514Sarybchik EFSYS_PROBE(fail2); 119283514Sarybchikfail1: 120291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 121283514Sarybchik 122283514Sarybchik return (rc); 123283514Sarybchik} 124283514Sarybchik 125283514Sarybchik void 126283514Sarybchikhunt_mcdi_fini( 127283514Sarybchik __in efx_nic_t *enp) 128283514Sarybchik{ 129283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 130283514Sarybchik 131283514Sarybchik emip->emi_new_epoch = B_FALSE; 132283514Sarybchik} 133283514Sarybchik 134283514Sarybchik void 135283514Sarybchikhunt_mcdi_request_copyin( 136283514Sarybchik __in efx_nic_t *enp, 137283514Sarybchik __in efx_mcdi_req_t *emrp, 138283514Sarybchik __in unsigned int seq, 139283514Sarybchik __in boolean_t ev_cpl, 140283514Sarybchik __in boolean_t new_epoch) 141283514Sarybchik{ 142283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 143283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 144283514Sarybchik efx_mcdi_header_type_t hdr_type; 145283514Sarybchik efx_dword_t dword; 146283514Sarybchik unsigned int xflags; 147283514Sarybchik unsigned int pos; 148283514Sarybchik size_t offset; 149283514Sarybchik 150283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 151283514Sarybchik 152283514Sarybchik xflags = 0; 153283514Sarybchik if (ev_cpl) 154283514Sarybchik xflags |= MCDI_HEADER_XFLAGS_EVREQ; 155283514Sarybchik 156283514Sarybchik offset = 0; 157283514Sarybchik 158283514Sarybchik hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd, 159283514Sarybchik MAX(emrp->emr_in_length, emrp->emr_out_length)); 160283514Sarybchik 161283514Sarybchik if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) { 162283514Sarybchik /* Construct MCDI v2 header */ 163283514Sarybchik EFX_POPULATE_DWORD_8(dword, 164283514Sarybchik MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 165283514Sarybchik MCDI_HEADER_RESYNC, 1, 166283514Sarybchik MCDI_HEADER_DATALEN, 0, 167283514Sarybchik MCDI_HEADER_SEQ, seq, 168283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 169283514Sarybchik MCDI_HEADER_ERROR, 0, 170283514Sarybchik MCDI_HEADER_RESPONSE, 0, 171283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 172283514Sarybchik EFSYS_MEM_WRITED(esmp, offset, &dword); 173283514Sarybchik offset += sizeof (dword); 174283514Sarybchik 175283514Sarybchik EFX_POPULATE_DWORD_2(dword, 176283514Sarybchik MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, 177283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); 178283514Sarybchik EFSYS_MEM_WRITED(esmp, offset, &dword); 179283514Sarybchik offset += sizeof (dword); 180283514Sarybchik } else { 181283514Sarybchik /* Construct MCDI v1 header */ 182283514Sarybchik EFX_POPULATE_DWORD_8(dword, 183283514Sarybchik MCDI_HEADER_CODE, emrp->emr_cmd, 184283514Sarybchik MCDI_HEADER_RESYNC, 1, 185283514Sarybchik MCDI_HEADER_DATALEN, emrp->emr_in_length, 186283514Sarybchik MCDI_HEADER_SEQ, seq, 187283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 188283514Sarybchik MCDI_HEADER_ERROR, 0, 189283514Sarybchik MCDI_HEADER_RESPONSE, 0, 190283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 191283514Sarybchik EFSYS_MEM_WRITED(esmp, offset, &dword); 192283514Sarybchik offset += sizeof (dword); 193283514Sarybchik } 194283514Sarybchik 195283514Sarybchik /* Construct the payload */ 196283514Sarybchik for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { 197283514Sarybchik memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), 198283514Sarybchik MIN(sizeof (dword), emrp->emr_in_length - pos)); 199283514Sarybchik EFSYS_MEM_WRITED(esmp, offset + pos, &dword); 200283514Sarybchik } 201283514Sarybchik 202283514Sarybchik /* Ring the doorbell to post the command DMA address to the MC */ 203283514Sarybchik EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0); 204283514Sarybchik 205283514Sarybchik /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ 206283514Sarybchik EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length); 207283514Sarybchik EFSYS_PIO_WRITE_BARRIER(); 208283514Sarybchik 209283514Sarybchik EFX_POPULATE_DWORD_1(dword, 210283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32); 211283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); 212283514Sarybchik 213283514Sarybchik EFX_POPULATE_DWORD_1(dword, 214283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff); 215283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 216283514Sarybchik} 217283514Sarybchik 218283514Sarybchik void 219283514Sarybchikhunt_mcdi_request_copyout( 220283514Sarybchik __in efx_nic_t *enp, 221283514Sarybchik __in efx_mcdi_req_t *emrp) 222283514Sarybchik{ 223283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 224283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 225283514Sarybchik unsigned int pos; 226283514Sarybchik unsigned int offset; 227283514Sarybchik efx_dword_t hdr; 228283514Sarybchik efx_dword_t hdr2; 229283514Sarybchik efx_dword_t data; 230283514Sarybchik size_t bytes; 231283514Sarybchik 232283514Sarybchik if (emrp->emr_out_buf == NULL) 233283514Sarybchik return; 234283514Sarybchik 235283514Sarybchik /* Read the command header to detect MCDI response format */ 236283514Sarybchik EFSYS_MEM_READD(esmp, 0, &hdr); 237283514Sarybchik if (EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 238283514Sarybchik offset = 2 * sizeof (efx_dword_t); 239283514Sarybchik 240283514Sarybchik /* 241283514Sarybchik * Read the actual payload length. The length given in the event 242283514Sarybchik * is only correct for responses with the V1 format. 243283514Sarybchik */ 244283514Sarybchik EFSYS_MEM_READD(esmp, sizeof (efx_dword_t), &hdr2); 245283514Sarybchik emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr2, 246283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 247283514Sarybchik } else { 248283514Sarybchik offset = sizeof (efx_dword_t); 249283514Sarybchik } 250283514Sarybchik 251283514Sarybchik /* Copy payload out into caller supplied buffer */ 252283514Sarybchik bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); 253283514Sarybchik for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) { 254283514Sarybchik EFSYS_MEM_READD(esmp, offset + pos, &data); 255283514Sarybchik memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data, 256283514Sarybchik MIN(sizeof (data), bytes - pos)); 257283514Sarybchik } 258283514Sarybchik} 259283514Sarybchik 260283514Sarybchik __checkReturn boolean_t 261283514Sarybchikhunt_mcdi_request_poll( 262283514Sarybchik __in efx_nic_t *enp) 263283514Sarybchik{ 264283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 265283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 266283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 267283514Sarybchik efx_mcdi_req_t *emrp; 268283514Sarybchik efx_dword_t dword; 269283514Sarybchik unsigned int seq; 270283514Sarybchik unsigned int cmd; 271283514Sarybchik unsigned int length; 272283514Sarybchik size_t offset; 273283514Sarybchik int state; 274291436Sarybchik efx_rc_t rc; 275283514Sarybchik 276283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 277283514Sarybchik 278283514Sarybchik /* Serialise against post-watchdog efx_mcdi_ev* */ 279283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 280283514Sarybchik 281283514Sarybchik EFSYS_ASSERT(emip->emi_pending_req != NULL); 282283514Sarybchik EFSYS_ASSERT(!emip->emi_ev_cpl); 283283514Sarybchik emrp = emip->emi_pending_req; 284283514Sarybchik 285283514Sarybchik offset = 0; 286283514Sarybchik 287283514Sarybchik /* Read the command header */ 288283514Sarybchik EFSYS_MEM_READD(esmp, offset, &dword); 289283514Sarybchik offset += sizeof (efx_dword_t); 290283514Sarybchik if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) { 291283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 292283514Sarybchik return (B_FALSE); 293283514Sarybchik } 294283514Sarybchik if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 295283514Sarybchik efx_dword_t dword2; 296283514Sarybchik 297283514Sarybchik EFSYS_MEM_READD(esmp, offset, &dword2); 298283514Sarybchik offset += sizeof (efx_dword_t); 299283514Sarybchik 300283514Sarybchik cmd = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 301283514Sarybchik length = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 302283514Sarybchik } else { 303283514Sarybchik cmd = EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE); 304283514Sarybchik length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN); 305283514Sarybchik } 306283514Sarybchik 307283514Sarybchik /* Request complete */ 308283514Sarybchik emip->emi_pending_req = NULL; 309283514Sarybchik seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ); 310283514Sarybchik 311283514Sarybchik /* Check for synchronous reboot */ 312283514Sarybchik if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && length == 0) { 313283514Sarybchik /* The MC has rebooted since the request was sent. */ 314283514Sarybchik EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 315283514Sarybchik hunt_mcdi_poll_reboot(enp); 316283514Sarybchik 317283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 318283514Sarybchik rc = EIO; 319283514Sarybchik goto fail1; 320283514Sarybchik } 321283514Sarybchik 322283514Sarybchik /* Ensure stale MCDI requests fail after an MC reboot. */ 323283514Sarybchik emip->emi_new_epoch = B_FALSE; 324283514Sarybchik 325283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 326283514Sarybchik 327283514Sarybchik /* Check that the returned data is consistent */ 328283514Sarybchik if (cmd != emrp->emr_cmd || 329283514Sarybchik EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) { 330283514Sarybchik /* Response is for a different request */ 331283514Sarybchik rc = EIO; 332283514Sarybchik goto fail2; 333283514Sarybchik } 334283514Sarybchik if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) { 335283514Sarybchik efx_dword_t errdword; 336283514Sarybchik int errcode; 337283514Sarybchik int argnum; 338283514Sarybchik 339283514Sarybchik /* Read error code (and arg num for MCDI v2 commands) */ 340283514Sarybchik EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_CODE_OFST, &errdword); 341283514Sarybchik errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0); 342283514Sarybchik 343283514Sarybchik EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_ARG_OFST, &errdword); 344283514Sarybchik argnum = EFX_DWORD_FIELD(errdword, EFX_DWORD_0); 345283514Sarybchik 346283514Sarybchik rc = efx_mcdi_request_errcode(errcode); 347283514Sarybchik if (!emrp->emr_quiet) { 348283514Sarybchik EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, 349283514Sarybchik int, errcode, int, argnum); 350283514Sarybchik } 351283514Sarybchik goto fail3; 352283514Sarybchik 353283514Sarybchik } else { 354283514Sarybchik emrp->emr_out_length_used = length; 355283514Sarybchik emrp->emr_rc = 0; 356283514Sarybchik hunt_mcdi_request_copyout(enp, emrp); 357283514Sarybchik } 358283514Sarybchik 359283514Sarybchik goto out; 360283514Sarybchik 361283514Sarybchikfail3: 362283514Sarybchik if (!emrp->emr_quiet) 363283514Sarybchik EFSYS_PROBE(fail3); 364283514Sarybchikfail2: 365283514Sarybchik if (!emrp->emr_quiet) 366283514Sarybchik EFSYS_PROBE(fail2); 367283514Sarybchikfail1: 368283514Sarybchik if (!emrp->emr_quiet) 369291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 370283514Sarybchik 371283514Sarybchik /* Fill out error state */ 372283514Sarybchik emrp->emr_rc = rc; 373283514Sarybchik emrp->emr_out_length_used = 0; 374283514Sarybchik 375283514Sarybchik /* Reboot/Assertion */ 376283514Sarybchik if (rc == EIO || rc == EINTR) 377283514Sarybchik efx_mcdi_raise_exception(enp, emrp, rc); 378283514Sarybchik 379283514Sarybchikout: 380283514Sarybchik return (B_TRUE); 381283514Sarybchik} 382283514Sarybchik 383291436Sarybchik efx_rc_t 384283514Sarybchikhunt_mcdi_poll_reboot( 385283514Sarybchik __in efx_nic_t *enp) 386283514Sarybchik{ 387283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 388283514Sarybchik efx_dword_t dword; 389283514Sarybchik uint32_t old_status; 390283514Sarybchik uint32_t new_status; 391291436Sarybchik efx_rc_t rc; 392283514Sarybchik 393283514Sarybchik old_status = emip->emi_mc_reboot_status; 394283514Sarybchik 395283514Sarybchik /* Update MC reboot status word */ 396283514Sarybchik EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 397283514Sarybchik new_status = dword.ed_u32[0]; 398283514Sarybchik 399283514Sarybchik /* MC has rebooted if the value has changed */ 400283514Sarybchik if (new_status != old_status) { 401283514Sarybchik emip->emi_mc_reboot_status = new_status; 402283514Sarybchik 403283514Sarybchik /* 404283514Sarybchik * FIXME: Ignore detected MC REBOOT for now. 405283514Sarybchik * 406283514Sarybchik * The Siena support for checking for MC reboot from status 407283514Sarybchik * flags is broken - see comments in siena_mcdi_poll_reboot(). 408283514Sarybchik * As the generic MCDI code is shared the Huntington reboot 409283514Sarybchik * detection suffers similar problems. 410283514Sarybchik * 411283514Sarybchik * Do not report an error when the boot status changes until 412283514Sarybchik * this can be handled by common code drivers (and reworked to 413283514Sarybchik * support Siena too). 414283514Sarybchik */ 415283514Sarybchik if (B_FALSE) { 416283514Sarybchik rc = EIO; 417283514Sarybchik goto fail1; 418283514Sarybchik } 419283514Sarybchik } 420283514Sarybchik 421283514Sarybchik return (0); 422283514Sarybchik 423283514Sarybchikfail1: 424291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 425283514Sarybchik 426283514Sarybchik return (rc); 427283514Sarybchik} 428283514Sarybchik 429291436Sarybchik __checkReturn efx_rc_t 430283514Sarybchikhunt_mcdi_fw_update_supported( 431283514Sarybchik __in efx_nic_t *enp, 432283514Sarybchik __out boolean_t *supportedp) 433283514Sarybchik{ 434283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 435283514Sarybchik 436283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 437283514Sarybchik 438291585Sarybchik /* 439291585Sarybchik * Use privilege mask state at MCDI attach. 440291585Sarybchik * Admin privilege must be used prior to introduction of 441291585Sarybchik * specific flag. 442291585Sarybchik */ 443283514Sarybchik *supportedp = (encp->enc_privilege_mask & 444283514Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) 445283514Sarybchik == MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN; 446283514Sarybchik 447283514Sarybchik return (0); 448283514Sarybchik} 449283514Sarybchik 450291436Sarybchik __checkReturn efx_rc_t 451283514Sarybchikhunt_mcdi_macaddr_change_supported( 452283514Sarybchik __in efx_nic_t *enp, 453283514Sarybchik __out boolean_t *supportedp) 454283514Sarybchik{ 455283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 456291585Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 457283514Sarybchik 458283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 459283514Sarybchik 460291585Sarybchik /* 461291585Sarybchik * Use privilege mask state at MCDI attach. 462291585Sarybchik * Admin privilege must be used prior to introduction of 463291585Sarybchik * specific flag (at v4.6). 464291585Sarybchik */ 465291585Sarybchik *supportedp = 466291585Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING) == 467291585Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING) || 468291585Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) == 469291585Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN); 470283514Sarybchik 471283514Sarybchik return (0); 472283514Sarybchik} 473283514Sarybchik 474291588Sarybchik __checkReturn efx_rc_t 475291588Sarybchikhunt_mcdi_link_control_supported( 476291588Sarybchik __in efx_nic_t *enp, 477291588Sarybchik __out boolean_t *supportedp) 478291588Sarybchik{ 479291588Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 480291588Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 481291588Sarybchik 482291588Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 483291588Sarybchik 484291588Sarybchik /* 485291588Sarybchik * Use privilege mask state at MCDI attach. 486291588Sarybchik * Admin privilege used prior to introduction of 487291588Sarybchik * specific flag. 488291588Sarybchik */ 489291588Sarybchik *supportedp = 490291588Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK) == 491291588Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK) || 492291588Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) == 493291588Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN); 494291588Sarybchik 495291588Sarybchik return (0); 496291588Sarybchik} 497291588Sarybchik 498283514Sarybchik#endif /* EFSYS_OPT_MCDI */ 499283514Sarybchik 500283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 501