Linux内核---29.yaffs2的ECC

一. ECC校验
ECC: error Checking and correct,既能检查错误也能纠正错误.
优点是: 速度奇快
缺点是: 只能检查2bit的错误,只能纠正1bit的错误

如果想验证这儿需要打开 param . no_tags_ecc=0,默认 param . no_tags_ecc=1不进行tags校验.
同时,mkyaffs2image中也要把ECC校验信息加进去,这样才能从nand_flash中读出ECC进行比较.
nandmtd2_read_chunk_tags
        -->  yaffs_unpack_tags2
  1. void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *ptint tags_ecc)
  2. {
  3.     enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
  4.     if (pt->t.seq_number != 0xffffffff && tags_ecc) {
  5.         struct yaffs_ecc_other ecc;
  6.         int result;
  7.         yaffs_ecc_calc_other((unsigned char *)&pt->tsizeof(struct yaffs_packed_tags2_tags_only), &ecc);
  8.         result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
  9.                 sizeof(struct yaffs_packed_tags2_tags_only), &pt->ecc, &ecc);
  10.         switch (result) {
  11.         case 0:
  12.             ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
  13.             break;
  14.         case 1:
  15.             ecc_result = YAFFS_ECC_RESULT_FIXED;
  16.             break;
  17.         case -1:
  18.             ecc_result = YAFFS_ECC_RESULT_UNFIXED;
  19.             break;
  20.         default:
  21.             ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
  22.         }
  23.     }
  24.     yaffs_unpack_tags2_tags_only(t, &pt->t);

  25.     t->ecc_result = ecc_result;            //保存校验后的结果, 调用它的函数是要检查的

  26.     yaffs_dump_packed_tags2(pt);        //打印而己,不关心
  27.     yaffs_dump_tags2(t);                //打印而己,不关心
  28. }
这部分主要是校验yaffs_packed_tags2* pt中的结果, sizeof(yaffs_packed_tags2)=4*7=28
  1. struct yaffs_packed_tags2_tags_only {
  2.     unsigned seq_number;
  3.     unsigned obj_id;
  4.     unsigned chunk_id;
  5.     unsigned n_bytes;
  6. };
  7. struct yaffs_ecc_other {
  8.     unsigned char col_parity;
  9.     unsigned line_parity;
  10.     unsigned line_parity_prime;
  11. };
  12. struct yaffs_packed_tags2 {
  13.     struct yaffs_packed_tags2_tags_only t;
  14.     struct yaffs_ecc_other ecc;
  15. };
注意: 这个校验只被 nandmtd2_read_chunk_tags所调用,因为 pt中的数据是存在nand flash的OOB区的,data区的数据在读取时己经被检验过了.
yaffs把OOB区前28个字节也拿来当数据使用了,所以这部分也需要校验.但是nand_flash只会对data区的数据进行校验,所以需要自己写代码来校验这OOB的28个字节
二.校验算法
2. 生成column_parity_table表
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. unsigned char entry(unsigned char x) 
  4. { 
  5.     unsigned char b0, b1, b2, b3, b4, b5, b6, b7; 
  6.     unsigned char p4, p2, p1, p4p, p2p, p1p; 
  7.     unsigned char linep; 
  8.     unsigned char result; 
  9.       
  10.     b0 = (& 0x01) ? 1 : 0; 
  11.     b1 = (& 0x02) ? 1 : 0; 
  12.     b2 = (& 0x04) ? 1 : 0; 
  13.     b3 = (& 0x08) ? 1 : 0; 
  14.     b4 = (& 0x10) ? 1 : 0; 
  15.     b5 = (& 0x20) ? 1 : 0; 
  16.     b6 = (& 0x40) ? 1 : 0; 
  17.     b7 = (& 0x80) ? 1 : 0; 
  18.       
  19.     p4 = b7 ^ b6 ^ b5 ^ b4; p4p = b3 ^ b2 ^ b1 ^ b0; 
  20.     p2 = b7 ^ b6 ^ b3 ^ b2; p2p = b5 ^ b4 ^ b1 ^ b0; 
  21.     p1 = b7 ^ b5 ^ b3 ^ b1; p1p = b6 ^ b4 ^ b2 ^ b0; 
  22.       
  23.     linep = p1 ^ p1p; 
  24.       
  25.     result = 0; 
  26.     if(p4) result |= 0x80; 
  27.     if(p4p) result |= 0x40; 
  28.     if(p2) result |= 0x20; 
  29.     if(p2p) result |= 0x10; 
  30.     if(p1) result |= 0x08; 
  31.     if(p1p) result |= 0x04; 
  32.     if(linep) result |= 0x01; 
  33.       
  34.     //result >>= 2; 
  35.     //if(linep) result |= 0x40;       
  36.     return result;       
  37. }   
  38.   
  39. int main(int argc, char *argv[]) 
  40. { 
  41.     unsigned i; 
  42.       
  43.     printf("const unsigned char column_parity_table[] = {"); 
  44.     for(= 0; i < 256; i++) 
  45.     { 
  46.         if((& 0xf) == 0) printf("\n"); 
  47.         printf("0x%02x, ",entry((unsigned char) i)); 
  48.     } 
  49.     printf("\n};\n"); 
  50. }



所以每一个result都是:



2.1校验步骤
     a. 通过yaffs_ecc_calc_other生成ECC, 称为new_ecc
     b. new_ecc与old_ecc进行异或,如果不一样,则说明出错
     c. 类似于二叉树,找到出错位,并进行校正
  1. void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytesstruct yaffs_ecc_other *ecc_other)  //生成新的ECC
  2. {
  3.     unsigned int i;
  4.     unsigned char col_parity = 0;
  5.     unsigned line_parity = 0;
  6.     unsigned line_parity_prime = 0;
  7.     unsigned char b;

  8.     for (= 0; i < n_bytes; i++) {
  9.         b = column_parity_table[*data++];
  10.         col_parity ^= b;
  11.         if (& 0x01) {
  12.             /* odd number of bits in the byte */
  13.             line_parity ^= i;
  14.             line_parity_prime ^= ~i;
  15.         }

  16.     }

  17.     ecc_other->col_parity = (col_parity >> 2) & 0x3f;
  18.     ecc_other->line_parity = line_parity;
  19.     ecc_other->line_parity_prime = line_parity_prime;
  20. }
3. 
  1. int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
  2.              struct yaffs_ecc_other *read_eccconst struct yaffs_ecc_other *test_ecc)     
  3. {                                                                //与test_ecc比较如果不同则进行校正
  4.     unsigned char delta_col; /* column parity delta */
  5.     unsigned delta_line; /* line parity delta */
  6.     unsigned delta_line_prime; /* line parity delta */
  7.     unsigned bit;
  8.     delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
  9.     delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
  10.     delta_line_prime = read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
  11.     if ((delta_col | delta_line | delta_line_prime) == 0)
  12.         return 0; /* no error */
  13.     if (delta_line == ~delta_line_prime && (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
  14.         bit = 0;                                                //bit <0-7>,代表哪一位出错
  15.         if (delta_col & 0x20)                                   
  16.             bit |= 0x04;
  17.         if (delta_col & 0x08)
  18.             bit |= 0x02;
  19.         if (delta_col & 0x02)
  20.             bit |= 0x01;
  21.         if (delta_line >= n_bytes)
  22.             return -1;
  23.         data[delta_line] ^= (<< bit);                            //找到出错的位了,把它反转                                
  24.         return 1; /* corrected */
  25.     }
  26.     if ((hweight32(delta_line) + hweight32(delta_line_prime) + hweight8(delta_col)) == 1) {
  27.         /* Reccoverable error in ecc */
  28.         *read_ecc = *test_ecc;
  29.         return 1; /* corrected */
  30.     }
  31.     /* Unrecoverable error */
  32.     return -1;
  33. }
分析ECC校验算法有一个非常好的文章:<h1 class="ts" color:#000000;letter-spacing:normal;orphans:auto;text-align:start;text-indent:0px;text-transform:none;white-space:normal;widows:auto;word-spacing:0px;-webkit-text-stroke-width:0px;"="" style="word-wrap: break-word; margin: 0px; padding: 0px; color: rgb(102, 102, 102); font-size: 16px; font-family: '';"> [原创]Nand ECC校验和纠错原理及2.6.27内核ECC代码分析  
http://bbs.chinaunix.net/thread-1975983-1-1.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值