From: Greg Kroah-Hartman Date: Mon, 23 Mar 2026 09:29:19 +0000 (+0100) Subject: 6.12-stable patches X-Git-Tag: v6.1.167~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f8d94439dbd6bc484f69c2574a471ae299173b5e;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: mtd-spi-nor-core-avoid-odd-length-address-reads-on-8d-8d-8d-mode.patch mtd-spi-nor-core-avoid-odd-length-address-writes-in-8d-8d-8d-mode.patch --- diff --git a/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-reads-on-8d-8d-8d-mode.patch b/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-reads-on-8d-8d-8d-mode.patch new file mode 100644 index 0000000000..4a48ecae68 --- /dev/null +++ b/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-reads-on-8d-8d-8d-mode.patch @@ -0,0 +1,121 @@ +From f156b23df6a84efb2f6686156be94d4988568954 Mon Sep 17 00:00:00 2001 +From: Pratyush Yadav +Date: Tue, 8 Jul 2025 17:16:45 +0800 +Subject: mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode + +From: Pratyush Yadav + +commit f156b23df6a84efb2f6686156be94d4988568954 upstream. + +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 +Reviewed-by: Michael Walle +Signed-off-by: Luke Wang +Signed-off-by: Pratyush Yadav +Link: https://lore.kernel.org/r/20250708091646.292-1-ziniu.wang_1@nxp.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/core.c | 76 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 75 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2037,6 +2037,76 @@ static const struct flash_info *spi_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) + { +@@ -2054,7 +2124,11 @@ static int spi_nor_read(struct mtd_info + 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; diff --git a/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-writes-in-8d-8d-8d-mode.patch b/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-writes-in-8d-8d-8d-mode.patch new file mode 100644 index 0000000000..79f78a1639 --- /dev/null +++ b/queue-6.12/mtd-spi-nor-core-avoid-odd-length-address-writes-in-8d-8d-8d-mode.patch @@ -0,0 +1,111 @@ +From 17926cd770ec837ed27d9856cf07f2da8dda4131 Mon Sep 17 00:00:00 2001 +From: Pratyush Yadav +Date: Tue, 8 Jul 2025 17:16:46 +0800 +Subject: mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode + +From: Pratyush Yadav + +commit 17926cd770ec837ed27d9856cf07f2da8dda4131 upstream. + +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 +Reviewed-by: Michael Walle +Signed-off-by: Luke Wang +Signed-off-by: Pratyush Yadav +Link: https://lore.kernel.org/r/20250708091646.292-2-ziniu.wang_1@nxp.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/core.c | 69 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 68 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2152,6 +2152,68 @@ read_err: + } + + /* ++ * 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 + * it is within the physical boundaries. +@@ -2187,7 +2249,12 @@ static int spi_nor_write(struct mtd_info + 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; diff --git a/queue-6.12/series b/queue-6.12/series index c1c1bd064e..77291af3f2 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -440,3 +440,5 @@ i2c-fsi-fix-a-potential-leak-in-fsi_i2c_probe.patch i2c-pxa-defer-reset-on-armada-3700-when-recovery-is-used.patch ring-buffer-fix-to-update-per-subbuf-entries-of-persistent-ring-buffer.patch x86-platform-uv-handle-deconfigured-sockets.patch +mtd-spi-nor-core-avoid-odd-length-address-reads-on-8d-8d-8d-mode.patch +mtd-spi-nor-core-avoid-odd-length-address-writes-in-8d-8d-8d-mode.patch