📄 nand_base.c
字号:
{
struct nand_chip * chip = mtd->priv;
unsigned long timeout;
uint32_t ready;
/* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(3000); // 3 sec timeout for now
while (time_before(jiffies, timeout)) {
PLATFORM_IOFLUSH_WAR();
ready = chip->ctrl_read(BCHP_NAND_INTFC_STATUS);
if (ready & (BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK | 0x1)) {
int ecc;
if (ready & 0x1) {
printk(KERN_ERR "%s: Flash chip report error %08x\n", __FUNCTION__, ready);
return NAND_FLASH_STATUS_ERROR;
}
//if (!raw) {
ecc = nand_verify_ecc(chip, state);
// Let caller handle it
//printk("%s: Possible Uncorrectable ECC error at offset %08x\n", __FUNCTION__, (unsigned long) offset);
return ecc;
//}
//return NAND_SUCCESS;
}
if (state != FL_READING)
cond_resched();
}
return NAND_TIMED_OUT; // TimeOut
}
#ifdef CONFIG_MTD_NAND_EDU
/*
* Returns 1: Success, no errors
* 0: Timeout
* -1: Errors
*/
static int nand_EDU_cache_is_valid(struct mtd_info* mtd, int state, L_OFF_T offset)
{
uint32 rd_data = 0;
int error = 0;
rd_data = EDU_poll(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_STATUS, HIF_INTR2_EDU_DONE, HIF_INTR2_EDU_DONE);
if(rd_data != 0)
{
error = nand_cache_is_valid(mtd, state, offset);
}
EDU_volatileWrite(EDU_BASE_ADDRESS + EDU_DONE, 0x00000000);
EDU_volatileWrite(EDU_BASE_ADDRESS + EDU_ERR_STATUS, 0x00000000);
EDU_volatileWrite(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_CLEAR, HIF_INTR2_EDU_CLEAR);
return error;
}
#endif // CONFIG_MTD_NAND_EDU
static int nand_select_cache_is_valid(struct mtd_info* mtd, int state, L_OFF_T offset)
{
int ret = 0;
#ifdef CONFIG_MTD_NAND_EDU
ret = nand_EDU_cache_is_valid(mtd,state,offset);
#else
ret = nand_cache_is_valid(mtd,state,offset);
#endif
return ret;
}
/*
* Returns 1: Success, no errors
* 0: Timeout
* -1: Errors
*/
static int nand_spare_is_valid(struct mtd_info* mtd, int state, int raw)
{
struct nand_chip * chip = mtd->priv;
unsigned long timeout;
uint32_t ready;
/* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(3000); // 3 sec timeout for now
while (time_before(jiffies, timeout)) {
PLATFORM_IOFLUSH_WAR();
ready = chip->ctrl_read(BCHP_NAND_INTFC_STATUS);
if (ready & BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK) {
int ecc;
if (!raw) {
ecc = nand_verify_ecc(chip, state);
if (ecc < 0) {
//printk("%s: Uncorrectable ECC error at offset %08x\n", __FUNCTION__, (unsigned long) offset);
return -1;
}
}
return 1;
}
if (state != FL_READING)
cond_resched();
}
return 0; // Timed out
}
#ifdef CONFIG_MTD_NAND_EDU
static int nand_EDU_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
uint32 rd_data = 0;
// printk("%s\n", __FUNCTION__);
*outp_needBBT = 1;
rd_data = EDU_poll(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_STATUS, HIF_INTR2_EDU_DONE, HIF_INTR2_EDU_DONE);
if ((rd_data & HIF_INTR2_EDU_DONE) == HIF_INTR2_EDU_DONE )
{
//Get status:
*outp_needBBT = EDU_get_error_status_register();
//Clear interrupt:
EDU_volatileWrite(EDU_BASE_ADDRESS + EDU_DONE, 0x00000000);
EDU_volatileWrite(EDU_BASE_ADDRESS + EDU_ERR_STATUS, 0x00000000);
EDU_volatileWrite(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_CLEAR, HIF_INTR2_EDU_CLEAR);
if (*outp_needBBT != 0)
{
printk("EDU_write_is_complete(): error 0x%08X\n", *outp_needBBT);
}
return 1; //Poll success!
}
printk("EDU_write_is_complete(): error 2 rd_data: %08x\n", (unsigned int)rd_data);
//Poll did not return HIF_INTR2_EDU_DONE:
return 0;
}
#endif // CONFIG_MTD_NAND_EDU
static int nand_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
int err;
uint32_t status;
uint32_t flashStatus = 0;
*outp_needBBT = 1;
err = nand_wait(mtd, FL_WRITING, &status);
if (!err) {
if (status & BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK) {
flashStatus = status & 0x01;
*outp_needBBT = flashStatus; // 0 = write completes with no errors
return 1;
}
else {
return 0;
}
}
return 0;
}
static int nand_select_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
int ret = 0;
#ifdef CONFIG_MTD_NAND_EDU
//Check the state of the current lock of the device:
struct nand_chip *this = mtd->priv;
if (this->state == FL_WRITING)
{
ret = nand_EDU_write_is_complete(mtd, outp_needBBT);
}
else
{
ret = nand_write_is_complete(mtd, outp_needBBT);
}
#else
ret = nand_write_is_complete(mtd, outp_needBBT);
#endif
return ret;
}
/**
* nand_transfer_oob - [Internal] Transfer oob to client buffer
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
*/
static uint8_t *
nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops)
{
size_t len = ops->ooblen;
switch(ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_RAW:
memcpy(oob, chip->oob_poi + ops->ooboffs, len);
return oob + len;
case MTD_OOB_AUTO: {
struct nand_oobfree *free = chip->ecclayout->oobfree;
uint32_t boffs = 0, roffs = ops->ooboffs;
size_t bytes = 0;
for(; free->length && len; free++, len -= bytes) {
/* Read request not from offset 0 ? */
if (unlikely(roffs)) {
if (roffs >= free->length) {
roffs -= free->length;
continue;
}
boffs = free->offset + roffs;
bytes = min_t(size_t, len,
(free->length - roffs));
roffs = 0;
} else {
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
memcpy(oob, chip->oob_poi + boffs, bytes);
oob += bytes;
}
return oob;
}
default:
BUG();
}
return NULL;
}
#ifdef CONFIG_MTD_NAND_EDU
/**
* nand_posted_read_cache - [NAND Interface] Read the 512B cache area
* Assuming nand_get_device() has been called to obtain exclusive lock
* @param mtd MTD data structure
* @param oobarea Spare area, pass NULL if not interested
* @param buffer the databuffer to put/get data, pass NULL if only spare area is wanted.
* @param offset offset to read from or write to, must be 512B aligned.
* @param raw: Ignore BBT bytes when raw = 1
*
* Caller is responsible to pass a buffer that is
* (1) large enough for 512B for data and optionally an oobarea large enough for 16B.
* (2) 4-byte aligned.
*
* Read the cache area into buffer. The size of the cache is mtd-->eccsize and is always 512B.
*/
static int nand_posted_read_cache(struct mtd_info* mtd,
void* buffer, u_char* oobarea, L_OFF_T offset)
{
int ecc;
#if 0
L_OFF_T blockOffset;
static int refresh_recursive = 0;
#endif
struct nand_chip* this = mtd->priv;
L_OFF_T sliceOffset = __ll_and32(offset, ~ (mtd->eccsize - 1));
int i, ret = 0;
int retries = 2, done = 0;
uint32_t* p32 = (uint32_t*) oobarea;
#ifdef ECC_UNCORRECTABLE_SIMULATION
uint8_t* my_buffer = NULL;
#endif
if (gdebug > 3) {
printk("%s: offset=%s, oobarea=%p\n", __FUNCTION__, __ll_sprintf(NandMsg, offset), oobarea);}
while (retries > 0 && !done)
{
if (unlikely(__ll_isub(offset, sliceOffset))) {
printk(KERN_ERR "%s: offset %s is not cache aligned, sliceOffset=%s, CacheSize=%d\n",
__FUNCTION__, __ll_sprintf(NandMsg, offset), __ll_sprintf(NandMsg, sliceOffset), mtd->eccsize);
return -EINVAL;
}
this->ctrl_writeAddr(this, sliceOffset, 0);
PLATFORM_IOFLUSH_WAR();
ret = EDU_read(buffer, EDU_ldw);
if (ret)
goto out;
// Wait until cache is filled up
ecc = nand_select_cache_is_valid(mtd, FL_READING, offset);
if (oobarea)
{
PLATFORM_IOFLUSH_WAR();
for (i = 0; i < 4; i++)
{
p32[i] = be32_to_cpu (this->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
}
if (gdebug) {printk("%s: offset=%s, oob=\n", __FUNCTION__, __ll_sprintf(NandMsg, sliceOffset));
print_oobbuf(oobarea, 16);}
}
switch (ecc)
{
case NAND_SUCCESS: /* Success, no errors */
{
ret = 0; // Success!
done = 1;
}
break;
case NAND_CORRECTABLE_ECC_ERROR:
{
#if 0
if (refresh_recursive == 0)
{
printk("%s: ECC correctable error at %s, refreshing block...\n",__FUNCTION__,__ll_sprintf(NandMsg, offset, this->xor_invert_val));
refresh_recursive = 1;
nand_deduce_blockOffset(mtd, offset, &blockOffset);
ret = nand_refresh_block(mtd, blockOffset);
refresh_recursive = 0;
if (ret == 0)
{
printk("%s: Block refreshed successfully\n",__FUNCTION__);
ret = -EECCCOR;
}
else
{
printk("%s: Block refresh failure!\n",__FUNCTION__);
}
}
#else
ret = 0; // Success!
#endif
done = 1;
}
break;
case NAND_UNCORRECTABLE_ECC_ERROR:
{
/* Flash chip returns errors
|| There is a bug in the controller, where if one reads from an erased block that has NOT been written to,
|| this error is raised.
|| (Writing to OOB area does not have any effect on this bug)
|| The workaround is to also look into the OOB area, to see if they are all 0xFF
*/
u_char oobbuf[16];
int all00, allFF;
// NAND CTRL BUG... EDU has stopped! Must copy buffer!!!
memcpy(buffer, this->vbase, mtd->eccsize);
if (!oobarea)
oobarea = &oobbuf[0];
p32 = (uint32_t*) oobarea;
for (i = 0; i < 4; i++) {
p32[i] = /* THT 11-30-06 */ be32_to_cpu (this->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
}
all00 = (oobarea[6] == 0xff && oobarea[7] == 0xff && oobarea[8] == 0xff);
allFF = (oobarea[6] == 0x00 && oobarea[7] == 0x00 && oobarea[8] == 0x00);
if ( all00 || allFF) {
/*
* For the first case, the slice is an erased block, and the ECC bytes are all 0xFF,
* for the 2nd, all bytes are 0xFF, so the Hamming Codes for it are all zeroes.
* The current version of the NAND controller treats these as un-correctable errors.
* For either case, fill data buffer with 0x00 or 0xff and return success. The error has already
* been cleared inside nand_verify_ecc.
* Both case will be handled correctly by the Nand controller in later releases.
*/
p32 = (uint32_t*) buffer;
for (i=0; i < mtd->eccsize/4; i++) {
p32[i] = 0xFFFFFFFF;
}
ret = 0; // Success!
}
else
{
#ifdef ECC_UNCORRECTABLE_SIMULATION
if (bEccUncor)
{
printk("Inserting errors in buffer\n");
if (buffer != NULL)
{
my_buffer = (uint8_t*) buffer;
//Invert data in buffer:
for (i = 0; i < mtd->eccsize; i++)
{
my_buffer[i] = ~my_buffer[i];
}
}
}
#endif
/* Real error: Disturb read returns uncorrectable errors */
if (gdebug) printk("%s: ECC noncorrectable error at %s\n",__FUNCTION__, __ll_sprintf(NandMsg, offset));
#if 0
//commented because yaffs2 and jffs2 are taking care of marking the bad blocks whenever we return -EECCUNCOR
printk("%s: Marking bad block @%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset, this->xor_invert_val));
ret = this->block_markbad(mtd, offset);
#endif
ret = -EBADMSG;
}
done = 1;
}
break;
case EDU_CORRECTABLE_ECC_ERROR:
{
memcpy(buffer, this->vbase, mtd->eccsize);
ret = 0; // Success!
done = 1;
if (gdebug) printk("%s: EDU Correctable ECC error: ret -EBADMSG !!!\n",__FUNCTION__);
}
break;
case EDU_UNCORRECTABLE_ECC_ERROR:
{
printk("EDU_read45\n");
// NAND CTRL BUG... EDU has stopped! BUT NO ERROR!!! Must copy buffer!!!
memcpy(buffer, this->vbase, mtd->eccsize);
ret = 0; // Success!
done = 1;
if (gdebug) printk("%s: EDU ECC noncorrectable error at %s",__FUNCTION__, __ll_sprintf(NandMsg, offset));
}
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -