aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2006-11-15 22:03:56 -0500
committerKyungmin Park <kyungmin.park@samsung.com>2006-11-15 22:03:56 -0500
commitf4f91ac3c833abbd7181ff2122c6b48a653b4e55 (patch)
tree16202b5e260e08e0b5401d55352d62b94ef8ad62
parent08f782b60a633cbd926ef5e49de303a752390719 (diff)
[MTD] OneNAND: Single bit error detection
Idea from Jarkko Lavinen Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/mtd/onenand/onenand_base.c18
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c1
-rw-r--r--include/linux/mtd/onenand_regs.h1
3 files changed, 15 insertions, 5 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index bef4f26ad2ed..fc84ddc4987f 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -331,9 +331,12 @@ static int onenand_wait(struct mtd_info *mtd, int state)
331 331
332 if (interrupt & ONENAND_INT_READ) { 332 if (interrupt & ONENAND_INT_READ) {
333 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); 333 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
334 if (ecc & ONENAND_ECC_2BIT_ALL) { 334 if (ecc) {
335 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); 335 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
336 return -EBADMSG; 336 if (ecc & ONENAND_ECC_2BIT_ALL)
337 mtd->ecc_stats.failed++;
338 else if (ecc & ONENAND_ECC_1BIT_ALL)
339 mtd->ecc_stats.corrected++;
337 } 340 }
338 } 341 }
339 342
@@ -715,6 +718,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
715 size_t *retlen, u_char *buf) 718 size_t *retlen, u_char *buf)
716{ 719{
717 struct onenand_chip *this = mtd->priv; 720 struct onenand_chip *this = mtd->priv;
721 struct mtd_ecc_stats stats;
718 int read = 0, column; 722 int read = 0, column;
719 int thislen; 723 int thislen;
720 int ret = 0; 724 int ret = 0;
@@ -733,6 +737,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
733 737
734 /* TODO handling oob */ 738 /* TODO handling oob */
735 739
740 stats = mtd->ecc_stats;
736 while (read < len) { 741 while (read < len) {
737 thislen = min_t(int, mtd->writesize, len - read); 742 thislen = min_t(int, mtd->writesize, len - read);
738 743
@@ -774,7 +779,11 @@ out:
774 * retlen == desired len and result == -EBADMSG 779 * retlen == desired len and result == -EBADMSG
775 */ 780 */
776 *retlen = read; 781 *retlen = read;
777 return ret; 782
783 if (mtd->ecc_stats.failed - stats.failed)
784 return -EBADMSG;
785
786 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
778} 787}
779 788
780/** 789/**
@@ -1390,7 +1399,6 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
1390 return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); 1399 return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
1391} 1400}
1392 1401
1393
1394/** 1402/**
1395 * onenand_unlock - [MTD Interface] Unlock block(s) 1403 * onenand_unlock - [MTD Interface] Unlock block(s)
1396 * @param mtd MTD device structure 1404 * @param mtd MTD device structure
@@ -1900,7 +1908,7 @@ static int onenand_probe(struct mtd_info *mtd)
1900 /* Read manufacturer and device IDs from Register */ 1908 /* Read manufacturer and device IDs from Register */
1901 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); 1909 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1902 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); 1910 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
1903 ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID); 1911 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
1904 1912
1905 /* Check OneNAND device */ 1913 /* Check OneNAND device */
1906 if (maf_id != bram_maf_id || dev_id != bram_dev_id) 1914 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 1b00dac3d7d6..c8067b8f20a6 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -100,6 +100,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
100 bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); 100 bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
101 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 101 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
102 i >> 1, (unsigned int) from); 102 i >> 1, (unsigned int) from);
103 mtd->ecc_stats.badblocks++;
103 break; 104 break;
104 } 105 }
105 } 106 }
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index 9e409fe6ded6..e31c8f5d4271 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -179,6 +179,7 @@
179 * ECC Status Reigser FF00h (R) 179 * ECC Status Reigser FF00h (R)
180 */ 180 */
181#define ONENAND_ECC_1BIT (1 << 0) 181#define ONENAND_ECC_1BIT (1 << 0)
182#define ONENAND_ECC_1BIT_ALL (0x5555)
182#define ONENAND_ECC_2BIT (1 << 1) 183#define ONENAND_ECC_2BIT (1 << 1)
183#define ONENAND_ECC_2BIT_ALL (0xAAAA) 184#define ONENAND_ECC_2BIT_ALL (0xAAAA)
184 185