The regression issue has been caused on S29GL064N and reported it. Also the change mentioned is to use chip_good() for buffered write. So disable the change on S29GL064N and use chip_ready() as before.
Fixes: dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") Signed-off-by: Tokunori Ikegami ikegami.t@gmail.com Tested-by: Ahmad Fatoum a.fatoum@pengutronix.de Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org --- drivers/mtd/chips/cfi_cmdset_0002.c | 105 ++++++++++++++++------------ 1 file changed, 59 insertions(+), 46 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a761134fd3be..a0dfc8ace899 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -48,6 +48,7 @@ #define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +#define S29GL064N_MN12 0x0c01
/* * Status Register bit description. Used by flash devices that don't @@ -109,6 +110,8 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { .module = THIS_MODULE };
+static bool use_chip_good_for_write; + /* * Use status register to poll for Erase/write completion when DQ is not * supported. This is indicated by Bit[1:0] of SoftwareFeatures field in @@ -283,6 +286,17 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) } #endif /* !FORCE_WORD_WRITE */
+static void fixup_use_chip_good_for_write(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + + if (cfi->mfr == CFI_MFR_AMD && cfi->id == S29GL064N_MN12) + return; + + use_chip_good_for_write = true; +} + /* Atmel chips don't use the same PRI format as AMD chips */ static void fixup_convert_atmel_pri(struct mtd_info *mtd) { @@ -462,7 +476,7 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, { CFI_MFR_AMD, 0x005F, fixup_use_secsi }, - { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, + { CFI_MFR_AMD, S29GL064N_MN12, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, @@ -474,6 +488,7 @@ static struct cfi_fixup cfi_fixup_table[] = { #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_chip_good_for_write }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { @@ -801,42 +816,61 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) return NULL; }
-/* - * Return true if the chip is ready. - * - * Ready is one of: read mode, query mode, erase-suspend-read mode (in any - * non-suspended sector) and is indicated by no toggle bits toggling. - * - * Note that anything more complicated than checking if no bits are toggling - * (including checking DQ5 for an error status) is tricky to get working - * correctly and is therefore not done (particularly with interleaved chips - * as each chip must be checked independently of the others). - */ -static int __xipram chip_ready(struct map_info *map, struct flchip *chip, - unsigned long addr) +static int __xipram chip_check(struct map_info *map, struct flchip *chip, + unsigned long addr, map_word *expected) { struct cfi_private *cfi = map->fldrv_priv; - map_word d, t; + map_word oldd, curd; + int ret;
if (cfi_use_status_reg(cfi)) { map_word ready = CMD(CFI_SR_DRB); + /* * For chips that support status register, check device * ready bit */ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - d = map_read(map, addr); + curd = map_read(map, addr);
- return map_word_andequal(map, d, ready, ready); + return map_word_andequal(map, curd, ready, ready); }
- d = map_read(map, addr); - t = map_read(map, addr); + oldd = map_read(map, addr); + curd = map_read(map, addr); + + ret = map_word_equal(map, oldd, curd); + + if (!ret || !expected) + return ret; + + return map_word_equal(map, curd, *expected); +} + +static int __xipram chip_good_for_write(struct map_info *map, + struct flchip *chip, unsigned long addr, + map_word expected) +{ + if (use_chip_good_for_write) + return chip_check(map, chip, addr, &expected);
- return map_word_equal(map, d, t); + return chip_check(map, chip, addr, NULL); }
+/* + * Return true if the chip is ready. + * + * Ready is one of: read mode, query mode, erase-suspend-read mode (in any + * non-suspended sector) and is indicated by no toggle bits toggling. + * + * Note that anything more complicated than checking if no bits are toggling + * (including checking DQ5 for an error status) is tricky to get working + * correctly and is therefore not done (particularly with interleaved chips + * as each chip must be checked independently of the others). + */ +#define chip_ready(map, chip, addr) chip_check(map, chip, addr, NULL) + /* * Return true if the chip is ready and has the correct value. * @@ -855,28 +889,7 @@ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, static int __xipram chip_good(struct map_info *map, struct flchip *chip, unsigned long addr, map_word expected) { - struct cfi_private *cfi = map->fldrv_priv; - map_word oldd, curd; - - if (cfi_use_status_reg(cfi)) { - map_word ready = CMD(CFI_SR_DRB); - - /* - * For chips that support status register, check device - * ready bit - */ - cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, - cfi->device_type, NULL); - curd = map_read(map, addr); - - return map_word_andequal(map, curd, ready, ready); - } - - oldd = map_read(map, addr); - curd = map_read(map, addr); - - return map_word_equal(map, oldd, curd) && - map_word_equal(map, curd, expected); + return chip_check(map, chip, addr, &expected); }
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) @@ -1699,7 +1712,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) && - !chip_good(map, chip, adr, datum)) { + !chip_good_for_write(map, chip, adr, datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr); @@ -1707,7 +1720,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, break; }
- if (chip_good(map, chip, adr, datum)) { + if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break; @@ -1979,14 +1992,14 @@ static int __xipram do_write_buffer_wait(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) && - !chip_good(map, chip, adr, datum)) { + !chip_good_for_write(map, chip, adr, datum)) { pr_err("MTD %s(): software timeout, address:0x%.8lx.\n", __func__, adr); ret = -EIO; break; }
- if (chip_good(map, chip, adr, datum)) { + if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
On 14.02.22 19:20, Tokunori Ikegami wrote:
The regression issue has been caused on S29GL064N and reported it. Also the change mentioned is to use chip_good() for buffered write. So disable the change on S29GL064N and use chip_ready() as before.
Fixes: dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") Signed-off-by: Tokunori Ikegami ikegami.t@gmail.com Tested-by: Ahmad Fatoum a.fatoum@pengutronix.de Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/linux-mtd/cedb1604-e024-2738-5b33-15703a653803@gmail...
I think a reference to the original thread may be useful.
Thanks for the fix! Ahmad
drivers/mtd/chips/cfi_cmdset_0002.c | 105 ++++++++++++++++------------ 1 file changed, 59 insertions(+), 46 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a761134fd3be..a0dfc8ace899 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -48,6 +48,7 @@ #define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +#define S29GL064N_MN12 0x0c01 /*
- Status Register bit description. Used by flash devices that don't
@@ -109,6 +110,8 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { .module = THIS_MODULE }; +static bool use_chip_good_for_write;
/*
- Use status register to poll for Erase/write completion when DQ is not
- supported. This is indicated by Bit[1:0] of SoftwareFeatures field in
@@ -283,6 +286,17 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) } #endif /* !FORCE_WORD_WRITE */ +static void fixup_use_chip_good_for_write(struct mtd_info *mtd) +{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- if (cfi->mfr == CFI_MFR_AMD && cfi->id == S29GL064N_MN12)
return;
- use_chip_good_for_write = true;
+}
/* Atmel chips don't use the same PRI format as AMD chips */ static void fixup_convert_atmel_pri(struct mtd_info *mtd) { @@ -462,7 +476,7 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, { CFI_MFR_AMD, 0x005F, fixup_use_secsi },
- { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
- { CFI_MFR_AMD, S29GL064N_MN12, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
@@ -474,6 +488,7 @@ static struct cfi_fixup cfi_fixup_table[] = { #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_chip_good_for_write }, { 0, 0, NULL }
}; static struct cfi_fixup jedec_fixup_table[] = { @@ -801,42 +816,61 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) return NULL; } -/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
-static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
unsigned long addr)
+static int __xipram chip_check(struct map_info *map, struct flchip *chip,
unsigned long addr, map_word *expected)
{ struct cfi_private *cfi = map->fldrv_priv;
- map_word d, t;
- map_word oldd, curd;
- int ret;
if (cfi_use_status_reg(cfi)) { map_word ready = CMD(CFI_SR_DRB);
- /*
*/ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
- For chips that support status register, check device
- ready bit
d = map_read(map, addr);
curd = map_read(map, addr);
return map_word_andequal(map, d, ready, ready);
}return map_word_andequal(map, curd, ready, ready);
- d = map_read(map, addr);
- t = map_read(map, addr);
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- ret = map_word_equal(map, oldd, curd);
- if (!ret || !expected)
return ret;
- return map_word_equal(map, curd, *expected);
+}
+static int __xipram chip_good_for_write(struct map_info *map,
struct flchip *chip, unsigned long addr,
map_word expected)
+{
- if (use_chip_good_for_write)
return chip_check(map, chip, addr, &expected);
- return map_word_equal(map, d, t);
- return chip_check(map, chip, addr, NULL);
} +/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
+#define chip_ready(map, chip, addr) chip_check(map, chip, addr, NULL)
/*
- Return true if the chip is ready and has the correct value.
@@ -855,28 +889,7 @@ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, static int __xipram chip_good(struct map_info *map, struct flchip *chip, unsigned long addr, map_word expected) {
- struct cfi_private *cfi = map->fldrv_priv;
- map_word oldd, curd;
- if (cfi_use_status_reg(cfi)) {
map_word ready = CMD(CFI_SR_DRB);
/*
* For chips that support status register, check device
* ready bit
*/
cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
curd = map_read(map, addr);
return map_word_andequal(map, curd, ready, ready);
- }
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- return map_word_equal(map, oldd, curd) &&
map_word_equal(map, curd, expected);
- return chip_check(map, chip, addr, &expected);
} static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) @@ -1699,7 +1712,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
!chip_good_for_write(map, chip, adr, datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr);
@@ -1707,7 +1720,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, break; }
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
@@ -1979,14 +1992,14 @@ static int __xipram do_write_buffer_wait(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
}!chip_good_for_write(map, chip, adr, datum)) { pr_err("MTD %s(): software timeout, address:0x%.8lx.\n", __func__, adr); ret = -EIO; break;
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
Hi,
On 14/02/22 11:50 pm, Tokunori Ikegami wrote:
The regression issue has been caused on S29GL064N and reported it. Also the change mentioned is to use chip_good() for buffered write. So disable the change on S29GL064N and use chip_ready() as before.
Fixes: dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") Signed-off-by: Tokunori Ikegami ikegami.t@gmail.com Tested-by: Ahmad Fatoum a.fatoum@pengutronix.de Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org
Thanks for working on the fix.
Please CC maintainers from
./scripts/get_maintainer.pl -f drivers/mtd/chips/cfi_cmdset_0002.c
Else, patch would not get attention in time.
drivers/mtd/chips/cfi_cmdset_0002.c | 105 ++++++++++++++++------------ 1 file changed, 59 insertions(+), 46 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a761134fd3be..a0dfc8ace899 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -48,6 +48,7 @@ #define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +#define S29GL064N_MN12 0x0c01 /*
- Status Register bit description. Used by flash devices that don't
@@ -109,6 +110,8 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { .module = THIS_MODULE }; +static bool use_chip_good_for_write;
Can we use per device private flag? Else this wont work on systems with multiple CFI flashes with one of them being S29GL064N_MN12.
/*
- Use status register to poll for Erase/write completion when DQ is not
- supported. This is indicated by Bit[1:0] of SoftwareFeatures field in
@@ -283,6 +286,17 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) } #endif /* !FORCE_WORD_WRITE */ +static void fixup_use_chip_good_for_write(struct mtd_info *mtd) +{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- if (cfi->mfr == CFI_MFR_AMD && cfi->id == S29GL064N_MN12)
return;
- use_chip_good_for_write = true;
+}
/* Atmel chips don't use the same PRI format as AMD chips */ static void fixup_convert_atmel_pri(struct mtd_info *mtd) { @@ -462,7 +476,7 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, { CFI_MFR_AMD, 0x005F, fixup_use_secsi },
- { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
- { CFI_MFR_AMD, S29GL064N_MN12, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
@@ -474,6 +488,7 @@ static struct cfi_fixup cfi_fixup_table[] = { #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_chip_good_for_write }, { 0, 0, NULL }
}; static struct cfi_fixup jedec_fixup_table[] = { @@ -801,42 +816,61 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) return NULL; } -/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
-static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
unsigned long addr)
+static int __xipram chip_check(struct map_info *map, struct flchip *chip,
unsigned long addr, map_word *expected)
{ struct cfi_private *cfi = map->fldrv_priv;
- map_word d, t;
- map_word oldd, curd;
- int ret;
if (cfi_use_status_reg(cfi)) { map_word ready = CMD(CFI_SR_DRB);
Unrelated change?
/* * For chips that support status register, check device * ready bit */ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
d = map_read(map, addr);
curd = map_read(map, addr);
return map_word_andequal(map, d, ready, ready);
}return map_word_andequal(map, curd, ready, ready);
- d = map_read(map, addr);
- t = map_read(map, addr);
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- ret = map_word_equal(map, oldd, curd);
- if (!ret || !expected)
return ret;
Why even read oldd and curd if !expected ?
- return map_word_equal(map, curd, *expected);
+}
+static int __xipram chip_good_for_write(struct map_info *map,
struct flchip *chip, unsigned long addr,
map_word expected)
+{
- if (use_chip_good_for_write)
return chip_check(map, chip, addr, &expected);
- return map_word_equal(map, d, t);
- return chip_check(map, chip, addr, NULL);
} +/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
+#define chip_ready(map, chip, addr) chip_check(map, chip, addr, NULL)
/*
- Return true if the chip is ready and has the correct value.
@@ -855,28 +889,7 @@ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, static int __xipram chip_good(struct map_info *map, struct flchip *chip, unsigned long addr, map_word expected) {
- struct cfi_private *cfi = map->fldrv_priv;
- map_word oldd, curd;
- if (cfi_use_status_reg(cfi)) {
map_word ready = CMD(CFI_SR_DRB);
/*
* For chips that support status register, check device
* ready bit
*/
cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
curd = map_read(map, addr);
return map_word_andequal(map, curd, ready, ready);
- }
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- return map_word_equal(map, oldd, curd) &&
map_word_equal(map, curd, expected);
- return chip_check(map, chip, addr, &expected);
} static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) @@ -1699,7 +1712,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
!chip_good_for_write(map, chip, adr, datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr);
@@ -1707,7 +1720,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, break; }
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
@@ -1979,14 +1992,14 @@ static int __xipram do_write_buffer_wait(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
}!chip_good_for_write(map, chip, adr, datum)) { pr_err("MTD %s(): software timeout, address:0x%.8lx.\n", __func__, adr); ret = -EIO; break;
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
Hi,
ThanksĀ for your review and comments.
On 2022/03/01 0:34, Vignesh Raghavendra wrote:
Hi,
On 14/02/22 11:50 pm, Tokunori Ikegami wrote:
The regression issue has been caused on S29GL064N and reported it. Also the change mentioned is to use chip_good() for buffered write. So disable the change on S29GL064N and use chip_ready() as before.
Fixes: dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") Signed-off-by: Tokunori Ikegami ikegami.t@gmail.com Tested-by: Ahmad Fatoum a.fatoum@pengutronix.de Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org
Thanks for working on the fix.
Please CC maintainers from
./scripts/get_maintainer.pl -f drivers/mtd/chips/cfi_cmdset_0002.c
Else, patch would not get attention in time.
Just added the maintainers as CC by the version 2 patch.
drivers/mtd/chips/cfi_cmdset_0002.c | 105 ++++++++++++++++------------ 1 file changed, 59 insertions(+), 46 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a761134fd3be..a0dfc8ace899 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -48,6 +48,7 @@ #define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +#define S29GL064N_MN12 0x0c01 /*
- Status Register bit description. Used by flash devices that don't
@@ -109,6 +110,8 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { .module = THIS_MODULE }; +static bool use_chip_good_for_write;
Can we use per device private flag? Else this wont work on systems with multiple CFI flashes with one of them being S29GL064N_MN12.
Yes fixed the patch to check the cfi mfr and id values directly instead of the static variable.
/*
- Use status register to poll for Erase/write completion when DQ is not
- supported. This is indicated by Bit[1:0] of SoftwareFeatures field in
@@ -283,6 +286,17 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) } #endif /* !FORCE_WORD_WRITE */ +static void fixup_use_chip_good_for_write(struct mtd_info *mtd) +{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- if (cfi->mfr == CFI_MFR_AMD && cfi->id == S29GL064N_MN12)
return;
- use_chip_good_for_write = true;
+}
- /* Atmel chips don't use the same PRI format as AMD chips */ static void fixup_convert_atmel_pri(struct mtd_info *mtd) {
@@ -462,7 +476,7 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, { CFI_MFR_AMD, 0x005F, fixup_use_secsi },
- { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
- { CFI_MFR_AMD, S29GL064N_MN12, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
@@ -474,6 +488,7 @@ static struct cfi_fixup cfi_fixup_table[] = { #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_chip_good_for_write }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = {
@@ -801,42 +816,61 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) return NULL; } -/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
-static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
unsigned long addr)
+static int __xipram chip_check(struct map_info *map, struct flchip *chip,
{ struct cfi_private *cfi = map->fldrv_priv;unsigned long addr, map_word *expected)
- map_word d, t;
- map_word oldd, curd;
- int ret;
if (cfi_use_status_reg(cfi)) { map_word ready = CMD(CFI_SR_DRB);
Unrelated change?
Yes deleted the empty line added.
/* * For chips that support status register, check device * ready bit */ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
d = map_read(map, addr);
curd = map_read(map, addr);
return map_word_andequal(map, d, ready, ready);
}return map_word_andequal(map, curd, ready, ready);
- d = map_read(map, addr);
- t = map_read(map, addr);
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- ret = map_word_equal(map, oldd, curd);
- if (!ret || !expected)
return ret;
Why even read oldd and curd if !expected ?
Since required this for chip ready that checks the oldd and curd if equal or not.
Regards, Ikegami
- return map_word_equal(map, curd, *expected);
+}
+static int __xipram chip_good_for_write(struct map_info *map,
struct flchip *chip, unsigned long addr,
map_word expected)
+{
- if (use_chip_good_for_write)
return chip_check(map, chip, addr, &expected);
- return map_word_equal(map, d, t);
- return chip_check(map, chip, addr, NULL); }
+/*
- Return true if the chip is ready.
- Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- non-suspended sector) and is indicated by no toggle bits toggling.
- Note that anything more complicated than checking if no bits are toggling
- (including checking DQ5 for an error status) is tricky to get working
- correctly and is therefore not done (particularly with interleaved chips
- as each chip must be checked independently of the others).
- */
+#define chip_ready(map, chip, addr) chip_check(map, chip, addr, NULL)
- /*
- Return true if the chip is ready and has the correct value.
@@ -855,28 +889,7 @@ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, static int __xipram chip_good(struct map_info *map, struct flchip *chip, unsigned long addr, map_word expected) {
- struct cfi_private *cfi = map->fldrv_priv;
- map_word oldd, curd;
- if (cfi_use_status_reg(cfi)) {
map_word ready = CMD(CFI_SR_DRB);
/*
* For chips that support status register, check device
* ready bit
*/
cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
curd = map_read(map, addr);
return map_word_andequal(map, curd, ready, ready);
- }
- oldd = map_read(map, addr);
- curd = map_read(map, addr);
- return map_word_equal(map, oldd, curd) &&
map_word_equal(map, curd, expected);
- return chip_check(map, chip, addr, &expected); }
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) @@ -1699,7 +1712,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
!chip_good_for_write(map, chip, adr, datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr);
@@ -1707,7 +1720,7 @@ static int __xipram do_write_oneword_once(struct map_info *map, break; }
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
@@ -1979,14 +1992,14 @@ static int __xipram do_write_buffer_wait(struct map_info *map, * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) &&
!chip_good(map, chip, adr, datum)) {
}!chip_good_for_write(map, chip, adr, datum)) { pr_err("MTD %s(): software timeout, address:0x%.8lx.\n", __func__, adr); ret = -EIO; break;
if (chip_good(map, chip, adr, datum)) {
if (chip_good_for_write(map, chip, adr, datum)) { if (cfi_check_err_status(map, chip, adr)) ret = -EIO; break;
Hi, this is your Linux kernel regression tracker.
On 14.02.22 19:20, Tokunori Ikegami wrote:
The regression issue has been caused on S29GL064N and reported it. Also the change mentioned is to use chip_good() for buffered write. So disable the change on S29GL064N and use chip_ready() as before.
Fixes: dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") Signed-off-by: Tokunori Ikegami ikegami.t@gmail.com Tested-by: Ahmad Fatoum a.fatoum@pengutronix.de Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org
This is missing a "Link:" tag pointing to the report:
Link: https://lore.kernel.org/r/b687c259-6413-26c9-d4c9-b3afa69ea124@pengutronix.d...
'Documentation/process/submitting-patches.rst' and 'Documentation/process/5.Posting.rst' explain this in more detail. Such tags are important for me, as it allows my regression tracking bot to connect the report with any patches posted or committed to fix the issue; this again allows the bot to show the current status of regressions and automatically resolve the issue when the fix hits the right tree.
BTW, what's the status of getting an improved fix merged? It seems the progress slowed down quite a bit.
Ciao, Thorsten (wearing his 'the Linux kernel's regression tracker' hat)
P.S.: As the Linux kernel's regression tracker I'm getting a lot of reports on my table. I can only look briefly into most of them and lack knowledge about most of the areas they concern. I thus unfortunately will sometimes get things wrong or miss something important. I hope that's not the case here; if you think it is, don't hesitate to tell me in a public reply, it's in everyone's interest to set the public record straight.
#regzbot ^backmonitor: https://lore.kernel.org/lkml/b687c259-6413-26c9-d4c9-b3afa69ea124@pengutroni...
linux-stable-mirror@lists.linaro.org