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 <[email protected]>
---
 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;
-- 
2.23.0

Reply via email to