[PATCH 2/3] mtd: spi-nor: Implement die erase command logic
Cyrille Pitchen
cyrille.pitchen at atmel.com
Tue Nov 29 08:46:45 PST 2016
Hi Marcin,
I know you have already answered some of my questions of IRC but I ask
them again here on the mailing list so everybody can benefit from your
answers.
Le 24/10/2016 à 15:03, marcin.krzeminski at nokia.com a écrit :
> From: Marcin Krzeminski <marcin.krzeminski at nokia.com>
>
> This commit implements die erase logic.
> Sector at a time procedure is moved to function,
> then erase algorithm will try to use die erase cmd
> if size and address cover one or more dies.
>
I'm reading your v2 series but indeed I try to understand the purpose of the
series simply because I don't know what does die erase do as compared to chip
erase of sector erase.
Is you series a bug fix or an optmization, maybe both?
Best regards,
Cyrille
> Signed-off-by: Marcin Krzeminski <marcin.krzeminski at nokia.com>
> ---
> drivers/mtd/spi-nor/spi-nor.c | 90 +++++++++++++++++++++++++++++++++++++------
> 1 file changed, 78 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 3afe207..17bbec0 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -360,6 +360,29 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
> return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
> }
>
> +static inline int spi_nor_sector_at_time_erase(struct mtd_info *mtd, u32 addr, u32 len)
> +{
> + struct spi_nor *nor = mtd_to_spi_nor(mtd);
> + int ret = 0;
> +
> + while (len) {
> + write_enable(nor);
> +
> + ret = spi_nor_erase_sector(nor, addr);
> + if (ret)
> + return ret;
> +
> + addr += mtd->erasesize;
> + len -= mtd->erasesize;
> +
> + ret = spi_nor_wait_till_ready(nor);
> + if (ret)
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> /*
> * Erase an address range on the nor chip. The address range may extend
> * one or more erase sectors. Return an error is there is a problem erasing.
> @@ -367,9 +390,11 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
> static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
> {
> struct spi_nor *nor = mtd_to_spi_nor(mtd);
> - u32 addr, len;
> + u32 addr, len, die_no, die_size;
> uint32_t rem;
> int ret;
> + unsigned long timeout;
> + u8 die_erase = nor->die_cnt && SNOR_F_DIE_ERASE;
>
> dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
> (long long)instr->len);
> @@ -386,7 +411,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
> return ret;
>
> /* whole-chip erase? */
> - if (len == mtd->size) {
> + if (len == mtd->size && !die_erase) {
> unsigned long timeout;
>
> write_enable(nor);
> @@ -416,17 +441,58 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
>
> /* "sector"-at-a-time erase */
> } else {
> - while (len) {
> - write_enable(nor);
> -
> - ret = spi_nor_erase_sector(nor, addr);
> - if (ret)
> + if (die_erase) {
> + die_size = div_u64_rem(mtd->size, nor->die_cnt, &rem);
> + if (rem) {
> + ret = -EINVAL;
> goto erase_err;
> -
> - addr += mtd->erasesize;
> - len -= mtd->erasesize;
> -
> - ret = spi_nor_wait_till_ready(nor);
> + }
> + while (len) {
> + die_no = div_u64_rem(addr, die_size, &rem);
> +
> + /* Check if address is aligned to die begin*/
> + if (!rem) {
> + /* die erase? */
> + if (len >= die_size) {
> + ret = spi_nor_die_erase(nor, addr);
> + if (ret)
> + goto erase_err;
> +
> + len -= die_size;
> + addr += die_size;
> +
> + timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
> + CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
> + (unsigned long)(die_size / SZ_2M));
> + ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
> + if (ret)
> + goto erase_err;
> + } else {
> + ret = spi_nor_sector_at_time_erase(mtd, addr, len);
> + if (ret)
> + goto erase_err;
> + len = 0;
> + }
> + } else {
> + /* check if end address cover at least one die */
> + if (div64_ul(addr + len, die_size) > ++die_no) {
> + /* align to next die */
> + rem = die_size - rem;
> + ret = spi_nor_sector_at_time_erase(mtd, addr, rem);
> + if (ret)
> + goto erase_err;
> + len -= rem;
> + addr += rem;
> + } else {
> + ret = spi_nor_sector_at_time_erase(mtd, addr, len);
> + if (ret)
> + goto erase_err;
> + len = 0;
> + }
> + }
> + }
> + } else {
> + ret = spi_nor_sector_at_time_erase(mtd, addr, len);
> if (ret)
> goto erase_err;
> }
>
More information about the linux-mtd
mailing list