mtd: spi-nor: refactor wait-till-ready
Subsystems (2)
cover mtd: spi-nor: refactor wait-till-ready
Hi all,
This patch series tackles a few pieces of the spi-nor framework that weren't abstracted very well. I did some limited testing on m25p80.c, and you can see patch 8, which adds a few test BUG_ON()'s. If any of them fail for you, please holler. I don't plan to merge that patch, although I could be convinced to rework it if it adds value to someone...
I'm especially interested in getting test coverage on fsl-quadspi.
Thanks,
Brian
Brian Norris (8):
mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{,fsr}_ready()
code
mtd: spi-nor: handle timeout errors in spi_nor_write()
mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
mtd: m25p80: drop wait-till-ready checks
mtd: fsl-quadspi: drop wait-till-ready checks
mtd: spi-nor: drop replaceable wait-till-ready function pointer
mtd: spi-nor: factor out write_enable() for erase commands
debug: mtd: spi-nor: add BUG_ON() prints to check for !ready
drivers/mtd/devices/m25p80.c | 17 ----- drivers/mtd/spi-nor/fsl-quadspi.c | 16 ----- drivers/mtd/spi-nor/spi-nor.c | 145 ++++++++++++++++++-------------------- include/linux/mtd/spi-nor.h | 8 ++- 4 files changed, 76 insertions(+), 110 deletions(-)
Signature · 1 line
1.9.1
PATCH 1/8 mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code
These functions were near-carbon-copies due to a small per-flash quirk. Let's add a new spi_nor::flags bitfield to support these types of quirks.
--- drivers/mtd/spi-nor/spi-nor.c | 66 ++++++++++++++++++++++--------------------- include/linux/mtd/spi-nor.h | 6 ++++ 2 files changed, 40 insertions(+), 32 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +34 -32
@@ -163,48 +163,51 @@ static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)return nor->write_reg (nor,SPINOR_OP_BRWR , nor->cmd_buf,1 ,0 ); } } - -static int spi_nor_wait_till_ready (struct spi_nor *nor) +static inline int spi_nor_sr_ready (struct spi_nor *nor) { -unsigned long deadline; -int sr; - - deadline = jiffies +MAX_READY_WAIT_JIFFIES ; - -do { -cond_resched (); +int sr =read_sr (nor); +if (sr <0 ) +return sr; +else +return !(sr &SR_WIP ); +} - sr =read_sr (nor); -if (sr <0 ) -break ; -else if (!(sr &SR_WIP )) -return 0 ; - }while (!time_after_eq (jiffies, deadline)); +static inline int spi_nor_fsr_ready (struct spi_nor *nor) +{ +int fsr =read_fsr (nor); +if (fsr <0 ) +return fsr; +else +return fsr &FSR_READY ; +} -return -ETIMEDOUT ; +static int spi_nor_ready (struct spi_nor *nor) +{ +int sr, fsr; + sr =spi_nor_sr_ready (nor); +if (sr <0 ) +return sr; + fsr = nor->flags &SNOR_F_USE_FSR ?spi_nor_fsr_ready (nor) :1 ; +if (fsr <0 ) +return sr; +return sr && fsr; } -static int spi_nor_wait_till_fsr_ready (struct spi_nor *nor) +static int spi_nor_wait_till_ready (struct spi_nor *nor) {unsigned long deadline; -int sr; -int fsr; +int ret; deadline = jiffies +MAX_READY_WAIT_JIFFIES ;do {cond_resched (); - sr =read_sr (nor); -if (sr <0 ) { -break ; - }else if (!(sr &SR_WIP )) { - fsr =read_fsr (nor); -if (fsr <0 ) -break ; -if (fsr &FSR_READY ) -return 0 ; - } + ret =spi_nor_ready (nor); +if (ret <0 ) +return ret; +if (ret) +return 0 ; }while (!time_after_eq (jiffies, deadline));return -ETIMEDOUT ;
@@ -1014,9 +1017,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,else mtd->_write = spi_nor_write; -if ((info->flags &USE_FSR ) && - nor->wait_till_ready == spi_nor_wait_till_ready) - nor->wait_till_ready = spi_nor_wait_till_fsr_ready; +if (info->flags &USE_FSR ) + nor->flags |=SNOR_F_USE_FSR ;/* prefer "small sector" erase if possible */ if (info->flags &SECT_4K ) {
include/linux/mtd/spi-nor.h +6 -0
@@ -116,6 +116,10 @@ enum spi_nor_ops { SPI_NOR_OPS_UNLOCK, }; +enum spi_nor_option_flags { +SNOR_F_USE_FSR =BIT (0 ), +}; +/** * struct spi_nor - Structure for defining a the SPI NOR layer * @mtd: point to a mtd_info structure
@@ -129,6 +133,7 @@ enum spi_nor_ops {* @program_opcode: the program opcode * @flash_read: the mode of the read * @sst_write_second: used by the SST write operation +* @flags: flag options for the current SPI-NOR (SNOR_F_*) * @cfg: used by the read_xfer/write_xfer * @cmd_buf: used by the write_reg * @prepare: [OPTIONAL] do some preparations for the
@@ -160,6 +165,7 @@ struct spi_nor {u8 program_opcode;enum read_mode flash_read;bool sst_write_second; +u32 flags;struct spi_nor_xfer_cfg cfg;u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE ];
Signature · 1 line
1.9.1
Re: [PATCH 1/8] mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code
Quoted 8 lines · Brian Norris
These functions were near-carbon-copies due to a small per-flash quirk. Let's add a new
spi_nor::flagsbitfield to support these types of quirks.Signed-off-by Brian Norris <[email protected]>Cc Graham Moore <[email protected]>Cc Huang Shijie <[email protected]>Signed-off-by Brian Norris <[email protected]>
Thanks for the cleanup,
Best regards,
Marek Vasut
Re: [PATCH 1/8] mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code
In reply to Brian NorrisQuoted 54 lines · Brian Norris
These functions were near-carbon-copies due to a small per-flash quirk. Let's add a new
spi_nor::flagsbitfield to support these types of quirks.Signed-off-by Brian Norris <[email protected]>Cc Graham Moore <[email protected]>Cc Huang Shijie <[email protected]>Signed-off-by Brian Norris <[email protected]>--- drivers/mtd/spi-nor/spi-nor.c | 66 ++++++++++++++++++++++--------------------- include/linux/mtd/spi-nor.h | 6 ++++ 2 files changed, 40 insertions(+), 32 deletions(-)drivers/mtd/spi-nor/spi-nor.c +15
-15@@ -163,48 +163,51 @@ static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)return nor->write_reg (nor,SPINOR_OP_BRWR , nor->cmd_buf,1 ,0 ); } } - -static int spi_nor_wait_till_ready (struct spi_nor *nor) +static inline int spi_nor_sr_ready (struct spi_nor *nor) { -unsigned long deadline; -int sr; - - deadline = jiffies +MAX_READY_WAIT_JIFFIES ; - -do { -cond_resched (); +int sr =read_sr (nor); +if (sr <0 ) +return sr; +else +return !(sr &SR_WIP ); +} - sr =read_sr (nor); -if (sr <0 ) -break ; -else if (!(sr &SR_WIP )) -return 0 ; - }while (!time_after_eq (jiffies, deadline)); +static inline int spi_nor_fsr_ready (struct spi_nor *nor) +{ +int fsr =read_fsr (nor); +if (fsr <0 ) +return fsr; +else +return fsr &FSR_READY ; +}
drivers/mtd/spi-nor/spi-nor.c static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable) · line 192
Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c +9
-1-return -ETIMEDOUT ; +static int spi_nor_ready (struct spi_nor *nor) +{ +int sr, fsr; + sr =spi_nor_sr_ready (nor); +if (sr <0 ) +return sr; + fsr = nor->flags &SNOR_F_USE_FSR ?spi_nor_fsr_ready (nor) :1 ; +if (fsr <0 ) +return sr;
return "fsr" here.
Beside this, i am ok with this patch.
thanks
Huang Shijie
Re: [PATCH 1/8] mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code
Quoted 5 lines · Huang Shijie
drivers/mtd/spi-nor/spi-nor.c static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable) · line 192
Quoted 3 lines · Brian Norris
drivers/mtd/spi-nor/spi-nor.c +3
-0+ fsr = nor->flags &SNOR_F_USE_FSR ?spi_nor_fsr_ready (nor) :1 ; +if (fsr <0 ) +return sr;return "fsr" here.
Will fix, thanks.
Brian
PATCH v2 1/10 mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code
In reply to Brian NorrisThese functions were near-carbon-copies due to a small per-flash quirk. Let's add a new spi_nor::flags bitfield to support these types of quirks.
---
v2: replace 'sr' with 'fsr' (typo)
I think this was the only patch (of the first 7) that required changes due to review. I may rework patch 8 eventually, but it was not meant for inclusion in its current form.
drivers/mtd/spi-nor/spi-nor.c | 66 ++++++++++++++++++++++--------------------- include/linux/mtd/spi-nor.h | 6 ++++ 2 files changed, 40 insertions(+), 32 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +34 -32
@@ -163,48 +163,51 @@ static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable)return nor->write_reg (nor,SPINOR_OP_BRWR , nor->cmd_buf,1 ,0 ); } } - -static int spi_nor_wait_till_ready (struct spi_nor *nor) +static inline int spi_nor_sr_ready (struct spi_nor *nor) { -unsigned long deadline; -int sr; - - deadline = jiffies +MAX_READY_WAIT_JIFFIES ; - -do { -cond_resched (); +int sr =read_sr (nor); +if (sr <0 ) +return sr; +else +return !(sr &SR_WIP ); +} - sr =read_sr (nor); -if (sr <0 ) -break ; -else if (!(sr &SR_WIP )) -return 0 ; - }while (!time_after_eq (jiffies, deadline)); +static inline int spi_nor_fsr_ready (struct spi_nor *nor) +{ +int fsr =read_fsr (nor); +if (fsr <0 ) +return fsr; +else +return fsr &FSR_READY ; +} -return -ETIMEDOUT ; +static int spi_nor_ready (struct spi_nor *nor) +{ +int sr, fsr; + sr =spi_nor_sr_ready (nor); +if (sr <0 ) +return sr; + fsr = nor->flags &SNOR_F_USE_FSR ?spi_nor_fsr_ready (nor) :1 ; +if (fsr <0 ) +return fsr; +return sr && fsr; } -static int spi_nor_wait_till_fsr_ready (struct spi_nor *nor) +static int spi_nor_wait_till_ready (struct spi_nor *nor) {unsigned long deadline; -int sr; -int fsr; +int ret; deadline = jiffies +MAX_READY_WAIT_JIFFIES ;do {cond_resched (); - sr =read_sr (nor); -if (sr <0 ) { -break ; - }else if (!(sr &SR_WIP )) { - fsr =read_fsr (nor); -if (fsr <0 ) -break ; -if (fsr &FSR_READY ) -return 0 ; - } + ret =spi_nor_ready (nor); +if (ret <0 ) +return ret; +if (ret) +return 0 ; }while (!time_after_eq (jiffies, deadline));return -ETIMEDOUT ;
@@ -1009,9 +1012,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,else mtd->_write = spi_nor_write; -if ((info->flags &USE_FSR ) && - nor->wait_till_ready == spi_nor_wait_till_ready) - nor->wait_till_ready = spi_nor_wait_till_fsr_ready; +if (info->flags &USE_FSR ) + nor->flags |=SNOR_F_USE_FSR ;/* prefer "small sector" erase if possible */ if (info->flags &SECT_4K ) {
include/linux/mtd/spi-nor.h +6 -0
@@ -116,6 +116,10 @@ enum spi_nor_ops { SPI_NOR_OPS_UNLOCK, }; +enum spi_nor_option_flags { +SNOR_F_USE_FSR =BIT (0 ), +}; +/** * struct spi_nor - Structure for defining a the SPI NOR layer * @mtd: point to a mtd_info structure
@@ -129,6 +133,7 @@ enum spi_nor_ops {* @program_opcode: the program opcode * @flash_read: the mode of the read * @sst_write_second: used by the SST write operation +* @flags: flag options for the current SPI-NOR (SNOR_F_*) * @cfg: used by the read_xfer/write_xfer * @cmd_buf: used by the write_reg * @prepare: [OPTIONAL] do some preparations for the
@@ -160,6 +165,7 @@ struct spi_nor {u8 program_opcode;enum read_mode flash_read;bool sst_write_second; +u32 flags;struct spi_nor_xfer_cfg cfg;u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE ];
Signature · 1 line
1.9.1
PATCH 2/8 mtd: spi-nor: handle timeout errors in spi_nor_write()
In reply to Brian NorrisThe error label was unused here. It looks like we're missing at least one case that should be doing 'goto write_err'.
--- drivers/mtd/spi-nor/spi-nor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +5 -2
@@ -809,7 +809,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,if (page_size > nor->page_size) page_size = nor->page_size; -wait_till_ready (nor); + ret =wait_till_ready (nor); +if (ret) + goto write_err; +write_enable (nor); nor->write (nor, to + i, page_size, retlen, buf + i);
@@ -818,7 +821,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, write_err:spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_WRITE ); -return 0 ; +return ret; }static int macronix_quad_enable (struct spi_nor *nor)
Signature · 1 line
1.9.1
Re: [PATCH 2/8] mtd: spi-nor: handle timeout errors in spi_nor_write()
Quoted 4 lines · Brian Norris
The error label was unused here. It looks like we're missing at least one case that should be doing 'goto
write_err'.Signed-off-by Brian Norris <[email protected]>
Best regards,
Marek Vasut
Re: [PATCH 2/8] mtd: spi-nor: handle timeout errors in spi_nor_write()
In reply to Brian NorrisQuoted 35 lines · Brian Norris
The error label was unused here. It looks like we're missing at least one case that should be doing 'goto
write_err'.Signed-off-by Brian Norris <[email protected]>--- drivers/mtd/spi-nor/spi-nor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)drivers/mtd/spi-nor/spi-nor.c +5
-2@@ -809,7 +809,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,if (page_size > nor->page_size) page_size = nor->page_size; -wait_till_ready (nor); + ret =wait_till_ready (nor); +if (ret) + goto write_err; +write_enable (nor); nor->write (nor, to + i, page_size, retlen, buf + i);@@ -818,7 +821,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, write_err:spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_WRITE ); -return 0 ; +return ret; }static int macronix_quad_enable (struct spi_nor *nor)Signature · 1 line
1.9.1
Huang Shijie
PATCH 3/8 mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
In reply to Brian NorrisWe shouldn't have *every* function checking if a previous write is complete; this should be done synchronously after each write/erase.
--- drivers/mtd/spi-nor/spi-nor.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +9 -27
@@ -229,15 +229,8 @@ static int wait_till_ready(struct spi_nor *nor)*/ static int erase_chip (struct spi_nor *nor) { -int ret; -dev_dbg (nor->dev," %lldKiB\n" , (long long )(nor->mtd->size >>10 )); -/* Wait until finished previous write command. */ - ret =wait_till_ready (nor); -if (ret) -return ret; -/* Send write enable, then erase commands. */ write_enable (nor);
@@ -300,6 +293,10 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) goto erase_err; } + ret =spi_nor_wait_till_ready (nor); +if (ret) + goto erase_err; +/* REVISIT in some cases we could speed up erasing large regions * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K. We may have set up * to use "small sector erase", but that's not always optimal.
@@ -315,6 +312,10 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr += mtd->erasesize; len -= mtd->erasesize; + + ret =spi_nor_wait_till_ready (nor); +if (ret) + goto erase_err; } }
@@ -342,11 +343,6 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)if (ret)return ret; -/* Wait until finished previous command */ - ret =wait_till_ready (nor); -if (ret) - goto err; - status_old =read_sr (nor);if (offset < mtd->size - (mtd->size /2 ))
@@ -389,11 +385,6 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)if (ret)return ret; -/* Wait until finished previous command */ - ret =wait_till_ready (nor); -if (ret) - goto err; - status_old =read_sr (nor);if (offset+len > mtd->size - (mtd->size /64 ))
@@ -710,11 +701,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,if (ret)return ret; -/* Wait until finished previous write command. */ - ret =wait_till_ready (nor); -if (ret) - goto time_out; -write_enable (nor); nor->sst_write_second = false;
@@ -786,11 +772,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,if (ret)return ret; -/* Wait until finished previous write command. */ - ret =wait_till_ready (nor); -if (ret) - goto write_err; -write_enable (nor); page_offset = to & (nor->page_size -1 );
@@ -819,6 +800,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } } + ret =spi_nor_wait_till_ready (nor); write_err:spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_WRITE );return ret;
Signature · 1 line
1.9.1
Re: [PATCH 3/8] mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
Quoted 4 lines · Brian Norris
We shouldn't have *every* function checking if a previous write is complete; this should be done synchronously after each write/erase.
Signed-off-by Brian Norris <[email protected]>
Nice!
Best regards,
Marek Vasut
Re: [PATCH 3/8] mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
In reply to Brian NorrisQuoted 2 lines · Brian Norris
We shouldn't have *every* function checking if a previous write is complete; this should be done synchronously after each write/erase.
IMHO, this is not a good idea. :(
this patch prevents the erase-suspend and program-suspend. We should add these two features for spi-nor in future.
thanks
Huang Shijie
Re: [PATCH 3/8] mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
Quoted 5 lines · Huang Shijie
Quoted 2 lines · Brian Norris
We shouldn't have *every* function checking if a previous write is complete; this should be done synchronously after each write/erase.
IMHO, this is not a good idea. :(
Do you mean you think it is a good idea for every unrelated function to check if the previous erase/write is complete?
Quoted 2 lines
this patch prevents the erase-suspend and program-suspend. We should add these two features for spi-nor in future.
OK, how would you propose that such features be implemented, and how would they be used to the benefit of higher layers?
Directed toward the former: specifically, how does leaving the SR/FSR-checking burden on all subsequent commands benefit a potential erase/program suspend implementation? The code is not written at all with erase/program suspend in mind, and the current patch solves a current problem; that we perform checking in all the wrong places.
To the latter: are file systems (e.g., UBIFS) aware of suspend-able program/erase? Would they have the knowledge to take advantage of suspend-able program/erase? i.e., could they suspend an unimportant erase command in order to prioritize a read or write?
Finally, this patch mostly prepares for elimination of code from lower-level drivers (m25p80.c and fsl-quadspi, in the following two patches). These drivers should *not* be worrying about the details of command statuses; this should be handled by the generic code (spi-nor.c).
So, unless you can provide some outline as to how program/erase suspend can be implemented reasonably within this framework, and how this particular patch makes that so much more difficult, I plan to move forward with this.
Thanks,
Brian
Re: [PATCH 3/8] mtd: spi-nor: move "wait-till-ready" checks into erase/write functions
Quoted 9 lines · Brian Norris
Quoted 5 lines · Huang Shijie
Quoted 2 lines · Brian Norris
We shouldn't have *every* function checking if a previous write is complete; this should be done synchronously after each write/erase.
IMHO, this is not a good idea. :(
Do you mean you think it is a good idea for every unrelated function to check if the previous erase/write is complete?
i guess only the read function should need the suspend. I does not dig this issue too.
Quoted 6 lines
Quoted 3 lines
this patch prevents the erase-suspend and program-suspend. We should add these two features for spi-nor in future.
OK, how would you propose that such features be implemented, and how would they be used to the benefit of higher layers?
Please refer to cfi_cmdset_0002.c. The parallel NOR has implemented this feature.
Quoted 9 lines
Directed toward the former: specifically, how does leaving the SR/FSR-checking burden on all subsequent commands benefit a potential erase/program suspend implementation? The code is not written at all with erase/program suspend in mind, and the current patch solves a current problem; that we perform checking in all the wrong places.
To the latter: are file systems (e.g., UBIFS) aware of suspend-able program/erase? Would they have the knowledge to take advantage of
The file systems should not know the suspend feature.
It is transparent to them. The suspend feature will make the file system run much faster. sorry, i have forgotten how did i test this feature, it was long time ago.
Quoted 2 lines
suspend-able program/erase? i.e., could they suspend an unimportant erase command in order to prioritize a read or write?
they do not suspend the erase, the SPI-NOR framework should do the job.
Quoted 11 lines
Finally, this patch mostly prepares for elimination of code from lower-level drivers (
m25p80.cand fsl-quadspi, in the following two patches). These drivers should *not* be worrying about the details of command statuses; this should be handled by the generic code (spi-nor.c).So, unless you can provide some outline as to how program/erase suspend can be implemented reasonably within this framework, and how this particular patch makes that so much more difficult, I plan to move forward with this.
I do not have time to implement this feature recently. Please go forward with your patch. I guess the one who want to add this feature will change the code himself.
thanks
Huang Shijie
PATCH 4/8 mtd: m25p80: drop wait-till-ready checks
In reply to Brian Norrisspi-nor.c should be taking care of these now.
--- drivers/mtd/devices/m25p80.c | 12 ------------ 1 file changed, 12 deletions(-)
drivers/mtd/devices/m25p80.c +0 -12
@@ -129,12 +129,6 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,struct spi_transfer t[2 ];struct spi_message m;int dummy = nor->read_dummy; -int ret; - -/* Wait till previous write/erase is done. */ - ret = nor->wait_till_ready (nor); -if (ret) -return ret;spi_message_init (&m);memset (t,0 , (sizeof t));
@@ -160,16 +154,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,static int m25p80_erase (struct spi_nor *nor,loff_t offset) {struct m25p *flash = nor->priv; -int ret;dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Wait until finished previous write command. */ - ret = nor->wait_till_ready (nor); -if (ret) -return ret; -/* Send write enable, then erase commands. */ ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 );if (ret)
Signature · 1 line
1.9.1
Re: [PATCH 4/8] mtd: m25p80: drop wait-till-ready checks
Quoted 3 lines · Brian Norris
spi-nor.cshould be taking care of these now.Signed-off-by Brian Norris <[email protected]>
Best regards,
Marek Vasut
PATCH 5/8 mtd: fsl-quadspi: drop wait-till-ready checks
In reply to Brian Norrisspi-nor.c should be taking care of these now.
--- drivers/mtd/spi-nor/fsl-quadspi.c | 11 ----------- 1 file changed, 11 deletions(-)
drivers/mtd/spi-nor/fsl-quadspi.c +0 -11
@@ -719,16 +719,10 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from, {struct fsl_qspi *q = nor->priv;u8 cmd = nor->read_opcode; -int ret;dev_dbg (q->dev,"cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n" , cmd, q->ahb_base, q->chip_base_addr, (unsigned int )from, len); -/* Wait until the previous command is finished. */ - ret = nor->wait_till_ready (nor); -if (ret) -return ret; -/* Read out the data directly from the AHB buffer.*/ memcpy (buf, q->ahb_base + q->chip_base_addr + from, len);
@@ -744,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Wait until finished previous write command. */ - ret = nor->wait_till_ready (nor); -if (ret) -return ret; -/* Send write enable, then erase commands. */ ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 );if (ret)
Signature · 1 line
1.9.1
Re: [PATCH 5/8] mtd: fsl-quadspi: drop wait-till-ready checks
Quoted 4 lines · Brian Norris
spi-nor.cshould be taking care of these now.Signed-off-by Brian Norris <[email protected]>Cc Huang Shijie <[email protected]>
Best regards,
Marek Vasut
PATCH 6/8 mtd: spi-nor: drop replaceable wait-till-ready function pointer
In reply to Brian NorrisWe don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core spi-nor.c library, and as of now, I see no need to provide a special driver-specific hook for it.
--- drivers/mtd/spi-nor/spi-nor.c | 27 ++++++++++----------------- include/linux/mtd/spi-nor.h | 2 -- 2 files changed, 10 insertions(+), 19 deletions(-)
drivers/mtd/spi-nor/spi-nor.c +10 -17
@@ -193,6 +193,10 @@ static int spi_nor_ready(struct spi_nor *nor)return sr && fsr; } +/* +* Service routine to read status register until ready, or timeout occurs. +* Returns non-zero if error. +*/ static int spi_nor_wait_till_ready (struct spi_nor *nor) {unsigned long deadline;
@@ -214,15 +218,6 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor) }/* -* Service routine to read status register until ready, or timeout occurs. -* Returns non-zero if error. -*/ -static int wait_till_ready (struct spi_nor *nor) -{ -return nor->wait_till_ready (nor); -} - -/* * Erase the whole flash memory * * Returns 0 if successful, non-zero otherwise.
@@ -712,7 +707,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,/* write one byte. */ nor->write (nor, to,1 , retlen, buf); - ret =wait_till_ready (nor); + ret =spi_nor_wait_till_ready (nor);if (ret) goto time_out; }
@@ -724,7 +719,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,/* write two bytes. */ nor->write (nor, to,2 , retlen, buf + actual); - ret =wait_till_ready (nor); + ret =spi_nor_wait_till_ready (nor);if (ret) goto time_out; to +=2 ;
@@ -733,7 +728,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, nor->sst_write_second = false;write_disable (nor); - ret =wait_till_ready (nor); + ret =spi_nor_wait_till_ready (nor);if (ret) goto time_out;
@@ -744,7 +739,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, nor->program_opcode =SPINOR_OP_BP ; nor->write (nor, to,1 , retlen, buf + actual); - ret =wait_till_ready (nor); + ret =spi_nor_wait_till_ready (nor);if (ret) goto time_out;write_disable (nor);
@@ -790,7 +785,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,if (page_size > nor->page_size) page_size = nor->page_size; - ret =wait_till_ready (nor); + ret =spi_nor_wait_till_ready (nor);if (ret) goto write_err;
@@ -816,7 +811,7 @@ static int macronix_quad_enable(struct spi_nor *nor) nor->cmd_buf[0 ] = val |SR_QUAD_EN_MX ; nor->write_reg (nor,SPINOR_OP_WRSR , nor->cmd_buf,1 ,0 ); -if (wait_till_ready (nor)) +if (spi_nor_wait_till_ready (nor))return 1 ; ret =read_sr (nor);
@@ -898,8 +893,6 @@ static int spi_nor_check(struct spi_nor *nor)if (!nor->read_id) nor->read_id = spi_nor_read_id; -if (!nor->wait_till_ready) - nor->wait_till_ready = spi_nor_wait_till_ready;return 0 ; }
include/linux/mtd/spi-nor.h +0 -2
@@ -146,7 +146,6 @@ enum spi_nor_option_flags {* @write_reg: [DRIVER-SPECIFIC] write data to the register * @read_id: [REPLACEABLE] read out the ID data, and find * the proper spi_device_id -* @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready * @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
@@ -179,7 +178,6 @@ struct spi_nor {int (*write_reg)(struct spi_nor *nor,u8 opcode,u8 *buf,int len,int write_enable);const struct spi_device_id *(*read_id)(struct spi_nor *nor); -int (*wait_till_ready)(struct spi_nor *nor);int (*read)(struct spi_nor *nor,loff_t from,size_t len,size_t *retlen,u_char *read_buf);
Signature · 1 line
1.9.1
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
Quoted 5 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.Signed-off-by Brian Norris <[email protected]>
Very nice,
Best regards,
Marek Vasut
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
In reply to Brian NorrisQuoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.
Please do not drop this hook, please see why we add this hook:
http://lists.infradead.org/pipermail/linux-mtd/2013-December/050561.html
"
The default implementation would do just as you suggest, and I would expect most H/W drivers to use the default implementation. However, some H/W Controllers can automate the polling of status registers, so having a hook allows the driver override the default behaviour.
"
The spi-nor framework will used by more drivers besides the m25p80 and fsl-quadspi. Some NOR flash controller may be very strange.
thanks
Huang Shijie
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
Quoted 15 lines · Huang Shijie
Quoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.Please do not drop this hook, please see why we add this hook:
http://lists.infradead.org/pipermail/linux-mtd/2013-December/050561.html"
The default implementation would do just as you suggest, and I would expect most H/W drivers to use the default implementation. However, some H/W Controllers can automate the polling of status registers, so having a hook allows the driver override the default behaviour.
"
Quoted 2 lines
The spi-nor framework will used by more drivers besides the m25p80 and fsl-quadspi. Some NOR flash controller may be very strange.
OK, but the wait-till-ready hook should not look like the current one. If it is used as an optimization of sorts, then we can provide it in *addition* to the checks we do, but not *instead of*. I sincerely doubt that any specialized SPI NOR controller will know how to check both SR and FSR where appropriate, and it probably won't understand other specialized sequences as they are developed / thrown on our lap by flash vendors.
So, the spi-nor.c "wait until ready" might have a sequence like this:
1. (Optionally) use low-level driver's "wait" function; skip if not present
2. use the read register hooks to check SR/FSR to confirm completion
I do not want to toss #2 into the low-level driver, so if there is a need for #1, it should be done in addition to our spi-nor.c code, not instead. (To this end, I believe Marek also complained about this when we were adding the FSR-checking code; we should not have drivers and spi-nor.c fighting over callback functions.)
So I'm inclined to at most address #1 through an optional callback, and possibly even to ignore that until we see an actual driver that needs it.
Brian
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
Quoted 34 lines · Brian Norris
Quoted 15 lines · Huang Shijie
Quoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.Please do not drop this hook, please see why we add this hook:
http://lists.infradead.org/pipermail/linux-mtd/2013-December/050561.html"
The default implementation would do just as you suggest, and I would expect most H/W drivers to use the default implementation. However, some H/W Controllers can automate the polling of status registers, so having a hook allows the driver override the default behaviour.
"Quoted 2 lines
The spi-nor framework will used by more drivers besides the m25p80 and fsl-quadspi. Some NOR flash controller may be very strange.
OK, but the wait-till-ready hook should not look like the current one. If it is used as an optimization of sorts, then we can provide it in *addition* to the checks we do, but not *instead of*. I sincerely doubt that any specialized SPI NOR controller will know how to check both SR and FSR where appropriate, and it probably won't understand other specialized sequences as they are developed / thrown on our lap by flash vendors.
So, the
spi-nor.c"wait until ready" might have a sequence like this:1. (Optionally) use low-level driver's "wait" function; skip if not present
2. use the read register hooks to check SR/FSR to confirm completion
Quoted 7 lines
I do not want to toss #2 into the low-level driver, so if there is a need for #1, it should be done in addition to our
spi-nor.ccode, not instead. (To this end, I believe Marek also complained about this when we were adding the FSR-checking code; we should not have drivers andspi-nor.cfighting over callback functions.)So I'm inclined to at most address #1 through an optional callback, and
but where to put the optional callback? in the spi_nor{} ?
Quoted 2 lines
possibly even to ignore that until we see an actual driver that needs it.
If you insist to remove it, i will be okay too. anyway, we can add it back when an actual driver appears.
thanks
Huang Shijie
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
Quoted 41 lines · Huang Shijie
Quoted 40 lines · Brian Norris
Quoted 15 lines · Huang Shijie
Quoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.Please do not drop this hook, please see why we add this hook:
http://lists.infradead.org/pipermail/linux-mtd/2013-December/050561.html"
The default implementation would do just as you suggest, and I would expect most H/W drivers to use the default implementation. However, some H/W Controllers can automate the polling of status registers, so having a hook allows the driver override the default behaviour.
"Quoted 2 lines
The spi-nor framework will used by more drivers besides the m25p80 and fsl-quadspi. Some NOR flash controller may be very strange.
OK, but the wait-till-ready hook should not look like the current one. If it is used as an optimization of sorts, then we can provide it in *addition* to the checks we do, but not *instead of*. I sincerely doubt that any specialized SPI NOR controller will know how to check both SR and FSR where appropriate, and it probably won't understand other specialized sequences as they are developed / thrown on our lap by flash vendors.
So, the
spi-nor.c"wait until ready" might have a sequence like this:1. (Optionally) use low-level driver's "wait" function; skip if not present
2. use the read register hooks to check SR/FSR to confirm completion
I do not want to toss #2 into the low-level driver, so if there is a need for #1, it should be done in addition to our
spi-nor.ccode, not instead. (To this end, I believe Marek also complained about this when we were adding the FSR-checking code; we should not have drivers andspi-nor.cfighting over callback functions.)
Quoted 3 lines
Quoted 1 line
So I'm inclined to at most address #1 through an optional callback, and
but where to put the optional callback? in the spi_nor{} ?
Probably.
Quoted 4 lines
Quoted 2 lines
possibly even to ignore that until we see an actual driver that needs it.
If you insist to remove it, i will be okay too. anyway, we can add it back when an actual driver appears.
Yeah. The point of this series is that without users, the current callback is both ambiguously defined (it was allegedly serving both a flash-specific and a controller-specific purpose) and unncecessary. It's easier to add back once we have a clear purpose.
Brian
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
In reply to Brian NorrisQuoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.
Do you think we could use spi-nor for Broadcom's SPI Atmel flashes? If so, we could need this.
Broadcom's code includes support for two Atmel flashes: AT25F512 and AT25F2048.
Quoted 1 line
From what I can see, Atmel-specific code uses command
0xD7(checking
for bit 0x80 to be unset). That is a bit different from "standard" flashes using command 0xD7 (checking for bit 0x80 to be unset).
Re: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer
Quoted 5 lines · Rafał Miłecki
Quoted 3 lines · Brian Norris
We don't need to expose a 'wait-till-ready' interface to drivers. Status register polling should be handled by the core
spi-nor.clibrary, and as of now, I see no need to provide a special driver-specific hook for it.
Quoted 8 lines
Do you think we could use spi-nor for Broadcom's SPI Atmel flashes? If so, we could need this.
Broadcom's code includes support for two Atmel flashes: AT25F512 and AT25F2048.
From what I can see, Atmel-specific code uses command
0xD7(checking for bit0x80to be unset). That is a bit different from "standard" flashes using command0xD7(checking for bit0x80to be unset).
I meant standard code using command 0x05 and checking for 0x01 to be unset.
Signature · 1 line
Rafał
PATCH 7/8 mtd: spi-nor: factor out write_enable() for erase commands
In reply to Brian Norriswrite_enable() was being duplicated to both m25p80.c and fsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.
At the same time, let's add write_disable() after erasing, so we don't leave the flash in a write-enabled state afterward.
--- drivers/mtd/devices/m25p80.c | 5 ----- drivers/mtd/spi-nor/fsl-quadspi.c | 5 ----- drivers/mtd/spi-nor/spi-nor.c | 7 ++++--- 3 files changed, 4 insertions(+), 13 deletions(-)
drivers/mtd/devices/m25p80.c +0 -5
@@ -158,11 +158,6 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -/* Set up command buffer. */ flash->command[0 ] = nor->erase_opcode;m25p_addr2cmd (nor, offset, flash->command);
drivers/mtd/spi-nor/fsl-quadspi.c +0 -5
@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; - ret =fsl_qspi_runcmd (q, nor->erase_opcode, offs,0 );if (ret)return ret;
drivers/mtd/spi-nor/spi-nor.c +4 -3
@@ -226,9 +226,6 @@ static int erase_chip(struct spi_nor *nor) {dev_dbg (nor->dev," %lldKiB\n" , (long long )(nor->mtd->size >>10 )); -/* Send write enable, then erase commands. */ -write_enable (nor); -return nor->write_reg (nor,SPINOR_OP_CHIP_ERASE ,NULL ,0 ,0 ); }
@@ -281,6 +278,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)if (ret)return ret; +write_enable (nor); +/* whole-chip erase? */ if (len == mtd->size) {if (erase_chip (nor)) {
@@ -314,6 +313,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) } } +write_disable (nor); +spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_ERASE ); instr->state =MTD_ERASE_DONE ;
Signature · 1 line
1.9.1
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 7 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>
Makes sense, thanks!
Best regards,
Marek Vasut
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
In reply to Brian NorrisQuoted 34 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>--- drivers/mtd/devices/m25p80.c | 5 ----- drivers/mtd/spi-nor/fsl-quadspi.c | 5 ----- drivers/mtd/spi-nor/spi-nor.c | 7 ++++--- 3 files changed, 4 insertions(+), 13 deletions(-)drivers/mtd/devices/m25p80.c +0
-5@@ -158,11 +158,6 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -/* Set up command buffer. */ flash->command[0 ] = nor->erase_opcode;m25p_addr2cmd (nor, offset, flash->command);drivers/mtd/spi-nor/fsl-quadspi.c +0
-0
drivers/mtd/spi-nor/fsl-quadspi.c static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) · line 745
Quoted 8 lines
drivers/mtd/spi-nor/fsl-quadspi.c +0
-5@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -
This write-enable is used for per-sector-erase, not for the whole chip erase.
So if you really want to remove this code, you should add an extra write-enable in the spi_nor_erase.
thanks
Huang Shijie
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 46 lines · Huang Shijie
Quoted 34 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>--- drivers/mtd/devices/m25p80.c | 5 ----- drivers/mtd/spi-nor/fsl-quadspi.c | 5 ----- drivers/mtd/spi-nor/spi-nor.c | 7 ++++--- 3 files changed, 4 insertions(+), 13 deletions(-)drivers/mtd/devices/m25p80.c +0
-5@@ -158,11 +158,6 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -/* Set up command buffer. */ flash->command[0 ] = nor->erase_opcode;m25p_addr2cmd (nor, offset, flash->command);drivers/mtd/spi-nor/fsl-quadspi.c +0
-0drivers/mtd/spi-nor/fsl-quadspi.c static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) · line 745
Quoted 8 lines
drivers/mtd/spi-nor/fsl-quadspi.c +0
-5@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -This write-enable is used for per-sector-erase, not for the whole chip erase.
Quoted 2 lines
So if you really want to remove this code, you should add an extra write-enable in the
spi_nor_erase.
I don't understand your comment.
Before this patch, there is a write-enable command in:
* m25p80.c, per-sector erase
* fsl-quadspi, per-sector erase
* spi-nor.c, whole-chip erase
With this patch, I am factoring all of these out into spi_nor_erase().
What is the problem?
Brian
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 52 lines · Brian Norris
Quoted 46 lines · Huang Shijie
Quoted 34 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>--- drivers/mtd/devices/m25p80.c | 5 ----- drivers/mtd/spi-nor/fsl-quadspi.c | 5 ----- drivers/mtd/spi-nor/spi-nor.c | 7 ++++--- 3 files changed, 4 insertions(+), 13 deletions(-)drivers/mtd/devices/m25p80.c +0
-5@@ -158,11 +158,6 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -/* Set up command buffer. */ flash->command[0 ] = nor->erase_opcode;m25p_addr2cmd (nor, offset, flash->command);drivers/mtd/spi-nor/fsl-quadspi.c +0
-0drivers/mtd/spi-nor/fsl-quadspi.c static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) · line 745
Quoted 8 lines
drivers/mtd/spi-nor/fsl-quadspi.c +0
-5@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -This write-enable is used for per-sector-erase, not for the whole chip erase.
Quoted 2 lines
So if you really want to remove this code, you should add an extra write-enable in the
spi_nor_erase.I don't understand your comment.
Quoted 8 lines
Before this patch, there is a write-enable command in:
*m25p80.c, per-sector erase
* fsl-quadspi, per-sector erase
*spi-nor.c, whole-chip eraseWith this patch, I am factoring all of these out into
spi_nor_erase().What is the problem?
Hi Brian:
For the spi_nor_erase(), the patch should like this:
drivers/mtd/spi-nor/spi-nor.c +2 -0
@@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor);if (erase_chip (nor)) { ret = -EIO ; goto erase_err;
@@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor);if (nor->erase (nor, addr)) { ret = -EIO ; goto erase_err;
thanks
Huang Shijie
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Hi Huang,
Quoted 49 lines · Huang Shijie
Quoted 23 lines · Brian Norris
Quoted 17 lines · Huang Shijie
drivers/mtd/spi-nor/fsl-quadspi.c static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) · line 745
Quoted 13 lines · Brian Norris
drivers/mtd/spi-nor/fsl-quadspi.c +0
-5@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -This write-enable is used for per-sector-erase, not for the whole chip erase.
Quoted 2 lines
So if you really want to remove this code, you should add an extra write-enable in the
spi_nor_erase.I don't understand your comment.
Quoted 8 lines
Before this patch, there is a write-enable command in:
*m25p80.c, per-sector erase
* fsl-quadspi, per-sector erase
*spi-nor.c, whole-chip eraseWith this patch, I am factoring all of these out into
spi_nor_erase().What is the problem?
Hi Brian:
For thespi_nor_erase(), the patch should like this:drivers/mtd/spi-nor/spi-nor.c +1
-0@@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor);if (erase_chip (nor)) { ret = -EIO ; goto erase_err;
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 344
Quoted 7 lines
drivers/mtd/spi-nor/spi-nor.c +1
-0@@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor);if (nor->erase (nor, addr)) { ret = -EIO ; goto erase_err;
How is your patch any different than mine? Mine has the exact same code, except it covers both paths by putting the write_enable() outside the conditional entirely.
Brian
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 44 lines · Brian Norris
Hi Huang,
Quoted 41 lines · Huang Shijie
Quoted 23 lines · Brian Norris
Quoted 17 lines · Huang Shijie
drivers/mtd/spi-nor/fsl-quadspi.c static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) · line 745
Quoted 13 lines · Brian Norris
drivers/mtd/spi-nor/fsl-quadspi.c +0
-5@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -This write-enable is used for per-sector-erase, not for the whole chip erase.
Quoted 2 lines
So if you really want to remove this code, you should add an extra write-enable in the
spi_nor_erase.I don't understand your comment.
Quoted 8 lines
Before this patch, there is a write-enable command in:
*m25p80.c, per-sector erase
* fsl-quadspi, per-sector erase
*spi-nor.c, whole-chip eraseWith this patch, I am factoring all of these out into
spi_nor_erase().What is the problem?
Hi Brian:
For thespi_nor_erase(), the patch should like this:drivers/mtd/spi-nor/spi-nor.c +0
-0@@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 341
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c +2
-0/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor);if (erase_chip (nor)) { ret = -EIO ; goto erase_err;@@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor);
The difference is here.
you miss a write_enable for each sector's erase.
thanks
Huang Shijie
Quoted 8 lines
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 344
Quoted 4 lines
drivers/mtd/spi-nor/spi-nor.c +0
-0if (nor->erase (nor, addr)) { ret = -EIO ; goto erase_err;How is your patch any different than mine? Mine has the exact same code, except it covers both paths by putting the
write_enable()outside the conditional entirely.
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 10 lines · Huang Shijie
Quoted 9 lines · Brian Norris
Quoted 8 lines · Huang Shijie
For the
spi_nor_erase(), the patch should like this:drivers/mtd/spi-nor/spi-nor.c +0
-0@@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
Quoted 12 lines
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 341
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c +2
-0/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor);if (erase_chip (nor)) { ret = -EIO ; goto erase_err;@@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor);The difference is here.
OK.
Quoted 1 line
you miss a
write_enablefor each sector's erase.
But is that necessary? I thought 'write-enabled' was retained across operations, so why would you have to perform it before each sector's erase?
Or do you have a flash datasheet which says you must send WREN before each sector erase?
I do see, now that I'm looking a little closer, that spi-nor doesn't actually have any concurrency protection (!). So it looks like we could potentially have other operations interleaved in this sequence of sector erasures, potentially running a write_disable() in the midst of this loop.
I really hope I'm wrong about that last paragraph.
If I'm correct though, the solution to this is not, AIUI, to add more write_enable() calls in this loop; the solution is to add some kind of concurrency protections, a la nand_get_device().
Quoted 8 lines
Quoted 8 lines
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 344
Quoted 4 lines
drivers/mtd/spi-nor/spi-nor.c +0
-0if (nor->erase (nor, addr)) { ret = -EIO ; goto erase_err;How is your patch any different than mine? Mine has the exact same code, except it covers both paths by putting the
write_enable()outside the conditional entirely.
Brian
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 24 lines · Brian Norris
Quoted 10 lines · Huang Shijie
Quoted 9 lines · Brian Norris
Quoted 8 lines · Huang Shijie
For the
spi_nor_erase(), the patch should like this:drivers/mtd/spi-nor/spi-nor.c +0
-0@@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)Quoted 12 lines
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) · line 341
Quoted 11 lines
drivers/mtd/spi-nor/spi-nor.c +2
-0/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor);if (erase_chip (nor)) { ret = -EIO ; goto erase_err;@@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor);The difference is here.
Quoted 7 lines
OK.
Quoted 1 line
you miss a
write_enablefor each sector's erase.But is that necessary? I thought 'write-enabled' was retained across operations, so why would you have to perform it before each sector's erase?
The legacy code did so.
Quoted 3 lines
Or do you have a flash datasheet which says you must send WREN before each sector erase?
See the belowing from Spansion Nor S25fl129:
"
The Sector Erase (SE) command sets all bits at all addresses within a specified sector to a logic 1. A WREN
command is required prior to writing the SE command.
"
It does not tell we send a WREN for each sector erase, but i am not sure if we can remove it.
thanks
Huang Shijie
Quoted 11 lines
I do see, now that I'm looking a little closer, that spi-nor doesn't actually have any concurrency protection (!). So it looks like we could potentially have other operations interleaved in this sequence of sector erasures, potentially running a
write_disable()in the midst of this loop.I really hope I'm wrong about that last paragraph.
If I'm correct though, the solution to this is not, AIUI, to add more
write_enable()calls in this loop; the solution is to add some kind of concurrency protections, a lanand_get_device().
Re: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 16 lines · Huang Shijie
Quoted 8 lines · Brian Norris
Quoted 3 lines · Huang Shijie
Quoted 1 line · Brian Norris
On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote:
you miss a
write_enablefor each sector's erase.But is that necessary? I thought 'write-enabled' was retained across operations, so why would you have to perform it before each sector's erase?
The legacy code did so.
Quoted 3 lines
Or do you have a flash datasheet which says you must send WREN before each sector erase?
See the belowing from Spansion Nor S25fl129:
Quoted 7 lines
"
The Sector Erase (SE) command sets all bits at all addresses within a specified sector to a logic 1. A WREN
command is required prior to writing the SE command.
"It does not tell we send a WREN for each sector erase, but i am not sure if we can remove it.
OK, well I guess I can rework this to retain the original behavior. That was in fact, an oversight (thanks for catching), although I'm not convinced it's actually necessary.
(Edit: I think you may be right that WREN is necessary before every erased command. From a Micron N25Q256 datasheet:
The write enable latch bit must be set before every PROGRAM, ERASE, WRITE, ENTER 4-BYTE ADDRESS MODE, and EXIT 4-BYTE ADDRESS MODE command.
But I don't recall seeing any ill effects last time I tested this on my Micron SPI flash, so I'm still mildly confused.)
Brian
PATCH v2 1/1 mtd: spi-nor: factor out write_enable() for erase commands
In reply to Brian Norriswrite_enable() was being duplicated to both m25p80.c and fsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.
At the same time, let's add write_disable() after erasing, so we don't leave the flash in a write-enabled state afterward.
--- drivers/mtd/devices/m25p80.c | 6 ------ drivers/mtd/spi-nor/fsl-quadspi.c | 5 ----- drivers/mtd/spi-nor/spi-nor.c | 9 ++++++--- 3 files changed, 6 insertions(+), 14 deletions(-)
drivers/mtd/devices/m25p80.c +0 -6
@@ -157,16 +157,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,static int m25p80_erase (struct spi_nor *nor,loff_t offset) {struct m25p *flash = nor->priv; -int ret;dev_dbg (nor->dev,"%dKiB at 0x%08x\n" , flash->mtd.erasesize /1024 , (u32 )offset); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; -/* Set up command buffer. */ flash->command[0 ] = nor->erase_opcode;m25p_addr2cmd (nor, offset, flash->command);
drivers/mtd/spi-nor/fsl-quadspi.c +0 -5
@@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)dev_dbg (nor->dev,"%dKiB at 0x%08x:0x%08x\n" , nor->mtd->erasesize /1024 , q->chip_base_addr, (u32 )offs); -/* Send write enable, then erase commands. */ - ret = nor->write_reg (nor,SPINOR_OP_WREN ,NULL ,0 ,0 ); -if (ret) -return ret; - ret =fsl_qspi_runcmd (q, nor->erase_opcode, offs,0 );if (ret)return ret;
drivers/mtd/spi-nor/spi-nor.c +6 -3
@@ -228,9 +228,6 @@ static int erase_chip(struct spi_nor *nor) {dev_dbg (nor->dev," %lldKiB\n" , (long long )(nor->mtd->size >>10 )); -/* Send write enable, then erase commands. */ -write_enable (nor); -return nor->write_reg (nor,SPINOR_OP_CHIP_ERASE ,NULL ,0 ,0 ); }
@@ -285,6 +282,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* whole-chip erase? */ if (len == mtd->size) { +write_enable (nor); +if (erase_chip (nor)) { ret = -EIO ; goto erase_err;
@@ -302,6 +301,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)/* "sector"-at-a-time erase */ }else {while (len) { +write_enable (nor); +if (nor->erase (nor, addr)) { ret = -EIO ; goto erase_err;
@@ -316,6 +317,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) } } +write_disable (nor); +spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_ERASE ); instr->state =MTD_ERASE_DONE ;
Signature · 1 line
1.9.1
Re: [PATCH v2] mtd: spi-nor: factor out write_enable() for erase commands
Quoted 7 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>
thanks
Brian Norris
AppliedRe: [PATCH v2] mtd: spi-nor: factor out write_enable() for erase commands
In reply to Brian NorrisQuoted 7 lines · Brian Norris
write_enable()was being duplicated to bothm25p80.candfsl-quadspi.c. But this should be handled within the spi-nor abstraction layer.At the same time, let's add
write_disable()after erasing, so we don't leave the flash in a write-enabled state afterward.Signed-off-by Brian Norris <[email protected]>
Applied to l2-mtd.git
RFC 8/8 debug: mtd: spi-nor: add BUG_ON() prints to check for !ready
In reply to Brian NorrisI hacked around the wait-till-ready sequencing just now, so let's add some debug checks for now.
These probably shouldn't be included in mainline (or at least they should be toned down to something less drastic; WARN_ON() perhaps?). I'm just using these for test purposes.
---
This patch is really just for testing. I don't think we really need it, although I suppose some form of it couldn't hurt...
drivers/mtd/spi-nor/spi-nor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/mtd/spi-nor/spi-nor.c +14 -0
@@ -226,6 +226,8 @@ static int erase_chip(struct spi_nor *nor) {dev_dbg (nor->dev," %lldKiB\n" , (long long )(nor->mtd->size >>10 )); +BUG_ON (spi_nor_ready (nor) <=0 ); +return nor->write_reg (nor,SPINOR_OP_CHIP_ERASE ,NULL ,0 ,0 ); }
@@ -278,6 +280,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); +write_enable (nor);/* whole-chip erase? */
@@ -339,6 +343,8 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); + status_old =read_sr (nor);if (offset < mtd->size - (mtd->size /2 ))
@@ -381,6 +387,8 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); + status_old =read_sr (nor);if (offset+len > mtd->size - (mtd->size /64 ))
@@ -678,6 +686,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); + ret = nor->read (nor, from, len, retlen, buf);spi_nor_unlock_and_unprep (nor,SPI_NOR_OPS_READ );
@@ -697,6 +707,8 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); +write_enable (nor); nor->sst_write_second = false;
@@ -768,6 +780,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,if (ret)return ret; +BUG_ON (spi_nor_ready (nor) <=0 ); +write_enable (nor); page_offset = to & (nor->page_size -1 );
Signature · 1 line
1.9.1
Re: [RFC 8/8] debug: mtd: spi-nor: add BUG_ON() prints to check for !ready
Quoted 8 lines · Brian Norris
I hacked around the wait-till-ready sequencing just now, so let's add some debug checks for now.
These probably shouldn't be included in mainline (or at least they should be toned down to something less drastic;
WARN_ON()perhaps?). I'm just using these for test purposes.Signed-off-by Brian Norris <[email protected]>
I'm all for this, but some kind of a WARN_ON_ONCE would do.
Best regards,
Marek Vasut
Quoted 8 lines · Brian Norris
Hi all,
This patch series tackles a few pieces of the spi-nor framework that weren't abstracted very well. I did some limited testing on
m25p80.c, and you can see patch 8, which adds a few test BUG_ON()'s. If any of them fail for you, please holler. I don't plan to merge that patch, although I could be convinced to rework it if it adds value to someone...
Quoted 4 lines
I'm especially interested in getting test coverage on fsl-quadspi.
Thanks,
Brian
Pushed the first 6, with some small rebasing. I took v2 for patch 1.
I'll update patch 7 and send it out later.
Brian