All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates
@ 2016-01-29 19:25 Brian Norris
  2016-01-29 19:25 ` [PATCH v2 1/8] mtd: spi-nor: wait for SR_WIP to clear on initial unlock Brian Norris
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

Hi,

These are an assortment of fixes and updates to the SPI NOR lock/unlock
feature. The biggest new features are:
(a) Status Register protection; I don't see why this shouldn't be enabled by
    default. See patch 4's description.
(b) Bottom-block protection support (via TB status bit)
(c) Lock/unlock support for a few Winbond flash

Since v1:
 * patches 3 and 7 are somewhat rewritten versions of patches 2 and 7 in v1
 * fix up several corner cases, seen in some local tests (poor, slow shell
   script appended)
 * remove SR protection (SR_SRWD) when unlocking the entire flash

Regards,
Brian

Brian Norris (8):
  mtd: spi-nor: wait for SR_WIP to clear on initial unlock
  mtd: spi-nor: silently drop lock/unlock for already locked/unlocked
    region
  mtd: spi-nor: make lock/unlock bounds checks more obvious and robust
  mtd: spi-nor: disallow further writes to SR if WP# is low
  mtd: spi-nor: use BIT() for flash_info flags
  mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
  mtd: spi-nor: add TB (Top/Bottom) protect support
  mtd: spi-nor: support lock/unlock for a few Winbond chips

 drivers/mtd/spi-nor/spi-nor.c | 195 ++++++++++++++++++++++++++++++++++--------
 include/linux/mtd/spi-nor.h   |   2 +
 2 files changed, 159 insertions(+), 38 deletions(-)


Appending badly-written shell test script. Requires latest mtd-utils
(flash_lock / flash_unlock).

------8<------
#!/bin/sh
#
# License: GPLv2
# Copyright (c) 2016 Google, Inc.

MTD=/dev/mtd0

UNLOCK="flash_unlock ${MTD}"
LOCK="flash_lock ${MTD}"
ISLOCKED="flash_lock --islocked ${MTD}"

MTD_SYSFS="/sys/class/mtd"

MTDX=$(echo $MTD | grep -o '[0-9]*$')
echo "MTD #: $MTDX"

MTDX_SYSFS="${MTD_SYSFS}/mtd${MTDX}"

SIZE=$(cat ${MTDX_SYSFS}/size)
EB_SIZE=$(cat ${MTDX_SYSFS}/erasesize)
NUM_EBS=$((SIZE / EB_SIZE))

log_msg() {
	echo "${MTD}: $@"
}

err_msg() {
	log_msg $@ 1>&2
}

dbg_msg() {
	# both go to stderr for now
	[ "$DEBUG" != "" ] && err_msg $@
}

exit_err_msg() {
	err_msg $@
	exit 1
}

# echo 1 for locked, 0 for unlocked; return non-zero on error
is_locked() {
	local out="$(${ISLOCKED} $@ | grep 'Return code:')"
	[ $? -ne 0 ] && return 1
	out=$(echo "$out" | cut -d' ' -f3)
	dbg_msg "Range [$@] lock status: $out"
	echo $out
}

# check that *each* eraseblock has a particular status; return non-zero on
# error, zero for successful match
is_locked_ebs() {
	local addr=${1:-0}
	local num_ebs=${2:-${NUM_EBS}}
	local lock_status=${3:-1}
	local last_addr=$((addr + (num_ebs - 1) * EB_SIZE))
	local ret=0

	for ofs in $(seq $addr $EB_SIZE $last_addr); do
		ret=$(is_locked $ofs 1)
		[ $? -ne 0 ] && return 1
		[ "$ret" -ne "$lock_status" ] && err_msg "block $ofs has unexpected status $ret" && return 1
	done
	return 0
}

check_locked() {
	local addr=$1
	local num_ebs=$2
	local lock_status=$3

	local ret=$(is_locked $addr $num_ebs) || exit 1
	is_locked_ebs $addr $num_ebs $lock_status || exit 1
	if [ "$ret" -ne "$lock_status" ]; then
		exit_err_msg "lock status is incorrect"
	else
		log_msg "verified lock status $@"
	fi
}

if ! ${UNLOCK} ; then
	err_msg "error unlocking; MEMUNLOCK not supported?"
	exit 1
fi

main() {
	log_msg "unlocked device"
	check_locked 0 $NUM_EBS 0

	log_msg "locking upper half"
	${LOCK} $((SIZE / 2)) $((NUM_EBS / 2)) || exit 1
	check_locked $((SIZE / 2)) $((NUM_EBS / 2)) 1
	check_locked 0 $((NUM_EBS / 2)) 0

	log_msg "relocking 4th quadrant"
	${LOCK} $((SIZE * 3 / 4)) $((NUM_EBS / 4)) || exit 1
	check_locked $((SIZE / 2)) $((NUM_EBS / 2)) 1
	check_locked 0 $((NUM_EBS / 2)) 0

	log_msg "relocking ranges"
	## Picked some arbitrary increments, since an exhaustive loop takes too
	## long
	for i in $(seq $((SIZE / 2)) $((EB_SIZE * 5)) $((SIZE - EB_SIZE))); do
		for j in $(seq 0 7 $(((SIZE - i) / EB_SIZE - 1))); do
			log_msg "Range: $i $j"
			${LOCK} $i $j || exit 1
		done
	done
	check_locked $((SIZE / 2)) $((NUM_EBS / 2)) 1
	check_locked 0 $((NUM_EBS / 2)) 0

	log_msg "unlocking 3rd quadrant"
	${UNLOCK} $((SIZE / 2)) $((NUM_EBS / 4)) || exit 1
	check_locked $((SIZE * 3 / 4)) $((NUM_EBS / 4)) 1
	check_locked 0 $((NUM_EBS * 3 / 4)) 0

	log_msg "unlocking 1st quadrant (again)"
	${UNLOCK} 0 $((NUM_EBS / 4)) || exit 1
	check_locked $((SIZE * 3 / 4)) $((NUM_EBS / 4)) 1
	check_locked 0 $((NUM_EBS * 3 / 4)) 0

	log_msg "unlocking 4th quadrant"
	${UNLOCK} $((SIZE * 3 / 4)) $((NUM_EBS / 4)) || exit 1
	check_locked 0 $NUM_EBS 0

	log_msg "locking 1st half"
	if ! ${LOCK} 0 $((NUM_EBS / 2)) ; then
		err_msg "does not support bottom-block protection? skipping tests"
		return 0
	fi
	check_locked 0 $((NUM_EBS / 2)) 1
	check_locked $((SIZE / 2)) $((NUM_EBS / 2)) 0

	${UNLOCK} 0 $((NUM_EBS / 4)) && \
		exit_err_msg "error: was able to unlock 1st quadrant"
	log_msg "saw error, expected"
	check_locked 0 $((NUM_EBS / 2)) 1
	check_locked $((SIZE / 2)) $((NUM_EBS / 2)) 0

	log_msg "unlocking 2nd quadrant"
	${UNLOCK} $((SIZE / 4)) $((NUM_EBS / 4)) || exit 1
	check_locked 0 $((NUM_EBS / 4)) 1
	check_locked $((SIZE / 4)) $((NUM_EBS * 3 / 4)) 0

	log_msg "unlocking top 3 quadrants (again)"
	${UNLOCK} $((SIZE / 4)) $((NUM_EBS * 3 / 4)) || exit 1
	check_locked 0 $((NUM_EBS / 4)) 1
	check_locked $((SIZE / 4)) $((NUM_EBS * 3 / 4)) 0
}

main
log_msg "test complete"

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/8] mtd: spi-nor: wait for SR_WIP to clear on initial unlock
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-01-29 19:25 ` [PATCH v2 2/8] mtd: spi-nor: silently drop lock/unlock for already locked/unlocked region Brian Norris
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz,
	Stas Sergeev

