merged. Bruce
In message: [linux-yocto][linux-yocto v6.1/standard/ti-sdk-6.1/ti-j7xxx & v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx][PATCH 1/2] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode on 13/06/2023 Xulin Sun wrote: > From: Pratyush Yadav <[email protected]> > > commit c515105b5c117888b6859534a7c694489f6bcf6d from > git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git > > 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 <[email protected]> > Signed-off-by: Apurva Nandan <[email protected]> > Signed-off-by: Vignesh Raghavendra <[email protected]> > Signed-off-by: Xulin Sun <[email protected]> > --- > drivers/mtd/spi-nor/core.c | 81 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 80 insertions(+), 1 deletion(-) > > diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c > index 99194aa07196..ad068610ae80 100644 > --- a/drivers/mtd/spi-nor/core.c > +++ b/drivers/mtd/spi-nor/core.c > @@ -1696,6 +1696,82 @@ static const struct flash_info *spi_nor_detect(struct > spi_nor *nor) > return info; > } > > +/* > + * 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. > + */ > +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); > + > + if (ret < 0) { > + ret = -EIO; > + goto out; > + } > + > + 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) > { > @@ -1713,7 +1789,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t > from, size_t len, > > addr = spi_nor_convert_addr(nor, addr); > > - 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.35.5 > In message: [linux-yocto][linux-yocto v6.1/standard/ti-sdk-6.1/ti-j7xxx & v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx][PATCH 2/2] mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode on 13/06/2023 Xulin Sun wrote: > From: Pratyush Yadav <[email protected]> > > commit a9f1c2f3eaa70c64348a3ac5ec9892bcdbaa5ae4 from > git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git > > 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 <[email protected]> > Signed-off-by: Apurva Nandan <[email protected]> > Signed-off-by: Vignesh Raghavendra <[email protected]> > Signed-off-by: Xulin Sun <[email protected]> > --- > drivers/mtd/spi-nor/core.c | 72 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 71 insertions(+), 1 deletion(-) > > diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c > index ad068610ae80..15b0f6df6083 100644 > --- a/drivers/mtd/spi-nor/core.c > +++ b/drivers/mtd/spi-nor/core.c > @@ -1814,6 +1814,71 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t > from, size_t len, > return ret; > } > > +/* > + * 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. > + */ > +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); > + > + if (ret < 0) > + ret = -EIO; > + > +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 > @@ -1858,7 +1923,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t > to, size_t len, > if (ret) > 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); > if (ret < 0) > goto write_err; > written = ret; > -- > 2.35.5 >
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#12752): https://lists.yoctoproject.org/g/linux-yocto/message/12752 Mute This Topic: https://lists.yoctoproject.org/mt/99513004/21656 Group Owner: [email protected] Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/leave/6687884/21656/624485779/xyzzy [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
