/* Wait for SPI command completion */ static int falcon_spi_wait(struct efx_nic *efx) { /* Most commands will finish quickly, so we start polling at * very short intervals. Sometimes the command may have to * wait for VPD or expansion ROM access outside of our * control, so we allow up to 100 ms. */ unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); int i; for (i = 0; i < 10; i++) { if (!falcon_spi_poll(efx)) return 0; udelay(10); } for (;;) { if (!falcon_spi_poll(efx)) return 0; if (time_after_eq(jiffies, timeout)) { netif_err(efx, hw, efx->net_dev, "timed out waiting for SPI\n"); return -ETIMEDOUT; } schedule_timeout_uninterruptible(1); } }
int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, unsigned int command, int address, const void *in, void *out, size_t len) { bool addressed = (address >= 0); bool reading = (out != NULL); efx_oword_t reg; int rc; /* Input validation */ if (len > FALCON_SPI_MAX_LEN) return -EINVAL; BUG_ON(!mutex_is_locked(&efx->spi_lock)); /* Check that previous command is not still running */ rc = falcon_spi_poll(efx); if (rc) return rc; /* Program address register, if we have an address */ if (addressed) { EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); efx_writeo(efx, ®, FR_AB_EE_SPI_HADR); } /* Program data register, if we have data */ if (in != NULL) { memcpy(®, in, len); efx_writeo(efx, ®, FR_AB_EE_SPI_HDATA); } /* Issue read/write command */ EFX_POPULATE_OWORD_7(reg, FRF_AB_EE_SPI_HCMD_CMD_EN, 1, FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, FRF_AB_EE_SPI_HCMD_DABCNT, len, FRF_AB_EE_SPI_HCMD_READ, reading, FRF_AB_EE_SPI_HCMD_DUBCNT, 0, FRF_AB_EE_SPI_HCMD_ADBCNT, (addressed ? spi->addr_len : 0), FRF_AB_EE_SPI_HCMD_ENC, command); efx_writeo(efx, ®, FR_AB_EE_SPI_HCMD); /* Wait for read/write to complete */ rc = falcon_spi_wait(efx); if (rc) return rc; /* Read data */ if (out != NULL) { efx_reado(efx, ®, FR_AB_EE_SPI_HDATA); memcpy(out, ®, len); } return 0; }
int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, unsigned int command, int address, const void *in, void *out, size_t len) { bool addressed = (address >= 0); bool reading = (out != NULL); efx_oword_t reg; int rc; if (len > FALCON_SPI_MAX_LEN) return -EINVAL; rc = falcon_spi_poll(efx); if (rc) return rc; if (addressed) { EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); efx_writeo(efx, ®, FR_AB_EE_SPI_HADR); } if (in != NULL) { memcpy(®, in, len); efx_writeo(efx, ®, FR_AB_EE_SPI_HDATA); } EFX_POPULATE_OWORD_7(reg, FRF_AB_EE_SPI_HCMD_CMD_EN, 1, FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, FRF_AB_EE_SPI_HCMD_DABCNT, len, FRF_AB_EE_SPI_HCMD_READ, reading, FRF_AB_EE_SPI_HCMD_DUBCNT, 0, FRF_AB_EE_SPI_HCMD_ADBCNT, (addressed ? spi->addr_len : 0), FRF_AB_EE_SPI_HCMD_ENC, command); efx_writeo(efx, ®, FR_AB_EE_SPI_HCMD); rc = falcon_spi_wait(efx); if (rc) return rc; if (out != NULL) { efx_reado(efx, ®, FR_AB_EE_SPI_HDATA); memcpy(out, ®, len); } return 0; }
static int falcon_spi_wait(struct efx_nic *efx) { unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); int i; for (i = 0; i < 10; i++) { if (!falcon_spi_poll(efx)) return 0; udelay(10); } for (;;) { if (!falcon_spi_poll(efx)) return 0; if (time_after_eq(jiffies, timeout)) { netif_err(efx, hw, efx->net_dev, "timed out waiting for SPI\n"); return -ETIMEDOUT; } schedule_timeout_uninterruptible(1); } }