diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-09-18 05:33:56 +0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2013-08-21 22:43:27 +0400 |
commit | f3ad50034425692965a0f2becdd9c45ecb45cd66 (patch) | |
tree | 0ada5470ce0cc43c1589ebd619bba22716b4844f /drivers/net/ethernet/sfc/siena.c | |
parent | f073dde03b3e8d11050d82f52caaf75fd924e069 (diff) | |
download | linux-f3ad50034425692965a0f2becdd9c45ecb45cd66.tar.xz |
sfc: Make MCDI independent of Siena
Move the lowest layer (transport) of the current MCDI code to
per-NIC-type operations.
Introduce a new structure and efx_nic member for MCDI-specific data.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/siena.c')
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 3dca771938f0..73b511af33f9 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -274,6 +274,7 @@ fail4: fail3: efx_mcdi_drv_attach(efx, false, NULL); fail2: + efx_mcdi_fini(efx); fail1: kfree(efx->nic_data); return rc; @@ -367,6 +368,8 @@ static void siena_remove_nic(struct efx_nic *efx) /* Tear down the private nic state */ kfree(efx->nic_data); efx->nic_data = NULL; + + efx_mcdi_fini(efx); } static int siena_try_update_nic_stats(struct efx_nic *efx) @@ -574,6 +577,89 @@ static void siena_init_wol(struct efx_nic *efx) } } +/************************************************************************** + * + * MCDI + * + ************************************************************************** + */ + +#define MCDI_PDU(efx) \ + (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) +#define MCDI_DOORBELL(efx) \ + (efx_port_num(efx) ? MC_SMEM_P1_DOORBELL_OFST : MC_SMEM_P0_DOORBELL_OFST) +#define MCDI_STATUS(efx) \ + (efx_port_num(efx) ? MC_SMEM_P1_STATUS_OFST : MC_SMEM_P0_STATUS_OFST) + +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_BUG_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 bool siena_mcdi_poll_response(struct efx_nic *efx) +{ + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + efx_dword_t hdr; + + efx_readd(efx, &hdr, pdu); + + /* All 1's indicates that shared memory is in reset (and is + * not a valid hdr). Wait for it to come out reset before + * completing the command + */ + return EFX_DWORD_FIELD(hdr, EFX_DWORD_0) != 0xffffffff && + EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE); +} + +static void siena_mcdi_read_response(struct efx_nic *efx, efx_dword_t *outbuf, + size_t offset, size_t outlen) +{ + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int outlen_dw = DIV_ROUND_UP(outlen, 4); + int i; + + for (i = 0; i < outlen_dw; i++) + efx_readd(efx, &outbuf[i], pdu + offset + 4 * i); +} + +static int siena_mcdi_poll_reboot(struct efx_nic *efx) +{ + 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); + + if (value == MC_STATUS_DWORD_ASSERT) + return -EINTR; + else + return -EIO; +} /************************************************************************** * @@ -613,6 +699,10 @@ const struct efx_nic_type siena_a0_nic_type = { .resume_wol = siena_init_wol, .test_chip = siena_test_chip, .test_nvram = efx_mcdi_nvram_test_all, + .mcdi_request = siena_mcdi_request, + .mcdi_poll_response = siena_mcdi_poll_response, + .mcdi_read_response = siena_mcdi_read_response, + .mcdi_poll_reboot = siena_mcdi_poll_reboot, .revision = EFX_REV_SIENA_A0, .mem_map_size = (FR_CZ_MC_TREG_SMEM + |