spi: Helper for deriving timeout values
Merge series from Miquel Raynal <miquel.raynal@bootlin.com>: I recently came across an issue with the Atmel spi controller driver which would stop my transfers after a too small timeout when performing big transfers (reading a 4MiB flash in one transfer). My initial idea was to derive a the maximum amount of time a transfer would take depending on its size and use that as value to avoid erroring-out when not relevant. Mark wanted to go further by creating a core helper doing that, based on the heuristics from the sun6i driver. Here is a small series of 3 patches doing exactly that.
This commit is contained in:
commit
a77541cab0
@ -233,7 +233,8 @@
|
||||
*/
|
||||
#define DMA_MIN_BYTES 16
|
||||
|
||||
#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
|
||||
#define SPI_DMA_MIN_TIMEOUT (msecs_to_jiffies(1000))
|
||||
#define SPI_DMA_TIMEOUT_PER_10K (msecs_to_jiffies(4))
|
||||
|
||||
#define AUTOSUSPEND_TIMEOUT 2000
|
||||
|
||||
@ -1279,7 +1280,8 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
|
||||
struct atmel_spi_device *asd;
|
||||
int timeout;
|
||||
int ret;
|
||||
unsigned long dma_timeout;
|
||||
unsigned int dma_timeout;
|
||||
long ret_timeout;
|
||||
|
||||
as = spi_controller_get_devdata(host);
|
||||
|
||||
@ -1333,11 +1335,13 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
|
||||
atmel_spi_unlock(as);
|
||||
}
|
||||
|
||||
dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
|
||||
SPI_DMA_TIMEOUT);
|
||||
if (WARN_ON(dma_timeout == 0)) {
|
||||
dev_err(&spi->dev, "spi transfer timeout\n");
|
||||
as->done_status = -EIO;
|
||||
dma_timeout = msecs_to_jiffies(spi_controller_xfer_timeout(host, xfer));
|
||||
ret_timeout = wait_for_completion_interruptible_timeout(&as->xfer_completion,
|
||||
dma_timeout);
|
||||
if (ret_timeout <= 0) {
|
||||
dev_err(&spi->dev, "spi transfer %s\n",
|
||||
!ret_timeout ? "timeout" : "canceled");
|
||||
as->done_status = ret_timeout < 0 ? ret_timeout : -EIO;
|
||||
}
|
||||
|
||||
if (as->done_status)
|
||||
|
@ -455,7 +455,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
|
||||
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
|
||||
|
||||
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
|
||||
tx_time = spi_controller_xfer_timeout(master, tfr);
|
||||
start = jiffies;
|
||||
timeout = wait_for_completion_timeout(&sspi->done,
|
||||
msecs_to_jiffies(tx_time));
|
||||
|
@ -1261,6 +1261,23 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_controller_xfer_timeout - Compute a suitable timeout value
|
||||
* @ctlr: SPI device
|
||||
* @xfer: Transfer descriptor
|
||||
*
|
||||
* Compute a relevant timeout value for the given transfer. We derive the time
|
||||
* that it would take on a single data line and take twice this amount of time
|
||||
* with a minimum of 500ms to avoid false positives on loaded systems.
|
||||
*
|
||||
* Returns: Transfer timeout value in milliseconds.
|
||||
*/
|
||||
static inline unsigned int spi_controller_xfer_timeout(struct spi_controller *ctlr,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
return max(xfer->len * 8 * 2 / (xfer->speed_hz / 1000), 500U);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* SPI transfer replacement methods which make use of spi_res */
|
||||
|
Loading…
x
Reference in New Issue
Block a user