Commit 068e3c0a authored by David A. Marlin's avatar David A. Marlin Committed by Thomas Gleixner

[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: default avatarDavid A. Marlin <dmarlin@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 99f2a8ae
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
* a "device recovery" operation must be performed when power is restored * a "device recovery" operation must be performed when power is restored
* to ensure correct operation. * to ensure correct operation.
* *
* 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
* perform extra error status checks on erase and write failures. This required
* adding a wrapper function for nand_read_ecc.
*
* Credits: * Credits:
* David Woodhouse for adding multichip support * David Woodhouse for adding multichip support
* *
...@@ -55,7 +59,7 @@ ...@@ -55,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement, * The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go. * which are not supported yet. Read / program 4 pages in one go.
* *
* $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * 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,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
if (!cached) { if (!cached) {
/* call wait ready function */ /* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING); status = this->waitfunc (mtd, this, FL_WRITING);
/* See if operation failed and additional status checks are available */
if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
status = this->errstat(mtd, this, FL_WRITING, status, page);
}
/* See if device thinks it succeeded */ /* See if device thinks it succeeded */
if (status & NAND_STATUS_FAIL) { if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
...@@ -1022,23 +1032,24 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int ...@@ -1022,23 +1032,24 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
#endif #endif
/** /**
* nand_read - [MTD Interface] MTD compability function for nand_read_ecc * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure * @mtd: MTD device structure
* @from: offset to read from * @from: offset to read from
* @len: number of bytes to read * @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes * @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data * @buf: the databuffer to put data
* *
* This function simply calls nand_read_ecc with oob buffer and oobsel = NULL * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
*/ * and flags = 0xff
*/
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
{ {
return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
} }
/** /**
* nand_read_ecc - [MTD Interface] Read data with ECC * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure * @mtd: MTD device structure
* @from: offset to read from * @from: offset to read from
* @len: number of bytes to read * @len: number of bytes to read
...@@ -1047,10 +1058,34 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re ...@@ -1047,10 +1058,34 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
* @oob_buf: filesystem supplied oob data buffer * @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure * @oobsel: oob selection structure
* *
* NAND read with ECC * This function simply calls nand_do_read_ecc with flags = 0xff
*/ */
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
{
return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
}
/**
* nand_do_read_ecc - [MTD Interface] Read data with ECC
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
* @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
* and how many corrected error bits are acceptable:
* bits 0..7 - number of tolerable errors
* bit 8 - 0 == do not get/release chip, 1 == get/release chip
*
* NAND read with ECC
*/
int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf,
struct nand_oobinfo *oobsel, int flags)
{ {
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
...@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
} }
/* Grab the lock and see if the device is available */ /* Grab the lock and see if the device is available */
nand_get_device (this, mtd, FL_READING); if (flags & NAND_GET_DEVICE)
nand_get_device (this, mtd, FL_READING);
/* use userspace supplied oobinfo, if zero */ /* use userspace supplied oobinfo, if zero */
if (oobsel == NULL) if (oobsel == NULL)
...@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* We calc error correction directly, it checks the hw /* We calc error correction directly, it checks the hw
* generator for an error, reads back the syndrome and * generator for an error, reads back the syndrome and
* does the error correction on the fly */ * does the error correction on the fly */
if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
ecc_failed++; ecc_failed++;
...@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
p[i] = ecc_status; p[i] = ecc_status;
} }
if (ecc_status == -1) { if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
ecc_failed++; ecc_failed++;
} }
...@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
} }
/* Deselect and wake up anyone waiting on the device */ /* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd); if (flags & NAND_GET_DEVICE)
nand_release_device(mtd);
/* /*
* Return success, if no ECC failures, else -EBADMSG * 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,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
status = this->waitfunc (mtd, this, FL_ERASING); status = this->waitfunc (mtd, this, FL_ERASING);
/* See if operation failed and additional status checks are available */
if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
status = this->errstat(mtd, this, FL_ERASING, status, page);
}
/* See if block erase succeeded */ /* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) { if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Steven J. Hill <sjhill@realitydiluted.com> * Steven J. Hill <sjhill@realitydiluted.com>
* Thomas Gleixner <tglx@linutronix.de> * Thomas Gleixner <tglx@linutronix.de>
* *
* $Id: nand.h,v 1.69 2005/01/17 18:29:18 dmarlin Exp $ * $Id: nand.h,v 1.70 2005/01/24 03:07:42 dmarlin Exp $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
* update of nand_chip structure description * update of nand_chip structure description
* 01-17-2005 dmarlin added extended commands for AG-AND device and added option * 01-17-2005 dmarlin added extended commands for AG-AND device and added option
* for BBT_AUTO_REFRESH. * for BBT_AUTO_REFRESH.
* 01-20-2005 dmarlin added optional pointer to hardware specific callback for
* extra error status checks.
*/ */
#ifndef __LINUX_MTD_NAND_H #ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H #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,7 +166,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* /*
* Constants for Hardware ECC * Constants for Hardware ECC
*/ */
/* Reset Hardware ECC for read */ /* Reset Hardware ECC for read */
#define NAND_ECC_READ 0 #define NAND_ECC_READ 0
/* Reset Hardware ECC for write */ /* 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,6 +174,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Enable Hardware ECC before syndrom is read back from flash */ /* Enable Hardware ECC before syndrom is read back from flash */
#define NAND_ECC_READSYN 2 #define NAND_ECC_READSYN 2
/* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80
/* Option constants for bizarre disfunctionality and real /* Option constants for bizarre disfunctionality and real
* features * features
*/ */
...@@ -308,6 +314,8 @@ struct nand_hw_control { ...@@ -308,6 +314,8 @@ struct nand_hw_control {
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
* @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
* @priv: [OPTIONAL] pointer to private chip date * @priv: [OPTIONAL] pointer to private chip date
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
* (determine if errors are correctable)
*/ */
struct nand_chip { struct nand_chip {
...@@ -363,6 +371,7 @@ struct nand_chip { ...@@ -363,6 +371,7 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern; struct nand_bbt_descr *badblock_pattern;
struct nand_hw_control *controller; struct nand_hw_control *controller;
void *priv; void *priv;
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
}; };
/* /*
...@@ -484,6 +493,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); ...@@ -484,6 +493,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt (struct mtd_info *mtd); extern int nand_default_bbt (struct mtd_info *mtd);
extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf,
struct nand_oobinfo *oobsel, int flags);
/* /*
* Constants for oob configuration * Constants for oob configuration
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment