[PATCH 08/15] mtd: spi-nor: Fix SWP for octal DTR chips
Miquel Raynal
miquel.raynal at bootlin.com
Fri Oct 2 05:21:21 PDT 2026
During the recent rework of status registers handling, we mostly focused
on quad capable devices, partially skipping ODTR devices in our mental
model. It seems that many (if not all?) ODTR devices have no SR2 read
opcode and have other control mechanisms. Because of that, the current
support in swp.c is broken, because reading back the written value may
or may not lead to the expected result.
Let's extend the _careful() suffix to the helper reading back the values
and comparing them. Maybe this "carfulness" will have to be moved back
to the core, it is a bit early to state it. For now, let's just make
sure that we read back 0s without errors when virtually accessing SR2 on
those chips.
Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
---
drivers/mtd/spi-nor/core.c | 2 +-
drivers/mtd/spi-nor/core.h | 1 +
drivers/mtd/spi-nor/swp.c | 23 +++++++++++++++++++++--
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 152add3834fc..4926a3193891 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -927,7 +927,7 @@ int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2)
*
* Return 0 or errno.
*/
-static int spi_nor_write_sr1_and_sr2(struct spi_nor *nor, const u8 *sr)
+int spi_nor_write_sr1_and_sr2(struct spi_nor *nor, const u8 *sr)
{
struct spi_nor_flash_parameter *params = nor->params;
int ret;
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index b64f26b69c05..cee33ca18b04 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -664,6 +664,7 @@ int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2);
int spi_nor_read_sr1_and_sr2(struct spi_nor *nor, u8 *sr);
int spi_nor_write_sr1(struct spi_nor *nor, const u8 *sr1);
int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2);
+int spi_nor_write_sr1_and_sr2(struct spi_nor *nor, const u8 *sr);
int spi_nor_write_sr1_and_sr2_and_check(struct spi_nor *nor, const u8 *sr);
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c
index 7e667e4ca84d..e9cf2ca23234 100644
--- a/drivers/mtd/spi-nor/swp.c
+++ b/drivers/mtd/spi-nor/swp.c
@@ -240,6 +240,25 @@ static int spi_nor_read_sr1_and_sr2_careful(struct spi_nor *nor, u8 *sr)
return spi_nor_read_sr2_careful(nor, &sr[1]);
}
+static int spi_nor_write_sr1_and_sr2_and_check_careful(struct spi_nor *nor, const u8 *sr)
+{
+ u8 tmp[2];
+ int ret;
+
+ ret = spi_nor_write_sr1_and_sr2(nor, sr);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_read_sr1_and_sr2_careful(nor, tmp);
+ if (ret)
+ return ret;
+
+ if (sr[0] != tmp[0] || sr[1] != tmp[1])
+ return -EIO;
+
+ return 0;
+}
+
/*
* Keep a local cache containing all lock-related bits for debugfs use only.
* This way, debugfs never needs to access the flash directly.
@@ -407,7 +426,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
(ofs_old < ofs_new || (ofs_new + len_new) < (ofs_old + len_old)))
return -EINVAL;
- ret = spi_nor_write_sr1_and_sr2_and_check(nor, best_status_new);
+ ret = spi_nor_write_sr1_and_sr2_and_check_careful(nor, best_status_new);
if (ret)
return ret;
@@ -529,7 +548,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
(ofs_new < ofs_old || (ofs_old + len_old) < (ofs_new + len_new)))
return -EINVAL;
- ret = spi_nor_write_sr1_and_sr2_and_check(nor, best_status_new);
+ ret = spi_nor_write_sr1_and_sr2_and_check_careful(nor, best_status_new);
if (ret)
return ret;
--
2.55.0
More information about the linux-mtd
mailing list