OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [ftape/] [ecc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/* Yo, Emacs! we're -*- Linux-C -*-
2
 *
3
 *      Copyright (c) 1993 Ning and David Mosberger.
4
 *
5
 * This is based on code originally written by Bas Laarhoven (bas@vimec.nl)
6
 * and David L. Brown, Jr., and incorporates improvements suggested by
7
 * Kai Harrekilde-Petersen.
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License as
11
 * published by the Free Software Foundation; either version 2, or (at
12
 * your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; see the file COPYING.  If not, write to
21
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
22
 * USA.
23
 *
24
 * $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/uclinux/uClinux-2.0.x/drivers/char/ftape/ecc.c,v $
25
 * $Author: simons $
26
 *
27
 * $Revision: 1.1.1.1 $
28
 * $Date: 2001-09-10 07:44:17 $
29
 * $State: Exp $
30
 *
31
 *      This file contains the Reed-Solomon error correction code
32
 *      for the QIC-40/80 floppy-tape driver for Linux.
33
 */
34
 
35
#include <linux/ftape.h>
36
#include <asm/errno.h>
37
 
38
#include "tracing.h"
39
#include "ecc.h"
40
 
41
/*
42
 * Machines that are big-endian should define macro BIG_ENDIAN.
43
 * Unfortunately, there doesn't appear to be a standard include
44
 * file that works for all OSs.
45
 */
46
 
47
#if defined(__sparc__) || defined(__hppa)
48
#define BIG_ENDIAN
49
#endif                          /* __sparc__ || __hppa */
50
 
51
#if defined(__mips__)
52
#error Find a smart way to determine the Endianness of the MIPS CPU
53
#endif
54
 
55
#ifdef TEST
56
 
57
#undef TRACE()
58
#undef TRACE_()
59
#undef TRACE()
60
#undef TRACEi()
61
#undef TRACElx()
62
#undef TRACE_FUN()
63
#undef TRACE_EXIT
64
#define printk  printf
65
#define TRACE_FUN( level, name) char __fun[] = name
66
#define TRACE_EXIT
67
#define TRACE_(l,m) { if (ftape_ecc_tracing >= (l) && (l) <= TOP_LEVEL) { \
68
    printk( "[%03d] " __FILE__ " (%s) - ", (int)ftape_trace_id++, __fun); \
69
    m;  } }
70
#define TRACE(l,m) TRACE_(l,printk(m".\n"))
71
#define TRACEi(l,m,i) TRACE_(l,printk(m" %d.\n",i))
72
#define TRACElx(l,m,i) TRACE_(l,printk(m" 0x%08lx.\n",i))
73
 
74
int ftape_ecc_tracing = 1;
75
unsigned char ftape_trace_id = 0;
76
 
77
#endif                          /* TEST */
78
 
79
/*
80
 * Notice: to minimize the potential for confusion, we use r to
81
 *         denote the independent variable of the polynomials
82
 *         in the Galois Field GF(2^8).  We reserve x for polynomials
83
 *         that have coefficients in GF(2^8).
84
 *
85
 * The Galois Field in which coefficient arithmetic is performed are
86
 * the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible
87
 * polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1.  A polynomial
88
 * is represented as a byte with the MSB as the coefficient of r^7 and
89
 * the LSB as the coefficient of r^0.  For example, the binary
90
 * representation of f(x) is 0x187 (of course, this doesn't fit into 8
91
 * bits).  In this field, the polynomial r is a primitive element.
92
 * That is, r^i with i in 0,...,255 enumerates all elements in the
93
 * field.
94
 *
95
 * The generator polynomial for the QIC-80 ECC is
96
 *
97
 *      g(x) = x^3 + r^105*x^2 + r^105*x + 1
98
 *
99
 * which can be factored into:
100
 *
101
 *      g(x) = (x-r^-1)(x-r^0)(x-r^1)
102
 *
103
 * the byte representation of the coefficients are:
104
 *
105
 *      r^105 = 0xc0
106
 *      r^-1  = 0xc3
107
 *      r^0   = 0x01
108
 *      r^1   = 0x02
109
 *
110
 * Notice that r^-1 = r^254 as exponent arithmetic is performed
111
 * modulo 2^8-1 = 255.
112
 *
113
 * For more information on Galois Fields and Reed-Solomon codes,
114
 * refer to any good book.  I found _An Introduction to Error
115
 * Correcting Codes with Applications_ by S. A. Vanstone and
116
 * P. C. van Oorschot to be a good introduction into the former.
117
 * _CODING THEORY: The Essentials_ I found very useful for its
118
 * concise description of Reed-Solomon encoding/decoding.
119
 *
120
 */
