aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorMichal Suchanek <hramrach@gmail.com>2016-05-05 20:31:54 -0400
committerBrian Norris <computersforpeace@gmail.com>2016-06-01 20:22:57 -0400
commite5d05cbd6d8b01f08c95c427a36c66aac769af4f (patch)
tree1f7a9f10bbbf61fc2c6d64adddc0a12072e31bae /drivers/mtd
parent2dd087b16946cf168f401526adf26afa771bb740 (diff)
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: Michal Suchanek <hramrach@gmail.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com> Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com> Acked-by: Michal Suchanek <hramrach@gmail.com> Tested-by: Michal Suchanek <hramrach@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c58
1 files changed, 25 insertions, 33 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 34dd95373e77..fe55b48be5b3 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1129,8 +1129,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
1129 size_t *retlen, const u_char *buf) 1129 size_t *retlen, const u_char *buf)
1130{ 1130{
1131 struct spi_nor *nor = mtd_to_spi_nor(mtd); 1131 struct spi_nor *nor = mtd_to_spi_nor(mtd);
1132 u32 page_offset, page_size, i; 1132 size_t page_offset, page_remain, i;
1133 int ret; 1133 ssize_t ret;
1134 1134
1135 dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); 1135 dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
1136 1136
@@ -1138,45 +1138,37 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
1138 if (ret) 1138 if (ret)
1139 return ret; 1139 return ret;
1140 1140
1141 write_enable(nor); 1141 for (i = 0; i < len; ) {
1142 1142 ssize_t written;
1143 page_offset = to & (nor->page_size - 1);
1144 1143
1145 /* do all the bytes fit onto one page? */ 1144 page_offset = (to + i) & (nor->page_size - 1);
1146 if (page_offset + len <= nor->page_size) { 1145 WARN_ONCE(page_offset,
1147 ret = nor->write(nor, to, len, buf); 1146 "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
1148 if (ret < 0) 1147 page_offset);
1149 goto write_err;
1150 *retlen += ret;
1151 } else {
1152 /* the size of data remaining on the first page */ 1148 /* the size of data remaining on the first page */
1153 page_size = nor->page_size - page_offset; 1149 page_remain = min_t(size_t,
1154 ret = nor->write(nor, to, page_size, buf); 1150 nor->page_size - page_offset, len - i);
1151
1152 write_enable(nor);
1153 ret = nor->write(nor, to + i, page_remain, buf + i);
1155 if (ret < 0) 1154 if (ret < 0)
1156 goto write_err; 1155 goto write_err;
1157 *retlen += ret; 1156 written = ret;
1158
1159 /* write everything in nor->page_size chunks */
1160 for (i = ret; i < len; ) {
1161 page_size = len - i;
1162 if (page_size > nor->page_size)
1163 page_size = nor->page_size;
1164
1165 ret = spi_nor_wait_till_ready(nor);
1166 if (ret)
1167 goto write_err;
1168 1157
1169 write_enable(nor); 1158 ret = spi_nor_wait_till_ready(nor);
1170 1159 if (ret)
1171 ret = nor->write(nor, to + i, page_size, buf + i); 1160 goto write_err;
1172 if (ret < 0) 1161 *retlen += written;
1173 goto write_err; 1162 i += written;
1174 *retlen += ret; 1163 if (written != page_remain) {
1175 i += ret; 1164 dev_err(nor->dev,
1165 "While writing %zu bytes written %zd bytes\n",
1166 page_remain, written);
1167 ret = -EIO;
1168 goto write_err;
1176 } 1169 }
1177 } 1170 }
1178 1171
1179 ret = spi_nor_wait_till_ready(nor);
1180write_err: 1172write_err:
1181 spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); 1173 spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
1182 return ret; 1174 return ret;