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]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to