static int siena_mcdi_poll_reboot(struct efx_nic *efx) { struct siena_nic_data *nic_data = efx->nic_data; unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx); efx_dword_t reg; u32 value; efx_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); efx_writed(efx, ®, addr); /* MAC statistics have been cleared on the NIC; clear the local * copies that we update with efx_update_diff_stat(). */ nic_data->stats[SIENA_STAT_tx_good_bytes] = 0; nic_data->stats[SIENA_STAT_rx_good_bytes] = 0; if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; else return -EIO; }
inline void falcon_irq_ack_a1(struct efx_nic *efx) { efx_dword_t reg; EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e); efx_writed(efx, ®, FR_AA_INT_ACK_KER); efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); }
static void siena_mcdi_request(struct efx_nic *efx, const efx_dword_t *hdr, size_t hdr_len, const efx_dword_t *sdu, size_t sdu_len) { unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); unsigned int i; unsigned int inlen_dw = DIV_ROUND_UP(sdu_len, 4); EFX_WARN_ON_PARANOID(hdr_len != 4); efx_writed(efx, hdr, pdu); for (i = 0; i < inlen_dw; i++) efx_writed(efx, &sdu[i], pdu + hdr_len + 4 * i); /* Ensure the request is written out before the doorbell */ wmb(); /* ring the doorbell with a distinctive value */ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); }
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(); }
/* Test and clear MC-rebooted flag for this port/function */ int efx_mcdi_poll_reboot(struct efx_nic *efx) { unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); efx_dword_t reg; uint32_t value; if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) return false; efx_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); efx_writed(efx, ®, addr); if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; else return -EIO; }