Fixup a piece leftover by commit 32321e950d8a ("mtd: spi-nor: wait until
lock/unlock operations are ready"). That commit made us wait for the WIP
bit to settle after lock/unlock operations, but it missed the open-coded
"unlock" that happens at probe() time.

We should probably have this code utilize the unlock() routines in the
future, to avoid duplication, but unfortunately, flash which need to be
unlocked don't all have a proper ->flash_unlock() callback.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Cc: Stas Sergeev <stsp@users.sourceforge.net>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
---
v2: no change

 drivers/mtd/spi-nor/spi-nor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index ed0c19c558b5..ef89bed1e5ea 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1236,6 +1236,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	    JEDEC_MFR(info) == SNOR_MFR_SST) {
 		write_enable(nor);
 		write_sr(nor, 0);
+		spi_nor_wait_till_ready(nor);
 	}
 
 	if (!mtd->name)
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/8] mtd: spi-nor: silently drop lock/unlock for already locked/unlocked region
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
  2016-01-29 19:25 ` [PATCH v2 1/8] mtd: spi-nor: wait for SR_WIP to clear on initial unlock Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-01-29 19:25 ` [PATCH v2 3/8] mtd: spi-nor: make lock/unlock bounds checks more obvious and robust Brian Norris
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

If, for instance, the entire flash is already unlocked and I try to
mtd_unlock() the entire device, I don't expect to see an EINVAL error.
It should just silently succeed. Ditto for mtd_lock().

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
---
v2: no change

 drivers/mtd/spi-nor/spi-nor.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index ef89bed1e5ea..77c88ac69ef9 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -515,8 +515,12 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	status_new = (status_old & ~mask) | val;
 
+	/* Don't bother if they're the same */
+	if (status_new == status_old)
+		return 0;
+
 	/* Only modify protection if it will not unlock other areas */
-	if ((status_new & mask) <= (status_old & mask))
+	if ((status_new & mask) < (status_old & mask))
 		return -EINVAL;
 
 	write_enable(nor);
@@ -569,8 +573,12 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	status_new = (status_old & ~mask) | val;
 
+	/* Don't bother if they're the same */
+	if (status_new == status_old)
+		return 0;
+
 	/* Only modify protection if it will not lock other areas */
-	if ((status_new & mask) >= (status_old & mask))
+	if ((status_new & mask) > (status_old & mask))
 		return -EINVAL;
 
 	write_enable(nor);
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/8] mtd: spi-nor: make lock/unlock bounds checks more obvious and robust
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
  2016-01-29 19:25 ` [PATCH v2 1/8] mtd: spi-nor: wait for SR_WIP to clear on initial unlock Brian Norris
  2016-01-29 19:25 ` [PATCH v2 2/8] mtd: spi-nor: silently drop lock/unlock for already locked/unlocked region Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-01-29 19:25 ` [PATCH v2 4/8] mtd: spi-nor: disallow further writes to SR if WP# is low Brian Norris
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

There are a few different corner cases to the current logic that seem
undesirable:

* mtd_lock() with offs==0 trips a bounds issue on
  ofs - mtd->erasesize < 0

* mtd_unlock() on the middle of a flash that is already unlocked will
  return -EINVAL

* probably other corner cases

So, let's stop doing "smart" checks like "check the block below us",
let's just do the following:

(a) pass only non-negative offsets/lengths to stm_is_locked_sr()
(b) add a similar stm_is_unlocked_sr() function, so we can check if the
    *entire* range is unlocked (and not just whether some part of it is
    unlocked)

Then armed with (b), we can make lock() and unlock() much more
symmetric:

(c) short-circuit the procedure if there is no work to be done, and
(d) check the entire range above/below

This also aligns well with the structure needed for proper TB
(Top/Bottom) support.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2:
 * mostly new (refactored from patch 2 in v1), since there were more corner
   cases, and this needed some more refactoring to prepare for TB support

 drivers/mtd/spi-nor/spi-nor.c | 68 +++++++++++++++++++++++++++++++------------
 1 file changed, 50 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 77c88ac69ef9..68133b949fe5 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -439,17 +439,38 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
 }
 
 /*
- * Return 1 if the entire region is locked, 0 otherwise
+ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
+ * @locked is false); 0 otherwise
  */
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-			    u8 sr)
+static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+				    u8 sr, bool locked)
 {
 	loff_t lock_offs;
 	uint64_t lock_len;
 
+	if (!len)
+		return 1;
+
 	stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
 
-	return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+	if (locked)
+		/* Requested range is a sub-range of locked range */
+		return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+	else
+		/* Requested range does not overlap with locked range */
+		return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
+}
+
+static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+			    u8 sr)
+{
+	return stm_check_lock_status_sr(nor, ofs, len, sr, true);
+}
+
+static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+			      u8 sr)
+{
+	return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
 /*
@@ -481,20 +502,24 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	int status_old, status_new;
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
 	u8 shift = ffs(mask) - 1, pow, val;
+	loff_t lock_len;
 	int ret;
 
 	status_old = read_sr(nor);
 	if (status_old < 0)
 		return status_old;
 
-	/* SPI NOR always locks to the end */
-	if (ofs + len != mtd->size) {
-		/* Does combined region extend to end? */
-		if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
-				      status_old))
-			return -EINVAL;
-		len = mtd->size - ofs;
-	}
+	/* If nothing in our range is unlocked, we don't need to do anything */
+	if (stm_is_locked_sr(nor, ofs, len, status_old))
+		return 0;
+
+	/* If anything above us is unlocked, we can't use 'top' protection */
+	if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
+				status_old))
+		return -EINVAL;
+
+	/* lock_len: length of region that should end up locked */
+	lock_len = mtd->size - ofs;
 
 	/*
 	 * Need smallest pow such that:
@@ -505,7 +530,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	 *
 	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
 	 */
-	pow = ilog2(mtd->size) - ilog2(len);
+	pow = ilog2(mtd->size) - ilog2(lock_len);
 	val = mask - (pow << shift);
 	if (val & ~mask)
 		return -EINVAL;
@@ -541,17 +566,24 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	int status_old, status_new;
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
 	u8 shift = ffs(mask) - 1, pow, val;
+	loff_t lock_len;
 	int ret;
 
 	status_old = read_sr(nor);
 	if (status_old < 0)
 		return status_old;
 
-	/* Cannot unlock; would unlock larger region than requested */
-	if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
-			     status_old))
+	/* If nothing in our range is locked, we don't need to do anything */
+	if (stm_is_unlocked_sr(nor, ofs, len, status_old))
+		return 0;
+
+	/* If anything below us is locked, we can't use 'top' protection */
+	if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
 		return -EINVAL;
 
+	/* lock_len: length of region that should remain locked */
+	lock_len = mtd->size - (ofs + len);
+
 	/*
 	 * Need largest pow such that:
 	 *
@@ -561,8 +593,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	 *
 	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
 	 */
-	pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
-	if (ofs + len == mtd->size) {
+	pow = ilog2(mtd->size) - order_base_2(lock_len);
+	if (lock_len == 0) {
 		val = 0; /* fully unlocked */
 	} else {
 		val = mask - (pow << shift);
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/8] mtd: spi-nor: disallow further writes to SR if WP# is low
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (2 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 3/8] mtd: spi-nor: make lock/unlock bounds checks more obvious and robust Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-01-29 19:25 ` [PATCH v2 5/8] mtd: spi-nor: use BIT() for flash_info flags Brian Norris
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

