summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2023-06-23 03:31:11 +0300
committerMark Brown <broonie@kernel.org>2023-06-23 03:31:11 +0300
commita77541cab0be8c8a68f70cdeb68359fbe15e4612 (patch)
tree369476450a9fda7456f764e2be68035f6c8fced8 /drivers/spi
parent01fa9edd8bcf1c4fe330ea000c3da9ecf76c76a0 (diff)
parent6eef895581c9b5fcd002ff77837e0c3a4b1eecf6 (diff)
downloadlinux-a77541cab0be8c8a68f70cdeb68359fbe15e4612.tar.xz
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.
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-atmel.c18
-rw-r--r--drivers/spi/spi-sun6i.c2
2 files changed, 12 insertions, 8 deletions
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 7f06305e16cb..152cd6773403 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -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)
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 02a3a4f2b3a0..30d541612253 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -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));