ef10_mcdi.c revision 291985
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 291985 2015-12-08 06:25:52Z 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; 146291677Sarybchik efx_dword_t hdr[2]; 147283514Sarybchik unsigned int xflags; 148283514Sarybchik unsigned int pos; 149283514Sarybchik size_t offset; 150283514Sarybchik 151283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 152283514Sarybchik 153283514Sarybchik xflags = 0; 154283514Sarybchik if (ev_cpl) 155283514Sarybchik xflags |= MCDI_HEADER_XFLAGS_EVREQ; 156283514Sarybchik 157283514Sarybchik offset = 0; 158283514Sarybchik 159283514Sarybchik hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd, 160283514Sarybchik MAX(emrp->emr_in_length, emrp->emr_out_length)); 161283514Sarybchik 162283514Sarybchik if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) { 163283514Sarybchik /* Construct MCDI v2 header */ 164291677Sarybchik EFX_POPULATE_DWORD_8(hdr[0], 165283514Sarybchik MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 166283514Sarybchik MCDI_HEADER_RESYNC, 1, 167283514Sarybchik MCDI_HEADER_DATALEN, 0, 168283514Sarybchik MCDI_HEADER_SEQ, seq, 169283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 170283514Sarybchik MCDI_HEADER_ERROR, 0, 171283514Sarybchik MCDI_HEADER_RESPONSE, 0, 172283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 173291677Sarybchik EFSYS_MEM_WRITED(esmp, offset, &hdr[0]); 174291677Sarybchik offset += sizeof (efx_dword_t); 175283514Sarybchik 176291677Sarybchik EFX_POPULATE_DWORD_2(hdr[1], 177283514Sarybchik MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, 178283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); 179291677Sarybchik EFSYS_MEM_WRITED(esmp, offset, &hdr[1]); 180291677Sarybchik offset += sizeof (efx_dword_t); 181283514Sarybchik } else { 182283514Sarybchik /* Construct MCDI v1 header */ 183291677Sarybchik EFX_POPULATE_DWORD_8(hdr[0], 184283514Sarybchik MCDI_HEADER_CODE, emrp->emr_cmd, 185283514Sarybchik MCDI_HEADER_RESYNC, 1, 186283514Sarybchik MCDI_HEADER_DATALEN, emrp->emr_in_length, 187283514Sarybchik MCDI_HEADER_SEQ, seq, 188283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 189283514Sarybchik MCDI_HEADER_ERROR, 0, 190283514Sarybchik MCDI_HEADER_RESPONSE, 0, 191283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 192291677Sarybchik EFSYS_MEM_WRITED(esmp, 0, &hdr[0]); 193291677Sarybchik offset += sizeof (efx_dword_t); 194283514Sarybchik } 195283514Sarybchik 196291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING 197291677Sarybchik if (emtp->emt_logger != NULL) { 198291677Sarybchik emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, 199291677Sarybchik &hdr, offset, 200291677Sarybchik emrp->emr_in_buf, emrp->emr_in_length); 201291677Sarybchik } 202291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 203291677Sarybchik 204283514Sarybchik /* Construct the payload */ 205283514Sarybchik for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { 206283514Sarybchik memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), 207283514Sarybchik MIN(sizeof (dword), emrp->emr_in_length - pos)); 208283514Sarybchik EFSYS_MEM_WRITED(esmp, offset + pos, &dword); 209283514Sarybchik } 210283514Sarybchik 211283514Sarybchik /* Ring the doorbell to post the command DMA address to the MC */ 212283514Sarybchik EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0); 213283514Sarybchik 214283514Sarybchik /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ 215283514Sarybchik EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length); 216283514Sarybchik EFSYS_PIO_WRITE_BARRIER(); 217283514Sarybchik 218283514Sarybchik EFX_POPULATE_DWORD_1(dword, 219283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32); 220283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); 221283514Sarybchik 222283514Sarybchik EFX_POPULATE_DWORD_1(dword, 223283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff); 224283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 225283514Sarybchik} 226283514Sarybchik 227283514Sarybchik void 228283514Sarybchikhunt_mcdi_request_copyout( 229283514Sarybchik __in efx_nic_t *enp, 230283514Sarybchik __in efx_mcdi_req_t *emrp) 231283514Sarybchik{ 232291985Sarybchik#if EFSYS_OPT_MCDI_LOGGING 233283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 234291985Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 235291677Sarybchik efx_dword_t hdr[2]; 236291985Sarybchik unsigned int hdr_len; 237283514Sarybchik size_t bytes; 238283514Sarybchik 239283514Sarybchik if (emrp->emr_out_buf == NULL) 240283514Sarybchik return; 241283514Sarybchik 242283514Sarybchik /* Read the command header to detect MCDI response format */ 243291985Sarybchik hdr_len = sizeof (hdr[0]); 244291985Sarybchik hunt_mcdi_read_response(enp, &hdr[0], 0, hdr_len); 245291677Sarybchik if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 246283514Sarybchik /* 247283514Sarybchik * Read the actual payload length. The length given in the event 248283514Sarybchik * is only correct for responses with the V1 format. 249283514Sarybchik */ 250291985Sarybchik hunt_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 251291985Sarybchik hdr_len += sizeof (hdr[1]); 252291985Sarybchik 253291677Sarybchik emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], 254283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 255283514Sarybchik } 256283514Sarybchik 257283514Sarybchik /* Copy payload out into caller supplied buffer */ 258283514Sarybchik bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); 259291985Sarybchik hunt_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes); 260291677Sarybchik 261291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING 262291677Sarybchik if (emtp->emt_logger != NULL) { 263291677Sarybchik emtp->emt_logger(emtp->emt_context, 264291677Sarybchik EFX_LOG_MCDI_RESPONSE, 265291985Sarybchik &hdr, hdr_len, 266291985Sarybchik emrp->emr_out_buf, bytes); 267291677Sarybchik } 268291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 269283514Sarybchik} 270283514Sarybchik 271291928Sarybchikstatic __checkReturn boolean_t 272291928Sarybchikhunt_mcdi_poll_response( 273291928Sarybchik __in efx_nic_t *enp) 274291928Sarybchik{ 275291928Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 276291928Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 277291928Sarybchik efx_dword_t hdr; 278291928Sarybchik 279291928Sarybchik EFSYS_MEM_READD(esmp, 0, &hdr); 280291928Sarybchik return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); 281291928Sarybchik} 282291928Sarybchik 283291985Sarybchik void 284291985Sarybchikhunt_mcdi_read_response( 285291985Sarybchik __in efx_nic_t *enp, 286291985Sarybchik __out void *bufferp, 287291985Sarybchik __in size_t offset, 288291985Sarybchik __in size_t length) 289291985Sarybchik{ 290291985Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 291291985Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 292291985Sarybchik unsigned int pos; 293291985Sarybchik efx_dword_t data; 294291985Sarybchik 295291985Sarybchik for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { 296291985Sarybchik EFSYS_MEM_READD(esmp, offset + pos, &data); 297291985Sarybchik memcpy((uint8_t *)bufferp + pos, &data, 298291985Sarybchik MIN(sizeof (data), length - pos)); 299291985Sarybchik } 300291985Sarybchik} 301291985Sarybchik 302283514Sarybchik __checkReturn boolean_t 303283514Sarybchikhunt_mcdi_request_poll( 304283514Sarybchik __in efx_nic_t *enp) 305283514Sarybchik{ 306291985Sarybchik#if EFSYS_OPT_MCDI_LOGGING 307291985Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 308291985Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 309283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 310283514Sarybchik efx_mcdi_req_t *emrp; 311291677Sarybchik efx_dword_t hdr[2]; 312291985Sarybchik unsigned int hdr_len; 313291985Sarybchik unsigned int data_len; 314283514Sarybchik unsigned int seq; 315283514Sarybchik unsigned int cmd; 316283514Sarybchik int state; 317291436Sarybchik efx_rc_t rc; 318283514Sarybchik 319283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 320283514Sarybchik 321283514Sarybchik /* Serialise against post-watchdog efx_mcdi_ev* */ 322283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 323283514Sarybchik 324283514Sarybchik EFSYS_ASSERT(emip->emi_pending_req != NULL); 325283514Sarybchik EFSYS_ASSERT(!emip->emi_ev_cpl); 326283514Sarybchik emrp = emip->emi_pending_req; 327283514Sarybchik 328291928Sarybchik /* Check if a response is available */ 329291928Sarybchik if (hunt_mcdi_poll_response(enp) == B_FALSE) { 330283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 331283514Sarybchik return (B_FALSE); 332283514Sarybchik } 333291928Sarybchik 334291928Sarybchik /* Read the response header */ 335291985Sarybchik hdr_len = sizeof (hdr[0]); 336291985Sarybchik hunt_mcdi_read_response(enp, &hdr[0], 0, hdr_len); 337291985Sarybchik 338291677Sarybchik if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 339291985Sarybchik hunt_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 340291985Sarybchik hdr_len += sizeof (hdr[1]); 341283514Sarybchik 342291677Sarybchik cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 343291985Sarybchik data_len = 344291985Sarybchik EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 345283514Sarybchik } else { 346291677Sarybchik cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE); 347291985Sarybchik data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN); 348283514Sarybchik } 349283514Sarybchik 350283514Sarybchik /* Request complete */ 351283514Sarybchik emip->emi_pending_req = NULL; 352283514Sarybchik seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ); 353283514Sarybchik 354283514Sarybchik /* Check for synchronous reboot */ 355291985Sarybchik if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR) != 0 && data_len == 0) { 356283514Sarybchik /* The MC has rebooted since the request was sent. */ 357283514Sarybchik EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 358283514Sarybchik hunt_mcdi_poll_reboot(enp); 359283514Sarybchik 360283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 361283514Sarybchik rc = EIO; 362283514Sarybchik goto fail1; 363283514Sarybchik } 364283514Sarybchik 365283514Sarybchik /* Ensure stale MCDI requests fail after an MC reboot. */ 366283514Sarybchik emip->emi_new_epoch = B_FALSE; 367283514Sarybchik 368283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 369283514Sarybchik 370283514Sarybchik /* Check that the returned data is consistent */ 371283514Sarybchik if (cmd != emrp->emr_cmd || 372291677Sarybchik EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ) != seq) { 373283514Sarybchik /* Response is for a different request */ 374283514Sarybchik rc = EIO; 375283514Sarybchik goto fail2; 376283514Sarybchik } 377291677Sarybchik if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR)) { 378291677Sarybchik efx_dword_t err[2]; 379291985Sarybchik unsigned int err_len = MIN(data_len, sizeof (err)); 380291985Sarybchik int err_code = MC_CMD_ERR_EPROTO; 381291985Sarybchik int err_arg = 0; 382283514Sarybchik 383283514Sarybchik /* Read error code (and arg num for MCDI v2 commands) */ 384291985Sarybchik hunt_mcdi_read_response(enp, &err[0], hdr_len, err_len); 385283514Sarybchik 386291985Sarybchik if (err_len >= MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)) 387291985Sarybchik err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0); 388283514Sarybchik 389291985Sarybchik if (err_len >= MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)) 390291985Sarybchik err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0); 391291985Sarybchik 392291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING 393291677Sarybchik if (emtp->emt_logger != NULL) { 394291677Sarybchik emtp->emt_logger(emtp->emt_context, 395291677Sarybchik EFX_LOG_MCDI_RESPONSE, 396291985Sarybchik &hdr, hdr_len, 397291985Sarybchik &err, err_len); 398291677Sarybchik } 399291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 400291677Sarybchik 401291985Sarybchik rc = efx_mcdi_request_errcode(err_code); 402283514Sarybchik if (!emrp->emr_quiet) { 403283514Sarybchik EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, 404291985Sarybchik int, err_code, int, err_arg); 405283514Sarybchik } 406283514Sarybchik goto fail3; 407283514Sarybchik 408283514Sarybchik } else { 409291985Sarybchik emrp->emr_out_length_used = data_len; 410283514Sarybchik emrp->emr_rc = 0; 411283514Sarybchik hunt_mcdi_request_copyout(enp, emrp); 412283514Sarybchik } 413283514Sarybchik 414283514Sarybchik goto out; 415283514Sarybchik 416283514Sarybchikfail3: 417283514Sarybchik if (!emrp->emr_quiet) 418283514Sarybchik EFSYS_PROBE(fail3); 419283514Sarybchikfail2: 420283514Sarybchik if (!emrp->emr_quiet) 421283514Sarybchik EFSYS_PROBE(fail2); 422283514Sarybchikfail1: 423283514Sarybchik if (!emrp->emr_quiet) 424291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 425283514Sarybchik 426283514Sarybchik /* Fill out error state */ 427283514Sarybchik emrp->emr_rc = rc; 428283514Sarybchik emrp->emr_out_length_used = 0; 429283514Sarybchik 430283514Sarybchik /* Reboot/Assertion */ 431283514Sarybchik if (rc == EIO || rc == EINTR) 432283514Sarybchik efx_mcdi_raise_exception(enp, emrp, rc); 433283514Sarybchik 434283514Sarybchikout: 435283514Sarybchik return (B_TRUE); 436283514Sarybchik} 437283514Sarybchik 438291436Sarybchik efx_rc_t 439283514Sarybchikhunt_mcdi_poll_reboot( 440283514Sarybchik __in efx_nic_t *enp) 441283514Sarybchik{ 442283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 443283514Sarybchik efx_dword_t dword; 444283514Sarybchik uint32_t old_status; 445283514Sarybchik uint32_t new_status; 446291436Sarybchik efx_rc_t rc; 447283514Sarybchik 448283514Sarybchik old_status = emip->emi_mc_reboot_status; 449283514Sarybchik 450283514Sarybchik /* Update MC reboot status word */ 451283514Sarybchik EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 452283514Sarybchik new_status = dword.ed_u32[0]; 453283514Sarybchik 454283514Sarybchik /* MC has rebooted if the value has changed */ 455283514Sarybchik if (new_status != old_status) { 456283514Sarybchik emip->emi_mc_reboot_status = new_status; 457283514Sarybchik 458283514Sarybchik /* 459283514Sarybchik * FIXME: Ignore detected MC REBOOT for now. 460283514Sarybchik * 461283514Sarybchik * The Siena support for checking for MC reboot from status 462283514Sarybchik * flags is broken - see comments in siena_mcdi_poll_reboot(). 463283514Sarybchik * As the generic MCDI code is shared the Huntington reboot 464283514Sarybchik * detection suffers similar problems. 465283514Sarybchik * 466283514Sarybchik * Do not report an error when the boot status changes until 467283514Sarybchik * this can be handled by common code drivers (and reworked to 468283514Sarybchik * support Siena too). 469283514Sarybchik */ 470283514Sarybchik if (B_FALSE) { 471283514Sarybchik rc = EIO; 472283514Sarybchik goto fail1; 473283514Sarybchik } 474283514Sarybchik } 475283514Sarybchik 476283514Sarybchik return (0); 477283514Sarybchik 478283514Sarybchikfail1: 479291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 480283514Sarybchik 481283514Sarybchik return (rc); 482283514Sarybchik} 483283514Sarybchik 484291436Sarybchik __checkReturn efx_rc_t 485283514Sarybchikhunt_mcdi_fw_update_supported( 486283514Sarybchik __in efx_nic_t *enp, 487283514Sarybchik __out boolean_t *supportedp) 488283514Sarybchik{ 489283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 490283514Sarybchik 491283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 492283514Sarybchik 493291585Sarybchik /* 494291585Sarybchik * Use privilege mask state at MCDI attach. 495291585Sarybchik * Admin privilege must be used prior to introduction of 496291585Sarybchik * specific flag. 497291585Sarybchik */ 498283514Sarybchik *supportedp = (encp->enc_privilege_mask & 499283514Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) 500283514Sarybchik == MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN; 501283514Sarybchik 502283514Sarybchik return (0); 503283514Sarybchik} 504283514Sarybchik 505291436Sarybchik __checkReturn efx_rc_t 506283514Sarybchikhunt_mcdi_macaddr_change_supported( 507283514Sarybchik __in efx_nic_t *enp, 508283514Sarybchik __out boolean_t *supportedp) 509283514Sarybchik{ 510283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 511291585Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 512283514Sarybchik 513283514Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 514283514Sarybchik 515291585Sarybchik /* 516291585Sarybchik * Use privilege mask state at MCDI attach. 517291585Sarybchik * Admin privilege must be used prior to introduction of 518291585Sarybchik * specific flag (at v4.6). 519291585Sarybchik */ 520291585Sarybchik *supportedp = 521291585Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING) == 522291585Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING) || 523291585Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) == 524291585Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN); 525283514Sarybchik 526283514Sarybchik return (0); 527283514Sarybchik} 528283514Sarybchik 529291588Sarybchik __checkReturn efx_rc_t 530291588Sarybchikhunt_mcdi_link_control_supported( 531291588Sarybchik __in efx_nic_t *enp, 532291588Sarybchik __out boolean_t *supportedp) 533291588Sarybchik{ 534291588Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 535291588Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 536291588Sarybchik 537291588Sarybchik EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 538291588Sarybchik 539291588Sarybchik /* 540291588Sarybchik * Use privilege mask state at MCDI attach. 541291588Sarybchik * Admin privilege used prior to introduction of 542291588Sarybchik * specific flag. 543291588Sarybchik */ 544291588Sarybchik *supportedp = 545291588Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK) == 546291588Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK) || 547291588Sarybchik ((privilege_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN) == 548291588Sarybchik MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN); 549291588Sarybchik 550291588Sarybchik return (0); 551291588Sarybchik} 552291588Sarybchik 553283514Sarybchik#endif /* EFSYS_OPT_MCDI */ 554283514Sarybchik 555283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 556