Locking the flash is most useful if it provides real hardware security.
Otherwise, it's little more than a software permission bit.

A reasonable use case that provides real HW security might be like
follows:

(1) hardware WP# is deasserted
(2) program flash
(3) flash range is protected via status register
(4) hardware WP# is asserted
(5) flash protection range can no longer be changed, until WP# is
    deasserted

In this way, flash protection is co-owned by hardware and software.

Now, one would expect to be able to perform step (3) with
ioctl(MEMLOCK), except that the spi-nor driver does not set the Status
Register Protect bit (a.k.a. Status Register Write Disable (SRWD)), so
even though the range is now locked, it does not satisfy step (5) -- it
can still be changed by a call to ioctl(MEMUNLOCK).

So, let's enable status register protection after the first lock
command, and disable protection only when the flash is fully unlocked.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2:
 * added clearing the SRWD bit when unlocking the entire flash

 drivers/mtd/spi-nor/spi-nor.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 68133b949fe5..54eaf4b5bf05 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -540,6 +540,9 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	status_new = (status_old & ~mask) | val;
 
+	/* Disallow further writes if WP pin is asserted */
+	status_new |= SR_SRWD;
+
 	/* Don't bother if they're the same */
 	if (status_new == status_old)
 		return 0;
@@ -605,6 +608,10 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	status_new = (status_old & ~mask) | val;
 
+	/* Don't protect status register if we're fully unlocked */
+	if (lock_len == mtd->size)
+		status_new &= ~SR_SRWD;
+
 	/* Don't bother if they're the same */
 	if (status_new == status_old)
 		return 0;
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/8] mtd: spi-nor: use BIT() for flash_info flags
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (3 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 4/8] mtd: spi-nor: disallow further writes to SR if WP# is low Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-01-29 19:25 ` [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag Brian Norris
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

It's a little easier to read and make sure there are no collisions
(IMO).

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
---
v2: no change

 drivers/mtd/spi-nor/spi-nor.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 54eaf4b5bf05..9cd92f135fa2 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -61,14 +61,14 @@ struct flash_info {
 	u16		addr_width;
 
 	u16		flags;
-#define	SECT_4K			0x01	/* SPINOR_OP_BE_4K works uniformly */
-#define	SPI_NOR_NO_ERASE	0x02	/* No erase command needed */
-#define	SST_WRITE		0x04	/* use SST byte programming */
-#define	SPI_NOR_NO_FR		0x08	/* Can't do fastread */
-#define	SECT_4K_PMC		0x10	/* SPINOR_OP_BE_4K_PMC works uniformly */
-#define	SPI_NOR_DUAL_READ	0x20    /* Flash supports Dual Read */
-#define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
-#define	USE_FSR			0x80	/* use flag status register */
+#define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */
+#define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */
+#define SST_WRITE		BIT(2)	/* use SST byte programming */
+#define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */
+#define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */
+#define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
+#define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
+#define USE_FSR			BIT(7)	/* use flag status register */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (4 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 5/8] mtd: spi-nor: use BIT() for flash_info flags Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-02-28 19:23   ` Ezequiel Garcia
  2016-01-29 19:25 ` [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support Brian Norris
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

We can't determine this purely by manufacturer type (see commit
67b9bcd36906 ("mtd: spi-nor: fix Spansion regressions (aliased with
Winbond)")), and it's not autodetectable by anything like SFDP. So make
a new flag for it.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
---
v2: no change

 drivers/mtd/spi-nor/spi-nor.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 9cd92f135fa2..a47e9dd29456 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -69,6 +69,7 @@ struct flash_info {
 #define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
 #define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
 #define USE_FSR			BIT(7)	/* use flag status register */
+#define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -1280,7 +1281,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
 	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
 	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
-	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+	    JEDEC_MFR(info) == SNOR_MFR_SST ||
+	    info->flags & SPI_NOR_HAS_LOCK) {
 		write_enable(nor);
 		write_sr(nor, 0);
 		spi_nor_wait_till_ready(nor);
@@ -1297,7 +1299,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	mtd->_read = spi_nor_read;
 
 	/* NOR protection support for STmicro/Micron chips and similar */
-	if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
+	if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+			info->flags & SPI_NOR_HAS_LOCK) {
 		nor->flash_lock = stm_lock;
 		nor->flash_unlock = stm_unlock;
 		nor->flash_is_locked = stm_is_locked;
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (5 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-02-29 20:35   ` Ezequiel Garcia
  2016-01-29 19:25 ` [PATCH v2 8/8] mtd: spi-nor: support lock/unlock for a few Winbond chips Brian Norris
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

Some flash support a bit in the status register that inverts protection
so that it applies to the bottom of the flash, not the top. This yields
additions to the protection range table, as noted in the comments.

Because this feature is not universal to all flash that support
lock/unlock, control it via a new flag.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2:
 * Rewrite the bounds checking for top/bottom support, since there were some
   bad corner cases. Now lock/unlock are more symmetric.

 drivers/mtd/spi-nor/spi-nor.c | 70 ++++++++++++++++++++++++++++++++++++++-----
 include/linux/mtd/spi-nor.h   |  2 ++
 2 files changed, 65 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index a47e9dd29456..00ebf0794ca6 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -70,6 +70,11 @@ struct flash_info {
 #define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
 #define USE_FSR			BIT(7)	/* use flag status register */
 #define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
+#define SPI_NOR_HAS_TB		BIT(9)	/*
+					 * Flash SR has Top/Bottom (TB) protect
+					 * bit. Must be used with
+					 * SPI_NOR_HAS_LOCK.
+					 */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -435,7 +440,10 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
 	} else {
 		pow = ((sr & mask) ^ mask) >> shift;
 		*len = mtd->size >> pow;
-		*ofs = mtd->size - *len;
+		if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+			*ofs = 0;
+		else
+			*ofs = mtd->size - *len;
 	}
 }
 
@@ -476,12 +484,14 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
 
 /*
  * Lock a region of the flash. Compatible with ST Micro and similar flash.
- * Supports only the block protection bits BP{0,1,2} in the status register
+ * Supports the block protection bits BP{0,1,2} in the status register
  * (SR). Does not support these features found in newer SR bitfields:
- *   - TB: top/bottom protect - only handle TB=0 (top protect)
  *   - SEC: sector/block protect - only handle SEC=0 (block protect)
  *   - CMP: complement protect - only support CMP=0 (range is not complemented)
  *
+ * Support for the following is provided conditionally for some flash:
+ *   - TB: top/bottom protect
+ *
  * Sample table portion for 8MB flash (Winbond w25q64fw):
  *
  *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
@@ -494,6 +504,13 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
  *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
  *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
  *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *  ------|-------|-------|-------|-------|---------------|-------------------
+ *    0   |   1   |   0   |   0   |   1   |  128 KB       | Lower 1/64
+ *    0   |   1   |   0   |   1   |   0   |  256 KB       | Lower 1/32
+ *    0   |   1   |   0   |   1   |   1   |  512 KB       | Lower 1/16
+ *    0   |   1   |   1   |   0   |   0   |  1 MB         | Lower 1/8
+ *    0   |   1   |   1   |   0   |   1   |  2 MB         | Lower 1/4
+ *    0   |   1   |   1   |   1   |   0   |  4 MB         | Lower 1/2
  *
  * Returns negative on errors, 0 on success.
  */
@@ -504,6 +521,8 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
 	u8 shift = ffs(mask) - 1, pow, val;
 	loff_t lock_len;
+	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
+	bool use_top;
 	int ret;
 
 	status_old = read_sr(nor);
@@ -514,13 +533,26 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	if (stm_is_locked_sr(nor, ofs, len, status_old))
 		return 0;
 
+	/* If anything below us is unlocked, we can't use 'bottom' protection */
+	if (!stm_is_locked_sr(nor, 0, ofs, status_old))
+		can_be_bottom = false;
+
 	/* If anything above us is unlocked, we can't use 'top' protection */
 	if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
 				status_old))
+		can_be_top = false;
+
+	if (!can_be_bottom && !can_be_top)
 		return -EINVAL;
 
+	/* Prefer top, if both are valid */
+	use_top = can_be_top;
+
 	/* lock_len: length of region that should end up locked */
-	lock_len = mtd->size - ofs;
+	if (use_top)
+		lock_len = mtd->size - ofs;
+	else
+		lock_len = ofs + len;
 
 	/*
 	 * Need smallest pow such that:
@@ -539,11 +571,14 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	if (!(val & mask))
 		return -EINVAL;
 
-	status_new = (status_old & ~mask) | val;
+	status_new = (status_old & ~mask & ~SR_TB) | val;
 
 	/* Disallow further writes if WP pin is asserted */
 	status_new |= SR_SRWD;
 
+	if (!use_top)
+		status_new |= SR_TB;
+
 	/* Don't bother if they're the same */
 	if (status_new == status_old)
 		return 0;
@@ -571,6 +606,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
 	u8 shift = ffs(mask) - 1, pow, val;
 	loff_t lock_len;
+	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
+	bool use_top;
 	int ret;
 
 	status_old = read_sr(nor);
@@ -583,10 +620,24 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 	/* If anything below us is locked, we can't use 'top' protection */
 	if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
+		can_be_top = false;
+
+	/* If anything above us is locked, we can't use 'bottom' protection */
+	if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
+				status_old))
+		can_be_bottom = false;
+
+	if (!can_be_bottom && !can_be_top)
 		return -EINVAL;
 
+	/* Prefer top, if both are valid */
+	use_top = can_be_top;
+
 	/* lock_len: length of region that should remain locked */
-	lock_len = mtd->size - (ofs + len);
+	if (use_top)
+		lock_len = mtd->size - (ofs + len);
+	else
+		lock_len = ofs;
 
 	/*
 	 * Need largest pow such that:
@@ -607,12 +658,15 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 			return -EINVAL;
 	}
 
-	status_new = (status_old & ~mask) | val;
+	status_new = (status_old & ~mask & ~SR_TB) | val;
 
 	/* Don't protect status register if we're fully unlocked */
 	if (lock_len == mtd->size)
 		status_new &= ~SR_SRWD;
 
+	if (!use_top)
+		status_new |= SR_TB;
+
 	/* Don't bother if they're the same */
 	if (status_new == status_old)
 		return 0;
@@ -1320,6 +1374,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
 	if (info->flags & USE_FSR)
 		nor->flags |= SNOR_F_USE_FSR;
+	if (info->flags & SPI_NOR_HAS_TB)
+		nor->flags |= SNOR_F_HAS_SR_TB;
 
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 	/* prefer "small sector" erase if possible */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 62356d50815b..3c36113a88e1 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -85,6 +85,7 @@
 #define SR_BP0			BIT(2)	/* Block protect 0 */
 #define SR_BP1			BIT(3)	/* Block protect 1 */
 #define SR_BP2			BIT(4)	/* Block protect 2 */
+#define SR_TB			BIT(5)	/* Top/Bottom protect */
 #define SR_SRWD			BIT(7)	/* SR write protect */
 
 #define SR_QUAD_EN_MX		BIT(6)	/* Macronix Quad I/O */
@@ -116,6 +117,7 @@ enum spi_nor_ops {
 
 enum spi_nor_option_flags {
 	SNOR_F_USE_FSR		= BIT(0),
+	SNOR_F_HAS_SR_TB	= BIT(1),
 };
 
 /**
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 8/8] mtd: spi-nor: support lock/unlock for a few Winbond chips
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (6 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support Brian Norris
@ 2016-01-29 19:25 ` Brian Norris
  2016-02-27  2:04 ` [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Ezequiel Garcia
  2016-03-08  2:18 ` Brian Norris
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-01-29 19:25 UTC (permalink / raw)
  To: linux-mtd
  Cc: Brian Norris, Rafał Miłecki, Ezequiel Garcia,
	Boris Brezillon, linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

These are recent Winbond models that are known to have lock/unlock
support via writing the Status Register, and that also support the TB
(Top/Bottom) protection bit.

Tested on w25q32dw.

[Note on style: these entries are getting pretty long lines, so I picked
a style that seems reasonable for splitting up the flags separate from
the other mostly-similar fields.]

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
---
v2: no change

 drivers/mtd/spi-nor/spi-nor.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 00ebf0794ca6..3e6934c941aa 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -962,11 +962,23 @@ static const struct flash_info spi_nor_ids[] = {
 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{
+		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-	{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{
+		"w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
+	{
+		"w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (7 preceding siblings ...)
  2016-01-29 19:25 ` [PATCH v2 8/8] mtd: spi-nor: support lock/unlock for a few Winbond chips Brian Norris
@ 2016-02-27  2:04 ` Ezequiel Garcia
  2016-03-08  2:18 ` Brian Norris
  9 siblings, 0 replies; 14+ messages in thread
From: Ezequiel Garcia @ 2016-02-27  2:04 UTC (permalink / raw)
  To: Brian Norris
  Cc: linux-mtd, Rafał Miłecki, Boris Brezillon,
	linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

[-- Attachment #1: Type: text/plain, Size: 1737 bytes --]

On 29 Jan 11:25 AM, Brian Norris wrote:
> Hi,
> 
> These are an assortment of fixes and updates to the SPI NOR lock/unlock
> feature. The biggest new features are:
> (a) Status Register protection; I don't see why this shouldn't be enabled by
>     default. See patch 4's description.
> (b) Bottom-block protection support (via TB status bit)
> (c) Lock/unlock support for a few Winbond flash
> 
> Since v1:
>  * patches 3 and 7 are somewhat rewritten versions of patches 2 and 7 in v1
>  * fix up several corner cases, seen in some local tests (poor, slow shell
>    script appended)
>  * remove SR protection (SR_SRWD) when unlocking the entire flash
> 
> Regards,
> Brian
> 
> Brian Norris (8):
>   mtd: spi-nor: wait for SR_WIP to clear on initial unlock
>   mtd: spi-nor: silently drop lock/unlock for already locked/unlocked
>     region
>   mtd: spi-nor: make lock/unlock bounds checks more obvious and robust
>   mtd: spi-nor: disallow further writes to SR if WP# is low
>   mtd: spi-nor: use BIT() for flash_info flags
>   mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
>   mtd: spi-nor: add TB (Top/Bottom) protect support
>   mtd: spi-nor: support lock/unlock for a few Winbond chips
> 
>  drivers/mtd/spi-nor/spi-nor.c | 195 ++++++++++++++++++++++++++++++++++--------
>  include/linux/mtd/spi-nor.h   |   2 +
>  2 files changed, 159 insertions(+), 38 deletions(-)
> 
> 
> Appending badly-written shell test script. Requires latest mtd-utils
> (flash_lock / flash_unlock).
> 

Thanks for the cool script. I've tested it on Armada XP GP board,
which has a n25q128a13 flash. Tests passed, the results are
attached.

Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
-- 
Ezequiel Garcia, VanguardiaSur
www.vanguardiasur.com.ar

[-- Attachment #2: spi-nor-locktest --]
[-- Type: text/plain, Size: 8894 bytes --]

# /locktest.sh 
MTD #: 0
/dev/mtd0: unlocked device
/dev/mtd0: verified lock status 0 256 0
/dev/mtd0: locking upper half
/dev/mtd0: verified lock status 8388608 128 1
/dev/mtd0: verified lock status 0 128 0
/dev/mtd0: relocking 4th quadrant
/dev/mtd0: verified lock status 8388608 128 1
/dev/mtd0: verified lock status 0 128 0
/dev/mtd0: relocking ranges
/dev/mtd0: Range: 8388608 0
/dev/mtd0: Range: 8388608 7
/dev/mtd0: Range: 8388608 14
/dev/mtd0: Range: 8388608 21
/dev/mtd0: Range: 8388608 28
/dev/mtd0: Range: 8388608 35
/dev/mtd0: Range: 8388608 42
/dev/mtd0: Range: 8388608 49
/dev/mtd0: Range: 8388608 56
/dev/mtd0: Range: 8388608 63
/dev/mtd0: Range: 8388608 70
/dev/mtd0: Range: 8388608 77
/dev/mtd0: Range: 8388608 84
/dev/mtd0: Range: 8388608 91
/dev/mtd0: Range: 8388608 98
/dev/mtd0: Range: 8388608 105
/dev/mtd0: Range: 8388608 112
/dev/mtd0: Range: 8388608 119
/dev/mtd0: Range: 8388608 126
/dev/mtd0: Range: 8716288 0
/dev/mtd0: Range: 8716288 7
/dev/mtd0: Range: 8716288 14
/dev/mtd0: Range: 8716288 21
/dev/mtd0: Range: 8716288 28
/dev/mtd0: Range: 8716288 35
/dev/mtd0: Range: 8716288 42
/dev/mtd0: Range: 8716288 49
/dev/mtd0: Range: 8716288 56
/dev/mtd0: Range: 8716288 63
/dev/mtd0: Range: 8716288 70
/dev/mtd0: Range: 8716288 77
/dev/mtd0: Range: 8716288 84
/dev/mtd0: Range: 8716288 91
/dev/mtd0: Range: 8716288 98
/dev/mtd0: Range: 8716288 105
/dev/mtd0: Range: 8716288 112
/dev/mtd0: Range: 8716288 119
/dev/mtd0: Range: 9043968 0
/dev/mtd0: Range: 9043968 7
/dev/mtd0: Range: 9043968 14
/dev/mtd0: Range: 9043968 21
/dev/mtd0: Range: 9043968 28
/dev/mtd0: Range: 9043968 35
/dev/mtd0: Range: 9043968 42
/dev/mtd0: Range: 9043968 49
/dev/mtd0: Range: 9043968 56
/dev/mtd0: Range: 9043968 63
/dev/mtd0: Range: 9043968 70
/dev/mtd0: Range: 9043968 77
/dev/mtd0: Range: 9043968 84
/dev/mtd0: Range: 9043968 91
/dev/mtd0: Range: 9043968 98
/dev/mtd0: Range: 9043968 105
/dev/mtd0: Range: 9043968 112
/dev/mtd0: Range: 9371648 0
/dev/mtd0: Range: 9371648 7
/dev/mtd0: Range: 9371648 14
/dev/mtd0: Range: 9371648 21
/dev/mtd0: Range: 9371648 28
/dev/mtd0: Range: 9371648 35
/dev/mtd0: Range: 9371648 42
/dev/mtd0: Range: 9371648 49
/dev/mtd0: Range: 9371648 56
/dev/mtd0: Range: 9371648 63
/dev/mtd0: Range: 9371648 70
/dev/mtd0: Range: 9371648 77
/dev/mtd0: Range: 9371648 84
/dev/mtd0: Range: 9371648 91
/dev/mtd0: Range: 9371648 98
/dev/mtd0: Range: 9371648 105
/dev/mtd0: Range: 9371648 112
/dev/mtd0: Range: 9699328 0
/dev/mtd0: Range: 9699328 7
/dev/mtd0: Range: 9699328 14
/dev/mtd0: Range: 9699328 21
/dev/mtd0: Range: 9699328 28
/dev/mtd0: Range: 9699328 35
/dev/mtd0: Range: 9699328 42
/dev/mtd0: Range: 9699328 49
/dev/mtd0: Range: 9699328 56
/dev/mtd0: Range: 9699328 63
/dev/mtd0: Range: 9699328 70
/dev/mtd0: Range: 9699328 77
/dev/mtd0: Range: 9699328 84
/dev/mtd0: Range: 9699328 91
/dev/mtd0: Range: 9699328 98
/dev/mtd0: Range: 9699328 105
/dev/mtd0: Range: 10027008 0
/dev/mtd0: Range: 10027008 7
/dev/mtd0: Range: 10027008 14
/dev/mtd0: Range: 10027008 21
/dev/mtd0: Range: 10027008 28
/dev/mtd0: Range: 10027008 35
/dev/mtd0: Range: 10027008 42
/dev/mtd0: Range: 10027008 49
/dev/mtd0: Range: 10027008 56
/dev/mtd0: Range: 10027008 63
/dev/mtd0: Range: 10027008 70
/dev/mtd0: Range: 10027008 77
/dev/mtd0: Range: 10027008 84
/dev/mtd0: Range: 10027008 91
/dev/mtd0: Range: 10027008 98
/dev/mtd0: Range: 10354688 0
/dev/mtd0: Range: 10354688 7
/dev/mtd0: Range: 10354688 14
/dev/mtd0: Range: 10354688 21
/dev/mtd0: Range: 10354688 28
/dev/mtd0: Range: 10354688 35
/dev/mtd0: Range: 10354688 42
/dev/mtd0: Range: 10354688 49
/dev/mtd0: Range: 10354688 56
/dev/mtd0: Range: 10354688 63
/dev/mtd0: Range: 10354688 70
/dev/mtd0: Range: 10354688 77
/dev/mtd0: Range: 10354688 84
/dev/mtd0: Range: 10354688 91
/dev/mtd0: Range: 10682368 0
/dev/mtd0: Range: 10682368 7
/dev/mtd0: Range: 10682368 14
/dev/mtd0: Range: 10682368 21
/dev/mtd0: Range: 10682368 28
/dev/mtd0: Range: 10682368 35
/dev/mtd0: Range: 10682368 42
/dev/mtd0: Range: 10682368 49
/dev/mtd0: Range: 10682368 56
/dev/mtd0: Range: 10682368 63
/dev/mtd0: Range: 10682368 70
/dev/mtd0: Range: 10682368 77
/dev/mtd0: Range: 10682368 84
/dev/mtd0: Range: 10682368 91
/dev/mtd0: Range: 11010048 0
/dev/mtd0: Range: 11010048 7
/dev/mtd0: Range: 11010048 14
/dev/mtd0: Range: 11010048 21
/dev/mtd0: Range: 11010048 28
/dev/mtd0: Range: 11010048 35
/dev/mtd0: Range: 11010048 42
/dev/mtd0: Range: 11010048 49
/dev/mtd0: Range: 11010048 56
/dev/mtd0: Range: 11010048 63
/dev/mtd0: Range: 11010048 70
/dev/mtd0: Range: 11010048 77
/dev/mtd0: Range: 11010048 84
/dev/mtd0: Range: 11337728 0
/dev/mtd0: Range: 11337728 7
/dev/mtd0: Range: 11337728 14
/dev/mtd0: Range: 11337728 21
/dev/mtd0: Range: 11337728 28
/dev/mtd0: Range: 11337728 35
/dev/mtd0: Range: 11337728 42
/dev/mtd0: Range: 11337728 49
/dev/mtd0: Range: 11337728 56
/dev/mtd0: Range: 11337728 63
/dev/mtd0: Range: 11337728 70
/dev/mtd0: Range: 11337728 77
/dev/mtd0: Range: 11665408 0
/dev/mtd0: Range: 11665408 7
/dev/mtd0: Range: 11665408 14
/dev/mtd0: Range: 11665408 21
/dev/mtd0: Range: 11665408 28
/dev/mtd0: Range: 11665408 35
/dev/mtd0: Range: 11665408 42
/dev/mtd0: Range: 11665408 49
/dev/mtd0: Range: 11665408 56
/dev/mtd0: Range: 11665408 63
/dev/mtd0: Range: 11665408 70
/dev/mtd0: Range: 11665408 77
/dev/mtd0: Range: 11993088 0
/dev/mtd0: Range: 11993088 7
/dev/mtd0: Range: 11993088 14
/dev/mtd0: Range: 11993088 21
/dev/mtd0: Range: 11993088 28
/dev/mtd0: Range: 11993088 35
/dev/mtd0: Range: 11993088 42
/dev/mtd0: Range: 11993088 49
/dev/mtd0: Range: 11993088 56
/dev/mtd0: Range: 11993088 63
/dev/mtd0: Range: 11993088 70
/dev/mtd0: Range: 12320768 0
/dev/mtd0: Range: 12320768 7
/dev/mtd0: Range: 12320768 14
/dev/mtd0: Range: 12320768 21
/dev/mtd0: Range: 12320768 28
/dev/mtd0: Range: 12320768 35
/dev/mtd0: Range: 12320768 42
/dev/mtd0: Range: 12320768 49
/dev/mtd0: Range: 12320768 56
/dev/mtd0: Range: 12320768 63
/dev/mtd0: Range: 12648448 0
/dev/mtd0: Range: 12648448 7
/dev/mtd0: Range: 12648448 14
/dev/mtd0: Range: 12648448 21
/dev/mtd0: Range: 12648448 28
/dev/mtd0: Range: 12648448 35
/dev/mtd0: Range: 12648448 42
/dev/mtd0: Range: 12648448 49
/dev/mtd0: Range: 12648448 56
/dev/mtd0: Range: 12976128 0
/dev/mtd0: Range: 12976128 7
/dev/mtd0: Range: 12976128 14
/dev/mtd0: Range: 12976128 21
/dev/mtd0: Range: 12976128 28
/dev/mtd0: Range: 12976128 35
/dev/mtd0: Range: 12976128 42
/dev/mtd0: Range: 12976128 49
/dev/mtd0: Range: 12976128 56
/dev/mtd0: Range: 13303808 0
/dev/mtd0: Range: 13303808 7
/dev/mtd0: Range: 13303808 14
/dev/mtd0: Range: 13303808 21
/dev/mtd0: Range: 13303808 28
/dev/mtd0: Range: 13303808 35
/dev/mtd0: Range: 13303808 42
/dev/mtd0: Range: 13303808 49
/dev/mtd0: Range: 13631488 0
/dev/mtd0: Range: 13631488 7
/dev/mtd0: Range: 13631488 14
/dev/mtd0: Range: 13631488 21
/dev/mtd0: Range: 13631488 28
/dev/mtd0: Range: 13631488 35
/dev/mtd0: Range: 13631488 42
/dev/mtd0: Range: 13959168 0
/dev/mtd0: Range: 13959168 7
/dev/mtd0: Range: 13959168 14
/dev/mtd0: Range: 13959168 21
/dev/mtd0: Range: 13959168 28
/dev/mtd0: Range: 13959168 35
/dev/mtd0: Range: 13959168 42
/dev/mtd0: Range: 14286848 0
/dev/mtd0: Range: 14286848 7
/dev/mtd0: Range: 14286848 14
/dev/mtd0: Range: 14286848 21
/dev/mtd0: Range: 14286848 28
/dev/mtd0: Range: 14286848 35
/dev/mtd0: Range: 14614528 0
/dev/mtd0: Range: 14614528 7
/dev/mtd0: Range: 14614528 14
/dev/mtd0: Range: 14614528 21
/dev/mtd0: Range: 14614528 28
/dev/mtd0: Range: 14942208 0
/dev/mtd0: Range: 14942208 7
/dev/mtd0: Range: 14942208 14
/dev/mtd0: Range: 14942208 21
/dev/mtd0: Range: 15269888 0
/dev/mtd0: Range: 15269888 7
/dev/mtd0: Range: 15269888 14
/dev/mtd0: Range: 15269888 21
/dev/mtd0: Range: 15597568 0
/dev/mtd0: Range: 15597568 7
/dev/mtd0: Range: 15597568 14
/dev/mtd0: Range: 15925248 0
/dev/mtd0: Range: 15925248 7
/dev/mtd0: Range: 16252928 0
/dev/mtd0: Range: 16252928 7
/dev/mtd0: Range: 16580608 0
/dev/mtd0: verified lock status 8388608 128 1
/dev/mtd0: verified lock status 0 128 0
/dev/mtd0: unlocking 3rd quadrant
/dev/mtd0: verified lock status 12582912 64 1
/dev/mtd0: verified lock status 0 192 0
/dev/mtd0: unlocking 1st quadrant (again)
/dev/mtd0: verified lock status 12582912 64 1
/dev/mtd0: verified lock status 0 192 0
/dev/mtd0: unlocking 4th quadrant
/dev/mtd0: verified lock status 0 256 0
/dev/mtd0: locking 1st half
/dev/mtd0: verified lock status 0 128 1
/dev/mtd0: verified lock status 8388608 128 0
flash_unlock: error!: could not unlock device: /dev/mtd0

              error 22 (Invalid argument)
/dev/mtd0: saw error, expected
/dev/mtd0: verified lock status 0 128 1
/dev/mtd0: verified lock status 8388608 128 0
/dev/mtd0: unlocking 2nd quadrant
/dev/mtd0: verified lock status 0 64 1
/dev/mtd0: verified lock status 4194304 192 0
/dev/mtd0: unlocking top 3 quadrants (again)
/dev/mtd0: verified lock status 0 64 1
/dev/mtd0: verified lock status 4194304 192 0
/dev/mtd0: test complete


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
  2016-01-29 19:25 ` [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag Brian Norris
@ 2016-02-28 19:23   ` Ezequiel Garcia
  0 siblings, 0 replies; 14+ messages in thread
From: Ezequiel Garcia @ 2016-02-28 19:23 UTC (permalink / raw)
  To: Brian Norris
  Cc: linux-mtd, Rafał Miłecki, Boris Brezillon,
	linux-kernel, Bayi Cheng, Marek Vasut, Daniel Kurtz

On 29 January 2016 at 16:25, Brian Norris <computersforpeace@gmail.com> wrote:
> We can't determine this purely by manufacturer type (see commit
> 67b9bcd36906 ("mtd: spi-nor: fix Spansion regressions (aliased with
> Winbond)")), and it's not autodetectable by anything like SFDP. So make
> a new flag for it.
>
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
> ---
> v2: no change
>
>  drivers/mtd/spi-nor/spi-nor.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 9cd92f135fa2..a47e9dd29456 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -69,6 +69,7 @@ struct flash_info {
>  #define SPI_NOR_DUAL_READ      BIT(5)  /* Flash supports Dual Read */
>  #define SPI_NOR_QUAD_READ      BIT(6)  /* Flash supports Quad Read */
>  #define USE_FSR                        BIT(7)  /* use flag status register */
> +#define SPI_NOR_HAS_LOCK       BIT(8)  /* Flash supports lock/unlock via SR */
>  };
>
>  #define JEDEC_MFR(info)        ((info)->id[0])
> @@ -1280,7 +1281,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
>
>         if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
>             JEDEC_MFR(info) == SNOR_MFR_INTEL ||
> -           JEDEC_MFR(info) == SNOR_MFR_SST) {
> +           JEDEC_MFR(info) == SNOR_MFR_SST ||
> +           info->flags & SPI_NOR_HAS_LOCK) {
>                 write_enable(nor);
>                 write_sr(nor, 0);
>                 spi_nor_wait_till_ready(nor);
> @@ -1297,7 +1299,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
>         mtd->_read = spi_nor_read;
>
>         /* NOR protection support for STmicro/Micron chips and similar */
> -       if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
> +       if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
> +                       info->flags & SPI_NOR_HAS_LOCK) {

Nitpick: indentation looks off here.
-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support
  2016-01-29 19:25 ` [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support Brian Norris
@ 2016-02-29 20:35   ` Ezequiel Garcia
  2016-03-08  2:12     ` Brian Norris
  0 siblings, 1 reply; 14+ messages in thread
From: Ezequiel Garcia @ 2016-02-29 20:35 UTC (permalink / raw)
  To: Brian Norris
  Cc: linux-mtd, Rafał Miłecki, Boris Brezillon,
	linux-kernel, Bayi Cheng, Marek Vasut, Daniel Kurtz

Hi Brian,

On 29 January 2016 at 16:25, Brian Norris <computersforpeace@gmail.com> wrote:
> Some flash support a bit in the status register that inverts protection
> so that it applies to the bottom of the flash, not the top. This yields
> additions to the protection range table, as noted in the comments.
>
> Because this feature is not universal to all flash that support
> lock/unlock, control it via a new flag.
>
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> ---
> v2:
>  * Rewrite the bounds checking for top/bottom support, since there were some
>    bad corner cases. Now lock/unlock are more symmetric.
>
>  drivers/mtd/spi-nor/spi-nor.c | 70 ++++++++++++++++++++++++++++++++++++++-----
>  include/linux/mtd/spi-nor.h   |  2 ++
>  2 files changed, 65 insertions(+), 7 deletions(-)
>
[..]
> @@ -476,12 +484,14 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
>
>  /*
>   * Lock a region of the flash. Compatible with ST Micro and similar flash.
> - * Supports only the block protection bits BP{0,1,2} in the status register
> + * Supports the block protection bits BP{0,1,2} in the status register
>   * (SR). Does not support these features found in newer SR bitfields:
> - *   - TB: top/bottom protect - only handle TB=0 (top protect)
>   *   - SEC: sector/block protect - only handle SEC=0 (block protect)

While reviewing and testing this patchset, I realised that *no* Micron device
define BIT(6) as SEC (sector/block) bit. Instead, it's used as BP3, to extend
the region defined by BP0-BP2.

I've checked the following:

  N25Q256A
  N25Q128A
  N25Q064A
  N25Q032A
  N25Q016A
  M25Pxx

So I believe we need to separate stm_{lock,unlock), from
winbond_{lock,unlock}. We might want to explicitly mark devices that
currently support locking with the new _HAS_LOCK flag.

Also, I wonder if we can really separate based on vendor, or if we'll need
more flags to distinguish the lock implementation per device.

Of course, all the devices that define a BP3 are broken with respect to flash
locking. I can try to cook some patches for this, once we are decided on how
to do it.
-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support
  2016-02-29 20:35   ` Ezequiel Garcia
@ 2016-03-08  2:12     ` Brian Norris
  0 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-03-08  2:12 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: linux-mtd, Rafał Miłecki, Boris Brezillon,
	linux-kernel, Bayi Cheng, Marek Vasut, Daniel Kurtz

On Mon, Feb 29, 2016 at 05:35:02PM -0300, Ezequiel Garcia wrote:
> On 29 January 2016 at 16:25, Brian Norris <computersforpeace@gmail.com> wrote:
> > Some flash support a bit in the status register that inverts protection
> > so that it applies to the bottom of the flash, not the top. This yields
> > additions to the protection range table, as noted in the comments.
> >
> > Because this feature is not universal to all flash that support
> > lock/unlock, control it via a new flag.
> >
> > Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> > ---
> > v2:
> >  * Rewrite the bounds checking for top/bottom support, since there were some
> >    bad corner cases. Now lock/unlock are more symmetric.
> >
> >  drivers/mtd/spi-nor/spi-nor.c | 70 ++++++++++++++++++++++++++++++++++++++-----
> >  include/linux/mtd/spi-nor.h   |  2 ++
> >  2 files changed, 65 insertions(+), 7 deletions(-)
> >
> [..]
> > @@ -476,12 +484,14 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> >
> >  /*
> >   * Lock a region of the flash. Compatible with ST Micro and similar flash.
> > - * Supports only the block protection bits BP{0,1,2} in the status register
> > + * Supports the block protection bits BP{0,1,2} in the status register
> >   * (SR). Does not support these features found in newer SR bitfields:
> > - *   - TB: top/bottom protect - only handle TB=0 (top protect)
> >   *   - SEC: sector/block protect - only handle SEC=0 (block protect)
> 
> While reviewing and testing this patchset, I realised that *no* Micron device
> define BIT(6) as SEC (sector/block) bit. Instead, it's used as BP3, to extend
> the region defined by BP0-BP2.

Hmm, OK. Maybe it's worth a note, if it's not going to get fixed
immediately.

> I've checked the following:
> 
>   N25Q256A
>   N25Q128A
>   N25Q064A
>   N25Q032A
>   N25Q016A
>   M25Pxx
> 
> So I believe we need to separate stm_{lock,unlock), from
> winbond_{lock,unlock}.

I'm not yet confident that we need separate functions. We would just
make SEC and BP3 support mutually exclusive, and then we can see whether
separate functions or a dual-purpose (single) implementation makes more
sense. I'd think the latter, actually, since adding an extra bit to the
'mask' should be pretty simple.

> We might want to explicitly mark devices that
> currently support locking with the new _HAS_LOCK flag.

Yeah, I think there are enough problems that we at least need a
_HAS_LOCK flag to opt in, rather than assuming every device by a certain
vendor works. It's really not clear which devices we claimed ever used
to work with lock/unlock, and some will change over time -- possibly
even in incompatible ways. You never know how wrong vendors can make
things.

> Also, I wonder if we can really separate based on vendor, or if we'll need
> more flags to distinguish the lock implementation per device.

For now, I'd like it if we can transition to using SPI_NOR_HAS_LOCK for
every flash that supports it, instead of auto-opting in all
Micron/STMicro flash. I think a new flag for SPI_NOR_HAS_BP3 would also
be in order.

> Of course, all the devices that define a BP3 are broken with respect to flash
> locking. I can try to cook some patches for this, once we are decided on how
> to do it.

Brian

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates
  2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
                   ` (8 preceding siblings ...)
  2016-02-27  2:04 ` [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Ezequiel Garcia
@ 2016-03-08  2:18 ` Brian Norris
  9 siblings, 0 replies; 14+ messages in thread
From: Brian Norris @ 2016-03-08  2:18 UTC (permalink / raw)
  To: linux-mtd
  Cc: Rafał Miłecki, Ezequiel Garcia, Boris Brezillon,
	linux-kernel, Bayi Cheng, Marek Vasut, djkurtz

On Fri, Jan 29, 2016 at 11:25:29AM -0800, Brian Norris wrote:
> Hi,
> 
> These are an assortment of fixes and updates to the SPI NOR lock/unlock
> feature. The biggest new features are:
> (a) Status Register protection; I don't see why this shouldn't be enabled by
>     default. See patch 4's description.
> (b) Bottom-block protection support (via TB status bit)
> (c) Lock/unlock support for a few Winbond flash
> 
> Since v1:
>  * patches 3 and 7 are somewhat rewritten versions of patches 2 and 7 in v1
>  * fix up several corner cases, seen in some local tests (poor, slow shell
>    script appended)
>  * remove SR protection (SR_SRWD) when unlocking the entire flash
> 
> Regards,
> Brian

Pushed all to l2-mtd.git

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2016-03-08  2:18 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-29 19:25 [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Brian Norris
2016-01-29 19:25 ` [PATCH v2 1/8] mtd: spi-nor: wait for SR_WIP to clear on initial unlock Brian Norris
2016-01-29 19:25 ` [PATCH v2 2/8] mtd: spi-nor: silently drop lock/unlock for already locked/unlocked region Brian Norris
2016-01-29 19:25 ` [PATCH v2 3/8] mtd: spi-nor: make lock/unlock bounds checks more obvious and robust Brian Norris
2016-01-29 19:25 ` [PATCH v2 4/8] mtd: spi-nor: disallow further writes to SR if WP# is low Brian Norris
2016-01-29 19:25 ` [PATCH v2 5/8] mtd: spi-nor: use BIT() for flash_info flags Brian Norris
2016-01-29 19:25 ` [PATCH v2 6/8] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag Brian Norris
2016-02-28 19:23   ` Ezequiel Garcia
2016-01-29 19:25 ` [PATCH v2 7/8] mtd: spi-nor: add TB (Top/Bottom) protect support Brian Norris
2016-02-29 20:35   ` Ezequiel Garcia
2016-03-08  2:12     ` Brian Norris
2016-01-29 19:25 ` [PATCH v2 8/8] mtd: spi-nor: support lock/unlock for a few Winbond chips Brian Norris
2016-02-27  2:04 ` [PATCH v2 0/8] mtd: spi-nor: locking fixes and updates Ezequiel Garcia
2016-03-08  2:18 ` Brian Norris

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.