From patchwork Fri Mar 20 10:14:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rasmus Villemoes X-Patchwork-Id: 244002 List-Id: U-Boot discussion From: rasmus.villemoes at prevas.dk (Rasmus Villemoes) Date: Fri, 20 Mar 2020 11:14:47 +0100 Subject: [PATCH v2 1/2] spi: call WATCHDOG_RESET() in spi_nor_wait_till_ready_with_timeout() In-Reply-To: <20200316201832.28693-1-rasmus.villemoes@prevas.dk> References: <20200316201832.28693-1-rasmus.villemoes@prevas.dk> Message-ID: <20200320101448.10714-1-rasmus.villemoes@prevas.dk> I have a board for which doing "sf erase 0x100000 0x80000" consistently causes the external watchdog circuit to reset the board. Make sure to pet the watchdog during slow operations such as erasing or writing large areas of a spi nor flash. Signed-off-by: Rasmus Villemoes --- drivers/mtd/spi/spi-nor-core.c | 2 ++ drivers/mtd/spi/spi-nor-tiny.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 7b6ad495ac..c5d98debf0 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "sf_internal.h" @@ -424,6 +425,7 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, unsigned long timebase; int ret; + WATCHDOG_RESET(); timebase = get_timer(0); while (get_timer(timebase) < timeout) { diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index ccc0ab07af..d91989567d 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sf_internal.h" @@ -324,6 +325,7 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, unsigned long timebase; int ret; + WATCHDOG_RESET(); timebase = get_timer(0); while (get_timer(timebase) < timeout) { 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;