Commit e5d05cbd authored by Michal Suchanek's avatar Michal Suchanek Committed by Brian Norris

mtd: spi-nor: simplify write loop

The spi-nor write loop assumes that what is passed to the hardware
driver write() is what gets written.

When write() writes less than page size at once data is dropped on the
floor. Check the amount of data writen and exit if it does not match
requested amount.
Signed-off-by: default avatarMichal Suchanek <hramrach@gmail.com>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
Acked-by: default avatarMichal Suchanek <hramrach@gmail.com>
Tested-by: default avatarMichal Suchanek <hramrach@gmail.com>
parent 2dd087b1
...@@ -1129,8 +1129,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1129,8 +1129,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf) size_t *retlen, const u_char *buf)
{ {
struct spi_nor *nor = mtd_to_spi_nor(mtd); struct spi_nor *nor = mtd_to_spi_nor(mtd);
u32 page_offset, page_size, i; size_t page_offset, page_remain, i;
int ret; ssize_t ret;
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
...@@ -1138,45 +1138,37 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1138,45 +1138,37 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
if (ret) if (ret)
return ret; return ret;
write_enable(nor); for (i = 0; i < len; ) {
ssize_t written;
page_offset = to & (nor->page_size - 1);
/* do all the bytes fit onto one page? */ page_offset = (to + i) & (nor->page_size - 1);
if (page_offset + len <= nor->page_size) { WARN_ONCE(page_offset,
ret = nor->write(nor, to, len, buf); "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
if (ret < 0) page_offset);
goto write_err;
*retlen += ret;
} else {
/* the size of data remaining on the first page */ /* the size of data remaining on the first page */
page_size = nor->page_size - page_offset; page_remain = min_t(size_t,
ret = nor->write(nor, to, page_size, buf); nor->page_size - page_offset, len - i);
write_enable(nor);
ret = nor->write(nor, to + i, page_remain, buf + i);
if (ret < 0) if (ret < 0)
goto write_err; goto write_err;
*retlen += ret; written = ret;
/* write everything in nor->page_size chunks */
for (i = ret; i < len; ) {
page_size = len - i;
if (page_size > nor->page_size)
page_size = nor->page_size;
ret = spi_nor_wait_till_ready(nor);
if (ret)
goto write_err;
write_enable(nor); ret = spi_nor_wait_till_ready(nor);
if (ret)
ret = nor->write(nor, to + i, page_size, buf + i); goto write_err;
if (ret < 0) *retlen += written;
goto write_err; i += written;
*retlen += ret; if (written != page_remain) {
i += ret; dev_err(nor->dev,
"While writing %zu bytes written %zd bytes\n",
page_remain, written);
ret = -EIO;
goto write_err;
} }
} }
ret = spi_nor_wait_till_ready(nor);
write_err: write_err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
return ret; return ret;
......
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