mtd: spi-nor: scale up timeout for full-chip erase

This patch fixes timeout issues seen on large NOR flash.
For full-chip erase, where we use the SPINOR_OP_CHIP_ERASE (0xc7)
opcode. Use a different timeout for full-chip erase than for other
commands.

 [Ported from Linux kernel commit
                09b6a377687b ("mtd: spi-nor: scale up timeout for
                               full-chip erase") ]

Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com>
This commit is contained in:
Venkatesh Yadav Abbarapu
2024-09-19 16:42:31 -06:00
committed by Tom Rini
parent 146be6f036
commit 948616894c
+29 -2
View File
@@ -44,6 +44,12 @@
#define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ)
/*
* For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
* for larger flash
*/
#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y))
struct sfdp_parameter_header {
@@ -855,6 +861,20 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
DEFAULT_READY_WAIT_JIFFIES);
}
static int spi_nor_erase_chip_wait_till_ready(struct spi_nor *nor, unsigned long size)
{
/*
* Scale the timeout linearly with the size of the flash, with
* a minimum calibrated to an old 2MB flash. We could try to
* pull these from CFI/SFDP, but these values should be good
* enough for now.
*/
unsigned long timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
(unsigned long)(size / SZ_2M));
return spi_nor_wait_till_ready_with_timeout(nor, timeout);
}
#ifdef CONFIG_SPI_FLASH_BAR
/*
* This "clean_bar" is necessary in a situation when one was accessing
@@ -989,7 +1009,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
bool addr_known = false;
u32 addr, len, rem;
u32 addr, len, rem, max_size;
int ret, err;
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
@@ -1003,6 +1023,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
addr = instr->addr;
len = instr->len;
max_size = instr->len;
instr->state = MTD_ERASING;
addr_known = true;
@@ -1035,7 +1056,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
addr += ret;
len -= ret;
ret = spi_nor_wait_till_ready(nor);
if (max_size == mtd->size &&
!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
ret = spi_nor_erase_chip_wait_till_ready(nor, mtd->size);
} else {
ret = spi_nor_wait_till_ready(nor);
}
if (ret)
goto erase_err;
}