Skip to contentSkip to conversation

FAILED: patch "[PATCH] mtd: spi-nor: swp: Improve locking user experience" failed to apply to 5.10-stable tree

PATCH New [email protected] 2 participants 6 messages Jul 20 – Jul 26

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x e1d456b26bf23e30db305a6184e8abd9ab68bbf2
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026072003-borrowing-opium-38cc@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From e1d456b26bf23e30db305a6184e8abd9ab68bbf2 Mon Sep 17 00:00:00 2001
From: Miquel Raynal <[email protected]>
Date: Tue, 26 May 2026 16:56:26 +0200
Subject: [PATCH] mtd: spi-nor: swp: Improve locking user experience

In the case of the first block being locked (or the few first blocks), if the user want to fully unlock the device it has two possibilities:
- either it asks to unlock the entire device, and this works;
- or it asks to unlock just the block(s) that are currently locked, which fails.

It fails because the conditions "can_be_top" and "can_be_bottom" are true. Indeed, in this case, we unlock everything, so the TB bit does not matter. However in the current implementation, use_top would be true (as this is the favourite option) and lock_len, which in practice should be reduced down to 0, is set to "nor->params->size - (ofs + len)" which is a positive number. This is wrong.

An easy way is to simply add an extra condition. In the unlock() path, if we can achieve the same result from both sides, it means we unlock everything and lock_len must simply be 0. A comment is added to clarify that logic.

Fixes 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support")
drivers/mtd/spi-nor/swp.c +9 -2
index e67a81dbb6bf..d5f4bf555cfc 100644
@@ -282,8 +282,15 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
 	/* Prefer top, if both are valid */
 	use_top = can_be_top;
 
-	/* lock_len: length of region that should remain locked */
-	if (use_top)
+	/*
+	 * lock_len: length of region that should remain locked.
+	 *
+	 * When can_be_top and can_be_bottom booleans are true, both adjacent
+	 * regions are unlocked, thus the entire flash can be unlocked.
+	 */
+	if (can_be_top && can_be_bottom)
+		lock_len = 0;
+	else if (use_top)
 		lock_len = nor->params->size - (ofs + len);
 	else
 		lock_len = ofs;
maintainer
#1 lore raw

PATCH 1/5 mtd: spi-nor: sst: remove global protection flag

From: Michael Walle <[email protected]>

[ Upstream commit a833383732116c2afe665520bbe6951999631ef1 ]

This is considered bad for the following reasons:
(1) We only support the block protection with BPn bits for write protection. Not all SST parts support this.
(2) Newly added flash chip will automatically inherit the "has locking" support and thus needs to explicitly tested. Better be opt-in instead of opt-out.
(3) There are already supported flashes which doesn't support the locking scheme. So I assume this wasn't properly tested before adding that chip; which enforces my previous argument that locking support should be an opt-in.

Remove the global flag and add individual flags to all flashes which supports BP locking. In particular the following flashes don't support the BP scheme:
- SST26VF016B
- SST26WF016B
- SST26VF064B

Stable-dep-of: e1d456b26bf2 ("mtd: spi-nor: swp: Improve locking user experience")

---
 drivers/mtd/spi-nor/sst.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)
drivers/mtd/spi-nor/sst.c +12 -18
index 777c8225f5bdcf..2fd2a162ab3be3 100644
@@ -11,27 +11,27 @@
 static const struct flash_info sst_parts[] = {
 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
 	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128,
-			      SECT_4K | SPI_NOR_4BIT_BP) },
+			      SECT_4K | SPI_NOR_4BIT_BP | SPI_NOR_HAS_LOCK) },
 	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4,
-			      SECT_4K | SST_WRITE) },
-	{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K) },
-	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
+	{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K | SPI_NOR_HAS_LOCK) },
+	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K | SPI_NOR_HAS_LOCK) },
 	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16,
-			      SECT_4K | SST_WRITE) },
+			      SECT_4K | SST_WRITE | SPI_NOR_HAS_LOCK) },
 	{ "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32,
 			      SECT_4K | SPI_NOR_DUAL_READ |
 			      SPI_NOR_QUAD_READ) },
@@ -141,11 +141,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 	return ret;
 }
 
