__checkReturn efx_rc_t ef10_mcdi_init( __in efx_nic_t *enp, __in const efx_mcdi_transport_t *emtp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efsys_mem_t *esmp = emtp->emt_dma_mem; efx_dword_t dword; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD || enp->en_family == EFX_FAMILY_MEDFORD2); EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); /* * All EF10 firmware supports MCDIv2 and MCDIv1. * Medford BootROM supports MCDIv2 and MCDIv1. * Huntington BootROM supports MCDIv1 only. */ emip->emi_max_version = 2; /* A host DMA buffer is required for EF10 MCDI */ if (esmp == NULL) { rc = EINVAL; goto fail1; } /* * Ensure that the MC doorbell is in a known state before issuing MCDI * commands. The recovery algorithm requires that the MC command buffer * must be 256 byte aligned. See bug24769. */ if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { rc = EINVAL; goto fail2; } EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); /* Save initial MC reboot status */ (void) ef10_mcdi_poll_reboot(enp); /* Start a new epoch (allow fresh MCDI requests to succeed) */ efx_mcdi_new_epoch(enp); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); }
void ef10_mcdi_send_request( __in efx_nic_t *enp, __in void *hdrp, __in size_t hdr_len, __in void *sdup, __in size_t sdu_len) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efsys_mem_t *esmp = emtp->emt_dma_mem; efx_dword_t dword; unsigned int pos; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); /* Write the header */ for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) { dword = *(efx_dword_t *)((uint8_t *)hdrp + pos); EFSYS_MEM_WRITED(esmp, pos, &dword); } /* Write the payload */ for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { dword = *(efx_dword_t *)((uint8_t *)sdup + pos); EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword); } /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len); EFSYS_PIO_WRITE_BARRIER(); /* Ring the doorbell to post the command DMA address to the MC */ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32); EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff); EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); }
void hunt_mcdi_request_copyin( __in efx_nic_t *enp, __in efx_mcdi_req_t *emrp, __in unsigned int seq, __in boolean_t ev_cpl, __in boolean_t new_epoch) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efsys_mem_t *esmp = emtp->emt_dma_mem; efx_mcdi_header_type_t hdr_type; efx_dword_t dword; efx_dword_t hdr[2]; unsigned int xflags; unsigned int pos; size_t offset; EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); xflags = 0; if (ev_cpl) xflags |= MCDI_HEADER_XFLAGS_EVREQ; offset = 0; hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd, MAX(emrp->emr_in_length, emrp->emr_out_length)); if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) { /* Construct MCDI v2 header */ EFX_POPULATE_DWORD_8(hdr[0], MCDI_HEADER_CODE, MC_CMD_V2_EXTN, MCDI_HEADER_RESYNC, 1, MCDI_HEADER_DATALEN, 0, MCDI_HEADER_SEQ, seq, MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, MCDI_HEADER_ERROR, 0, MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_XFLAGS, xflags); EFSYS_MEM_WRITED(esmp, offset, &hdr[0]); offset += sizeof (efx_dword_t); EFX_POPULATE_DWORD_2(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); EFSYS_MEM_WRITED(esmp, offset, &hdr[1]); offset += sizeof (efx_dword_t); } else { /* Construct MCDI v1 header */ EFX_POPULATE_DWORD_8(hdr[0], MCDI_HEADER_CODE, emrp->emr_cmd, MCDI_HEADER_RESYNC, 1, MCDI_HEADER_DATALEN, emrp->emr_in_length, MCDI_HEADER_SEQ, seq, MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, MCDI_HEADER_ERROR, 0, MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_XFLAGS, xflags); EFSYS_MEM_WRITED(esmp, 0, &hdr[0]); offset += sizeof (efx_dword_t); } #if EFSYS_OPT_MCDI_LOGGING if (emtp->emt_logger != NULL) { emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, &hdr, offset, emrp->emr_in_buf, emrp->emr_in_length); } #endif /* EFSYS_OPT_MCDI_LOGGING */ /* Construct the payload */ for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), MIN(sizeof (dword), emrp->emr_in_length - pos)); EFSYS_MEM_WRITED(esmp, offset + pos, &dword); } /* Ring the doorbell to post the command DMA address to the MC */ EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0); /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length); EFSYS_PIO_WRITE_BARRIER(); EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32); EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff); EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); }