[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>
This commit is contained in:
parent
99f2a8aea1
commit
068e3c0a00
2 changed files with 68 additions and 13 deletions
|
@ -42,6 +42,10 @@
|
|||
* a "device recovery" operation must be performed when power is restored
|
||||
* 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:
|
||||
* David Woodhouse for adding multichip support
|
||||
*
|
||||
|
@ -55,7 +59,7 @@
|
|||
* The AG-AND chips have nice features for speed improvement,
|
||||
* 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
|
||||
* 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
|
|||
if (!cached) {
|
||||
/* call wait ready function */
|
||||
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 */
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
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
|
|||
#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
|
||||
* @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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
* @from: offset to read from
|
||||
* @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
|
|||
* @oob_buf: filesystem supplied oob data buffer
|
||||
* @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,
|
||||
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 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,
|
|||
}
|
||||
|
||||
/* 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 */
|
||||
if (oobsel == NULL)
|
||||
|
@ -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
|
||||
* generator for an error, reads back the syndrome and
|
||||
* 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: "
|
||||
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
|
||||
ecc_failed++;
|
||||
|
@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
|||
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);
|
||||
ecc_failed++;
|
||||
}
|
||||
|
@ -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 */
|
||||
nand_release_device(mtd);
|
||||
if (flags & NAND_GET_DEVICE)
|
||||
nand_release_device(mtd);
|
||||
|
||||
/*
|
||||
* 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
|
|||
|
||||
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 */
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -50,6 +50,8 @@
|
|||
* update of nand_chip structure description
|
||||
* 01-17-2005 dmarlin added extended commands for AG-AND device and added option
|
||||
* 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
|
||||
#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_
|
|||
|
||||
/*
|
||||
* Constants for Hardware ECC
|
||||
*/
|
||||
*/
|
||||
/* Reset Hardware ECC for read */
|
||||
#define NAND_ECC_READ 0
|
||||
/* 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_
|
|||
/* Enable Hardware ECC before syndrom is read back from flash */
|
||||
#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
|
||||
* features
|
||||
*/
|
||||
|
@ -308,6 +314,8 @@ struct nand_hw_control {
|
|||
* @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
|
||||
* @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 {
|
||||
|
@ -363,6 +371,7 @@ struct nand_chip {
|
|||
struct nand_bbt_descr *badblock_pattern;
|
||||
struct nand_hw_control *controller;
|
||||
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);
|
|||
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_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
|
||||
|
|
Loading…
Reference in a new issue