static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; bool rx_fc = !!(efx->link_fc & EFX_FC_RX); EFX_POPULATE_DWORD_3(reg, XM_RX_JUMBO_MODE, 1, XM_TX_STAT_EN, 1, XM_RX_STAT_EN, 1); falcon_write(efx, ®, XM_GLB_CFG_REG); EFX_POPULATE_DWORD_6(reg, XM_TXEN, 1, XM_TX_PRMBL, 1, XM_AUTO_PAD, 1, XM_TXCRC, 1, XM_FCNTL, 1, XM_IPG, 0x3); falcon_write(efx, ®, XM_TX_CFG_REG); EFX_POPULATE_DWORD_5(reg, XM_RXEN, 1, XM_AUTO_DEPAD, 0, XM_ACPT_ALL_MCAST, 1, XM_ACPT_ALL_UCAST, efx->promiscuous, XM_PASS_CRC_ERR, 1); falcon_write(efx, ®, XM_RX_CFG_REG); max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); falcon_write(efx, ®, XM_RX_PARAM_REG); EFX_POPULATE_DWORD_2(reg, XM_MAX_TX_FRM_SIZE, max_frame_len, XM_TX_JUMBO_MODE, 1); falcon_write(efx, ®, XM_TX_PARAM_REG); EFX_POPULATE_DWORD_2(reg, XM_PAUSE_TIME, 0xfffe, XM_DIS_FCNTL, !rx_fc); falcon_write(efx, ®, XM_FC_REG); EFX_POPULATE_DWORD_4(reg, XM_ADR_0, efx->net_dev->dev_addr[0], XM_ADR_1, efx->net_dev->dev_addr[1], XM_ADR_2, efx->net_dev->dev_addr[2], XM_ADR_3, efx->net_dev->dev_addr[3]); falcon_write(efx, ®, XM_ADR_LO_REG); EFX_POPULATE_DWORD_2(reg, XM_ADR_4, efx->net_dev->dev_addr[4], XM_ADR_5, efx->net_dev->dev_addr[5]); falcon_write(efx, ®, XM_ADR_HI_REG); }
static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, size_t inlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); unsigned int i; efx_dword_t hdr; u32 xflags, seqno; BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); BUG_ON(inlen & 3 || inlen >= 0x100); seqno = mcdi->seqno & SEQ_MASK; xflags = 0; if (mcdi->mode == MCDI_MODE_EVENTS) xflags |= MCDI_HEADER_XFLAGS_EVREQ; EFX_POPULATE_DWORD_6(hdr, MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_RESYNC, 1, MCDI_HEADER_CODE, cmd, MCDI_HEADER_DATALEN, inlen, MCDI_HEADER_SEQ, seqno, MCDI_HEADER_XFLAGS, xflags); efx_writed(efx, &hdr, pdu); for (i = 0; i < inlen; i += 4) { _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); /* use wmb() within loop to inhibit write combining */ wmb(); } /* ring the doorbell with a distinctive value */ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); wmb(); }
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); }