sfc: Clean up waits for flash/EEPROM operations
authorBen Hutchings <bhutchings@solarflare.com>
Sat, 13 Dec 2008 05:33:50 +0000 (21:33 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Dec 2008 05:57:35 +0000 (21:57 -0800)
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>
drivers/net/sfc/falcon.c
drivers/net/sfc/mtd.c
drivers/net/sfc/spi.h

index 1d160daf83bbd5aefe48de82e7d6c9cf065819a4..5113085604877691b064c1f0d45380db78870044 100644 (file)
@@ -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;
 
index a1e6c2875fc086c93c36c7dd9a32e5137c1b4dd8..665cafb88d6a087a190b0391497a681442109018 100644 (file)
@@ -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;
 
index 38e22ff4d7afd63b0191e601c5dc5c46a9fb008a..1b1ceb41167193f13279a1d29aa17446c4886364 100644 (file)
@@ -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,