~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/driver-api/mtd/nand_ecc.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /Documentation/driver-api/mtd/nand_ecc.rst (Architecture ppc) and /Documentation/driver-api/mtd/nand_ecc.rst (Architecture sparc)


  1 ==========================                          1 ==========================
  2 NAND Error-correction Code                          2 NAND Error-correction Code
  3 ==========================                          3 ==========================
  4                                                     4 
  5 Introduction                                        5 Introduction
  6 ============                                        6 ============
  7                                                     7 
  8 Having looked at the linux mtd/nand Hamming so      8 Having looked at the linux mtd/nand Hamming software ECC engine driver
  9 I felt there was room for optimisation. I bash      9 I felt there was room for optimisation. I bashed the code for a few hours
 10 performing tricks like table lookup removing s     10 performing tricks like table lookup removing superfluous code etc.
 11 After that the speed was increased by 35-40%.      11 After that the speed was increased by 35-40%.
 12 Still I was not too happy as I felt there was      12 Still I was not too happy as I felt there was additional room for improvement.
 13                                                    13 
 14 Bad! I was hooked.                                 14 Bad! I was hooked.
 15 I decided to annotate my steps in this file. P     15 I decided to annotate my steps in this file. Perhaps it is useful to someone
 16 or someone learns something from it.               16 or someone learns something from it.
 17                                                    17 
 18                                                    18 
 19 The problem                                        19 The problem
 20 ===========                                        20 ===========
 21                                                    21 
 22 NAND flash (at least SLC one) typically has se     22 NAND flash (at least SLC one) typically has sectors of 256 bytes.
 23 However NAND flash is not extremely reliable s     23 However NAND flash is not extremely reliable so some error detection
 24 (and sometimes correction) is needed.              24 (and sometimes correction) is needed.
 25                                                    25 
 26 This is done by means of a Hamming code. I'll      26 This is done by means of a Hamming code. I'll try to explain it in
 27 laymans terms (and apologies to all the pro's      27 laymans terms (and apologies to all the pro's in the field in case I do
 28 not use the right terminology, my coding theor     28 not use the right terminology, my coding theory class was almost 30
 29 years ago, and I must admit it was not one of      29 years ago, and I must admit it was not one of my favourites).
 30                                                    30 
 31 As I said before the ecc calculation is perfor     31 As I said before the ecc calculation is performed on sectors of 256
 32 bytes. This is done by calculating several par     32 bytes. This is done by calculating several parity bits over the rows and
 33 columns. The parity used is even parity which      33 columns. The parity used is even parity which means that the parity bit = 1
 34 if the data over which the parity is calculate     34 if the data over which the parity is calculated is 1 and the parity bit = 0
 35 if the data over which the parity is calculate     35 if the data over which the parity is calculated is 0. So the total
 36 number of bits over the data over which the pa     36 number of bits over the data over which the parity is calculated + the
 37 parity bit is even. (see wikipedia if you can'     37 parity bit is even. (see wikipedia if you can't follow this).
 38 Parity is often calculated by means of an excl     38 Parity is often calculated by means of an exclusive or operation,
 39 sometimes also referred to as xor. In C the op     39 sometimes also referred to as xor. In C the operator for xor is ^
 40                                                    40 
 41 Back to ecc.                                       41 Back to ecc.
 42 Let's give a small figure:                         42 Let's give a small figure:
 43                                                    43 
 44 =========  ==== ==== ==== ==== ==== ==== ====      44 =========  ==== ==== ==== ==== ==== ==== ==== ====   === === === === ====
 45 byte   0:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      45 byte   0:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp4 ... rp14
 46 byte   1:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      46 byte   1:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp2 rp4 ... rp14
 47 byte   2:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      47 byte   2:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp4 ... rp14
 48 byte   3:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      48 byte   3:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp4 ... rp14
 49 byte   4:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      49 byte   4:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp5 ... rp14
 50 ...                                                50 ...
 51 byte 254:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      51 byte 254:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp5 ... rp15
 52 byte 255:  bit7 bit6 bit5 bit4 bit3 bit2 bit1      52 byte 255:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp5 ... rp15
 53            cp1  cp0  cp1  cp0  cp1  cp0  cp1       53            cp1  cp0  cp1  cp0  cp1  cp0  cp1  cp0
 54            cp3  cp3  cp2  cp2  cp3  cp3  cp2       54            cp3  cp3  cp2  cp2  cp3  cp3  cp2  cp2
 55            cp5  cp5  cp5  cp5  cp4  cp4  cp4       55            cp5  cp5  cp5  cp5  cp4  cp4  cp4  cp4
 56 =========  ==== ==== ==== ==== ==== ==== ====      56 =========  ==== ==== ==== ==== ==== ==== ==== ====   === === === === ====
 57                                                    57 
 58 This figure represents a sector of 256 bytes.      58 This figure represents a sector of 256 bytes.
 59 cp is my abbreviation for column parity, rp fo     59 cp is my abbreviation for column parity, rp for row parity.
 60                                                    60 
 61 Let's start to explain column parity.              61 Let's start to explain column parity.
 62                                                    62 
 63 - cp0 is the parity that belongs to all bit0,      63 - cp0 is the parity that belongs to all bit0, bit2, bit4, bit6.
 64                                                    64 
 65   so the sum of all bit0, bit2, bit4 and bit6      65   so the sum of all bit0, bit2, bit4 and bit6 values + cp0 itself is even.
 66                                                    66 
 67 Similarly cp1 is the sum of all bit1, bit3, bi     67 Similarly cp1 is the sum of all bit1, bit3, bit5 and bit7.
 68                                                    68 
 69 - cp2 is the parity over bit0, bit1, bit4 and      69 - cp2 is the parity over bit0, bit1, bit4 and bit5
 70 - cp3 is the parity over bit2, bit3, bit6 and      70 - cp3 is the parity over bit2, bit3, bit6 and bit7.
 71 - cp4 is the parity over bit0, bit1, bit2 and      71 - cp4 is the parity over bit0, bit1, bit2 and bit3.
 72 - cp5 is the parity over bit4, bit5, bit6 and      72 - cp5 is the parity over bit4, bit5, bit6 and bit7.
 73                                                    73 
 74 Note that each of cp0 .. cp5 is exactly one bi     74 Note that each of cp0 .. cp5 is exactly one bit.
 75                                                    75 
 76 Row parity actually works almost the same.         76 Row parity actually works almost the same.
 77                                                    77 
 78 - rp0 is the parity of all even bytes (0, 2, 4     78 - rp0 is the parity of all even bytes (0, 2, 4, 6, ... 252, 254)
 79 - rp1 is the parity of all odd bytes (1, 3, 5,     79 - rp1 is the parity of all odd bytes (1, 3, 5, 7, ..., 253, 255)
 80 - rp2 is the parity of all bytes 0, 1, 4, 5, 8     80 - rp2 is the parity of all bytes 0, 1, 4, 5, 8, 9, ...
 81   (so handle two bytes, then skip 2 bytes).        81   (so handle two bytes, then skip 2 bytes).
 82 - rp3 is covers the half rp2 does not cover (b     82 - rp3 is covers the half rp2 does not cover (bytes 2, 3, 6, 7, 10, 11, ...)
 83 - for rp4 the rule is cover 4 bytes, skip 4 by     83 - for rp4 the rule is cover 4 bytes, skip 4 bytes, cover 4 bytes, skip 4 etc.
 84                                                    84 
 85   so rp4 calculates parity over bytes 0, 1, 2,     85   so rp4 calculates parity over bytes 0, 1, 2, 3, 8, 9, 10, 11, 16, ...)
 86 - and rp5 covers the other half, so bytes 4, 5     86 - and rp5 covers the other half, so bytes 4, 5, 6, 7, 12, 13, 14, 15, 20, ..
 87                                                    87 
 88 The story now becomes quite boring. I guess yo     88 The story now becomes quite boring. I guess you get the idea.
 89                                                    89 
 90 - rp6 covers 8 bytes then skips 8 etc              90 - rp6 covers 8 bytes then skips 8 etc
 91 - rp7 skips 8 bytes then covers 8 etc              91 - rp7 skips 8 bytes then covers 8 etc
 92 - rp8 covers 16 bytes then skips 16 etc            92 - rp8 covers 16 bytes then skips 16 etc
 93 - rp9 skips 16 bytes then covers 16 etc            93 - rp9 skips 16 bytes then covers 16 etc
 94 - rp10 covers 32 bytes then skips 32 etc           94 - rp10 covers 32 bytes then skips 32 etc
 95 - rp11 skips 32 bytes then covers 32 etc           95 - rp11 skips 32 bytes then covers 32 etc
 96 - rp12 covers 64 bytes then skips 64 etc           96 - rp12 covers 64 bytes then skips 64 etc
 97 - rp13 skips 64 bytes then covers 64 etc           97 - rp13 skips 64 bytes then covers 64 etc
 98 - rp14 covers 128 bytes then skips 128             98 - rp14 covers 128 bytes then skips 128
 99 - rp15 skips 128 bytes then covers 128             99 - rp15 skips 128 bytes then covers 128
100                                                   100 
101 In the end the parity bits are grouped togethe    101 In the end the parity bits are grouped together in three bytes as
102 follows:                                          102 follows:
103                                                   103 
104 =====  ===== ===== ===== ===== ===== ===== ===    104 =====  ===== ===== ===== ===== ===== ===== ===== =====
105 ECC    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit    105 ECC    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
106 =====  ===== ===== ===== ===== ===== ===== ===    106 =====  ===== ===== ===== ===== ===== ===== ===== =====
107 ECC 0   rp07  rp06  rp05  rp04  rp03  rp02  rp    107 ECC 0   rp07  rp06  rp05  rp04  rp03  rp02  rp01  rp00
108 ECC 1   rp15  rp14  rp13  rp12  rp11  rp10  rp    108 ECC 1   rp15  rp14  rp13  rp12  rp11  rp10  rp09  rp08
109 ECC 2   cp5   cp4   cp3   cp2   cp1   cp0         109 ECC 2   cp5   cp4   cp3   cp2   cp1   cp0      1     1
110 =====  ===== ===== ===== ===== ===== ===== ===    110 =====  ===== ===== ===== ===== ===== ===== ===== =====
111                                                   111 
112 I detected after writing this that ST applicat    112 I detected after writing this that ST application note AN1823
113 (http://www.st.com/stonline/) gives a much        113 (http://www.st.com/stonline/) gives a much
114 nicer picture.(but they use line parity as ter    114 nicer picture.(but they use line parity as term where I use row parity)
115 Oh well, I'm graphically challenged, so suffer    115 Oh well, I'm graphically challenged, so suffer with me for a moment :-)
116                                                   116 
117 And I could not reuse the ST picture anyway fo    117 And I could not reuse the ST picture anyway for copyright reasons.
118                                                   118 
119                                                   119 
120 Attempt 0                                         120 Attempt 0
121 =========                                         121 =========
122                                                   122 
123 Implementing the parity calculation is pretty     123 Implementing the parity calculation is pretty simple.
124 In C pseudocode::                                 124 In C pseudocode::
125                                                   125 
126   for (i = 0; i < 256; i++)                       126   for (i = 0; i < 256; i++)
127   {                                               127   {
128     if (i & 0x01)                                 128     if (i & 0x01)
129        rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     129        rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1;
130     else                                          130     else
131        rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     131        rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp0;
132     if (i & 0x02)                                 132     if (i & 0x02)
133        rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     133        rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3;
134     else                                          134     else
135        rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     135        rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp2;
136     if (i & 0x04)                                 136     if (i & 0x04)
137       rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    137       rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp5;
138     else                                          138     else
139       rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    139       rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp4;
140     if (i & 0x08)                                 140     if (i & 0x08)
141       rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    141       rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp7;
142     else                                          142     else
143       rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    143       rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp6;
144     if (i & 0x10)                                 144     if (i & 0x10)
145       rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    145       rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp9;
146     else                                          146     else
147       rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^    147       rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp8;
148     if (i & 0x20)                                 148     if (i & 0x20)
149       rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     149       rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11;
150     else                                          150     else
151       rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     151       rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10;
152     if (i & 0x40)                                 152     if (i & 0x40)
153       rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     153       rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13;
154     else                                          154     else
155       rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     155       rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp12;
156     if (i & 0x80)                                 156     if (i & 0x80)
157       rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     157       rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp15;
158     else                                          158     else
159       rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3     159       rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp14;
160     cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0;        160     cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0;
161     cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1;        161     cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1;
162     cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2;        162     cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2;
163     cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3         163     cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3
164     cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4         164     cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4
165     cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5         165     cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5
166   }                                               166   }
167                                                   167 
168                                                   168 
169 Analysis 0                                        169 Analysis 0
170 ==========                                        170 ==========
171                                                   171 
172 C does have bitwise operators but not really o    172 C does have bitwise operators but not really operators to do the above
173 efficiently (and most hardware has no such ins    173 efficiently (and most hardware has no such instructions either).
174 Therefore without implementing this it was cle    174 Therefore without implementing this it was clear that the code above was
175 not going to bring me a Nobel prize :-)           175 not going to bring me a Nobel prize :-)
176                                                   176 
177 Fortunately the exclusive or operation is comm    177 Fortunately the exclusive or operation is commutative, so we can combine
178 the values in any order. So instead of calcula    178 the values in any order. So instead of calculating all the bits
179 individually, let us try to rearrange things.     179 individually, let us try to rearrange things.
180 For the column parity this is easy. We can jus    180 For the column parity this is easy. We can just xor the bytes and in the
181 end filter out the relevant bits. This is pret    181 end filter out the relevant bits. This is pretty nice as it will bring
182 all cp calculation out of the for loop.           182 all cp calculation out of the for loop.
183                                                   183 
184 Similarly we can first xor the bytes for the v    184 Similarly we can first xor the bytes for the various rows.
185 This leads to:                                    185 This leads to:
186                                                   186 
187                                                   187 
188 Attempt 1                                         188 Attempt 1
189 =========                                         189 =========
190                                                   190 
191 ::                                                191 ::
192                                                   192 
193   const char parity[256] = {                      193   const char parity[256] = {
194       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    194       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
195       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    195       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
196       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    196       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
197       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    197       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
198       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    198       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
199       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    199       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
200       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    200       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
201       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    201       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
202       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    202       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
203       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    203       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
204       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    204       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
205       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    205       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
206       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    206       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
207       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    207       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
208       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0    208       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
209       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1    209       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
210   };                                              210   };
211                                                   211 
212   void ecc1(const unsigned char *buf, unsigned    212   void ecc1(const unsigned char *buf, unsigned char *code)
213   {                                               213   {
214       int i;                                      214       int i;
215       const unsigned char *bp = buf;              215       const unsigned char *bp = buf;
216       unsigned char cur;                          216       unsigned char cur;
217       unsigned char rp0, rp1, rp2, rp3, rp4, r    217       unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
218       unsigned char rp8, rp9, rp10, rp11, rp12    218       unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
219       unsigned char par;                          219       unsigned char par;
220                                                   220 
221       par = 0;                                    221       par = 0;
222       rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;         222       rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
223       rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;         223       rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
224       rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;       224       rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
225       rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;     225       rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
226                                                   226 
227       for (i = 0; i < 256; i++)                   227       for (i = 0; i < 256; i++)
228       {                                           228       {
229           cur = *bp++;                            229           cur = *bp++;
230           par ^= cur;                             230           par ^= cur;
231           if (i & 0x01) rp1 ^= cur; else rp0 ^    231           if (i & 0x01) rp1 ^= cur; else rp0 ^= cur;
232           if (i & 0x02) rp3 ^= cur; else rp2 ^    232           if (i & 0x02) rp3 ^= cur; else rp2 ^= cur;
233           if (i & 0x04) rp5 ^= cur; else rp4 ^    233           if (i & 0x04) rp5 ^= cur; else rp4 ^= cur;
234           if (i & 0x08) rp7 ^= cur; else rp6 ^    234           if (i & 0x08) rp7 ^= cur; else rp6 ^= cur;
235           if (i & 0x10) rp9 ^= cur; else rp8 ^    235           if (i & 0x10) rp9 ^= cur; else rp8 ^= cur;
236           if (i & 0x20) rp11 ^= cur; else rp10    236           if (i & 0x20) rp11 ^= cur; else rp10 ^= cur;
237           if (i & 0x40) rp13 ^= cur; else rp12    237           if (i & 0x40) rp13 ^= cur; else rp12 ^= cur;
238           if (i & 0x80) rp15 ^= cur; else rp14    238           if (i & 0x80) rp15 ^= cur; else rp14 ^= cur;
239       }                                           239       }
240       code[0] =                                   240       code[0] =
241           (parity[rp7] << 7) |                    241           (parity[rp7] << 7) |
242           (parity[rp6] << 6) |                    242           (parity[rp6] << 6) |
243           (parity[rp5] << 5) |                    243           (parity[rp5] << 5) |
244           (parity[rp4] << 4) |                    244           (parity[rp4] << 4) |
245           (parity[rp3] << 3) |                    245           (parity[rp3] << 3) |
246           (parity[rp2] << 2) |                    246           (parity[rp2] << 2) |
247           (parity[rp1] << 1) |                    247           (parity[rp1] << 1) |
248           (parity[rp0]);                          248           (parity[rp0]);
249       code[1] =                                   249       code[1] =
250           (parity[rp15] << 7) |                   250           (parity[rp15] << 7) |
251           (parity[rp14] << 6) |                   251           (parity[rp14] << 6) |
252           (parity[rp13] << 5) |                   252           (parity[rp13] << 5) |
253           (parity[rp12] << 4) |                   253           (parity[rp12] << 4) |
254           (parity[rp11] << 3) |                   254           (parity[rp11] << 3) |
255           (parity[rp10] << 2) |                   255           (parity[rp10] << 2) |
256           (parity[rp9]  << 1) |                   256           (parity[rp9]  << 1) |
257           (parity[rp8]);                          257           (parity[rp8]);
258       code[2] =                                   258       code[2] =
259           (parity[par & 0xf0] << 7) |             259           (parity[par & 0xf0] << 7) |
260           (parity[par & 0x0f] << 6) |             260           (parity[par & 0x0f] << 6) |
261           (parity[par & 0xcc] << 5) |             261           (parity[par & 0xcc] << 5) |
262           (parity[par & 0x33] << 4) |             262           (parity[par & 0x33] << 4) |
263           (parity[par & 0xaa] << 3) |             263           (parity[par & 0xaa] << 3) |
264           (parity[par & 0x55] << 2);              264           (parity[par & 0x55] << 2);
265       code[0] = ~code[0];                         265       code[0] = ~code[0];
266       code[1] = ~code[1];                         266       code[1] = ~code[1];
267       code[2] = ~code[2];                         267       code[2] = ~code[2];
268   }                                               268   }
269                                                   269 
270 Still pretty straightforward. The last three i    270 Still pretty straightforward. The last three invert statements are there to
271 give a checksum of 0xff 0xff 0xff for an empty    271 give a checksum of 0xff 0xff 0xff for an empty flash. In an empty flash
272 all data is 0xff, so the checksum then matches    272 all data is 0xff, so the checksum then matches.
273                                                   273 
274 I also introduced the parity lookup. I expecte    274 I also introduced the parity lookup. I expected this to be the fastest
275 way to calculate the parity, but I will invest    275 way to calculate the parity, but I will investigate alternatives later
276 on.                                               276 on.
277                                                   277 
278                                                   278 
279 Analysis 1                                        279 Analysis 1
280 ==========                                        280 ==========
281                                                   281 
282 The code works, but is not terribly efficient.    282 The code works, but is not terribly efficient. On my system it took
283 almost 4 times as much time as the linux drive    283 almost 4 times as much time as the linux driver code. But hey, if it was
284 *that* easy this would have been done long bef    284 *that* easy this would have been done long before.
285 No pain. no gain.                                 285 No pain. no gain.
286                                                   286 
287 Fortunately there is plenty of room for improv    287 Fortunately there is plenty of room for improvement.
288                                                   288 
289 In step 1 we moved from bit-wise calculation t    289 In step 1 we moved from bit-wise calculation to byte-wise calculation.
290 However in C we can also use the unsigned long    290 However in C we can also use the unsigned long data type and virtually
291 every modern microprocessor supports 32 bit op    291 every modern microprocessor supports 32 bit operations, so why not try
292 to write our code in such a way that we proces    292 to write our code in such a way that we process data in 32 bit chunks.
293                                                   293 
294 Of course this means some modification as the     294 Of course this means some modification as the row parity is byte by
295 byte. A quick analysis:                           295 byte. A quick analysis:
296 for the column parity we use the par variable.    296 for the column parity we use the par variable. When extending to 32 bits
297 we can in the end easily calculate rp0 and rp1    297 we can in the end easily calculate rp0 and rp1 from it.
298 (because par now consists of 4 bytes, contribu    298 (because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0
299 respectively, from MSB to LSB)                    299 respectively, from MSB to LSB)
300 also rp2 and rp3 can be easily retrieved from     300 also rp2 and rp3 can be easily retrieved from par as rp3 covers the
301 first two MSBs and rp2 covers the last two LSB    301 first two MSBs and rp2 covers the last two LSBs.
302                                                   302 
303 Note that of course now the loop is executed o    303 Note that of course now the loop is executed only 64 times (256/4).
304 And note that care must taken wrt byte orderin    304 And note that care must taken wrt byte ordering. The way bytes are
305 ordered in a long is machine dependent, and mi    305 ordered in a long is machine dependent, and might affect us.
306 Anyway, if there is an issue: this code is dev    306 Anyway, if there is an issue: this code is developed on x86 (to be
307 precise: a DELL PC with a D920 Intel CPU)         307 precise: a DELL PC with a D920 Intel CPU)
308                                                   308 
309 And of course the performance might depend on     309 And of course the performance might depend on alignment, but I expect
310 that the I/O buffers in the nand driver are al    310 that the I/O buffers in the nand driver are aligned properly (and
311 otherwise that should be fixed to get maximum     311 otherwise that should be fixed to get maximum performance).
312                                                   312 
313 Let's give it a try...                            313 Let's give it a try...
314                                                   314 
315                                                   315 
316 Attempt 2                                         316 Attempt 2
317 =========                                         317 =========
318                                                   318 
319 ::                                                319 ::
320                                                   320 
321   extern const char parity[256];                  321   extern const char parity[256];
322                                                   322 
323   void ecc2(const unsigned char *buf, unsigned    323   void ecc2(const unsigned char *buf, unsigned char *code)
324   {                                               324   {
325       int i;                                      325       int i;
326       const unsigned long *bp = (unsigned long    326       const unsigned long *bp = (unsigned long *)buf;
327       unsigned long cur;                          327       unsigned long cur;
328       unsigned long rp0, rp1, rp2, rp3, rp4, r    328       unsigned long rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
329       unsigned long rp8, rp9, rp10, rp11, rp12    329       unsigned long rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
330       unsigned long par;                          330       unsigned long par;
331                                                   331 
332       par = 0;                                    332       par = 0;
333       rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;         333       rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
334       rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;         334       rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
335       rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;       335       rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
336       rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;     336       rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
337                                                   337 
338       for (i = 0; i < 64; i++)                    338       for (i = 0; i < 64; i++)
339       {                                           339       {
340           cur = *bp++;                            340           cur = *bp++;
341           par ^= cur;                             341           par ^= cur;
342           if (i & 0x01) rp5 ^= cur; else rp4 ^    342           if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
343           if (i & 0x02) rp7 ^= cur; else rp6 ^    343           if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
344           if (i & 0x04) rp9 ^= cur; else rp8 ^    344           if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
345           if (i & 0x08) rp11 ^= cur; else rp10    345           if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
346           if (i & 0x10) rp13 ^= cur; else rp12    346           if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
347           if (i & 0x20) rp15 ^= cur; else rp14    347           if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
348       }                                           348       }
349       /*                                          349       /*
350          we need to adapt the code generation     350          we need to adapt the code generation for the fact that rp vars are now
351          long; also the column parity calculat    351          long; also the column parity calculation needs to be changed.
352          we'll bring rp4 to 15 back to single     352          we'll bring rp4 to 15 back to single byte entities by shifting and
353          xoring                                   353          xoring
354       */                                          354       */
355       rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); r    355       rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); rp4 &= 0xff;
356       rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); r    356       rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); rp5 &= 0xff;
357       rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); r    357       rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); rp6 &= 0xff;
358       rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); r    358       rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); rp7 &= 0xff;
359       rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); r    359       rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); rp8 &= 0xff;
360       rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); r    360       rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); rp9 &= 0xff;
361       rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8    361       rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8); rp10 &= 0xff;
362       rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8    362       rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8); rp11 &= 0xff;
363       rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8    363       rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8); rp12 &= 0xff;
364       rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8    364       rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8); rp13 &= 0xff;
365       rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8    365       rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8); rp14 &= 0xff;
366       rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8    366       rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8); rp15 &= 0xff;
367       rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp    367       rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp3 &= 0xff;
368       rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); r    368       rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); rp2 &= 0xff;
369       par ^= (par >> 16);                         369       par ^= (par >> 16);
370       rp1 = (par >> 8); rp1 &= 0xff;              370       rp1 = (par >> 8); rp1 &= 0xff;
371       rp0 = (par & 0xff);                         371       rp0 = (par & 0xff);
372       par ^= (par >> 8); par &= 0xff;             372       par ^= (par >> 8); par &= 0xff;
373                                                   373 
374       code[0] =                                   374       code[0] =
375           (parity[rp7] << 7) |                    375           (parity[rp7] << 7) |
376           (parity[rp6] << 6) |                    376           (parity[rp6] << 6) |
377           (parity[rp5] << 5) |                    377           (parity[rp5] << 5) |
378           (parity[rp4] << 4) |                    378           (parity[rp4] << 4) |
379           (parity[rp3] << 3) |                    379           (parity[rp3] << 3) |
380           (parity[rp2] << 2) |                    380           (parity[rp2] << 2) |
381           (parity[rp1] << 1) |                    381           (parity[rp1] << 1) |
382           (parity[rp0]);                          382           (parity[rp0]);
383       code[1] =                                   383       code[1] =
384           (parity[rp15] << 7) |                   384           (parity[rp15] << 7) |
385           (parity[rp14] << 6) |                   385           (parity[rp14] << 6) |
386           (parity[rp13] << 5) |                   386           (parity[rp13] << 5) |
387           (parity[rp12] << 4) |                   387           (parity[rp12] << 4) |
388           (parity[rp11] << 3) |                   388           (parity[rp11] << 3) |
389           (parity[rp10] << 2) |                   389           (parity[rp10] << 2) |
390           (parity[rp9]  << 1) |                   390           (parity[rp9]  << 1) |
391           (parity[rp8]);                          391           (parity[rp8]);
392       code[2] =                                   392       code[2] =
393           (parity[par & 0xf0] << 7) |             393           (parity[par & 0xf0] << 7) |
394           (parity[par & 0x0f] << 6) |             394           (parity[par & 0x0f] << 6) |
395           (parity[par & 0xcc] << 5) |             395           (parity[par & 0xcc] << 5) |
396           (parity[par & 0x33] << 4) |             396           (parity[par & 0x33] << 4) |
397           (parity[par & 0xaa] << 3) |             397           (parity[par & 0xaa] << 3) |
398           (parity[par & 0x55] << 2);              398           (parity[par & 0x55] << 2);
399       code[0] = ~code[0];                         399       code[0] = ~code[0];
400       code[1] = ~code[1];                         400       code[1] = ~code[1];
401       code[2] = ~code[2];                         401       code[2] = ~code[2];
402   }                                               402   }
403                                                   403 
404 The parity array is not shown any more. Note a    404 The parity array is not shown any more. Note also that for these
405 examples I kinda deviated from my regular prog    405 examples I kinda deviated from my regular programming style by allowing
406 multiple statements on a line, not using { } i    406 multiple statements on a line, not using { } in then and else blocks
407 with only a single statement and by using oper    407 with only a single statement and by using operators like ^=
408                                                   408 
409                                                   409 
410 Analysis 2                                        410 Analysis 2
411 ==========                                        411 ==========
412                                                   412 
413 The code (of course) works, and hurray: we are    413 The code (of course) works, and hurray: we are a little bit faster than
414 the linux driver code (about 15%). But wait, d    414 the linux driver code (about 15%). But wait, don't cheer too quickly.
415 There is more to be gained.                       415 There is more to be gained.
416 If we look at e.g. rp14 and rp15 we see that w    416 If we look at e.g. rp14 and rp15 we see that we either xor our data with
417 rp14 or with rp15. However we also have par wh    417 rp14 or with rp15. However we also have par which goes over all data.
418 This means there is no need to calculate rp14     418 This means there is no need to calculate rp14 as it can be calculated from
419 rp15 through rp14 = par ^ rp15, because par =     419 rp15 through rp14 = par ^ rp15, because par = rp14 ^ rp15;
420 (or if desired we can avoid calculating rp15 a    420 (or if desired we can avoid calculating rp15 and calculate it from
421 rp14).  That is why some places refer to inver    421 rp14).  That is why some places refer to inverse parity.
422 Of course the same thing holds for rp4/5, rp6/    422 Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13.
423 Effectively this means we can eliminate the el    423 Effectively this means we can eliminate the else clause from the if
424 statements. Also we can optimise the calculati    424 statements. Also we can optimise the calculation in the end a little bit
425 by going from long to byte first. Actually we     425 by going from long to byte first. Actually we can even avoid the table
426 lookups                                           426 lookups
427                                                   427 
428 Attempt 3                                         428 Attempt 3
429 =========                                         429 =========
430                                                   430 
431 Odd replaced::                                    431 Odd replaced::
432                                                   432 
433           if (i & 0x01) rp5 ^= cur; else rp4 ^    433           if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
434           if (i & 0x02) rp7 ^= cur; else rp6 ^    434           if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
435           if (i & 0x04) rp9 ^= cur; else rp8 ^    435           if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
436           if (i & 0x08) rp11 ^= cur; else rp10    436           if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
437           if (i & 0x10) rp13 ^= cur; else rp12    437           if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
438           if (i & 0x20) rp15 ^= cur; else rp14    438           if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
439                                                   439 
440 with::                                            440 with::
441                                                   441 
442           if (i & 0x01) rp5 ^= cur;               442           if (i & 0x01) rp5 ^= cur;
443           if (i & 0x02) rp7 ^= cur;               443           if (i & 0x02) rp7 ^= cur;
444           if (i & 0x04) rp9 ^= cur;               444           if (i & 0x04) rp9 ^= cur;
445           if (i & 0x08) rp11 ^= cur;              445           if (i & 0x08) rp11 ^= cur;
446           if (i & 0x10) rp13 ^= cur;              446           if (i & 0x10) rp13 ^= cur;
447           if (i & 0x20) rp15 ^= cur;              447           if (i & 0x20) rp15 ^= cur;
448                                                   448 
449 and outside the loop added::                      449 and outside the loop added::
450                                                   450 
451           rp4  = par ^ rp5;                       451           rp4  = par ^ rp5;
452           rp6  = par ^ rp7;                       452           rp6  = par ^ rp7;
453           rp8  = par ^ rp9;                       453           rp8  = par ^ rp9;
454           rp10  = par ^ rp11;                     454           rp10  = par ^ rp11;
455           rp12  = par ^ rp13;                     455           rp12  = par ^ rp13;
456           rp14  = par ^ rp15;                     456           rp14  = par ^ rp15;
457                                                   457 
458 And after that the code takes about 30% more t    458 And after that the code takes about 30% more time, although the number of
459 statements is reduced. This is also reflected     459 statements is reduced. This is also reflected in the assembly code.
460                                                   460 
461                                                   461 
462 Analysis 3                                        462 Analysis 3
463 ==========                                        463 ==========
464                                                   464 
465 Very weird. Guess it has to do with caching or    465 Very weird. Guess it has to do with caching or instruction parallelism
466 or so. I also tried on an eeePC (Celeron, cloc    466 or so. I also tried on an eeePC (Celeron, clocked at 900 Mhz). Interesting
467 observation was that this one is only 30% slow    467 observation was that this one is only 30% slower (according to time)
468 executing the code as my 3Ghz D920 processor.     468 executing the code as my 3Ghz D920 processor.
469                                                   469 
470 Well, it was expected not to be easy so maybe     470 Well, it was expected not to be easy so maybe instead move to a
471 different track: let's move back to the code f    471 different track: let's move back to the code from attempt2 and do some
472 loop unrolling. This will eliminate a few if s    472 loop unrolling. This will eliminate a few if statements. I'll try
473 different amounts of unrolling to see what wor    473 different amounts of unrolling to see what works best.
474                                                   474 
475                                                   475 
476 Attempt 4                                         476 Attempt 4
477 =========                                         477 =========
478                                                   478 
479 Unrolled the loop 1, 2, 3 and 4 times.            479 Unrolled the loop 1, 2, 3 and 4 times.
480 For 4 the code starts with::                      480 For 4 the code starts with::
481                                                   481 
482     for (i = 0; i < 4; i++)                       482     for (i = 0; i < 4; i++)
483     {                                             483     {
484         cur = *bp++;                              484         cur = *bp++;
485         par ^= cur;                               485         par ^= cur;
486         rp4 ^= cur;                               486         rp4 ^= cur;
487         rp6 ^= cur;                               487         rp6 ^= cur;
488         rp8 ^= cur;                               488         rp8 ^= cur;
489         rp10 ^= cur;                              489         rp10 ^= cur;
490         if (i & 0x1) rp13 ^= cur; else rp12 ^=    490         if (i & 0x1) rp13 ^= cur; else rp12 ^= cur;
491         if (i & 0x2) rp15 ^= cur; else rp14 ^=    491         if (i & 0x2) rp15 ^= cur; else rp14 ^= cur;
492         cur = *bp++;                              492         cur = *bp++;
493         par ^= cur;                               493         par ^= cur;
494         rp5 ^= cur;                               494         rp5 ^= cur;
495         rp6 ^= cur;                               495         rp6 ^= cur;
496         ...                                       496         ...
497                                                   497 
498                                                   498 
499 Analysis 4                                        499 Analysis 4
500 ==========                                        500 ==========
501                                                   501 
502 Unrolling once gains about 15%                    502 Unrolling once gains about 15%
503                                                   503 
504 Unrolling twice keeps the gain at about 15%       504 Unrolling twice keeps the gain at about 15%
505                                                   505 
506 Unrolling three times gives a gain of 30% comp    506 Unrolling three times gives a gain of 30% compared to attempt 2.
507                                                   507 
508 Unrolling four times gives a marginal improvem    508 Unrolling four times gives a marginal improvement compared to unrolling
509 three times.                                      509 three times.
510                                                   510 
511 I decided to proceed with a four time unrolled    511 I decided to proceed with a four time unrolled loop anyway. It was my gut
512 feeling that in the next steps I would obtain     512 feeling that in the next steps I would obtain additional gain from it.
513                                                   513 
514 The next step was triggered by the fact that p    514 The next step was triggered by the fact that par contains the xor of all
515 bytes and rp4 and rp5 each contain the xor of     515 bytes and rp4 and rp5 each contain the xor of half of the bytes.
516 So in effect par = rp4 ^ rp5. But as xor is co    516 So in effect par = rp4 ^ rp5. But as xor is commutative we can also say
517 that rp5 = par ^ rp4. So no need to keep both     517 that rp5 = par ^ rp4. So no need to keep both rp4 and rp5 around. We can
518 eliminate rp5 (or rp4, but I already foresaw a    518 eliminate rp5 (or rp4, but I already foresaw another optimisation).
519 The same holds for rp6/7, rp8/9, rp10/11 rp12/    519 The same holds for rp6/7, rp8/9, rp10/11 rp12/13 and rp14/15.
520                                                   520 
521                                                   521 
522 Attempt 5                                         522 Attempt 5
523 =========                                         523 =========
524                                                   524 
525 Effectively so all odd digit rp assignments in    525 Effectively so all odd digit rp assignments in the loop were removed.
526 This included the else clause of the if statem    526 This included the else clause of the if statements.
527 Of course after the loop we need to correct th    527 Of course after the loop we need to correct things by adding code like::
528                                                   528 
529     rp5 = par ^ rp4;                              529     rp5 = par ^ rp4;
530                                                   530 
531 Also the initial assignments (rp5 = 0; etc) co    531 Also the initial assignments (rp5 = 0; etc) could be removed.
532 Along the line I also removed the initialisati    532 Along the line I also removed the initialisation of rp0/1/2/3.
533                                                   533 
534                                                   534 
535 Analysis 5                                        535 Analysis 5
536 ==========                                        536 ==========
537                                                   537 
538 Measurements showed this was a good move. The     538 Measurements showed this was a good move. The run-time roughly halved
539 compared with attempt 4 with 4 times unrolled,    539 compared with attempt 4 with 4 times unrolled, and we only require 1/3rd
540 of the processor time compared to the current     540 of the processor time compared to the current code in the linux kernel.
541                                                   541 
542 However, still I thought there was more. I did    542 However, still I thought there was more. I didn't like all the if
543 statements. Why not keep a running parity and     543 statements. Why not keep a running parity and only keep the last if
544 statement. Time for yet another version!          544 statement. Time for yet another version!
545                                                   545 
546                                                   546 
547 Attempt 6                                         547 Attempt 6
548 =========                                         548 =========
549                                                   549 
550 THe code within the for loop was changed to::     550 THe code within the for loop was changed to::
551                                                   551 
552     for (i = 0; i < 4; i++)                       552     for (i = 0; i < 4; i++)
553     {                                             553     {
554         cur = *bp++; tmppar  = cur; rp4 ^= cur    554         cur = *bp++; tmppar  = cur; rp4 ^= cur;
555         cur = *bp++; tmppar ^= cur; rp6 ^= tmp    555         cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
556         cur = *bp++; tmppar ^= cur; rp4 ^= cur    556         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
557         cur = *bp++; tmppar ^= cur; rp8 ^= tmp    557         cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
558                                                   558 
559         cur = *bp++; tmppar ^= cur; rp4 ^= cur    559         cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
560         cur = *bp++; tmppar ^= cur; rp6 ^= cur    560         cur = *bp++; tmppar ^= cur; rp6 ^= cur;
561         cur = *bp++; tmppar ^= cur; rp4 ^= cur    561         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
562         cur = *bp++; tmppar ^= cur; rp10 ^= tm    562         cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
563                                                   563 
564         cur = *bp++; tmppar ^= cur; rp4 ^= cur    564         cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur;
565         cur = *bp++; tmppar ^= cur; rp6 ^= cur    565         cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur;
566         cur = *bp++; tmppar ^= cur; rp4 ^= cur    566         cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur;
567         cur = *bp++; tmppar ^= cur; rp8 ^= cur    567         cur = *bp++; tmppar ^= cur; rp8 ^= cur;
568                                                   568 
569         cur = *bp++; tmppar ^= cur; rp4 ^= cur    569         cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
570         cur = *bp++; tmppar ^= cur; rp6 ^= cur    570         cur = *bp++; tmppar ^= cur; rp6 ^= cur;
571         cur = *bp++; tmppar ^= cur; rp4 ^= cur    571         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
572         cur = *bp++; tmppar ^= cur;               572         cur = *bp++; tmppar ^= cur;
573                                                   573 
574         par ^= tmppar;                            574         par ^= tmppar;
575         if ((i & 0x1) == 0) rp12 ^= tmppar;       575         if ((i & 0x1) == 0) rp12 ^= tmppar;
576         if ((i & 0x2) == 0) rp14 ^= tmppar;       576         if ((i & 0x2) == 0) rp14 ^= tmppar;
577     }                                             577     }
578                                                   578 
579 As you can see tmppar is used to accumulate th    579 As you can see tmppar is used to accumulate the parity within a for
580 iteration. In the last 3 statements is added t    580 iteration. In the last 3 statements is added to par and, if needed,
581 to rp12 and rp14.                                 581 to rp12 and rp14.
582                                                   582 
583 While making the changes I also found that I c    583 While making the changes I also found that I could exploit that tmppar
584 contains the running parity for this iteration    584 contains the running parity for this iteration. So instead of having:
585 rp4 ^= cur; rp6 ^= cur;                           585 rp4 ^= cur; rp6 ^= cur;
586 I removed the rp6 ^= cur; statement and did rp    586 I removed the rp6 ^= cur; statement and did rp6 ^= tmppar; on next
587 statement. A similar change was done for rp8 a    587 statement. A similar change was done for rp8 and rp10
588                                                   588 
589                                                   589 
590 Analysis 6                                        590 Analysis 6
591 ==========                                        591 ==========
592                                                   592 
593 Measuring this code again showed big gain. Whe    593 Measuring this code again showed big gain. When executing the original
594 linux code 1 million times, this took about 1     594 linux code 1 million times, this took about 1 second on my system.
595 (using time to measure the performance). After    595 (using time to measure the performance). After this iteration I was back
596 to 0.075 sec. Actually I had to decide to star    596 to 0.075 sec. Actually I had to decide to start measuring over 10
597 million iterations in order not to lose too mu    597 million iterations in order not to lose too much accuracy. This one
598 definitely seemed to be the jackpot!              598 definitely seemed to be the jackpot!
599                                                   599 
600 There is a little bit more room for improvemen    600 There is a little bit more room for improvement though. There are three
601 places with statements::                          601 places with statements::
602                                                   602 
603         rp4 ^= cur; rp6 ^= cur;                   603         rp4 ^= cur; rp6 ^= cur;
604                                                   604 
605 It seems more efficient to also maintain a var    605 It seems more efficient to also maintain a variable rp4_6 in the while
606 loop; This eliminates 3 statements per loop. O    606 loop; This eliminates 3 statements per loop. Of course after the loop we
607 need to correct by adding::                       607 need to correct by adding::
608                                                   608 
609         rp4 ^= rp4_6;                             609         rp4 ^= rp4_6;
610         rp6 ^= rp4_6                              610         rp6 ^= rp4_6
611                                                   611 
612 Furthermore there are 4 sequential assignments    612 Furthermore there are 4 sequential assignments to rp8. This can be
613 encoded slightly more efficiently by saving tm    613 encoded slightly more efficiently by saving tmppar before those 4 lines
614 and later do rp8 = rp8 ^ tmppar ^ notrp8;         614 and later do rp8 = rp8 ^ tmppar ^ notrp8;
615 (where notrp8 is the value of rp8 before those    615 (where notrp8 is the value of rp8 before those 4 lines).
616 Again a use of the commutative property of xor    616 Again a use of the commutative property of xor.
617 Time for a new test!                              617 Time for a new test!
618                                                   618 
619                                                   619 
620 Attempt 7                                         620 Attempt 7
621 =========                                         621 =========
622                                                   622 
623 The new code now looks like::                     623 The new code now looks like::
624                                                   624 
625     for (i = 0; i < 4; i++)                       625     for (i = 0; i < 4; i++)
626     {                                             626     {
627         cur = *bp++; tmppar  = cur; rp4 ^= cur    627         cur = *bp++; tmppar  = cur; rp4 ^= cur;
628         cur = *bp++; tmppar ^= cur; rp6 ^= tmp    628         cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
629         cur = *bp++; tmppar ^= cur; rp4 ^= cur    629         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
630         cur = *bp++; tmppar ^= cur; rp8 ^= tmp    630         cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
631                                                   631 
632         cur = *bp++; tmppar ^= cur; rp4_6 ^= c    632         cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
633         cur = *bp++; tmppar ^= cur; rp6 ^= cur    633         cur = *bp++; tmppar ^= cur; rp6 ^= cur;
634         cur = *bp++; tmppar ^= cur; rp4 ^= cur    634         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
635         cur = *bp++; tmppar ^= cur; rp10 ^= tm    635         cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
636                                                   636 
637         notrp8 = tmppar;                          637         notrp8 = tmppar;
638         cur = *bp++; tmppar ^= cur; rp4_6 ^= c    638         cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
639         cur = *bp++; tmppar ^= cur; rp6 ^= cur    639         cur = *bp++; tmppar ^= cur; rp6 ^= cur;
640         cur = *bp++; tmppar ^= cur; rp4 ^= cur    640         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
641         cur = *bp++; tmppar ^= cur;               641         cur = *bp++; tmppar ^= cur;
642         rp8 = rp8 ^ tmppar ^ notrp8;              642         rp8 = rp8 ^ tmppar ^ notrp8;
643                                                   643 
644         cur = *bp++; tmppar ^= cur; rp4_6 ^= c    644         cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
645         cur = *bp++; tmppar ^= cur; rp6 ^= cur    645         cur = *bp++; tmppar ^= cur; rp6 ^= cur;
646         cur = *bp++; tmppar ^= cur; rp4 ^= cur    646         cur = *bp++; tmppar ^= cur; rp4 ^= cur;
647         cur = *bp++; tmppar ^= cur;               647         cur = *bp++; tmppar ^= cur;
648                                                   648 
649         par ^= tmppar;                            649         par ^= tmppar;
650         if ((i & 0x1) == 0) rp12 ^= tmppar;       650         if ((i & 0x1) == 0) rp12 ^= tmppar;
651         if ((i & 0x2) == 0) rp14 ^= tmppar;       651         if ((i & 0x2) == 0) rp14 ^= tmppar;
652     }                                             652     }
653     rp4 ^= rp4_6;                                 653     rp4 ^= rp4_6;
654     rp6 ^= rp4_6;                                 654     rp6 ^= rp4_6;
655                                                   655 
656                                                   656 
657 Not a big change, but every penny counts :-)      657 Not a big change, but every penny counts :-)
658                                                   658 
659                                                   659 
660 Analysis 7                                        660 Analysis 7
661 ==========                                        661 ==========
662                                                   662 
663 Actually this made things worse. Not very much    663 Actually this made things worse. Not very much, but I don't want to move
664 into the wrong direction. Maybe something to i    664 into the wrong direction. Maybe something to investigate later. Could
665 have to do with caching again.                    665 have to do with caching again.
666                                                   666 
667 Guess that is what there is to win within the     667 Guess that is what there is to win within the loop. Maybe unrolling one
668 more time will help. I'll keep the optimisatio    668 more time will help. I'll keep the optimisations from 7 for now.
669                                                   669 
670                                                   670 
671 Attempt 8                                         671 Attempt 8
672 =========                                         672 =========
673                                                   673 
674 Unrolled the loop one more time.                  674 Unrolled the loop one more time.
675                                                   675 
676                                                   676 
677 Analysis 8                                        677 Analysis 8
678 ==========                                        678 ==========
679                                                   679 
680 This makes things worse. Let's stick with atte    680 This makes things worse. Let's stick with attempt 6 and continue from there.
681 Although it seems that the code within the loo    681 Although it seems that the code within the loop cannot be optimised
682 further there is still room to optimize the ge    682 further there is still room to optimize the generation of the ecc codes.
683 We can simply calculate the total parity. If t    683 We can simply calculate the total parity. If this is 0 then rp4 = rp5
684 etc. If the parity is 1, then rp4 = !rp5;         684 etc. If the parity is 1, then rp4 = !rp5;
685                                                   685 
686 But if rp4 = rp5 we do not need rp5 etc. We ca    686 But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits
687 in the result byte and then do something like:    687 in the result byte and then do something like::
688                                                   688 
689     code[0] |= (code[0] << 1);                    689     code[0] |= (code[0] << 1);
690                                                   690 
691 Lets test this.                                   691 Lets test this.
692                                                   692 
693                                                   693 
694 Attempt 9                                         694 Attempt 9
695 =========                                         695 =========
696                                                   696 
697 Changed the code but again this slightly degra    697 Changed the code but again this slightly degrades performance. Tried all
698 kind of other things, like having dedicated pa    698 kind of other things, like having dedicated parity arrays to avoid the
699 shift after parity[rp7] << 7; No gain.            699 shift after parity[rp7] << 7; No gain.
700 Change the lookup using the parity array by us    700 Change the lookup using the parity array by using shift operators (e.g.
701 replace parity[rp7] << 7 with::                   701 replace parity[rp7] << 7 with::
702                                                   702 
703         rp7 ^= (rp7 << 4);                        703         rp7 ^= (rp7 << 4);
704         rp7 ^= (rp7 << 2);                        704         rp7 ^= (rp7 << 2);
705         rp7 ^= (rp7 << 1);                        705         rp7 ^= (rp7 << 1);
706         rp7 &= 0x80;                              706         rp7 &= 0x80;
707                                                   707 
708 No gain.                                          708 No gain.
709                                                   709 
710 The only marginal change was inverting the par    710 The only marginal change was inverting the parity bits, so we can remove
711 the last three invert statements.                 711 the last three invert statements.
712                                                   712 
713 Ah well, pity this does not deliver more. Then    713 Ah well, pity this does not deliver more. Then again 10 million
714 iterations using the linux driver code takes b    714 iterations using the linux driver code takes between 13 and 13.5
715 seconds, whereas my code now takes about 0.73     715 seconds, whereas my code now takes about 0.73 seconds for those 10
716 million iterations. So basically I've improved    716 million iterations. So basically I've improved the performance by a
717 factor 18 on my system. Not that bad. Of cours    717 factor 18 on my system. Not that bad. Of course on different hardware
718 you will get different results. No warranties!    718 you will get different results. No warranties!
719                                                   719 
720 But of course there is no such thing as a free    720 But of course there is no such thing as a free lunch. The codesize almost
721 tripled (from 562 bytes to 1434 bytes). Then a    721 tripled (from 562 bytes to 1434 bytes). Then again, it is not that much.
722                                                   722 
723                                                   723 
724 Correcting errors                                 724 Correcting errors
725 =================                                 725 =================
726                                                   726 
727 For correcting errors I again used the ST appl    727 For correcting errors I again used the ST application note as a starter,
728 but I also peeked at the existing code.           728 but I also peeked at the existing code.
729                                                   729 
730 The algorithm itself is pretty straightforward    730 The algorithm itself is pretty straightforward. Just xor the given and
731 the calculated ecc. If all bytes are 0 there i    731 the calculated ecc. If all bytes are 0 there is no problem. If 11 bits
732 are 1 we have one correctable bit error. If th    732 are 1 we have one correctable bit error. If there is 1 bit 1, we have an
733 error in the given ecc code.                      733 error in the given ecc code.
734                                                   734 
735 It proved to be fastest to do some table looku    735 It proved to be fastest to do some table lookups. Performance gain
736 introduced by this is about a factor 2 on my s    736 introduced by this is about a factor 2 on my system when a repair had to
737 be done, and 1% or so if no repair had to be d    737 be done, and 1% or so if no repair had to be done.
738                                                   738 
739 Code size increased from 330 bytes to 686 byte    739 Code size increased from 330 bytes to 686 bytes for this function.
740 (gcc 4.2, -O3)                                    740 (gcc 4.2, -O3)
741                                                   741 
742                                                   742 
743 Conclusion                                        743 Conclusion
744 ==========                                        744 ==========
745                                                   745 
746 The gain when calculating the ecc is tremendou    746 The gain when calculating the ecc is tremendous. Om my development hardware
747 a speedup of a factor of 18 for ecc calculatio    747 a speedup of a factor of 18 for ecc calculation was achieved. On a test on an
748 embedded system with a MIPS core a factor 7 wa    748 embedded system with a MIPS core a factor 7 was obtained.
749                                                   749 
750 On a test with a Linksys NSLU2 (ARMv5TE proces    750 On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor
751 5 (big endian mode, gcc 4.1.2, -O3)               751 5 (big endian mode, gcc 4.1.2, -O3)
752                                                   752 
753 For correction not much gain could be obtained    753 For correction not much gain could be obtained (as bitflips are rare). Then
754 again there are also much less cycles spent th    754 again there are also much less cycles spent there.
755                                                   755 
756 It seems there is not much more gain possible     756 It seems there is not much more gain possible in this, at least when
757 programmed in C. Of course it might be possibl    757 programmed in C. Of course it might be possible to squeeze something more
758 out of it with an assembler program, but due t    758 out of it with an assembler program, but due to pipeline behaviour etc
759 this is very tricky (at least for intel hw).      759 this is very tricky (at least for intel hw).
760                                                   760 
761 Author: Frans Meulenbroeks                        761 Author: Frans Meulenbroeks
762                                                   762 
763 Copyright (C) 2008 Koninklijke Philips Electro    763 Copyright (C) 2008 Koninklijke Philips Electronics NV.
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php