diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-30 02:37:34 +0400 |
---|---|---|
committer | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-30 02:37:34 +0400 |
commit | f1a28c02843efcfcc41982149880bac3ac180234 (patch) | |
tree | b15ca1a140e463ef3cde6b9a8591e7be172ee1f1 /drivers/mtd/mtdpart.c | |
parent | 9a1fcdfd4bee27c418424cac47abf7c049541297 (diff) | |
download | linux-f1a28c02843efcfcc41982149880bac3ac180234.tar.xz |
[MTD] NAND Expose the new raw mode function and status info to userspace
The raw read/write access to NAND (without ECC) has been changed in the
NAND rework. Expose the new way - setting the file mode via ioctl - to
userspace. Also allow to read out the ecc statistics information so userspace
tools can see that bitflips happened and whether errors where correctable
or not. Also expose the number of bad blocks for the partition, so nandwrite
can check if the data fits into the parition before writing to it.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/mtdpart.c')
-rw-r--r-- | drivers/mtd/mtdpart.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index f22aeccf01e7..77a7123a5c56 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -51,12 +51,21 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); + int res; + if (from >= mtd->size) len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->read (part->master, from + part->offset, + res = part->master->read (part->master, from + part->offset, len, retlen, buf); + if (unlikely(res)) { + if (res == -EUCLEAN) + mtd->ecc_stats.corrected++; + if (res == -EBADMSG) + mtd->ecc_stats.failed++; + } + return res; } static int part_point (struct mtd_info *mtd, loff_t from, size_t len, @@ -82,12 +91,21 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); + int res; if (from >= mtd->size) return -EINVAL; if (from + ops->len > mtd->size) return -EINVAL; - return part->master->read_oob(part->master, from + part->offset, ops); + res = part->master->read_oob(part->master, from + part->offset, ops); + + if (unlikely(res)) { + if (res == -EUCLEAN) + mtd->ecc_stats.corrected++; + if (res == -EBADMSG) + mtd->ecc_stats.failed++; + } + return res; } static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, @@ -246,12 +264,17 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); + int res; + if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (ofs >= mtd->size) return -EINVAL; ofs += part->offset; - return part->master->block_markbad(part->master, ofs); + res = part->master->block_markbad(part->master, ofs); + if (!res) + mtd->ecc_stats.badblocks++; + return res; } /* @@ -436,6 +459,16 @@ int add_mtd_partitions(struct mtd_info *master, } slave->mtd.ecclayout = master->ecclayout; + if (master->block_isbad) { + uint32_t offs = 0; + + while(offs < slave->mtd.size) { + if (master->block_isbad(master, + offs + slave->offset)) + slave->mtd.ecc_stats.badblocks++; + offs += slave->mtd.erasesize; + } + } if(parts[i].mtdp) { /* store the object pointer (caller may or may not register it */ |