aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/ubi/build.c5
-rw-r--r--drivers/mtd/ubi/io.c58
-rw-r--r--drivers/mtd/ubi/ubi.h4
3 files changed, 64 insertions, 3 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index db0b9cb64c6c..e1f7d0a78b9d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
657 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) 657 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
658 ubi->bad_allowed = 1; 658 ubi->bad_allowed = 1;
659 659
660 if (ubi->mtd->type == MTD_NORFLASH) {
661 ubi_assert(ubi->mtd->writesize == 1);
662 ubi->nor_flash = 1;
663 }
664
660 ubi->min_io_size = ubi->mtd->writesize; 665 ubi->min_io_size = ubi->mtd->writesize;
661 ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; 666 ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
662 667
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 1ea14218de02..c3bd2e34c642 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -266,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
266 addr = (loff_t)pnum * ubi->peb_size + offset; 266 addr = (loff_t)pnum * ubi->peb_size + offset;
267 err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); 267 err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
268 if (err) { 268 if (err) {
269 ubi_err("error %d while writing %d bytes to PEB %d:%d, written" 269 ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
270 " %zd bytes", err, len, pnum, offset, written); 270 "%zd bytes", err, len, pnum, offset, written);
271 ubi_dbg_dump_stack(); 271 ubi_dbg_dump_stack();
272 } else 272 } else
273 ubi_assert(written == len); 273 ubi_assert(written == len);
@@ -454,6 +454,54 @@ out:
454} 454}
455 455
456/** 456/**
457 * nor_erase_prepare - prepare a NOR flash PEB for erasure.
458 * @ubi: UBI device description object
459 * @pnum: physical eraseblock number to prepare
460 *
461 * NOR flash, or at least some of them, have peculiar embedded PEB erasure
462 * algorithm: the PEB is first filled with zeroes, then it is erased. And
463 * filling with zeroes starts from the end of the PEB. This was observed with
464 * Spansion S29GL512N NOR flash.
465 *
466 * This means that in case of a power cut we may end up with intact data at the
467 * beginning of the PEB, and all zeroes at the end of PEB. In other words, the
468 * EC and VID headers are OK, but a large chunk of data at the end of PEB is
469 * zeroed. This makes UBI mistakenly treat this PEB as used and associate it
470 * with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
471 *
472 * This function is called before erasing NOR PEBs and it zeroes out EC and VID
473 * magic numbers in order to invalidate them and prevent the failures. Returns
474 * zero in case of success and a negative error code in case of failure.
475 */
476static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
477{
478 int err;
479 size_t written;
480 loff_t addr;
481 uint32_t data = 0;
482
483 addr = (loff_t)pnum * ubi->peb_size;
484 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, &data);
485 if (err) {
486 ubi_err("error %d while writing 4 bytes to PEB %d:0, written "
487 "%zd bytes", err, pnum, 0, written);
488 ubi_dbg_dump_stack();
489 return err;
490 }
491
492 addr += ubi->vid_hdr_aloffset;
493 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, &data);
494 if (err) {
495 ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
496 "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
497 ubi_dbg_dump_stack();
498 return err;
499 }
500
501 return 0;
502}
503
504/**
457 * ubi_io_sync_erase - synchronously erase a physical eraseblock. 505 * ubi_io_sync_erase - synchronously erase a physical eraseblock.
458 * @ubi: UBI device description object 506 * @ubi: UBI device description object
459 * @pnum: physical eraseblock number to erase 507 * @pnum: physical eraseblock number to erase
@@ -484,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
484 return -EROFS; 532 return -EROFS;
485 } 533 }
486 534
535 if (ubi->nor_flash) {
536 err = nor_erase_prepare(ubi, pnum);
537 if (err)
538 return err;
539 }
540
487 if (torture) { 541 if (torture) {
488 ret = torture_peb(ubi, pnum); 542 ret = torture_peb(ubi, pnum);
489 if (ret < 0) 543 if (ret < 0)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 64604e8809ec..6a5fe9633783 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -373,6 +373,7 @@ struct ubi_wl_entry;
373 * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset 373 * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
374 * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or 374 * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
375 * not 375 * not
376 * @nor_flash: non-zero if working on top of NOR flash
376 * @mtd: MTD device descriptor 377 * @mtd: MTD device descriptor
377 * 378 *
378 * @peb_buf1: a buffer of PEB size used for different purposes 379 * @peb_buf1: a buffer of PEB size used for different purposes
@@ -454,7 +455,8 @@ struct ubi_device {
454 int vid_hdr_offset; 455 int vid_hdr_offset;
455 int vid_hdr_aloffset; 456 int vid_hdr_aloffset;
456 int vid_hdr_shift; 457 int vid_hdr_shift;
457 int bad_allowed; 458 unsigned int bad_allowed:1;
459 unsigned int nor_flash:1;
458 struct mtd_info *mtd; 460 struct mtd_info *mtd;
459 461
460 void *peb_buf1; 462 void *peb_buf1;