Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be4ea89c authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller
Browse files

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: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1ab00629
Loading
Loading
Loading
Loading
+37 −21
Original line number Original line Diff line number Diff line
@@ -1607,24 +1607,37 @@ void falcon_fini_interrupt(struct efx_nic *efx)


#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
#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 */
/* Wait for SPI command completion */
static int falcon_spi_wait(struct efx_nic *efx)
static int falcon_spi_wait(struct efx_nic *efx)
{
{
	unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10);
	/* Most commands will finish quickly, so we start polling at
	efx_oword_t reg;
	 * very short intervals.  Sometimes the command may have to
	bool cmd_en, timer_active;
	 * 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 (;;) {
	for (;;) {
		falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
		if (!falcon_spi_poll(efx))
		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)
			return 0;
			return 0;
		if (time_after_eq(jiffies, timeout)) {
		if (time_after_eq(jiffies, timeout)) {
			EFX_ERR(efx, "timed out waiting for SPI\n");
			EFX_ERR(efx, "timed out waiting for SPI\n");
			return -ETIMEDOUT;
			return -ETIMEDOUT;
		}
		}
		cpu_relax();
		schedule_timeout_uninterruptible(1);
	}
	}
}
}


@@ -1643,8 +1656,8 @@ int falcon_spi_cmd(const struct efx_spi_device *spi,
		return -EINVAL;
		return -EINVAL;
	BUG_ON(!mutex_is_locked(&efx->spi_lock));
	BUG_ON(!mutex_is_locked(&efx->spi_lock));


	/* Check SPI not currently being accessed */
	/* Check that previous command is not still running */
	rc = falcon_spi_wait(efx);
	rc = falcon_spi_poll(efx);
	if (rc)
	if (rc)
		return rc;
		return rc;


@@ -1700,27 +1713,30 @@ efx_spi_munge_command(const struct efx_spi_device *spi,
	return command | (((address >> 8) & spi->munge_address) << 3);
	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;
	u8 status;
	int i, rc;
	int rc;

	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
	for (i = 0; i < 50; i++) {
		udelay(20);


	for (;;) {
		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
				    &status, sizeof(status));
				    &status, sizeof(status));
		if (rc)
		if (rc)
			return rc;
			return rc;
		if (!(status & SPI_STATUS_NRDY))
		if (!(status & SPI_STATUS_NRDY))
			return 0;
			return 0;
	}
		if (time_after_eq(jiffies, timeout)) {
	EFX_ERR(spi->efx,
			EFX_ERR(efx, "SPI write timeout on device %d"
		"timed out waiting for device %d last status=0x%02x\n",
				" last status=0x%02x\n",
				spi->device_id, status);
				spi->device_id, status);
			return -ETIMEDOUT;
			return -ETIMEDOUT;
		}
		}
		schedule_timeout_uninterruptible(1);
	}
}


int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
		    size_t len, size_t *retlen, u8 *buffer)
		    size_t len, size_t *retlen, u8 *buffer)
@@ -1773,7 +1789,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
		if (rc)
		if (rc)
			break;
			break;


		rc = falcon_spi_fast_wait(spi);
		rc = falcon_spi_wait_write(spi);
		if (rc)
		if (rc)
			break;
			break;


+1 −1
Original line number Original line Diff line number Diff line
@@ -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));
	rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status));
	if (rc)
	if (rc)
		return rc;
		return rc;
	rc = falcon_spi_fast_wait(spi);
	rc = falcon_spi_wait_write(spi);
	if (rc)
	if (rc)
		return rc;
		return rc;


+1 −1
Original line number Original line Diff line number Diff line
@@ -69,7 +69,7 @@ struct efx_spi_device {


int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command,
int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command,
		   int address, const void* in, void *out, size_t len);
		   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,
int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
		    size_t len, size_t *retlen, u8 *buffer);
		    size_t len, size_t *retlen, u8 *buffer);
int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,