aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid A. Marlin <dmarlin@redhat.com>2005-01-23 22:07:46 -0500
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 06:08:59 -0400
commit068e3c0a002c79a5e3cc7c42cb749c4bb126288c (patch)
treefdf2db2edf03c4520a204476b0edc652ae2c9c47
parent99f2a8aea18c9779c141050c6f95a8f1da63bbe4 (diff)
[MTD] NAND Add optional ECC status check callback
Add optional hardware specific callback routine to perform extra error status checks on erase and write failures for devices with hardware ECC. Signed-off-by: David A. Marlin <dmarlin@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/mtd/nand/nand_base.c65
-rw-r--r--include/linux/mtd/nand.h16
2 files changed, 68 insertions, 13 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9f7c42ceecfa..7094dd5716dc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -42,6 +42,10 @@
42 * a "device recovery" operation must be performed when power is restored 42 * a "device recovery" operation must be performed when power is restored
43 * to ensure correct operation. 43 * to ensure correct operation.
44 * 44 *
45 * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
46 * perform extra error status checks on erase and write failures. This required
47 * adding a wrapper function for nand_read_ecc.
48 *
45 * Credits: 49 * Credits:
46 * David Woodhouse for adding multichip support 50 * David Woodhouse for adding multichip support
47 * 51 *
@@ -55,7 +59,7 @@
55 * The AG-AND chips have nice features for speed improvement, 59 * The AG-AND chips have nice features for speed improvement,
56 * which are not supported yet. Read / program 4 pages in one go. 60 * which are not supported yet. Read / program 4 pages in one go.
57 * 61 *
58 * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ 62 * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
59 * 63 *
60 * This program is free software; you can redistribute it and/or modify 64 * This program is free software; you can redistribute it and/or modify
61 * it under the terms of the GNU General Public License version 2 as 65 * it under the terms of the GNU General Public License version 2 as
@@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
896 if (!cached) { 900 if (!cached) {
897 /* call wait ready function */ 901 /* call wait ready function */
898 status = this->waitfunc (mtd, this, FL_WRITING); 902 status = this->waitfunc (mtd, this, FL_WRITING);
903
904 /* See if operation failed and additional status checks are available */
905 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
906 status = this->errstat(mtd, this, FL_WRITING, status, page);
907 }
908
899 /* See if device thinks it succeeded */ 909 /* See if device thinks it succeeded */
900 if (status & NAND_STATUS_FAIL) { 910 if (status & NAND_STATUS_FAIL) {
901 DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); 911 DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
@@ -1022,23 +1032,24 @@ out:
1022#endif 1032#endif
1023 1033
1024/** 1034/**
1025 * nand_read - [MTD Interface] MTD compability function for nand_read_ecc 1035 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
1026 * @mtd: MTD device structure 1036 * @mtd: MTD device structure
1027 * @from: offset to read from 1037 * @from: offset to read from
1028 * @len: number of bytes to read 1038 * @len: number of bytes to read
1029 * @retlen: pointer to variable to store the number of read bytes 1039 * @retlen: pointer to variable to store the number of read bytes
1030 * @buf: the databuffer to put data 1040 * @buf: the databuffer to put data
1031 * 1041 *
1032 * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL 1042 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1033*/ 1043 * and flags = 0xff
1044 */
1034static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) 1045static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
1035{ 1046{
1036 return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); 1047 return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
1037} 1048}
1038 1049
1039 1050
1040/** 1051/**
1041 * nand_read_ecc - [MTD Interface] Read data with ECC 1052 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
1042 * @mtd: MTD device structure 1053 * @mtd: MTD device structure
1043 * @from: offset to read from 1054 * @from: offset to read from
1044 * @len: number of bytes to read 1055 * @len: number of bytes to read
@@ -1047,11 +1058,35 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
1047 * @oob_buf: filesystem supplied oob data buffer 1058 * @oob_buf: filesystem supplied oob data buffer
1048 * @oobsel: oob selection structure 1059 * @oobsel: oob selection structure
1049 * 1060 *
1050 * NAND read with ECC 1061 * This function simply calls nand_do_read_ecc with flags = 0xff
1051 */ 1062 */
1052static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 1063static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1053 size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) 1064 size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
1054{ 1065{
1066 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1067}
1068
1069
1070/**
1071 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1072 * @mtd: MTD device structure
1073 * @from: offset to read from
1074 * @len: number of bytes to read
1075 * @retlen: pointer to variable to store the number of read bytes
1076 * @buf: the databuffer to put data
1077 * @oob_buf: filesystem supplied oob data buffer
1078 * @oobsel: oob selection structure
1079 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1080 * and how many corrected error bits are acceptable:
1081 * bits 0..7 - number of tolerable errors
1082 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1083 *
1084 * NAND read with ECC
1085 */
1086int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1087 size_t * retlen, u_char * buf, u_char * oob_buf,
1088 struct nand_oobinfo *oobsel, int flags)
1089{
1055 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; 1090 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1056 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; 1091 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1057 struct nand_chip *this = mtd->priv; 1092 struct nand_chip *this = mtd->priv;
@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1076 } 1111 }
1077 1112
1078 /* Grab the lock and see if the device is available */ 1113 /* Grab the lock and see if the device is available */
1079 nand_get_device (this, mtd, FL_READING); 1114 if (flags & NAND_GET_DEVICE)
1115 nand_get_device (this, mtd, FL_READING);
1080 1116
1081 /* use userspace supplied oobinfo, if zero */ 1117 /* use userspace supplied oobinfo, if zero */
1082 if (oobsel == NULL) 1118 if (oobsel == NULL)
@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1180 /* We calc error correction directly, it checks the hw 1216 /* We calc error correction directly, it checks the hw
1181 * generator for an error, reads back the syndrome and 1217 * generator for an error, reads back the syndrome and
1182 * does the error correction on the fly */ 1218 * does the error correction on the fly */
1183 if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { 1219 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1220 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
1184 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 1221 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1185 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); 1222 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
1186 ecc_failed++; 1223 ecc_failed++;
@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1219 p[i] = ecc_status; 1256 p[i] = ecc_status;
1220 } 1257 }
1221 1258
1222 if (ecc_status == -1) { 1259 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
1223 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); 1260 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
1224 ecc_failed++; 1261 ecc_failed++;
1225 } 1262 }
@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1289 } 1326 }
1290 1327
1291 /* Deselect and wake up anyone waiting on the device */ 1328 /* Deselect and wake up anyone waiting on the device */
1292 nand_release_device(mtd); 1329 if (flags & NAND_GET_DEVICE)
1330 nand_release_device(mtd);
1293 1331
1294 /* 1332 /*
1295 * Return success, if no ECC failures, else -EBADMSG 1333 * Return success, if no ECC failures, else -EBADMSG
@@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
2103 2141
2104 status = this->waitfunc (mtd, this, FL_ERASING); 2142 status = this->waitfunc (mtd, this, FL_ERASING);
2105 2143
2144 /* See if operation failed and additional status checks are available */
2145 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2146 status = this->errstat(mtd, this, FL_ERASING, status, page);
2147 }
2148
2106 /* See if block erase succeeded */ 2149 /* See if block erase succeeded */
2107 if (status & NAND_STATUS_FAIL) { 2150 if (status & NAND_STATUS_FAIL) {
2108 DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); 2151 DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 0118128ae384..cf52f20c6de2 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -5,7 +5,7 @@
5 * Steven J. Hill <sjhill@realitydiluted.com> 5 * Steven J. Hill <sjhill@realitydiluted.com>
6 * Thomas Gleixner <tglx@linutronix.de> 6 * Thomas Gleixner <tglx@linutronix.de>
7 * 7 *
8 * $Id: nand.h,v 1.69 2005/01/17 18:29:18 dmarlin Exp $ 8 * $Id: nand.h,v 1.70 2005/01/24 03:07:42 dmarlin Exp $
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
@@ -50,6 +50,8 @@
50 * update of nand_chip structure description 50 * update of nand_chip structure description
51 * 01-17-2005 dmarlin added extended commands for AG-AND device and added option 51 * 01-17-2005 dmarlin added extended commands for AG-AND device and added option
52 * for BBT_AUTO_REFRESH. 52 * for BBT_AUTO_REFRESH.
53 * 01-20-2005 dmarlin added optional pointer to hardware specific callback for
54 * extra error status checks.
53 */ 55 */
54#ifndef __LINUX_MTD_NAND_H 56#ifndef __LINUX_MTD_NAND_H
55#define __LINUX_MTD_NAND_H 57#define __LINUX_MTD_NAND_H
@@ -164,7 +166,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
164 166
165/* 167/*
166 * Constants for Hardware ECC 168 * Constants for Hardware ECC
167*/ 169 */
168/* Reset Hardware ECC for read */ 170/* Reset Hardware ECC for read */
169#define NAND_ECC_READ 0 171#define NAND_ECC_READ 0
170/* Reset Hardware ECC for write */ 172/* Reset Hardware ECC for write */
@@ -172,6 +174,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
172/* Enable Hardware ECC before syndrom is read back from flash */ 174/* Enable Hardware ECC before syndrom is read back from flash */
173#define NAND_ECC_READSYN 2 175#define NAND_ECC_READSYN 2
174 176
177/* Bit mask for flags passed to do_nand_read_ecc */
178#define NAND_GET_DEVICE 0x80
179
180
175/* Option constants for bizarre disfunctionality and real 181/* Option constants for bizarre disfunctionality and real
176* features 182* features
177*/ 183*/
@@ -308,6 +314,8 @@ struct nand_hw_control {
308 * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan 314 * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
309 * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices 315 * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
310 * @priv: [OPTIONAL] pointer to private chip date 316 * @priv: [OPTIONAL] pointer to private chip date
317 * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
318 * (determine if errors are correctable)
311 */ 319 */
312 320
313struct nand_chip { 321struct nand_chip {
@@ -363,6 +371,7 @@ struct nand_chip {
363 struct nand_bbt_descr *badblock_pattern; 371 struct nand_bbt_descr *badblock_pattern;
364 struct nand_hw_control *controller; 372 struct nand_hw_control *controller;
365 void *priv; 373 void *priv;
374 int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
366}; 375};
367 376
368/* 377/*
@@ -484,6 +493,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
484extern int nand_default_bbt (struct mtd_info *mtd); 493extern int nand_default_bbt (struct mtd_info *mtd);
485extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); 494extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
486extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); 495extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
496extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
497 size_t * retlen, u_char * buf, u_char * oob_buf,
498 struct nand_oobinfo *oobsel, int flags);
487 499
488/* 500/*
489* Constants for oob configuration 501* Constants for oob configuration