linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode
@ 2025-07-08  9:16 ziniu.wang_1
  2025-07-08  9:16 ` [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in " ziniu.wang_1
  2025-09-01 14:19 ` [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on " Pratyush Yadav
  0 siblings, 2 replies; 5+ messages in thread
From: ziniu.wang_1 @ 2025-07-08  9:16 UTC (permalink / raw)
  To: pratyush, tudor.ambarus, mwalle, miquel.raynal, richard, vigneshr
  Cc: linux-mtd, linux-kernel, haibo.chen, han.xu

From: Pratyush Yadav <p.yadav@ti.com>

On Octal DTR capable flashes like Micron Xcella reads cannot start or
end at an odd address in Octal DTR mode. Extra bytes need to be read at
the start or end to make sure both the start address and length remain
even.

To avoid allocating too much extra memory, thereby putting unnecessary
memory pressure on the system, the temporary buffer containing the extra
padding bytes is capped at PAGE_SIZE bytes. The rest of the 2-byte
aligned part should be read directly in the main buffer.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Reviewed-by: Michael Walle <michael@walle.cc>
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
Changes in v3:
- remove last if (ret < 0) check, as ret always >= 0
- remove Micron manufacturers info in comments
---
 drivers/mtd/spi-nor/core.c | 76 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index ac4b960101cc..1b594f720b6c 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2014,6 +2014,76 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
 	return info;
 }
 
+/*
+ * On Octal DTR capable flashes, reads cannot start or end at an odd
+ * address in Octal DTR mode. Extra bytes need to be read at the start
+ * or end to make sure both the start address and length remain even.
+ */
+static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len,
+				  u_char *buf)
+{
+	u_char *tmp_buf;
+	size_t tmp_len;
+	loff_t start, end;
+	int ret, bytes_read;
+
+	if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2))
+		return spi_nor_read_data(nor, from, len, buf);
+	else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE)
+		return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE),
+					 buf);
+
+	tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!tmp_buf)
+		return -ENOMEM;
+
+	start = round_down(from, 2);
+	end = round_up(from + len, 2);
+
+	/*
+	 * Avoid allocating too much memory. The requested read length might be
+	 * quite large. Allocating a buffer just as large (slightly bigger, in
+	 * fact) would put unnecessary memory pressure on the system.
+	 *
+	 * For example if the read is from 3 to 1M, then this will read from 2
+	 * to 4098. The reads from 4098 to 1M will then not need a temporary
+	 * buffer so they can proceed as normal.
+	 */
+	tmp_len = min_t(size_t, end - start, PAGE_SIZE);
+
+	ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf);
+	if (ret == 0) {
+		ret = -EIO;
+		goto out;
+	}
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * More bytes are read than actually requested, but that number can't be
+	 * reported to the calling function or it will confuse its calculations.
+	 * Calculate how many of the _requested_ bytes were read.
+	 */
+	bytes_read = ret;
+
+	if (from != start)
+		ret -= from - start;
+
+	/*
+	 * Only account for extra bytes at the end if they were actually read.
+	 * For example, if the total length was truncated because of temporary
+	 * buffer size limit then the adjustment for the extra bytes at the end
+	 * is not needed.
+	 */
+	if (start + bytes_read == end)
+		ret -= end - (from + len);
+
+	memcpy(buf, tmp_buf + (from - start), ret);
+out:
+	kfree(tmp_buf);
+	return ret;
+}
+
 static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, u_char *buf)
 {
@@ -2031,7 +2101,11 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 	while (len) {
 		loff_t addr = from;
 
-		ret = spi_nor_read_data(nor, addr, len, buf);
+		if (nor->read_proto == SNOR_PROTO_8_8_8_DTR)
+			ret = spi_nor_octal_dtr_read(nor, addr, len, buf);
+		else
+			ret = spi_nor_read_data(nor, addr, len, buf);
+
 		if (ret == 0) {
 			/* We shouldn't see 0-length reads */
 			ret = -EIO;
-- 
2.34.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode
  2025-07-08  9:16 [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode ziniu.wang_1
@ 2025-07-08  9:16 ` ziniu.wang_1
  2025-08-13  2:49   ` Luke Wang
  2025-09-01 14:19 ` [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on " Pratyush Yadav
  1 sibling, 1 reply; 5+ messages in thread
From: ziniu.wang_1 @ 2025-07-08  9:16 UTC (permalink / raw)
  To: pratyush, tudor.ambarus, mwalle, miquel.raynal, richard, vigneshr
  Cc: linux-mtd, linux-kernel, haibo.chen, han.xu

From: Pratyush Yadav <p.yadav@ti.com>

On Octal DTR capable flashes like Micron Xcella the writes cannot start
or end at an odd address in Octal DTR mode. Extra 0xff bytes need to be
appended or prepended to make sure the start address and end address are
even. 0xff is used because on NOR flashes a program operation can only
flip bits from 1 to 0, not the other way round. 0 to 1 flip needs to
happen via erases.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Reviewed-by: Michael Walle <michael@walle.cc>
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
Changes in v3:
- remove last if (ret < 0) check, as ret always >= 0
- remove Micron manufacturers info in comments
- change nor->page_size to nor->params->page_size for latest kernel
---
 drivers/mtd/spi-nor/core.c | 69 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 1b594f720b6c..20ea80450f22 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2128,6 +2128,68 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 	return ret;
 }
 
+/*
+ * On Octal DTR capable flashes, writes cannot start or end at an odd address
+ * in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to
+ * make sure the start address and end address are even. 0xff is used because
+ * on NOR flashes a program operation can only flip bits from 1 to 0, not the
+ * other way round. 0 to 1 flip needs to happen via erases.
+ */
+static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len,
+				   const u8 *buf)
+{
+	u8 *tmp_buf;
+	size_t bytes_written;
+	loff_t start, end;
+	int ret;
+
+	if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2))
+		return spi_nor_write_data(nor, to, len, buf);
+
+	tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL);
+	if (!tmp_buf)
+		return -ENOMEM;
+
+	memset(tmp_buf, 0xff, nor->params->page_size);
+
+	start = round_down(to, 2);
+	end = round_up(to + len, 2);
+
+	memcpy(tmp_buf + (to - start), buf, len);
+
+	ret = spi_nor_write_data(nor, start, end - start, tmp_buf);
+	if (ret == 0) {
+		ret = -EIO;
+		goto out;
+	}
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * More bytes are written than actually requested, but that number can't
+	 * be reported to the calling function or it will confuse its
+	 * calculations. Calculate how many of the _requested_ bytes were
+	 * written.
+	 */
+	bytes_written = ret;
+
+	if (to != start)
+		ret -= to - start;
+
+	/*
+	 * Only account for extra bytes at the end if they were actually
+	 * written. For example, if for some reason the controller could only
+	 * complete a partial write then the adjustment for the extra bytes at
+	 * the end is not needed.
+	 */
+	if (start + bytes_written == end)
+		ret -= end - (to + len);
+
+out:
+	kfree(tmp_buf);
+	return ret;
+}
+
 /*
  * Write an address range to the nor chip.  Data must be written in
  * FLASH_PAGESIZE chunks.  The address range may be any size provided
@@ -2164,7 +2226,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 			goto write_err;
 		}
 
-		ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
+		if (nor->write_proto == SNOR_PROTO_8_8_8_DTR)
+			ret = spi_nor_octal_dtr_write(nor, addr, page_remain,
+						      buf + i);
+		else
+			ret = spi_nor_write_data(nor, addr, page_remain,
+						 buf + i);
 		spi_nor_unlock_device(nor);
 		if (ret < 0)
 			goto write_err;
-- 
2.34.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* RE: [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode
  2025-07-08  9:16 ` [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in " ziniu.wang_1
@ 2025-08-13  2:49   ` Luke Wang
  2025-08-13 12:46     ` Pratyush Yadav
  0 siblings, 1 reply; 5+ messages in thread
From: Luke Wang @ 2025-08-13  2:49 UTC (permalink / raw)
  To: pratyush@kernel.org, tudor.ambarus@linaro.org, mwalle@kernel.org,
	miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com
  Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org,
	Bough Chen, Han Xu

Gentle ping on this, are there any comments or issues?

Thanks,
Luke

> -----Original Message-----
> From: Luke Wang
> Sent: Tuesday, July 8, 2025 5:18 PM
> To: pratyush@kernel.org; tudor.ambarus@linaro.org; mwalle@kernel.org;
> miquel.raynal@bootlin.com; richard@nod.at; vigneshr@ti.com
> Cc: linux-mtd@lists.infradead.org; linux-kernel@vger.kernel.org; Bough Chen
> <haibo.chen@nxp.com>; Han Xu <han.xu@nxp.com>
> Subject: [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in
> 8D-8D-8D mode
> 
> From: Pratyush Yadav <p.yadav@ti.com>
> 
> On Octal DTR capable flashes like Micron Xcella the writes cannot start
> or end at an odd address in Octal DTR mode. Extra 0xff bytes need to be
> appended or prepended to make sure the start address and end address are
> even. 0xff is used because on NOR flashes a program operation can only
> flip bits from 1 to 0, not the other way round. 0 to 1 flip needs to
> happen via erases.
> 
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> Reviewed-by: Michael Walle <michael@walle.cc>
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---
> Changes in v3:
> - remove last if (ret < 0) check, as ret always >= 0
> - remove Micron manufacturers info in comments
> - change nor->page_size to nor->params->page_size for latest kernel
> ---
>  drivers/mtd/spi-nor/core.c | 69
> +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 68 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
> index 1b594f720b6c..20ea80450f22 100644
> --- a/drivers/mtd/spi-nor/core.c
> +++ b/drivers/mtd/spi-nor/core.c
> @@ -2128,6 +2128,68 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t
> from, size_t len,
>  	return ret;
>  }
> 
> +/*
> + * On Octal DTR capable flashes, writes cannot start or end at an odd address
> + * in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to
> + * make sure the start address and end address are even. 0xff is used because
> + * on NOR flashes a program operation can only flip bits from 1 to 0, not the
> + * other way round. 0 to 1 flip needs to happen via erases.
> + */
> +static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len,
> +				   const u8 *buf)
> +{
> +	u8 *tmp_buf;
> +	size_t bytes_written;
> +	loff_t start, end;
> +	int ret;
> +
> +	if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2))
> +		return spi_nor_write_data(nor, to, len, buf);
> +
> +	tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL);
> +	if (!tmp_buf)
> +		return -ENOMEM;
> +
> +	memset(tmp_buf, 0xff, nor->params->page_size);
> +
> +	start = round_down(to, 2);
> +	end = round_up(to + len, 2);
> +
> +	memcpy(tmp_buf + (to - start), buf, len);
> +
> +	ret = spi_nor_write_data(nor, start, end - start, tmp_buf);
> +	if (ret == 0) {
> +		ret = -EIO;
> +		goto out;
> +	}
> +	if (ret < 0)
> +		goto out;
> +
> +	/*
> +	 * More bytes are written than actually requested, but that number
> can't
> +	 * be reported to the calling function or it will confuse its
> +	 * calculations. Calculate how many of the _requested_ bytes were
> +	 * written.
> +	 */
> +	bytes_written = ret;
> +
> +	if (to != start)
> +		ret -= to - start;
> +
> +	/*
> +	 * Only account for extra bytes at the end if they were actually
> +	 * written. For example, if for some reason the controller could only
> +	 * complete a partial write then the adjustment for the extra bytes at
> +	 * the end is not needed.
> +	 */
> +	if (start + bytes_written == end)
> +		ret -= end - (to + len);
> +
> +out:
> +	kfree(tmp_buf);
> +	return ret;
> +}
> +
>  /*
>   * Write an address range to the nor chip.  Data must be written in
>   * FLASH_PAGESIZE chunks.  The address range may be any size provided
> @@ -2164,7 +2226,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t
> to, size_t len,
>  			goto write_err;
>  		}
> 
> -		ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
> +		if (nor->write_proto == SNOR_PROTO_8_8_8_DTR)
> +			ret = spi_nor_octal_dtr_write(nor, addr, page_remain,
> +						      buf + i);
> +		else
> +			ret = spi_nor_write_data(nor, addr, page_remain,
> +						 buf + i);
>  		spi_nor_unlock_device(nor);
>  		if (ret < 0)
>  			goto write_err;
> --
> 2.34.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode
  2025-08-13  2:49   ` Luke Wang
@ 2025-08-13 12:46     ` Pratyush Yadav
  0 siblings, 0 replies; 5+ messages in thread
From: Pratyush Yadav @ 2025-08-13 12:46 UTC (permalink / raw)
  To: Luke Wang
  Cc: pratyush@kernel.org, tudor.ambarus@linaro.org, mwalle@kernel.org,
	miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com,
	linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org,
	Bough Chen, Han Xu

Hi Luke,

On Wed, Aug 13 2025, Luke Wang wrote:

> Gentle ping on this, are there any comments or issues?

I plan to review it this in the next couple weeks (hopefully this one).

>> 
>> On Octal DTR capable flashes like Micron Xcella the writes cannot start
>> or end at an odd address in Octal DTR mode. Extra 0xff bytes need to be
>> appended or prepended to make sure the start address and end address are
>> even. 0xff is used because on NOR flashes a program operation can only
>> flip bits from 1 to 0, not the other way round. 0 to 1 flip needs to
>> happen via erases.
>> 
>> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
>> Reviewed-by: Michael Walle <michael@walle.cc>
>> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
[...]

-- 
Regards,
Pratyush Yadav

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode
  2025-07-08  9:16 [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode ziniu.wang_1
  2025-07-08  9:16 ` [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in " ziniu.wang_1
@ 2025-09-01 14:19 ` Pratyush Yadav
  1 sibling, 0 replies; 5+ messages in thread
From: Pratyush Yadav @ 2025-09-01 14:19 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: pratyush, tudor.ambarus, mwalle, miquel.raynal, richard, vigneshr,
	linux-mtd, linux-kernel, haibo.chen, han.xu

Hi,

On Tue, Jul 08 2025, ziniu.wang_1@nxp.com wrote:

> From: Pratyush Yadav <p.yadav@ti.com>
>
> On Octal DTR capable flashes like Micron Xcella reads cannot start or
> end at an odd address in Octal DTR mode. Extra bytes need to be read at
> the start or end to make sure both the start address and length remain
> even.
>
> To avoid allocating too much extra memory, thereby putting unnecessary
> memory pressure on the system, the temporary buffer containing the extra
> padding bytes is capped at PAGE_SIZE bytes. The rest of the 2-byte
> aligned part should be read directly in the main buffer.
>
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> Reviewed-by: Michael Walle <michael@walle.cc>
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>

Series applied to spi-nor/next. Thanks!

[...]

-- 
Regards,
Pratyush Yadav

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

end of thread, other threads:[~2025-09-01 17:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-08  9:16 [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode ziniu.wang_1
2025-07-08  9:16 ` [PATCH v3 2/2] mtd: spi-nor: core: avoid odd length/address writes in " ziniu.wang_1
2025-08-13  2:49   ` Luke Wang
2025-08-13 12:46     ` Pratyush Yadav
2025-09-01 14:19 ` [PATCH v3 1/2] mtd: spi-nor: core: avoid odd length/address reads on " Pratyush Yadav

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).