121
 
122
typedef unsigned char Matrix[3][3];
123
 
124
/*
125
 * gfpow[] is defined such that gfpow[i] returns r^i if
126
 * i is in the range [0..255].
127
 */
128
static const unsigned char gfpow[] =
129
{
130
        0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
131
        0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
132
        0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb,
133
        0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd,
134
        0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31,
135
        0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67,
136
        0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc,
137
        0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b,
138
        0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4,
139
        0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26,
140
        0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21,
141
        0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba,
142
        0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30,
143
        0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0,
144
        0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3,
145
        0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a,
146
        0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9,
147
        0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44,
148
        0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef,
149
        0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85,
150
        0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6,
151
        0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf,
152
        0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff,
153
        0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58,
154
        0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a,
155
        0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24,
156
        0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8,
157
        0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64,
158
        0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
159
        0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
160
        0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
161
        0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
162
};
163
 
164
/*
165
 * This is a log table.  That is, gflog[r^i] returns i (modulo f(r)).
166
 * gflog[0] is undefined and the first element is therefore not valid.
167
 */
168
static const unsigned char gflog[256] =
169
{
170
        0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
171
        0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a,
172
        0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1,
173
        0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3,
174
        0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83,
175
        0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4,
176
        0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35,
177
        0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38,
178
        0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70,
179
        0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48,
180
        0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24,
181
        0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15,
182
        0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f,
183
        0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10,
184
        0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7,
185
        0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b,
186
        0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08,
187
        0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a,
188
        0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91,
189
        0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb,
190
        0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2,
191
        0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf,
192
        0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52,
193
        0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86,
194
        0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc,
195
        0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc,
196
        0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8,
197
        0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44,
198
        0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1,
199
        0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97,
200
        0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5,
201
        0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
202
};
203
 
204
/*
205
 * This is a multiplication table for the factor
206
 * 0xc0 (i.e., r^105 (modulo f(r)).
207
 * gfmul_c0[f] returns r^105 * f(r) (modulo f(r)).
208
 */
209
static const unsigned char gfmul_c0[256] =
210
{
211
        0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9,
212
        0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5,
213
        0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1,
214
        0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed,
215
        0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9,
216
        0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5,
217
        0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81,
218
        0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d,
219
        0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29,
220
        0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35,
221
        0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11,
222
        0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d,
223
        0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59,
224
        0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45,
225
        0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61,
226
        0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d,
227
        0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e,
228
        0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92,
229
        0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6,
230
        0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa,
231
        0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe,
232
        0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2,
233
        0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6,
234
        0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda,
235
        0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e,
236
        0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72,
237
        0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56,
238
        0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a,
239
        0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e,
240
        0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02,
241
        0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26,
242
        0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a
243
};
244
 
245
 
246
/*
247
 * Returns V modulo 255 provided V is in the range -255,-254,...,509.
248
 */
249
static inline unsigned char mod255(int v)
250
{
251
        if (v > 0) {
252
                if (v < 255) {
253
                        return v;
254
                } else {
255
                        return v - 255;
256
                }
257
        } else {
258
                return v + 255;
259
        }
260
}
261
 
262
 
263
/*
264
 * Add two numbers in the field.  Addition in this field is
265
 * equivalent to a bit-wise exclusive OR operation---subtraction
266
 * is therefore identical to addition.
267
 */
268
static inline unsigned char gfadd(unsigned char a, unsigned char b)
269
{
270
        return a ^ b;
271
}
272
 
273
 
274
/*
275
 * Add two vectors of numbers in the field.  Each byte in A and B get
276
 * added individually.
277
 */
278
static inline unsigned long gfadd_long(unsigned long a, unsigned long b)
279
{
280
        return a ^ b;
281
}
282
 
283
 
284
/*
285
 * Multiply two numbers in the field:
286
 */
287
static inline unsigned char gfmul(unsigned char a, unsigned char b)
288
{
289
        if (a && b) {
290
                return gfpow[mod255(gflog[a] + gflog[b])];
291
        } else {
292
                return 0;
293
        }
294
}
295
 
296
 
297
/*
298
 * Just like gfmul, except we have already looked up the log
299
 * of the second number.
300
 */
301
static inline unsigned char gfmul_exp(unsigned char a, int b)
302
{
303
        if (a) {
304
                return gfpow[mod255(gflog[a] + b)];
305
        } else {
306
                return 0;
307
        }
308
}
309
 
310
 
311
/*
312
 * Just like gfmul_exp, except that A is a vector of numbers.  That is,
313
 * each byte in A gets multiplied by gfpow[mod255(B)].
314
 */
315
static inline unsigned long gfmul_exp_long(unsigned long a, int b)
316
{
317
        TRACE_FUN(8, "gfmul_exp_long");
318
        unsigned char t;
319
 
320
        if (sizeof(long) == 4) {
321
                TRACE_EXIT;
322
                return
323
                    ((t = a >> 24 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
324
                    ((t = a >> 16 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
325
                    ((t = a >> 8 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
326
                    ((t = a >> 0 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 0) : 0);
327
#if !defined(linux)
328
        } else if (sizeof(long) == 8) {
329
                TRACE_EXIT;
330
                return
331
                    ((t = a >> 56 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 56) : 0) |
332
                    ((t = a >> 48 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 48) : 0) |
333
                    ((t = a >> 40 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 40) : 0) |
334
                    ((t = a >> 32 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 32) : 0) |
335
                    ((t = a >> 24 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
336
                    ((t = a >> 16 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
337
                    ((t = a >> 8 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
338
                    ((t = a >> 0 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 0) : 0);
339
#endif
340
        } else {
341
                TRACEx1(1, "Error: size of long is %d bytes", (int) sizeof(long));
342
        }
343
        TRACE_EXIT;
344
        return -1;
345
}
346
 
347
 
348
/*
349
 * Divide two numbers in the field.  Returns a/b (modulo f(x)).
350
 */
351
static inline unsigned char gfdiv(unsigned char a, unsigned char b)
352
{
353
        TRACE_FUN(8, "gfdiv");
354
        if (!b) {
355
                TRACE(-1, "Error: division by zero");
356
                return 0xff;
357
        } else if (a == 0) {
358
                return 0;
359
        } else {
360
                return gfpow[mod255(gflog[a] - gflog[b])];
361
        }
362
        TRACE_EXIT;
363
}
364
 
365
 
366
/*
367
 * The following functions return the inverse of the matrix of the
368
 * linear system that needs to be solved to determine the error
369
 * magnitudes.  The first deals with matrices of rank 3, while the
370
 * second deals with matrices of rank 2.  The error indices are passed
371
 * in arguments L0,..,L2 (0=first sector, 31=last sector).  The
372
 * error indices must be sorted in ascending order, i.e., L0<L1<L2.
373
 *
374
 * The linear system that needs to be solved for the error
375
 * magnitudes is A * b = s, where s is the known vector of
376
 * syndromes, b is the vector of error magnitudes and A in
377
 * the ORDER=3 case:
378
 *
379
 *    A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]},
380
 *          {        1,        1,        1},
381
 *          {   r^L[0],   r^L[1],   r^L[2]}}
382
 */
383
static inline int gfinv3(unsigned char l0, unsigned char l1, unsigned char l2, Matrix Ainv)
384
{
385
        TRACE_FUN(8, "gfinv3");
386
        unsigned char det;
387
        unsigned char t20, t10, t21, t12, t01, t02;
388
        int log_det;
389
 
390
        /* compute some intermediate results: */
391
        t20 = gfpow[l2 - l0];   /* t20 = r^l2/r^l0 */
392
        t10 = gfpow[l1 - l0];   /* t10 = r^l1/r^l0 */
393
        t21 = gfpow[l2 - l1];   /* t21 = r^l2/r^l1 */
394
        t12 = gfpow[l1 - l2 + 255];     /* t12 = r^l1/r^l2 */
395
        t01 = gfpow[l0 - l1 + 255];     /* t01 = r^l0/r^l1 */
396
        t02 = gfpow[l0 - l2 + 255];     /* t02 = r^l0/r^l2 */
397
        /*
398
         * Calculate the determinant of matrix A_3^-1 (sometimes called
399
         * the Vandermonde determinant):
400
         */
401
        det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02)))));
402
        if (!det) {
403
                TRACE(1, "Inversion failed (3 CRC errors, >0 CRC failures)");
404
                TRACE_EXIT;
405
                return 0;
406
        }
407
        log_det = 255 - gflog[det];
408
 
409
        /*
410
         * Now, calculate all of the coefficients:
411
         */
412
        Ainv[0][0] = gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det);
413
        Ainv[0][1] = gfmul_exp(gfadd(t21, t12), log_det);
414
        Ainv[0][2] = gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]), log_det);
415
 
416
        Ainv[1][0] = gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det);
417
        Ainv[1][1] = gfmul_exp(gfadd(t20, t02), log_det);
418
        Ainv[1][2] = gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]), log_det);
