Exemplo n.º 1
0
void
efx_mcdi_request_start(
    __in		efx_nic_t *enp,
    __in		efx_mcdi_req_t *emrp,
    __in		boolean_t ev_cpl)
{
    efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
    efx_dword_t dword;
    unsigned int seq;
    unsigned int xflags;
    unsigned int pdur;
    unsigned int dbr;
    unsigned int pos;
    int state;

    EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
    EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
    EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);

    switch (emip->emi_port)	{
    case 1:
        pdur = MCDI_P1_PDU_OFST;
        dbr = MCDI_P1_DBL_OFST;
        break;
    case 2:
        pdur = MCDI_P2_PDU_OFST;
        dbr = MCDI_P2_DBL_OFST;
        break;
    default:
        EFSYS_ASSERT(0);
        pdur = dbr = 0;
    };

    /*
     * efx_mcdi_request_start() is naturally serialised against both
     * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
     * by virtue of there only being one oustanding MCDI request.
     * Unfortunately, upper layers may also call efx_mcdi_request_abort()
     * at any time, to timeout a pending mcdi request, That request may
     * then subsequently complete, meaning efx_mcdi_ev_cpl() or
     * efx_mcdi_ev_death() may end up running in parallel with
     * efx_mcdi_request_start(). This race is handled by ensuring that
     * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
     * en_eslp lock.
     */
    EFSYS_LOCK(enp->en_eslp, state);
    EFSYS_ASSERT(emip->emi_pending_req == NULL);
    emip->emi_pending_req = emrp;
    emip->emi_ev_cpl = ev_cpl;
    emip->emi_poll_cnt = 0;
    seq = emip->emi_seq++ & 0xf;
    EFSYS_UNLOCK(enp->en_eslp, state);

    xflags = 0;
    if (ev_cpl)
        xflags |= MCDI_HEADER_XFLAGS_EVREQ;

    /* Construct the header in shared memory */
    EFX_POPULATE_DWORD_6(dword,
                         MCDI_HEADER_CODE, emrp->emr_cmd,
                         MCDI_HEADER_RESYNC, 1,
                         MCDI_HEADER_DATALEN, emrp->emr_in_length,
                         MCDI_HEADER_SEQ, seq,
                         MCDI_HEADER_RESPONSE, 0,
                         MCDI_HEADER_XFLAGS, xflags);
    EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);

    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));
        EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
                           pdur + 1 + (pos >> 2), &dword, B_FALSE);
    }

    /* Ring the doorbell */
    EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
    EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
}
Exemplo n.º 2
0
			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);
}