From patchwork Fri Mar 20 10:14:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rasmus Villemoes X-Patchwork-Id: 244003 List-Id: U-Boot discussion From: rasmus.villemoes at prevas.dk (Rasmus Villemoes) Date: Fri, 20 Mar 2020 11:14:48 +0100 Subject: [PATCH v2 2/2] spi: allow calling WATCHDOG_RESET during long reads In-Reply-To: <20200320101448.10714-1-rasmus.villemoes@prevas.dk> References: <20200316201832.28693-1-rasmus.villemoes@prevas.dk> <20200320101448.10714-1-rasmus.villemoes@prevas.dk> Message-ID: <20200320101448.10714-2-rasmus.villemoes@prevas.dk> Some boards have a watchdog with a short (~1s) timeout and a slowish nor flash. For example, I'm currently working on a board where doing a 2MB read from the flash will cause the board to reset. Similar to the various CHUNKSZ, CHUNKSZ_SHA1 etc. defines that are used to chop hash digest and/or memmove operations into chunks, doing a WATCHDOG_RESET for each, introduce a CONFIG_SPI_FLASH_READ_CHUNKSZ config knob. We keep the default of doing the whole read in one go, but the board config can set a suitable threshold. Signed-off-by: Rasmus Villemoes --- drivers/mtd/spi/Kconfig | 12 ++++++++++++ drivers/mtd/spi/spi-nor-core.c | 4 +++- drivers/mtd/spi/spi-nor-tiny.c | 4 +++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 018e8c597e..9dda0047d2 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -169,6 +169,18 @@ config SPI_FLASH_USE_4K_SECTORS Please note that some tools/drivers/filesystems may not work with 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). +config SPI_FLASH_READ_CHUNKSZ + int "Chunk size for reading from SPI flash" + depends on SPI_FLASH + default 0 + help + Some boards have a watchdog with a very short timeout + period. Doing large reads from a SPI flash on such a board + causes the watchdog to fire and reset the board. Setting + this option to a non-zero value will ensure that + watchdog_reset() gets called after each read of that many + bytes. + config SPI_FLASH_DATAFLASH bool "AT45xxx DataFlash support" depends on SPI_FLASH && DM_SPI_FLASH diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index c5d98debf0..8c846a4b42 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -82,6 +82,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, SPI_MEM_OP_DUMMY(nor->read_dummy, 1), SPI_MEM_OP_DATA_IN(len, buf, 1)); size_t remaining = len; + size_t chunksz = CONFIG_SPI_FLASH_READ_CHUNKSZ ?: UINT_MAX; int ret; /* get transfer protocols. */ @@ -94,7 +95,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; while (remaining) { - op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + op.data.nbytes = min(remaining, chunksz); ret = spi_mem_adjust_op_size(nor->spi, &op); if (ret) return ret; @@ -102,6 +103,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, ret = spi_mem_exec_op(nor->spi, &op); if (ret) return ret; + WATCHDOG_RESET(); op.addr.val += op.data.nbytes; remaining -= op.data.nbytes; diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index d91989567d..e9d490ba52 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -81,6 +81,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, SPI_MEM_OP_DUMMY(nor->read_dummy, 1), SPI_MEM_OP_DATA_IN(len, buf, 1)); size_t remaining = len; + size_t chunksz = CONFIG_SPI_FLASH_READ_CHUNKSZ ?: UINT_MAX; int ret; /* get transfer protocols. */ @@ -93,7 +94,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; while (remaining) { - op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + op.data.nbytes = min(remaining, chunksz); ret = spi_mem_adjust_op_size(nor->spi, &op); if (ret) return ret; @@ -101,6 +102,7 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, ret = spi_mem_exec_op(nor->spi, &op); if (ret) return ret; + WATCHDOG_RESET(); op.addr.val += op.data.nbytes; remaining -= op.data.nbytes;