-static void sst_default_init(struct spi_nor *nor)
-{
-	nor->flags |= SNOR_F_HAS_LOCK;
-}
-
 static void sst_post_sfdp_fixups(struct spi_nor *nor)
 {
 	if (nor->info->flags & SST_WRITE)
@@ -153,7 +148,6 @@ static void sst_post_sfdp_fixups(struct spi_nor *nor)
 }
 
 static const struct spi_nor_fixups sst_fixups = {
-	.default_init = sst_default_init,
 	.post_sfdp = sst_post_sfdp_fixups,
 };
 
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/5 mtd: spi-nor: intel: remove global protection flag

From: Michael Walle <[email protected]>

[ Upstream commit afcf93e9d63fc1e15935a2df9457f803394e4f20 ]

For the Atmel and SST parts this flag was already moved to individual flash parts because it is considered bad esp. because newer flash chips will automatically inherit the "has locking" support. While this won't likely be the case for the Intel parts, we do it for consistency reasons.

Stable-dep-of: e1d456b26bf2 ("mtd: spi-nor: swp: Improve locking user experience")

---
 drivers/mtd/spi-nor/intel.c | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)
drivers/mtd/spi-nor/intel.c +3 -13
index d8196f101368fd..6c31bef3fc60d1 100644
@@ -10,23 +10,13 @@
 
 static const struct flash_info intel_parts[] = {
 	/* Intel/Numonyx -- xxxs33b */
-	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
-	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
-	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
-};
-
-static void intel_default_init(struct spi_nor *nor)
-{
-	nor->flags |= SNOR_F_HAS_LOCK;
-}
-
-static const struct spi_nor_fixups intel_fixups = {
-	.default_init = intel_default_init,
+	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, SPI_NOR_HAS_LOCK) },
+	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, SPI_NOR_HAS_LOCK) },
+	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, SPI_NOR_HAS_LOCK) },
 };
 
 const struct spi_nor_manufacturer spi_nor_intel = {
 	.name = "intel",
 	.parts = intel_parts,
 	.nparts = ARRAY_SIZE(intel_parts),
-	.fixups = &intel_fixups,
 };
Signature · 1 line
2.53.0
maintainer
#3 lore raw

PATCH 3/5 mtd: spi-nor: Move Software Write Protection logic out of the core

In reply to Sasha Levin

From: Tudor Ambarus <[email protected]>

[ Upstream commit c4c795105f2924c80752c30ffd3c7029a8e0ef28 ]

It makes the core file a bit smaller and provides better separation between the Software Write Protection features and the core logic. All the next generic software write protection features (e.g. Individual Block Protection) will reside in swp.c.

Stable-dep-of: e1d456b26bf2 ("mtd: spi-nor: swp: Improve locking user experience")

---
 drivers/mtd/spi-nor/Makefile |   2 +-
 drivers/mtd/spi-nor/core.c   | 406 +--------------------------------
 drivers/mtd/spi-nor/core.h   |   5 +
 drivers/mtd/spi-nor/swp.c    | 421 +++++++++++++++++++++++++++++++++++
 4 files changed, 431 insertions(+), 403 deletions(-)
 create mode 100644 drivers/mtd/spi-nor/swp.c
drivers/mtd/spi-nor/Makefile +1 -1
index 653923896205c2..da05b03f28d2f0 100644
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spi-nor-objs			:= core.o sfdp.o
+spi-nor-objs			:= core.o sfdp.o swp.o
 spi-nor-objs			+= atmel.o
 spi-nor-objs			+= catalyst.o
 spi-nor-objs			+= eon.o
drivers/mtd/spi-nor/core.c +4 -402

442 lines not on this page · raw message

drivers/mtd/spi-nor/core.h +5 -0
index 788775bb67958d..ae59600138c598 100644
@@ -409,6 +409,7 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor);
 int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
 int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
+int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
 int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
 
 int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
@@ -435,6 +436,10 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor,
 			     const struct sfdp_bfpt *bfpt,
 			     struct spi_nor_flash_parameter *params);
 
+void spi_nor_init_default_locking_ops(struct spi_nor *nor);
+void spi_nor_try_unlock_all(struct spi_nor *nor);
+void spi_nor_register_locking_ops(struct spi_nor *nor);
+
 static struct spi_nor __maybe_unused *mtd_to_spi_nor(struct mtd_info *mtd)
 {
 	return mtd->priv;
drivers/mtd/spi-nor/swp.c new file +421 -0

421 lines not on this page · raw message

Signature · 1 line
2.53.0
maintainer
#4 lore raw

PATCH 4/5 mtd: spi-nor: Fix spi_nor_try_unlock_all()

In reply to Sasha Levin

From: Michael Walle <[email protected]>

[ Upstream commit 2e3a7476ec3989e77270b9481e76e137824b17c0 ]

Commit ff67592cbdfc ("mtd: spi-nor: Introduce spi_nor_set_mtd_info()") moved all initialization of the mtd fields at the end of spi_nor_scan(). Normally, the mtd info is only needed for the mtd ops on the device, with one exception: spi_nor_try_unlock_all(), which will also make use of the mtd->size parameter. With that commit, the size will always be zero because it is not initialized. Fix that by not using the size of the mtd_info struct, but use the size from struct spi_nor_flash_parameter.

Stable-dep-of: e1d456b26bf2 ("mtd: spi-nor: swp: Improve locking user experience")

---
 drivers/mtd/spi-nor/swp.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)
