aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuanxiao Dong <chuanxiao.dong@intel.com>2010-08-09 12:07:01 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-08-10 19:28:39 -0400
commit8ae61ebddba8a0cf96f61e592acaa12800e50727 (patch)
treef098bacb9c388ff44d6a9e62c4e87d72428ed65a
parent24c3fa36dedd12616c273bfa4adfed3bb652637f (diff)
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 <chuanxiao.dong@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/nand/denali.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 4ab9d89eae56..e4462c0740b2 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -643,6 +643,7 @@ static void clear_interrupts(struct denali_nand_info *denali)
643 spin_lock_irq(&denali->irq_lock); 643 spin_lock_irq(&denali->irq_lock);
644 644
645 status = read_interrupt_status(denali); 645 status = read_interrupt_status(denali);
646 clear_interrupt(denali, status);
646 647
647#if DEBUG_DENALI 648#if DEBUG_DENALI
648 denali->irq_debug_array[denali->idx++] = 0x30000000 | status; 649 denali->irq_debug_array[denali->idx++] = 0x30000000 | status;
@@ -1015,12 +1016,12 @@ bool is_erased(uint8_t *buf, int len)
1015#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) 1016#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
1016#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET)) 1017#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET))
1017#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) 1018#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
1018#define ECC_ERROR_CORRECTABLE(x) (!((x) & ERR_CORRECTION_INFO)) 1019#define ECC_ERROR_CORRECTABLE(x) (!((x) & ERR_CORRECTION_INFO__ERROR_TYPE))
1019#define ECC_ERR_DEVICE(x) ((x) & ERR_CORRECTION_INFO__DEVICE_NR >> 8) 1020#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
1020#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) 1021#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
1021 1022
1022static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, 1023static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
1023 uint8_t *oobbuf, uint32_t irq_status) 1024 uint32_t irq_status)
1024{ 1025{
1025 bool check_erased_page = false; 1026 bool check_erased_page = false;
1026 1027
@@ -1029,6 +1030,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
1029 uint32_t err_address = 0, err_correction_info = 0; 1030 uint32_t err_address = 0, err_correction_info = 0;
1030 uint32_t err_byte = 0, err_sector = 0, err_device = 0; 1031 uint32_t err_byte = 0, err_sector = 0, err_device = 0;
1031 uint32_t err_correction_value = 0; 1032 uint32_t err_correction_value = 0;
1033 denali_set_intr_modes(denali, false);
1032 1034
1033 do { 1035 do {
1034 err_address = ioread32(denali->flash_reg + 1036 err_address = ioread32(denali->flash_reg +
@@ -1036,7 +1038,6 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
1036 err_sector = ECC_SECTOR(err_address); 1038 err_sector = ECC_SECTOR(err_address);
1037 err_byte = ECC_BYTE(err_address); 1039 err_byte = ECC_BYTE(err_address);
1038 1040
1039
1040 err_correction_info = ioread32(denali->flash_reg + 1041 err_correction_info = ioread32(denali->flash_reg +
1041 ERR_CORRECTION_INFO); 1042 ERR_CORRECTION_INFO);
1042 err_correction_value = 1043 err_correction_value =
@@ -1044,20 +1045,23 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
1044 err_device = ECC_ERR_DEVICE(err_correction_info); 1045 err_device = ECC_ERR_DEVICE(err_correction_info);
1045 1046
1046 if (ECC_ERROR_CORRECTABLE(err_correction_info)) { 1047 if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
1047 /* offset in our buffer is computed as: 1048 /* If err_byte is larger than ECC_SECTOR_SIZE,
1048 sector number * sector size + offset in 1049 * means error happend in OOB, so we ignore
1049 sector 1050 * it. It's no need for us to correct it
1050 */ 1051 * err_device is represented the NAND error
1051 int offset = err_sector * ECC_SECTOR_SIZE + 1052 * bits are happened in if there are more
1052 err_byte; 1053 * than one NAND connected.
1053 if (offset < denali->mtd.writesize) { 1054 * */
1055 if (err_byte < ECC_SECTOR_SIZE) {
1056 int offset;
1057 offset = (err_sector *
1058 ECC_SECTOR_SIZE +
1059 err_byte) *
1060 denali->devnum +
1061 err_device;
1054 /* correct the ECC error */ 1062 /* correct the ECC error */
1055 buf[offset] ^= err_correction_value; 1063 buf[offset] ^= err_correction_value;
1056 denali->mtd.ecc_stats.corrected++; 1064 denali->mtd.ecc_stats.corrected++;
1057 } else {
1058 /* bummer, couldn't correct the error */
1059 printk(KERN_ERR "ECC offset invalid\n");
1060 denali->mtd.ecc_stats.failed++;
1061 } 1065 }
1062 } else { 1066 } else {
1063 /* if the error is not correctable, need to 1067 /* if the error is not correctable, need to
@@ -1074,6 +1078,15 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
1074 err_correction_info); 1078 err_correction_info);
1075#endif 1079#endif
1076 } while (!ECC_LAST_ERR(err_correction_info)); 1080 } while (!ECC_LAST_ERR(err_correction_info));
1081 /* Once handle all ecc errors, controller will triger
1082 * a ECC_TRANSACTION_DONE interrupt, so here just wait
1083 * for a while for this interrupt
1084 * */
1085 while (!(read_interrupt_status(denali) &
1086 INTR_STATUS0__ECC_TRANSACTION_DONE))
1087 cpu_relax();
1088 clear_interrupts(denali);
1089 denali_set_intr_modes(denali, true);
1077 } 1090 }
1078 return check_erased_page; 1091 return check_erased_page;
1079} 1092}
@@ -1237,7 +1250,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1237 1250
1238 memcpy(buf, denali->buf.buf, mtd->writesize); 1251 memcpy(buf, denali->buf.buf, mtd->writesize);
1239 1252
1240 check_erased_page = handle_ecc(denali, buf, chip->oob_poi, irq_status); 1253 check_erased_page = handle_ecc(denali, buf, irq_status);
1241 denali_enable_dma(denali, false); 1254 denali_enable_dma(denali, false);
1242 1255
1243 if (check_erased_page) { 1256 if (check_erased_page) {