diff options
author | Ben Hutchings | 2008-12-13 06:33:50 +0100 |
---|---|---|
committer | David S. Miller | 2008-12-13 06:57:35 +0100 |
commit | be4ea89c8df06f48d0d64cf1d9d20009e83c77c8 (patch) | |
tree | fb48f89ea32ef55e336242e33d6ccfd1f5ff4295 /drivers/net/sfc | |
parent | sfc: Make reset_workqueue driver-global rather than per-NIC (diff) | |
download | kernel-qcow2-linux-be4ea89c8df06f48d0d64cf1d9d20009e83c77c8.tar.gz kernel-qcow2-linux-be4ea89c8df06f48d0d64cf1d9d20009e83c77c8.tar.xz kernel-qcow2-linux-be4ea89c8df06f48d0d64cf1d9d20009e83c77c8.zip |
sfc: Clean up waits for flash/EEPROM operations
Make falcon_spi_wait() ignore the write timer - it is only relevant to
write commands, it only works for the device that contains VPD, and it
might not be initialised properly at all.
Rename falcon_spi_fast_wait() to falcon_spi_wait_write(), reflecting
its use, and make it wait up to 10 ms (not 1 ms) since buffered writes
to EEPROM may take this long to complete.
Make both wait functions sleep instead of busy-waiting.
Replace wait for command completion at top of falcon_spi_cmd() with a
single poll; no command should be running when the function starts.
Correct some comments.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/falcon.c | 58 | ||||
-rw-r--r-- | drivers/net/sfc/mtd.c | 2 | ||||
-rw-r--r-- | drivers/net/sfc/spi.h | 2 |
3 files changed, 39 insertions, 23 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 1d160daf83bb..511308560487 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1607,24 +1607,37 @@ void falcon_fini_interrupt(struct efx_nic *efx) #define FALCON_SPI_MAX_LEN sizeof(efx_oword_t) +static int falcon_spi_poll(struct efx_nic *efx) +{ + efx_oword_t reg; + falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); + return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; +} + /* Wait for SPI command completion */ static int falcon_spi_wait(struct efx_nic *efx) { - unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10); - efx_oword_t reg; - bool cmd_en, timer_active; + /* 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 (;;) { - falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); - cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN); - timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE); - if (!cmd_en && !timer_active) + if (!falcon_spi_poll(efx)) return 0; if (time_after_eq(jiffies, timeout)) { EFX_ERR(efx, "timed out waiting for SPI\n"); return -ETIMEDOUT; } - cpu_relax(); + schedule_timeout_uninterruptible(1); } } @@ -1643,8 +1656,8 @@ int falcon_spi_cmd(const struct efx_spi_device *spi, return -EINVAL; BUG_ON(!mutex_is_locked(&efx->spi_lock)); - /* Check SPI not currently being accessed */ - rc = falcon_spi_wait(efx); + /* Check that previous command is not still running */ + rc = falcon_spi_poll(efx); if (rc) return rc; @@ -1700,26 +1713,29 @@ efx_spi_munge_command(const struct efx_spi_device *spi, return command | (((address >> 8) & spi->munge_address) << 3); } -int falcon_spi_fast_wait(const struct efx_spi_device *spi) +/* Wait up to 10 ms for buffered write completion */ +int falcon_spi_wait_write(const struct efx_spi_device *spi) { + struct efx_nic *efx = spi->efx; + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); u8 status; - int i, rc; - - /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */ - for (i = 0; i < 50; i++) { - udelay(20); + int rc; + for (;;) { rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; if (!(status & SPI_STATUS_NRDY)) return 0; + if (time_after_eq(jiffies, timeout)) { + EFX_ERR(efx, "SPI write timeout on device %d" + " last status=0x%02x\n", + spi->device_id, status); + return -ETIMEDOUT; + } + schedule_timeout_uninterruptible(1); } - EFX_ERR(spi->efx, - "timed out waiting for device %d last status=0x%02x\n", - spi->device_id, status); - return -ETIMEDOUT; } int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, @@ -1773,7 +1789,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, if (rc) break; - rc = falcon_spi_fast_wait(spi); + rc = falcon_spi_wait_write(spi); if (rc) break; diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index a1e6c2875fc0..665cafb88d6a 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -76,7 +76,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); if (rc) return rc; - rc = falcon_spi_fast_wait(spi); + rc = falcon_spi_wait_write(spi); if (rc) return rc; diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 38e22ff4d7af..1b1ceb411671 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -69,7 +69,7 @@ struct efx_spi_device { int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, int address, const void* in, void *out, size_t len); -int falcon_spi_fast_wait(const struct efx_spi_device *spi); +int falcon_spi_wait_write(const struct efx_spi_device *spi); int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer); int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, |