drivers/mtd/spi-nor/swp.c +6 -8
index df573601fe85c6..8036073a199ee1 100644
@@ -50,7 +50,6 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
 static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
 					uint64_t *len)
 {
-	struct mtd_info *mtd = &nor->mtd;
 	u64 min_prot_len;
 	u8 mask = spi_nor_get_sr_bp_mask(nor);
 	u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
@@ -71,13 +70,13 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
 	min_prot_len = spi_nor_get_min_prot_length_sr(nor);
 	*len = min_prot_len << (bp - 1);
 
-	if (*len > mtd->size)
-		*len = mtd->size;
+	if (*len > nor->params->size)
+		*len = nor->params->size;
 
 	if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
 		*ofs = 0;
 	else
-		*ofs = mtd->size - *len;
+		*ofs = nor->params->size - *len;
 }
 
 /*
@@ -150,7 +149,6 @@ static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
  */
 static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-	struct mtd_info *mtd = &nor->mtd;
 	u64 min_prot_len;
 	int ret, status_old, status_new;
 	u8 mask = spi_nor_get_sr_bp_mask(nor);
@@ -175,7 +173,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 		can_be_bottom = false;
 
 	/* If anything above us is unlocked, we can't use 'top' protection */
-	if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
+	if (!spi_nor_is_locked_sr(nor, ofs + len, nor->params->size - (ofs + len),
 				  status_old))
 		can_be_top = false;
 
@@ -187,11 +185,11 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	/* lock_len: length of region that should end up locked */
 	if (use_top)
-		lock_len = mtd->size - ofs;
+		lock_len = nor->params->size - ofs;
 	else
 		lock_len = ofs + len;
 
-	if (lock_len == mtd->size) {
+	if (lock_len == nor->params->size) {
 		val = mask;
 	} else {
 		min_prot_len = spi_nor_get_min_prot_length_sr(nor);
Signature · 1 line
2.53.0
maintainer
#5 lore raw

PATCH 5/5 mtd: spi-nor: swp: Improve locking user experience

In reply to Sasha Levin

From: Miquel Raynal <[email protected]>

[ Upstream commit e1d456b26bf23e30db305a6184e8abd9ab68bbf2 ]

In the case of the first block being locked (or the few first blocks), if the user want to fully unlock the device it has two possibilities:
- either it asks to unlock the entire device, and this works;
- or it asks to unlock just the block(s) that are currently locked, which fails.

It fails because the conditions "can_be_top" and "can_be_bottom" are true. Indeed, in this case, we unlock everything, so the TB bit does not matter. However in the current implementation, use_top would be true (as this is the favourite option) and lock_len, which in practice should be reduced down to 0, is set to "nor->params->size - (ofs + len)" which is a positive number. This is wrong.

An easy way is to simply add an extra condition. In the unlock() path, if we can achieve the same result from both sides, it means we unlock everything and lock_len must simply be 0. A comment is added to clarify that logic.

Fixes 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support")
---
 drivers/mtd/spi-nor/swp.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/spi-nor/swp.c +9 -2
index 8036073a199ee1..8aca0203a62157 100644
@@ -267,8 +267,15 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	/* Prefer top, if both are valid */
 	use_top = can_be_top;
 
-	/* lock_len: length of region that should remain locked */
-	if (use_top)
+	/*
+	 * lock_len: length of region that should remain locked.
+	 *
+	 * When can_be_top and can_be_bottom booleans are true, both adjacent
+	 * regions are unlocked, thus the entire flash can be unlocked.
+	 */
+	if (can_be_top && can_be_bottom)
+		lock_len = 0;
+	else if (use_top)
 		lock_len = nor->params->size - (ofs + len);
 	else
 		lock_len = ofs;
Signature · 1 line
2.53.0