nand/denali: Fixed handle ECC error bugs
Subsystems (2)
PATCH 3/4 nand/denali: Fixed handle ECC error bugs
From 3e40d412afda3d5ec508b8ee66e468bcc79cb710 Mon Sep 17 00:00:00 2001
From: Chuanxiao Dong <[email protected]>
Date: Tue, 10 Aug 2010 00:07:01 +0800
Subject: [PATCH 3/4] nand/denali: Fixed handle ECC error bugs
Once the last ECC error was handled, controller will triger an interrupt. If this interrupt can not be clean on time, controller may corrupt.
Signed-off-by Chuanxiao Dong <[email protected]>
--- drivers/mtd/nand/denali.c | 45 +++++++++++++++++++++++++++++---------------- 1 files changed, 29 insertions(+), 16 deletions(-)
drivers/mtd/nand/denali.c +29 -16
@@ -643,6 +643,7 @@ static void clear_interrupts(struct denali_nand_info *denali)spin_lock_irq (&denali->irq_lock); status =read_interrupt_status (denali); +clear_interrupt (denali, status);#if DEBUG_DENALI denali->irq_debug_array[denali->idx++] =0x30000000 | status;
@@ -1015,12 +1016,12 @@ bool is_erased(uint8_t *buf, int len)#define ECC_SECTOR (x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)#define ECC_BYTE (x) (((x) & ECC_ERROR_ADDRESS__OFFSET))#define ECC_CORRECTION_VALUE (x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) -#define ECC_ERROR_CORRECTABLE (x) (!((x) & ERR_CORRECTION_INFO)) -#define ECC_ERR_DEVICE (x) ((x) & ERR_CORRECTION_INFO__DEVICE_NR >> 8) +#define ECC_ERROR_CORRECTABLE (x) (!((x) & ERR_CORRECTION_INFO__ERROR_TYPE)) +#define ECC_ERR_DEVICE (x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)#define ECC_LAST_ERR (x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)static bool handle_ecc (struct denali_nand_info *denali,uint8_t *buf, -uint8_t *oobbuf,uint32_t irq_status) +uint32_t irq_status) {bool check_erased_page = false;
@@ -1029,6 +1030,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,uint32_t err_address =0 , err_correction_info =0 ;uint32_t err_byte =0 , err_sector =0 , err_device =0 ;uint32_t err_correction_value =0 ; +denali_set_intr_modes (denali, false); do { err_address = ioread32(denali->flash_reg +
@@ -1036,7 +1038,6 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_sector =ECC_SECTOR (err_address); err_byte =ECC_BYTE (err_address); - err_correction_info =ioread32 (denali->flash_reg +ERR_CORRECTION_INFO ); err_correction_value =
@@ -1044,20 +1045,23 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_device =ECC_ERR_DEVICE (err_correction_info);if (ECC_ERROR_CORRECTABLE (err_correction_info)) { -/* offset in our buffer is computed as: -sector number * sector size + offset in -sector -*/ -int offset = err_sector *ECC_SECTOR_SIZE + - err_byte; -if (offset < denali->mtd.writesize) { +/* If err_byte is larger than ECC_SECTOR_SIZE, +* means error happend in OOB, so we ignore +* it. It's no need for us to correct it +* err_device is represented the NAND error +* bits are happened in if there are more +* than one NAND connected. +* */ +if (err_byte <ECC_SECTOR_SIZE ) { +int offset; + offset = (err_sector * +ECC_SECTOR_SIZE + + err_byte) * + denali->devnum + + err_device;/* correct the ECC error */ buf[offset] ^= err_correction_value; denali->mtd.ecc_stats.corrected++; - }else { -/* bummer, couldn't correct the error */ -printk (KERN_ERR "ECC offset invalid\n" ); - denali->mtd.ecc_stats.failed++; } }else {/* if the error is not correctable, need to
@@ -1074,6 +1078,15 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_correction_info);#endif }while (!ECC_LAST_ERR (err_correction_info)); +/* Once handle all ecc errors, controller will triger +* a ECC_TRANSACTION_DONE interrupt, so here just wait +* for a while for this interrupt +* */ +while (!(read_interrupt_status (denali) & +INTR_STATUS0__ECC_TRANSACTION_DONE )) +cpu_relax (); +clear_interrupts (denali); +denali_set_intr_modes (denali, true); }return check_erased_page; }
@@ -1237,7 +1250,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,memcpy (buf, denali->buf.buf, mtd->writesize); - check_erased_page =handle_ecc (denali, buf, chip->oob_poi, irq_status); + check_erased_page =handle_ecc (denali, buf, irq_status);denali_enable_dma (denali, false);if (check_erased_page) {
Signature · 1 line
1.6.6.1