419
 
420
        Ainv[2][0] = gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det);
421
        Ainv[2][1] = gfmul_exp(gfadd(t10, t01), log_det);
422
        Ainv[2][2] = gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]), log_det);
423
 
424
        TRACE_EXIT;
425
        return 1;
426
}
427
 
428
 
429
static inline int gfinv2(unsigned char l0, unsigned char l1, Matrix Ainv)
430
{
431
        TRACE_FUN(8, "gfinv2");
432
        unsigned char det;
433
        unsigned char t1, t2;
434
        int log_det;
435
 
436
        t1 = gfpow[255 - l0];
437
        t2 = gfpow[255 - l1];
438
        det = gfadd(t1, t2);
439
        if (!det) {
440
                TRACE(1, "Inversion failed (2 CRC errors, >0 CRC failures)");
441
                TRACE_EXIT;
442
                return 0;
443
        }
444
        log_det = 255 - gflog[det];
445
 
446
        /*
447
         * Now, calculate all of the coefficients:
448
         */
449
        Ainv[0][0] = Ainv[1][0] = gfpow[log_det];
450
 
451
        Ainv[0][1] = gfmul_exp(t2, log_det);
452
        Ainv[1][1] = gfmul_exp(t1, log_det);
453
 
454
        TRACE_EXIT;
455
        return 1;
456
}
457
 
458
 
459
/*
460
 * Multiply matrix A by vector S and return result in vector B.
461
 * M is assumed to be of order NxN, S and B of order Nx1.
462
 */
463
static inline void gfmat_mul(int n, Matrix A, unsigned char *s, unsigned char *b)
464
{
465
        int i, j;
466
        unsigned char dot_prod;
467
 
468
        for (i = 0; i < n; ++i) {
469
                dot_prod = 0;
470
                for (j = 0; j < n; ++j) {
471
                        dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j]));
472
                }
473
                b[i] = dot_prod;
474
        }
475
}
476
 
477
 
478
 
479
/*
480
 * The Reed Solomon ECC codes are computed over the N-th byte of each
481
 * block, where N=SECTOR_SIZE.  There are up to 29 blocks of data, and
482
 * 3 blocks of ECC.  The blocks are stored contiguously in memory.
483
 * A segment, consequently, is assumed to have at least 4 blocks:
484
 * one or more data blocks plus three ECC blocks.
485
 *
486
 * Notice: In QIC-80 speak, a CRC error is a sector with an incorrect
487
 *         CRC.  A CRC failure is a sector with incorrect data, but
488
 *         a valid CRC.  In the error control literature, the former
489
 *         is usually called "erasure", the latter "error."
490
 */
491
/*
492
 * Compute the parity bytes for C columns of data, where C is the
493
 * number of bytes that fit into a long integer.  We use a linear
494
 * feed-back register to do this.  The parity bytes P[0], P[STRIDE],
495
 * P[2*STRIDE] are computed such that:
496
 *
497
 *              x^k * p(x) + m(x) = 0 (modulo g(x))
498
 *
499
 * where k = NBLOCKS,
500
 *       p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and
501
 *       m(x) = sum_{i=0}^k m_i*x^i.
502
 *       m_i  = DATA[i*SECTOR_SIZE]
503
 */
504
static inline void set_parity(unsigned long *data, int nblocks, unsigned long *p, int stride)
505
{
506
        TRACE_FUN(8, "set_parity");
507
        unsigned long p0, p1, p2, t1, t2, *end;
508
 
509
        end = data + nblocks * (SECTOR_SIZE / sizeof(long));
510
        p0 = p1 = p2 = 0;
511
        while (data < end) {
512
                /*
513
                 * The new parity bytes p0_i, p1_i, p2_i are computed from the old
514
                 * values p0_{i-1}, p1_{i-1}, p2_{i-1} recursively as:
515
                 *
516
                 *        p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
517
                 *        p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
518
                 *        p2_i =                    (m_{i-1} - p0_{i-1})
519
                 *
520
                 * With the initial condition: p0_0 = p1_0 = p2_0 = 0.
521
                 */
522
                t1 = gfadd_long(*data, p0);
523
                /*
524
                 * Multiply each byte in t1 by 0xc0:
525
                 */
526
                if (sizeof(long) == 4) {
527
                        t2 = ((unsigned long) gfmul_c0[t1 >> 24 & 0xff]) << 24 |
528
                            ((unsigned long) gfmul_c0[t1 >> 16 & 0xff]) << 16 |
529
                            ((unsigned long) gfmul_c0[t1 >> 8 & 0xff]) << 8 |
530
                            ((unsigned long) gfmul_c0[t1 >> 0 & 0xff]) << 0;
531
#if !defined(linux)
532
                } else if (sizeof(long) == 8) {
533
                        t2 = ((unsigned long) gfmul_c0[t1 >> 56 & 0xff]) << 56 |
534
                            ((unsigned long) gfmul_c0[t1 >> 48 & 0xff]) << 48 |
535
                            ((unsigned long) gfmul_c0[t1 >> 40 & 0xff]) << 40 |
536
                            ((unsigned long) gfmul_c0[t1 >> 32 & 0xff]) << 32 |
537
                            ((unsigned long) gfmul_c0[t1 >> 24 & 0xff]) << 24 |
538
                            ((unsigned long) gfmul_c0[t1 >> 16 & 0xff]) << 16 |
539
                            ((unsigned long) gfmul_c0[t1 >> 8 & 0xff]) << 8 |
540
                            ((unsigned long) gfmul_c0[t1 >> 0 & 0xff]) << 0;
541
#endif
542
                } else {
543
                        TRACEx1(1, "Error: long is of size %d", (int) sizeof(long));
544
                }
545
                p0 = gfadd_long(t2, p1);
546
                p1 = gfadd_long(t2, p2);
547
                p2 = t1;
548
                data += SECTOR_SIZE / sizeof(long);
549
        }
550
        *p = p0;
551
        p += stride;
552
        *p = p1;
553
        p += stride;
554
        *p = p2;
555
        TRACE_EXIT;
556
}
557
 
558
 
559
/*
560
 * Compute the 3 syndrome values.  DATA should point to the first byte
561
 * of the column for which the syndromes are desired.  The syndromes
562
 * are computed over the first NBLOCKS of rows.  The three bytes will be
563
 * placed in S[0], S[1], and S[2].
564
 *
565
 * S[i] is the value of the "message" polynomial m(x) evaluated at the
566
 * i-th root of the generator polynomial g(x).
567
 *
568
 * As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at
569
 * x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2].
570
 * This could be done directly and efficiently via the Horner scheme.
571
 * However, it would require multiplication tables for the factors
572
 * r^-1 (0xc3) and r (0x02).  The following scheme does not require
573
 * any multiplication tables beyond what's needed for set_parity()
574
 * anyway and is slightly faster if there are no errors and slightly
575
 * slower if there are errors.  The latter is hopefully the infrequent
576
 * case.
577
 *
578
 * To understand the alternative algorithm, notice that
579
 * set_parity(m, k, p) computes parity bytes such that:
580
 *
581
 *      x^k * p(x) = m(x) (modulo g(x)).
582
 *
583
 * That is, to evaluate m(r^m), where r^m is a root of g(x), we can
584
 * simply evaluate (r^m)^k*p(r^m).  Also, notice that p is 0 if and
585
 * only if s is zero.  That is, if all parity bytes are 0, we know
586
 * there is no error in the data and consequently there is no need to
587
 * compute s(x) at all!  In all other cases, we compute s(x) from p(x)
588
 * by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1.  The p(x)
589
 * polynomial is evaluated via the Horner scheme.
590
 */
591
static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s)
592
{
593
        unsigned long p[3];
594
 
595
        set_parity(data, nblocks, p, 1);
596
        if (p[0] | p[1] | p[2]) {
597
                /*
598
                 * Some of the checked columns do not have a zero syndrome.  For
599
                 * simplicity, we compute the syndromes for all columns that we
600
                 * have computed the remainders for.
601
                 */
602
                s[0] = gfmul_exp_long(gfadd_long(p[0], gfmul_exp_long(gfadd_long(p[1],
603
                              gfmul_exp_long(p[2], -1)), -1)), -nblocks);
604
                s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]);
605
                s[2] = gfmul_exp_long(gfadd_long(p[0], gfmul_exp_long(gfadd_long(p[1],
606
                                 gfmul_exp_long(p[2], 1)), 1)), nblocks);
607
                return 0;
608
        } else {
609
                return 1;
610
        }
611
}
612
 
613
 
614
/*
615
 * Correct the block in the column pointed to by DATA.  There are NBAD
616
 * CRC errors and their indices are in BAD_LOC[0], up to
617
 * BAD_LOC[NBAD-1].  If NBAD>1, Ainv holds the inverse of the matrix
618
 * of the linear system that needs to be solved to determine the error
619
 * magnitudes.  S[0], S[1], and S[2] are the syndrome values.  If row
620
 * j gets corrected, then bit j will be set in CORRECTION_MAP.
621
 */
622
static inline int correct_block(unsigned char *data, int nblocks,
623
                                int nbad, int *bad_loc, Matrix Ainv,
624
                                unsigned char *s,
625
                                BAD_SECTOR * correction_map)
626
{
627
        TRACE_FUN(8, "correct_block");
628
        int ncorrected = 0;
629
        int i;
630
        unsigned char t1, t2;
631
        unsigned char c0, c1, c2;       /* check bytes */
632
        unsigned char error_mag[3], log_error_mag;
633
        unsigned char *dp, l, e;
634
 
635
        switch (nbad) {
636
        case 0:
637
                /* might have a CRC failure: */
638
                if (s[0] == 0) {
639
                        /* more than one error */
640
                        TRACE(1, "ECC failed (0 CRC errors, >1 CRC failures)");
641
                        TRACE_EXIT;
642
                        return -1;
643
                }               /* if */
644
                t1 = gfdiv(s[1], s[0]);
645
                if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) {
646
                        TRACE(1, "ECC failed (0 CRC errors, >1 CRC failures): ");
647
                        TRACEi(1, "attempt to correct data at ", bad_loc[0]);
648
                        TRACE_EXIT;
649
                        return -1;
650
                }
651
                error_mag[0] = s[1];
652
                break;
653
        case 1:
654
                t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]);
655
                t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]);
656
                if (t1 == 0 && t2 == 0) {
657
                        /* one erasure, no error: */
658
                        Ainv[0][0] = gfpow[bad_loc[0]];
659
                } else if (t1 == 0 || t2 == 0) {
660
                        /* one erasure and more than one error: */
661
                        TRACE(1, "ECC failed (1 erasure, >1 error)");
662
                        TRACE_EXIT;
663
                        return -1;
664
                } else {
665
                        /* one erasure, one error: */
666
                        if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) >= nblocks) {
667
                                TRACE(1, "ECC failed (1 CRC errors, >1 CRC failures): ");
668
                                TRACEi(1, "attempt to correct data at ", bad_loc[1]);
669
                                TRACE_EXIT;
670
                                return -1;
671
                        }       /* if */
672
                        if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) {
673
                                /* inversion failed---must have more than one error */
674
                                TRACE_EXIT;
675
                                return -1;
676
                        }
677
                }
678
                /*
679
                 *  FALL THROUGH TO ERROR MAGNITUDE COMPUTATION:
680
                 */
681
        case 2:
682
        case 3:
683
                /* compute error magnitudes: */
684
                gfmat_mul(nbad, Ainv, s, error_mag);
685
                break;
686
 
687
        default:
688
                TRACE(1, "Internal Error: number of CRC errors > 3");
689
                TRACE_EXIT;
690
                return -1;
691
        }
692
 
693
        /*
694
         * Perform correction by adding ERROR_MAG[i] to the byte at offset
695
         * BAD_LOC[i].  Also add the value of the computed error polynomial
696
         * to the syndrome values.  If the correction was successful, the
697
         * resulting check bytes should be zero (i.e., the corrected data
698
         * is a valid code word).
699
         */
700
        c0 = s[0];
701
        c1 = s[1];
702
        c2 = s[2];
703
        for (i = 0; i < nbad; ++i) {
704
                e = error_mag[i];
705
                if (e) {
706
                        /* correct the byte at offset L by magnitude E: */
707
                        l = bad_loc[i];
708
                        dp = &data[l * SECTOR_SIZE];
709
                        *dp = gfadd(*dp, e);
710
                        *correction_map |= 1 << l;
711
                        ++ncorrected;
712
 
713
                        log_error_mag = gflog[e];
714
                        c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]);
715
                        c1 = gfadd(c1, e);
716
                        c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]);
717
                }
718
        }
719
        if (c0 || c1 || c2) {
720
                TRACE(1, "ECC self-check failed, too many errors");
721
                TRACE_EXIT;
722
                return -1;
723
        }
724
        TRACE_EXIT;
725
        return ncorrected;
726
}
727
 
728
 
729
#if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID)
730
 
731
/*
732
 * Perform a sanity check on the computed parity bytes:
733
 */
734
static int sanity_check(unsigned long *data, int nblocks)
735
{
736
        TRACE_FUN(8, "sanity_check");
737
        unsigned long s[3];
738
 
739
        if (!compute_syndromes(data, nblocks, s)) {
740
                TRACE(-1, "Internal Error: syndrome self-check failed");
741
                TRACE_EXIT;
742
                return 0;
743
        }
744
        TRACE_EXIT;
745
        return 1;
746
}
747
 
748
#endif                          /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */
749
 
750
 
751
 
752
/*
753
 * Compute the parity for an entire segment of data.
754
 */
755
int ecc_set_segment_parity(struct memory_segment *mseg)
756
{
757
        int i;
758
        unsigned char *parity_bytes;
759
 
760
        parity_bytes = &mseg->data[(mseg->blocks - 3) * SECTOR_SIZE];
761
        for (i = 0; i < SECTOR_SIZE; i += sizeof(long)) {
762
                set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3,
763
                           (unsigned long *) &parity_bytes[i],
764
                           SECTOR_SIZE / sizeof(long));
765
#ifdef ECC_PARANOID
766
                if (!sanity_check((unsigned long *) &mseg->data[i], mseg->blocks)) {
767
                        return -1;
768
                }
769
#endif                          /* ECC_PARANOID */
770
        }
771
        return 0;
772
}
773
 
774
 
775
/*
776
 * Checks and corrects (if possible) the segment MSEG.  Returns one of
777
 * ECC_OK, ECC_CORRECTED, and ECC_FAILED.
778
 */
779
int ecc_correct_data(struct memory_segment *mseg)
780
{
781
        TRACE_FUN(5, "ecc_correct_data");
782
        int col, i, result;
783
        int ncorrected = 0;
784
        int nerasures = 0;       /* # of erasures (CRC errors) */
785
        int erasure_loc[3];     /* erasure locations */
786
        unsigned long ss[3];
787
        unsigned char s[3];
788
        Matrix Ainv;
789
 
790
        mseg->corrected = 0;
791
 
792
        /* find first column that has non-zero syndromes: */
793
        for (col = 0; col < SECTOR_SIZE; col += sizeof(long)) {
794
                if (!compute_syndromes((unsigned long *) &mseg->data[col],
795
                                       mseg->blocks, ss)) {
796
                        /* something is wrong---have to fix things */
797
                        break;
798
                }
799
        }
800
        if (col >= SECTOR_SIZE) {
801
                /* all syndromes are ok, therefore nothing to correct */
802
                TRACE_EXIT;
803
                return ECC_OK;
804
        }
805
        /* count the number of CRC errors if there were any: */
806
        if (mseg->read_bad) {
807
                for (i = 0; i < mseg->blocks; i++) {
808
                        if (BAD_CHECK(mseg->read_bad, i)) {
809
                                if (nerasures >= 3) {
810
                                        /* this is too much for ECC */
811
                                        TRACE(1, "ECC failed (>3 CRC errors)");
812
                                        TRACE_EXIT;
813
                                        return ECC_FAILED;
814
                                }       /* if */
815
                                erasure_loc[nerasures++] = i;
816
                        }
817
                }
818
        }
819
        /*
820
           * If there are at least 2 CRC errors, determine inverse of matrix
821
           * of linear system to be solved:
822
         */
823
        switch (nerasures) {
824
        case 2:
825
                if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) {
826
                        TRACE_EXIT;
827
                        return ECC_FAILED;
828
                }
829
                break;
830
        case 3:
831
                if (!gfinv3(erasure_loc[0], erasure_loc[1], erasure_loc[2], Ainv)) {
832
                        TRACE_EXIT;
833
                        return ECC_FAILED;
834
                }
835
                break;
836
        default:
837
                /* this is not an error condition... */
838
                break;
839
        }
840
 
841
        do {
842
                for (i = 0; i < sizeof(long); ++i) {
843
                        s[0] = ss[0];
844
                        s[1] = ss[1];
845
                        s[2] = ss[2];
846
                        if (s[0] | s[1] | s[2]) {
847
#ifdef BIG_ENDIAN
848
                                result = correct_block(&mseg->data[col + sizeof(long) - 1 - i],
849
                                                       mseg->blocks,
850
                                         nerasures, erasure_loc, Ainv, s,
851
                                                       &mseg->corrected);
852
#else
853
                                result = correct_block(&mseg->data[col + i], mseg->blocks,
854
                                         nerasures, erasure_loc, Ainv, s,
855
                                                       &mseg->corrected);
856
#endif
857
                                if (result < 0) {
858
                                        TRACE_EXIT;
859
                                        return ECC_FAILED;
860
                                }
861
                                ncorrected += result;
862
                        }
863
                        ss[0] >>= 8;
864
                        ss[1] >>= 8;
865
                        ss[2] >>= 8;
866
                }
867
 
868
#ifdef ECC_SANITY_CHECK
869
                if (!sanity_check((unsigned long *) &mseg->data[col], mseg->blocks)) {
870
                        TRACE_EXIT;
871
                        return ECC_FAILED;
872
                }
873
#endif                          /* ECC_SANITY_CHECK */
874
 
875
                /* find next column with non-zero syndromes: */
876
                while ((col += sizeof(long)) < SECTOR_SIZE) {
877
                        if (!compute_syndromes((unsigned long *) &mseg->data[col],
878
                                               mseg->blocks, ss)) {
879
                                /* something is wrong---have to fix things */
880
                                break;
881
                        }
882
                }
883
        } while (col < SECTOR_SIZE);
884
        if (ncorrected && nerasures == 0) {
885
                TRACE(2, "block contained error not caught by CRC");
886
        }
887
        TRACEi((ncorrected > 0) ? 4 : 8, "number of corrections:", ncorrected);
888
        TRACE_EXIT;
889
        return ncorrected ? ECC_CORRECTED : ECC_OK;
890
}
891
 
892
/*** end of ecc.c ***/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.