summaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/falcon.c
diff options
context:
space:
mode:
authorBen Hutchings2008-12-13 06:33:50 +0100
committerDavid S. Miller2008-12-13 06:57:35 +0100
commitbe4ea89c8df06f48d0d64cf1d9d20009e83c77c8 (patch)
treefb48f89ea32ef55e336242e33d6ccfd1f5ff4295 /drivers/net/sfc/falcon.c
parentsfc: Make reset_workqueue driver-global rather than per-NIC (diff)
downloadkernel-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/falcon.c')
-rw-r--r--drivers/net/sfc/falcon.c58
1 files changed, 37 insertions, 21 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, &reg, 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, &reg, 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;