Re: [PATCH 7/7] eeprom: at25: Split reads into chunks and cap write size

2020-08-20 Thread Mark Brown
On Thu, Aug 20, 2020 at 12:02:28PM -0500, Eddie James wrote:
> From: Brad Bishop 
> 
> Make use of spi_max_transfer_size to avoid requesting transfers that are
> too large for some spi controllers.

This is an unrelated patch to a separate subsystem and should be sent
separately to the maintainers of that subsystem.


signature.asc
Description: PGP signature


[PATCH 7/7] eeprom: at25: Split reads into chunks and cap write size

2020-08-20 Thread Eddie James
From: Brad Bishop 

Make use of spi_max_transfer_size to avoid requesting transfers that are
too large for some spi controllers.

Signed-off-by: Brad Bishop 
Signed-off-by: Eddie James 
Signed-off-by: Joel Stanley 
---
 drivers/misc/eeprom/at25.c | 94 ++
 1 file changed, 54 insertions(+), 40 deletions(-)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index ed8d38b09925..30f0704ab2d4 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -64,12 +64,17 @@ static int at25_ee_read(void *priv, unsigned int offset,
 {
struct at25_data *at25 = priv;
char *buf = val;
+   size_t max_chunk = spi_max_transfer_size(at25->spi);
+   size_t num_msgs = DIV_ROUND_UP(count, max_chunk);
+   size_t  nr_bytes = 0;
u8  command[EE_MAXADDRLEN + 1];
u8  *cp;
ssize_t status;
struct spi_transfer t[2];
struct spi_message  m;
u8  instr;
+   unsigned intmsg_offset;
+   size_t  msg_count;
 
if (unlikely(offset >= at25->chip.byte_len))
return -EINVAL;
@@ -78,57 +83,64 @@ static int at25_ee_read(void *priv, unsigned int offset,
if (unlikely(!count))
return -EINVAL;
 
-   cp = command;
-
-   instr = AT25_READ;
-   if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
-   if (offset >= (1U << (at25->addrlen * 8)))
-   instr |= AT25_INSTR_BIT3;
-   *cp++ = instr;
-
-   /* 8/16/24-bit address is written MSB first */
-   switch (at25->addrlen) {
-   default:/* case 3 */
-   *cp++ = offset >> 16;
-   fallthrough;
-   case 2:
-   *cp++ = offset >> 8;
-   fallthrough;
-   case 1:
-   case 0: /* can't happen: for better codegen */
-   *cp++ = offset >> 0;
-   }
+   msg_offset = (unsigned int)offset;
+   msg_count = min(count, max_chunk);
+   while (num_msgs) {
+   cp = command;
+
+   instr = AT25_READ;
+   if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+   if (msg_offset >= (1U << (at25->addrlen * 8)))
+   instr |= AT25_INSTR_BIT3;
+   *cp++ = instr;
+
+   /* 8/16/24-bit address is written MSB first */
+   switch (at25->addrlen) {
+   default:/* case 3 */
+   *cp++ = msg_offset >> 16;
+   fallthrough;
+   case 2:
+   *cp++ = msg_offset >> 8;
+   fallthrough;
+   case 1:
+   case 0: /* can't happen: for better codegen */
+   *cp++ = msg_offset >> 0;
+   }
 
-   spi_message_init();
-   memset(t, 0, sizeof(t));
+   spi_message_init();
+   memset(t, 0, sizeof(t));
 
-   t[0].tx_buf = command;
-   t[0].len = at25->addrlen + 1;
-   spi_message_add_tail([0], );
+   t[0].tx_buf = command;
+   t[0].len = at25->addrlen + 1;
+   spi_message_add_tail([0], );
 
-   t[1].rx_buf = buf;
-   t[1].len = count;
-   spi_message_add_tail([1], );
+   t[1].rx_buf = buf + nr_bytes;
+   t[1].len = msg_count;
+   spi_message_add_tail([1], );
 
-   mutex_lock(>lock);
+   mutex_lock(>lock);
 
-   /* Read it all at once.
-*
-* REVISIT that's potentially a problem with large chips, if
-* other devices on the bus need to be accessed regularly or
-* this chip is clocked very slowly
-*/
-   status = spi_sync(at25->spi, );
-   dev_dbg(>spi->dev, "read %zu bytes at %d --> %zd\n",
-   count, offset, status);
+   status = spi_sync(at25->spi, );
 
-   mutex_unlock(>lock);
-   return status;
+   mutex_unlock(>lock);
+
+   if (status)
+   return status;
+
+   --num_msgs;
+   msg_offset += msg_count;
+   nr_bytes += msg_count;
+   }
+
+   dev_dbg(>spi->dev, "read %zu bytes at %d\n",
+   count, offset);
+   return 0;
 }
 
 static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
 {
struct at25_data *at25 = priv;
+   size_t maxsz = spi_max_transfer_size(at25->spi);
const char *buf = val;
int status = 0;
unsignedbuf_size;
@@ -191,6 +203,8 @@ static int at25_ee_write(void *priv, unsigned int off, void 
*val, size_t count)
segment = buf_size - (offset % buf_size);
if (segment > count)
segment = count;
+   if (segment > maxsz)
+