Commit 19e506b3 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Greg Kroah-Hartman

eeprom: at25: Rework buggy read splitting

The recent change to split reads into chunks has several problems:
  1. If an SPI controller has no transfer size limit, max_chunk is
     SIZE_MAX, and num_msgs becomes zero, causing no data to be read
     into the buffer, and exposing the original contents of the buffer
     to userspace,
  2. If the requested read size is not a multiple of the maximum
     transfer size, the last transfer reads too much data, overflowing
     the buffer,
  3. The loop logic differs from the write case.

Fix the above by:
  1. Keeping track of the number of bytes that are still to be
     transferred, instead of precalculating the number of messages and
     keeping track of the number of bytes tranfered,
  2. Calculating the transfer size of each individual message, taking
     into account the number of bytes left,
  3. Switching from a "while"-loop to a "do-while"-loop, and renaming
     "msg_count" to "segment".

While at it, drop the superfluous cast from "unsigned int" to "unsigned
int", also from at25_ee_write(), where it was probably copied from.

Fixes: 0a35780c ("eeprom: at25: Split reads into chunks and cap write size")
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/7ae260778d2c08986348ea48ce02ef148100e088.1655817534.git.geert+renesas@glider.beSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 03c765b0
...@@ -80,10 +80,9 @@ static int at25_ee_read(void *priv, unsigned int offset, ...@@ -80,10 +80,9 @@ static int at25_ee_read(void *priv, unsigned int offset,
struct at25_data *at25 = priv; struct at25_data *at25 = priv;
char *buf = val; char *buf = val;
size_t max_chunk = spi_max_transfer_size(at25->spi); size_t max_chunk = spi_max_transfer_size(at25->spi);
size_t num_msgs = DIV_ROUND_UP(count, max_chunk); unsigned int msg_offset = offset;
size_t nr_bytes = 0; size_t bytes_left = count;
unsigned int msg_offset; size_t segment;
size_t msg_count;
u8 *cp; u8 *cp;
ssize_t status; ssize_t status;
struct spi_transfer t[2]; struct spi_transfer t[2];
...@@ -97,9 +96,8 @@ static int at25_ee_read(void *priv, unsigned int offset, ...@@ -97,9 +96,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
if (unlikely(!count)) if (unlikely(!count))
return -EINVAL; return -EINVAL;
msg_offset = (unsigned int)offset; do {
msg_count = min(count, max_chunk); segment = min(bytes_left, max_chunk);
while (num_msgs) {
cp = at25->command; cp = at25->command;
instr = AT25_READ; instr = AT25_READ;
...@@ -131,8 +129,8 @@ static int at25_ee_read(void *priv, unsigned int offset, ...@@ -131,8 +129,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
t[0].len = at25->addrlen + 1; t[0].len = at25->addrlen + 1;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf + nr_bytes; t[1].rx_buf = buf;
t[1].len = msg_count; t[1].len = segment;
spi_message_add_tail(&t[1], &m); spi_message_add_tail(&t[1], &m);
status = spi_sync(at25->spi, &m); status = spi_sync(at25->spi, &m);
...@@ -142,10 +140,10 @@ static int at25_ee_read(void *priv, unsigned int offset, ...@@ -142,10 +140,10 @@ static int at25_ee_read(void *priv, unsigned int offset,
if (status) if (status)
return status; return status;
--num_msgs; msg_offset += segment;
msg_offset += msg_count; buf += segment;
nr_bytes += msg_count; bytes_left -= segment;
} } while (bytes_left > 0);
dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n", dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n",
count, offset); count, offset);
...@@ -229,7 +227,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) ...@@ -229,7 +227,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
do { do {
unsigned long timeout, retries; unsigned long timeout, retries;
unsigned segment; unsigned segment;
unsigned offset = (unsigned) off; unsigned offset = off;
u8 *cp = bounce; u8 *cp = bounce;
int sr; int sr;
u8 instr; u8 instr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment