0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/types.h>
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <linux/mtd/nand.h>
0021 #include <linux/mtd/nand-ecc-sw-hamming.h>
0022 #include <linux/slab.h>
0023 #include <asm/byteorder.h>
0024
0025
0026
0027
0028
0029
0030
0031 static const char invparity[256] = {
0032 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0033 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0034 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0035 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0036 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0037 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0038 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0039 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0040 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0041 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0042 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0043 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0044 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0045 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0046 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0047 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
0048 };
0049
0050
0051
0052
0053
0054
0055 static const char bitsperbyte[256] = {
0056 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
0057 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
0058 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
0059 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0060 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
0061 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0062 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0063 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
0064 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
0065 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0066 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0067 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
0068 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
0069 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
0070 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
0071 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
0072 };
0073
0074
0075
0076
0077
0078
0079
0080 static const char addressbits[256] = {
0081 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
0082 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
0083 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
0084 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
0085 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
0086 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
0087 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
0088 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
0089 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
0090 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
0091 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
0092 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
0093 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
0094 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
0095 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
0096 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
0097 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
0098 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
0099 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
0100 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
0101 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
0102 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
0103 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
0104 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
0105 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
0106 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
0107 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
0108 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
0109 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
0110 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
0111 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
0112 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
0113 };
0114
0115 int ecc_sw_hamming_calculate(const unsigned char *buf, unsigned int step_size,
0116 unsigned char *code, bool sm_order)
0117 {
0118 const u32 *bp = (uint32_t *)buf;
0119 const u32 eccsize_mult = (step_size == 256) ? 1 : 2;
0120
0121 u32 cur;
0122
0123 u32 rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9, rp10, rp11, rp12,
0124 rp13, rp14, rp15, rp16, rp17;
0125
0126 u32 par;
0127
0128 u32 tmppar;
0129 int i;
0130
0131 par = 0;
0132 rp4 = 0;
0133 rp6 = 0;
0134 rp8 = 0;
0135 rp10 = 0;
0136 rp12 = 0;
0137 rp14 = 0;
0138 rp16 = 0;
0139 rp17 = 0;
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 for (i = 0; i < eccsize_mult << 2; i++) {
0152 cur = *bp++;
0153 tmppar = cur;
0154 rp4 ^= cur;
0155 cur = *bp++;
0156 tmppar ^= cur;
0157 rp6 ^= tmppar;
0158 cur = *bp++;
0159 tmppar ^= cur;
0160 rp4 ^= cur;
0161 cur = *bp++;
0162 tmppar ^= cur;
0163 rp8 ^= tmppar;
0164
0165 cur = *bp++;
0166 tmppar ^= cur;
0167 rp4 ^= cur;
0168 rp6 ^= cur;
0169 cur = *bp++;
0170 tmppar ^= cur;
0171 rp6 ^= cur;
0172 cur = *bp++;
0173 tmppar ^= cur;
0174 rp4 ^= cur;
0175 cur = *bp++;
0176 tmppar ^= cur;
0177 rp10 ^= tmppar;
0178
0179 cur = *bp++;
0180 tmppar ^= cur;
0181 rp4 ^= cur;
0182 rp6 ^= cur;
0183 rp8 ^= cur;
0184 cur = *bp++;
0185 tmppar ^= cur;
0186 rp6 ^= cur;
0187 rp8 ^= cur;
0188 cur = *bp++;
0189 tmppar ^= cur;
0190 rp4 ^= cur;
0191 rp8 ^= cur;
0192 cur = *bp++;
0193 tmppar ^= cur;
0194 rp8 ^= cur;
0195
0196 cur = *bp++;
0197 tmppar ^= cur;
0198 rp4 ^= cur;
0199 rp6 ^= cur;
0200 cur = *bp++;
0201 tmppar ^= cur;
0202 rp6 ^= cur;
0203 cur = *bp++;
0204 tmppar ^= cur;
0205 rp4 ^= cur;
0206 cur = *bp++;
0207 tmppar ^= cur;
0208
0209 par ^= tmppar;
0210 if ((i & 0x1) == 0)
0211 rp12 ^= tmppar;
0212 if ((i & 0x2) == 0)
0213 rp14 ^= tmppar;
0214 if (eccsize_mult == 2 && (i & 0x4) == 0)
0215 rp16 ^= tmppar;
0216 }
0217
0218
0219
0220
0221
0222
0223
0224 rp4 ^= (rp4 >> 16);
0225 rp4 ^= (rp4 >> 8);
0226 rp4 &= 0xff;
0227 rp6 ^= (rp6 >> 16);
0228 rp6 ^= (rp6 >> 8);
0229 rp6 &= 0xff;
0230 rp8 ^= (rp8 >> 16);
0231 rp8 ^= (rp8 >> 8);
0232 rp8 &= 0xff;
0233 rp10 ^= (rp10 >> 16);
0234 rp10 ^= (rp10 >> 8);
0235 rp10 &= 0xff;
0236 rp12 ^= (rp12 >> 16);
0237 rp12 ^= (rp12 >> 8);
0238 rp12 &= 0xff;
0239 rp14 ^= (rp14 >> 16);
0240 rp14 ^= (rp14 >> 8);
0241 rp14 &= 0xff;
0242 if (eccsize_mult == 2) {
0243 rp16 ^= (rp16 >> 16);
0244 rp16 ^= (rp16 >> 8);
0245 rp16 &= 0xff;
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 #ifdef __BIG_ENDIAN
0259 rp2 = (par >> 16);
0260 rp2 ^= (rp2 >> 8);
0261 rp2 &= 0xff;
0262 rp3 = par & 0xffff;
0263 rp3 ^= (rp3 >> 8);
0264 rp3 &= 0xff;
0265 #else
0266 rp3 = (par >> 16);
0267 rp3 ^= (rp3 >> 8);
0268 rp3 &= 0xff;
0269 rp2 = par & 0xffff;
0270 rp2 ^= (rp2 >> 8);
0271 rp2 &= 0xff;
0272 #endif
0273
0274
0275 par ^= (par >> 16);
0276 #ifdef __BIG_ENDIAN
0277 rp0 = (par >> 8) & 0xff;
0278 rp1 = (par & 0xff);
0279 #else
0280 rp1 = (par >> 8) & 0xff;
0281 rp0 = (par & 0xff);
0282 #endif
0283
0284
0285 par ^= (par >> 8);
0286 par &= 0xff;
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 rp5 = (par ^ rp4) & 0xff;
0298 rp7 = (par ^ rp6) & 0xff;
0299 rp9 = (par ^ rp8) & 0xff;
0300 rp11 = (par ^ rp10) & 0xff;
0301 rp13 = (par ^ rp12) & 0xff;
0302 rp15 = (par ^ rp14) & 0xff;
0303 if (eccsize_mult == 2)
0304 rp17 = (par ^ rp16) & 0xff;
0305
0306
0307
0308
0309
0310
0311
0312 if (sm_order) {
0313 code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
0314 (invparity[rp5] << 5) | (invparity[rp4] << 4) |
0315 (invparity[rp3] << 3) | (invparity[rp2] << 2) |
0316 (invparity[rp1] << 1) | (invparity[rp0]);
0317 code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
0318 (invparity[rp13] << 5) | (invparity[rp12] << 4) |
0319 (invparity[rp11] << 3) | (invparity[rp10] << 2) |
0320 (invparity[rp9] << 1) | (invparity[rp8]);
0321 } else {
0322 code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
0323 (invparity[rp5] << 5) | (invparity[rp4] << 4) |
0324 (invparity[rp3] << 3) | (invparity[rp2] << 2) |
0325 (invparity[rp1] << 1) | (invparity[rp0]);
0326 code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
0327 (invparity[rp13] << 5) | (invparity[rp12] << 4) |
0328 (invparity[rp11] << 3) | (invparity[rp10] << 2) |
0329 (invparity[rp9] << 1) | (invparity[rp8]);
0330 }
0331
0332 if (eccsize_mult == 1)
0333 code[2] =
0334 (invparity[par & 0xf0] << 7) |
0335 (invparity[par & 0x0f] << 6) |
0336 (invparity[par & 0xcc] << 5) |
0337 (invparity[par & 0x33] << 4) |
0338 (invparity[par & 0xaa] << 3) |
0339 (invparity[par & 0x55] << 2) |
0340 3;
0341 else
0342 code[2] =
0343 (invparity[par & 0xf0] << 7) |
0344 (invparity[par & 0x0f] << 6) |
0345 (invparity[par & 0xcc] << 5) |
0346 (invparity[par & 0x33] << 4) |
0347 (invparity[par & 0xaa] << 3) |
0348 (invparity[par & 0x55] << 2) |
0349 (invparity[rp17] << 1) |
0350 (invparity[rp16] << 0);
0351
0352 return 0;
0353 }
0354 EXPORT_SYMBOL(ecc_sw_hamming_calculate);
0355
0356
0357
0358
0359
0360
0361
0362 int nand_ecc_sw_hamming_calculate(struct nand_device *nand,
0363 const unsigned char *buf, unsigned char *code)
0364 {
0365 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
0366 unsigned int step_size = nand->ecc.ctx.conf.step_size;
0367 bool sm_order = engine_conf ? engine_conf->sm_order : false;
0368
0369 return ecc_sw_hamming_calculate(buf, step_size, code, sm_order);
0370 }
0371 EXPORT_SYMBOL(nand_ecc_sw_hamming_calculate);
0372
0373 int ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
0374 unsigned char *calc_ecc, unsigned int step_size,
0375 bool sm_order)
0376 {
0377 const u32 eccsize_mult = step_size >> 8;
0378 unsigned char b0, b1, b2, bit_addr;
0379 unsigned int byte_addr;
0380
0381
0382
0383
0384
0385
0386 if (sm_order) {
0387 b0 = read_ecc[0] ^ calc_ecc[0];
0388 b1 = read_ecc[1] ^ calc_ecc[1];
0389 } else {
0390 b0 = read_ecc[1] ^ calc_ecc[1];
0391 b1 = read_ecc[0] ^ calc_ecc[0];
0392 }
0393
0394 b2 = read_ecc[2] ^ calc_ecc[2];
0395
0396
0397
0398
0399
0400
0401 if ((b0 | b1 | b2) == 0)
0402 return 0;
0403
0404 if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
0405 (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
0406 ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
0407 (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425 if (eccsize_mult == 1)
0426 byte_addr = (addressbits[b1] << 4) + addressbits[b0];
0427 else
0428 byte_addr = (addressbits[b2 & 0x3] << 8) +
0429 (addressbits[b1] << 4) + addressbits[b0];
0430 bit_addr = addressbits[b2 >> 2];
0431
0432 buf[byte_addr] ^= (1 << bit_addr);
0433 return 1;
0434
0435 }
0436
0437 if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
0438 return 1;
0439
0440 pr_err("%s: uncorrectable ECC error\n", __func__);
0441 return -EBADMSG;
0442 }
0443 EXPORT_SYMBOL(ecc_sw_hamming_correct);
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454 int nand_ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
0455 unsigned char *read_ecc,
0456 unsigned char *calc_ecc)
0457 {
0458 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
0459 unsigned int step_size = nand->ecc.ctx.conf.step_size;
0460 bool sm_order = engine_conf ? engine_conf->sm_order : false;
0461
0462 return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, step_size,
0463 sm_order);
0464 }
0465 EXPORT_SYMBOL(nand_ecc_sw_hamming_correct);
0466
0467 int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
0468 {
0469 struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
0470 struct nand_ecc_sw_hamming_conf *engine_conf;
0471 struct mtd_info *mtd = nanddev_to_mtd(nand);
0472 int ret;
0473
0474 if (!mtd->ooblayout) {
0475 switch (mtd->oobsize) {
0476 case 8:
0477 case 16:
0478 mtd_set_ooblayout(mtd, nand_get_small_page_ooblayout());
0479 break;
0480 case 64:
0481 case 128:
0482 mtd_set_ooblayout(mtd,
0483 nand_get_large_page_hamming_ooblayout());
0484 break;
0485 default:
0486 return -ENOTSUPP;
0487 }
0488 }
0489
0490 conf->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
0491 conf->algo = NAND_ECC_ALGO_HAMMING;
0492 conf->step_size = nand->ecc.user_conf.step_size;
0493 conf->strength = 1;
0494
0495
0496 if (conf->step_size != 256 && conf->step_size != 512)
0497 conf->step_size = 256;
0498
0499 engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
0500 if (!engine_conf)
0501 return -ENOMEM;
0502
0503 ret = nand_ecc_init_req_tweaking(&engine_conf->req_ctx, nand);
0504 if (ret)
0505 goto free_engine_conf;
0506
0507 engine_conf->code_size = 3;
0508 engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
0509 engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
0510 if (!engine_conf->calc_buf || !engine_conf->code_buf) {
0511 ret = -ENOMEM;
0512 goto free_bufs;
0513 }
0514
0515 nand->ecc.ctx.priv = engine_conf;
0516 nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size;
0517 nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size;
0518
0519 return 0;
0520
0521 free_bufs:
0522 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
0523 kfree(engine_conf->calc_buf);
0524 kfree(engine_conf->code_buf);
0525 free_engine_conf:
0526 kfree(engine_conf);
0527
0528 return ret;
0529 }
0530 EXPORT_SYMBOL(nand_ecc_sw_hamming_init_ctx);
0531
0532 void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand)
0533 {
0534 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
0535
0536 if (engine_conf) {
0537 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
0538 kfree(engine_conf->calc_buf);
0539 kfree(engine_conf->code_buf);
0540 kfree(engine_conf);
0541 }
0542 }
0543 EXPORT_SYMBOL(nand_ecc_sw_hamming_cleanup_ctx);
0544
0545 static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand,
0546 struct nand_page_io_req *req)
0547 {
0548 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
0549 struct mtd_info *mtd = nanddev_to_mtd(nand);
0550 int eccsize = nand->ecc.ctx.conf.step_size;
0551 int eccbytes = engine_conf->code_size;
0552 int eccsteps = nand->ecc.ctx.nsteps;
0553 int total = nand->ecc.ctx.total;
0554 u8 *ecccalc = engine_conf->calc_buf;
0555 const u8 *data;
0556 int i;
0557
0558
0559 if (req->mode == MTD_OPS_RAW)
0560 return 0;
0561
0562
0563 if (!req->datalen)
0564 return 0;
0565
0566 nand_ecc_tweak_req(&engine_conf->req_ctx, req);
0567
0568
0569 if (req->type == NAND_PAGE_READ)
0570 return 0;
0571
0572
0573 for (i = 0, data = req->databuf.out;
0574 eccsteps;
0575 eccsteps--, i += eccbytes, data += eccsize)
0576 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
0577
0578 return mtd_ooblayout_set_eccbytes(mtd, ecccalc, (void *)req->oobbuf.out,
0579 0, total);
0580 }
0581
0582 static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
0583 struct nand_page_io_req *req)
0584 {
0585 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
0586 struct mtd_info *mtd = nanddev_to_mtd(nand);
0587 int eccsize = nand->ecc.ctx.conf.step_size;
0588 int total = nand->ecc.ctx.total;
0589 int eccbytes = engine_conf->code_size;
0590 int eccsteps = nand->ecc.ctx.nsteps;
0591 u8 *ecccalc = engine_conf->calc_buf;
0592 u8 *ecccode = engine_conf->code_buf;
0593 unsigned int max_bitflips = 0;
0594 u8 *data = req->databuf.in;
0595 int i, ret;
0596
0597
0598 if (req->mode == MTD_OPS_RAW)
0599 return 0;
0600
0601
0602 if (!req->datalen)
0603 return 0;
0604
0605
0606 if (req->type == NAND_PAGE_WRITE) {
0607 nand_ecc_restore_req(&engine_conf->req_ctx, req);
0608 return 0;
0609 }
0610
0611
0612 ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, req->oobbuf.in, 0,
0613 total);
0614 if (ret)
0615 return ret;
0616
0617
0618 for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
0619 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
0620
0621
0622 for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in;
0623 eccsteps;
0624 eccsteps--, i += eccbytes, data += eccsize) {
0625 int stat = nand_ecc_sw_hamming_correct(nand, data,
0626 &ecccode[i],
0627 &ecccalc[i]);
0628 if (stat < 0) {
0629 mtd->ecc_stats.failed++;
0630 } else {
0631 mtd->ecc_stats.corrected += stat;
0632 max_bitflips = max_t(unsigned int, max_bitflips, stat);
0633 }
0634 }
0635
0636 nand_ecc_restore_req(&engine_conf->req_ctx, req);
0637
0638 return max_bitflips;
0639 }
0640
0641 static struct nand_ecc_engine_ops nand_ecc_sw_hamming_engine_ops = {
0642 .init_ctx = nand_ecc_sw_hamming_init_ctx,
0643 .cleanup_ctx = nand_ecc_sw_hamming_cleanup_ctx,
0644 .prepare_io_req = nand_ecc_sw_hamming_prepare_io_req,
0645 .finish_io_req = nand_ecc_sw_hamming_finish_io_req,
0646 };
0647
0648 static struct nand_ecc_engine nand_ecc_sw_hamming_engine = {
0649 .ops = &nand_ecc_sw_hamming_engine_ops,
0650 };
0651
0652 struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void)
0653 {
0654 return &nand_ecc_sw_hamming_engine;
0655 }
0656 EXPORT_SYMBOL(nand_ecc_sw_hamming_get_engine);
0657
0658 MODULE_LICENSE("GPL");
0659 MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
0660 MODULE_DESCRIPTION("NAND software Hamming ECC support");