root/drivers/mtd/tests/mtd_nandecctest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. single_bit_error_data
  2. double_bit_error_data
  3. random_ecc_bit
  4. single_bit_error_ecc
  5. double_bit_error_ecc
  6. no_bit_error
  7. no_bit_error_verify
  8. single_bit_error_in_data
  9. single_bit_error_in_ecc
  10. single_bit_error_correct
  11. double_bit_error_in_data
  12. single_bit_error_in_data_and_ecc
  13. double_bit_error_in_ecc
  14. double_bit_error_detect
  15. dump_data_ecc
  16. nand_ecc_test_run
  17. nand_ecc_test_run
  18. ecc_test_init
  19. ecc_test_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   3 
   4 #include <linux/kernel.h>
   5 #include <linux/module.h>
   6 #include <linux/list.h>
   7 #include <linux/random.h>
   8 #include <linux/string.h>
   9 #include <linux/bitops.h>
  10 #include <linux/slab.h>
  11 #include <linux/mtd/nand_ecc.h>
  12 
  13 #include "mtd_test.h"
  14 
  15 /*
  16  * Test the implementation for software ECC
  17  *
  18  * No actual MTD device is needed, So we don't need to warry about losing
  19  * important data by human error.
  20  *
  21  * This covers possible patterns of corruption which can be reliably corrected
  22  * or detected.
  23  */
  24 
  25 #if IS_ENABLED(CONFIG_MTD_RAW_NAND)
  26 
  27 struct nand_ecc_test {
  28         const char *name;
  29         void (*prepare)(void *, void *, void *, void *, const size_t);
  30         int (*verify)(void *, void *, void *, const size_t);
  31 };
  32 
  33 /*
  34  * The reason for this __change_bit_le() instead of __change_bit() is to inject
  35  * bit error properly within the region which is not a multiple of
  36  * sizeof(unsigned long) on big-endian systems
  37  */
  38 #ifdef __LITTLE_ENDIAN
  39 #define __change_bit_le(nr, addr) __change_bit(nr, addr)
  40 #elif defined(__BIG_ENDIAN)
  41 #define __change_bit_le(nr, addr) \
  42                 __change_bit((nr) ^ ((BITS_PER_LONG - 1) & ~0x7), addr)
  43 #else
  44 #error "Unknown byte order"
  45 #endif
  46 
  47 static void single_bit_error_data(void *error_data, void *correct_data,
  48                                 size_t size)
  49 {
  50         unsigned int offset = prandom_u32() % (size * BITS_PER_BYTE);
  51 
  52         memcpy(error_data, correct_data, size);
  53         __change_bit_le(offset, error_data);
  54 }
  55 
  56 static void double_bit_error_data(void *error_data, void *correct_data,
  57                                 size_t size)
  58 {
  59         unsigned int offset[2];
  60 
  61         offset[0] = prandom_u32() % (size * BITS_PER_BYTE);
  62         do {
  63                 offset[1] = prandom_u32() % (size * BITS_PER_BYTE);
  64         } while (offset[0] == offset[1]);
  65 
  66         memcpy(error_data, correct_data, size);
  67 
  68         __change_bit_le(offset[0], error_data);
  69         __change_bit_le(offset[1], error_data);
  70 }
  71 
  72 static unsigned int random_ecc_bit(size_t size)
  73 {
  74         unsigned int offset = prandom_u32() % (3 * BITS_PER_BYTE);
  75 
  76         if (size == 256) {
  77                 /*
  78                  * Don't inject a bit error into the insignificant bits (16th
  79                  * and 17th bit) in ECC code for 256 byte data block
  80                  */
  81                 while (offset == 16 || offset == 17)
  82                         offset = prandom_u32() % (3 * BITS_PER_BYTE);
  83         }
  84 
  85         return offset;
  86 }
  87 
  88 static void single_bit_error_ecc(void *error_ecc, void *correct_ecc,
  89                                 size_t size)
  90 {
  91         unsigned int offset = random_ecc_bit(size);
  92 
  93         memcpy(error_ecc, correct_ecc, 3);
  94         __change_bit_le(offset, error_ecc);
  95 }
  96 
  97 static void double_bit_error_ecc(void *error_ecc, void *correct_ecc,
  98                                 size_t size)
  99 {
 100         unsigned int offset[2];
 101 
 102         offset[0] = random_ecc_bit(size);
 103         do {
 104                 offset[1] = random_ecc_bit(size);
 105         } while (offset[0] == offset[1]);
 106 
 107         memcpy(error_ecc, correct_ecc, 3);
 108         __change_bit_le(offset[0], error_ecc);
 109         __change_bit_le(offset[1], error_ecc);
 110 }
 111 
 112 static void no_bit_error(void *error_data, void *error_ecc,
 113                 void *correct_data, void *correct_ecc, const size_t size)
 114 {
 115         memcpy(error_data, correct_data, size);
 116         memcpy(error_ecc, correct_ecc, 3);
 117 }
 118 
 119 static int no_bit_error_verify(void *error_data, void *error_ecc,
 120                                 void *correct_data, const size_t size)
 121 {
 122         unsigned char calc_ecc[3];
 123         int ret;
 124 
 125         __nand_calculate_ecc(error_data, size, calc_ecc,
 126                              IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 127         ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
 128                                   IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 129         if (ret == 0 && !memcmp(correct_data, error_data, size))
 130                 return 0;
 131 
 132         return -EINVAL;
 133 }
 134 
 135 static void single_bit_error_in_data(void *error_data, void *error_ecc,
 136                 void *correct_data, void *correct_ecc, const size_t size)
 137 {
 138         single_bit_error_data(error_data, correct_data, size);
 139         memcpy(error_ecc, correct_ecc, 3);
 140 }
 141 
 142 static void single_bit_error_in_ecc(void *error_data, void *error_ecc,
 143                 void *correct_data, void *correct_ecc, const size_t size)
 144 {
 145         memcpy(error_data, correct_data, size);
 146         single_bit_error_ecc(error_ecc, correct_ecc, size);
 147 }
 148 
 149 static int single_bit_error_correct(void *error_data, void *error_ecc,
 150                                 void *correct_data, const size_t size)
 151 {
 152         unsigned char calc_ecc[3];
 153         int ret;
 154 
 155         __nand_calculate_ecc(error_data, size, calc_ecc,
 156                              IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 157         ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
 158                                   IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 159         if (ret == 1 && !memcmp(correct_data, error_data, size))
 160                 return 0;
 161 
 162         return -EINVAL;
 163 }
 164 
 165 static void double_bit_error_in_data(void *error_data, void *error_ecc,
 166                 void *correct_data, void *correct_ecc, const size_t size)
 167 {
 168         double_bit_error_data(error_data, correct_data, size);
 169         memcpy(error_ecc, correct_ecc, 3);
 170 }
 171 
 172 static void single_bit_error_in_data_and_ecc(void *error_data, void *error_ecc,
 173                 void *correct_data, void *correct_ecc, const size_t size)
 174 {
 175         single_bit_error_data(error_data, correct_data, size);
 176         single_bit_error_ecc(error_ecc, correct_ecc, size);
 177 }
 178 
 179 static void double_bit_error_in_ecc(void *error_data, void *error_ecc,
 180                 void *correct_data, void *correct_ecc, const size_t size)
 181 {
 182         memcpy(error_data, correct_data, size);
 183         double_bit_error_ecc(error_ecc, correct_ecc, size);
 184 }
 185 
 186 static int double_bit_error_detect(void *error_data, void *error_ecc,
 187                                 void *correct_data, const size_t size)
 188 {
 189         unsigned char calc_ecc[3];
 190         int ret;
 191 
 192         __nand_calculate_ecc(error_data, size, calc_ecc,
 193                              IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 194         ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
 195                                   IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 196 
 197         return (ret == -EBADMSG) ? 0 : -EINVAL;
 198 }
 199 
 200 static const struct nand_ecc_test nand_ecc_test[] = {
 201         {
 202                 .name = "no-bit-error",
 203                 .prepare = no_bit_error,
 204                 .verify = no_bit_error_verify,
 205         },
 206         {
 207                 .name = "single-bit-error-in-data-correct",
 208                 .prepare = single_bit_error_in_data,
 209                 .verify = single_bit_error_correct,
 210         },
 211         {
 212                 .name = "single-bit-error-in-ecc-correct",
 213                 .prepare = single_bit_error_in_ecc,
 214                 .verify = single_bit_error_correct,
 215         },
 216         {
 217                 .name = "double-bit-error-in-data-detect",
 218                 .prepare = double_bit_error_in_data,
 219                 .verify = double_bit_error_detect,
 220         },
 221         {
 222                 .name = "single-bit-error-in-data-and-ecc-detect",
 223                 .prepare = single_bit_error_in_data_and_ecc,
 224                 .verify = double_bit_error_detect,
 225         },
 226         {
 227                 .name = "double-bit-error-in-ecc-detect",
 228                 .prepare = double_bit_error_in_ecc,
 229                 .verify = double_bit_error_detect,
 230         },
 231 };
 232 
 233 static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data,
 234                         void *correct_ecc, const size_t size)
 235 {
 236         pr_info("hexdump of error data:\n");
 237         print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
 238                         error_data, size, false);
 239         print_hex_dump(KERN_INFO, "hexdump of error ecc: ",
 240                         DUMP_PREFIX_NONE, 16, 1, error_ecc, 3, false);
 241 
 242         pr_info("hexdump of correct data:\n");
 243         print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
 244                         correct_data, size, false);
 245         print_hex_dump(KERN_INFO, "hexdump of correct ecc: ",
 246                         DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false);
 247 }
 248 
 249 static int nand_ecc_test_run(const size_t size)
 250 {
 251         int i;
 252         int err = 0;
 253         void *error_data;
 254         void *error_ecc;
 255         void *correct_data;
 256         void *correct_ecc;
 257 
 258         error_data = kmalloc(size, GFP_KERNEL);
 259         error_ecc = kmalloc(3, GFP_KERNEL);
 260         correct_data = kmalloc(size, GFP_KERNEL);
 261         correct_ecc = kmalloc(3, GFP_KERNEL);
 262 
 263         if (!error_data || !error_ecc || !correct_data || !correct_ecc) {
 264                 err = -ENOMEM;
 265                 goto error;
 266         }
 267 
 268         prandom_bytes(correct_data, size);
 269         __nand_calculate_ecc(correct_data, size, correct_ecc,
 270                              IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 271 
 272         for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
 273                 nand_ecc_test[i].prepare(error_data, error_ecc,
 274                                 correct_data, correct_ecc, size);
 275                 err = nand_ecc_test[i].verify(error_data, error_ecc,
 276                                                 correct_data, size);
 277 
 278                 if (err) {
 279                         pr_err("not ok - %s-%zd\n",
 280                                 nand_ecc_test[i].name, size);
 281                         dump_data_ecc(error_data, error_ecc,
 282                                 correct_data, correct_ecc, size);
 283                         break;
 284                 }
 285                 pr_info("ok - %s-%zd\n",
 286                         nand_ecc_test[i].name, size);
 287 
 288                 err = mtdtest_relax();
 289                 if (err)
 290                         break;
 291         }
 292 error:
 293         kfree(error_data);
 294         kfree(error_ecc);
 295         kfree(correct_data);
 296         kfree(correct_ecc);
 297 
 298         return err;
 299 }
 300 
 301 #else
 302 
 303 static int nand_ecc_test_run(const size_t size)
 304 {
 305         return 0;
 306 }
 307 
 308 #endif
 309 
 310 static int __init ecc_test_init(void)
 311 {
 312         int err;
 313 
 314         err = nand_ecc_test_run(256);
 315         if (err)
 316                 return err;
 317 
 318         return nand_ecc_test_run(512);
 319 }
 320 
 321 static void __exit ecc_test_exit(void)
 322 {
 323 }
 324 
 325 module_init(ecc_test_init);
 326 module_exit(ecc_test_exit);
 327 
 328 MODULE_DESCRIPTION("NAND ECC function test module");
 329 MODULE_AUTHOR("Akinobu Mita");
 330 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */