blob: d3e8873ad38ac4e74c6b9c1e63eb7fff9506bc00 [file] [log] [blame]
Akinobu Mita7126bd82009-10-22 16:53:33 +09001#include <linux/kernel.h>
2#include <linux/module.h>
3#include <linux/list.h>
Akinobu Mita7126bd82009-10-22 16:53:33 +09004#include <linux/random.h>
5#include <linux/string.h>
6#include <linux/bitops.h>
Akinobu Mita1749c002012-09-03 22:00:01 +09007#include <linux/slab.h>
Akinobu Mita7126bd82009-10-22 16:53:33 +09008#include <linux/mtd/nand_ecc.h>
9
10#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
11
12static void inject_single_bit_error(void *data, size_t size)
13{
14 unsigned long offset = random32() % (size * BITS_PER_BYTE);
15
16 __change_bit(offset, data);
17}
18
Akinobu Mitac5b83842012-09-03 22:00:00 +090019static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data,
20 void *correct_ecc, const size_t size)
21{
22 pr_info("hexdump of error data:\n");
23 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
24 error_data, size, false);
25 print_hex_dump(KERN_INFO, "hexdump of error ecc: ",
26 DUMP_PREFIX_NONE, 16, 1, error_ecc, 3, false);
27
28 pr_info("hexdump of correct data:\n");
29 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
30 correct_data, size, false);
31 print_hex_dump(KERN_INFO, "hexdump of correct ecc: ",
32 DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false);
33}
34
Akinobu Mita7126bd82009-10-22 16:53:33 +090035static int nand_ecc_test(const size_t size)
36{
Akinobu Mita1749c002012-09-03 22:00:01 +090037 int err = 0;
38 void *error_data;
39 void *error_ecc;
40 void *correct_data;
41 void *correct_ecc;
Akinobu Mita7126bd82009-10-22 16:53:33 +090042 char testname[30];
43
Akinobu Mita1749c002012-09-03 22:00:01 +090044 error_data = kmalloc(size, GFP_KERNEL);
45 error_ecc = kmalloc(3, GFP_KERNEL);
46 correct_data = kmalloc(size, GFP_KERNEL);
47 correct_ecc = kmalloc(3, GFP_KERNEL);
48
49 if (!error_data || !error_ecc || !correct_data || !correct_ecc) {
50 err = -ENOMEM;
51 goto error;
52 }
Akinobu Mita7126bd82009-10-22 16:53:33 +090053
54 sprintf(testname, "nand-ecc-%zu", size);
55
Akinobu Mitac5b83842012-09-03 22:00:00 +090056 get_random_bytes(correct_data, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090057
Akinobu Mitac5b83842012-09-03 22:00:00 +090058 memcpy(error_data, correct_data, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090059 inject_single_bit_error(error_data, size);
60
Akinobu Mitac5b83842012-09-03 22:00:00 +090061 __nand_calculate_ecc(correct_data, size, correct_ecc);
62 __nand_calculate_ecc(error_data, size, error_ecc);
63 __nand_correct_data(error_data, correct_ecc, error_ecc, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090064
Akinobu Mita1749c002012-09-03 22:00:01 +090065 if (memcmp(correct_data, error_data, size)) {
66 pr_err("mtd_nandecctest: not ok - %s\n", testname);
67 dump_data_ecc(error_data, error_ecc, correct_data, correct_ecc,
68 size);
69 err = -EINVAL;
70 goto error;
Akinobu Mita7126bd82009-10-22 16:53:33 +090071 }
Akinobu Mita1749c002012-09-03 22:00:01 +090072 pr_info("mtd_nandecctest: ok - %s\n", testname);
73error:
74 kfree(error_data);
75 kfree(error_ecc);
76 kfree(correct_data);
77 kfree(correct_ecc);
Akinobu Mita7126bd82009-10-22 16:53:33 +090078
Akinobu Mita1749c002012-09-03 22:00:01 +090079 return err;
Akinobu Mita7126bd82009-10-22 16:53:33 +090080}
81
82#else
83
84static int nand_ecc_test(const size_t size)
85{
86 return 0;
87}
88
89#endif
90
91static int __init ecc_test_init(void)
92{
Akinobu Mitaf45c2992012-08-26 21:06:44 +090093 int err;
Akinobu Mita7126bd82009-10-22 16:53:33 +090094
Akinobu Mitaf45c2992012-08-26 21:06:44 +090095 err = nand_ecc_test(256);
96 if (err)
97 return err;
98
99 return nand_ecc_test(512);
Akinobu Mita7126bd82009-10-22 16:53:33 +0900100}
101
102static void __exit ecc_test_exit(void)
103{
104}
105
106module_init(ecc_test_init);
107module_exit(ecc_test_exit);
108
109MODULE_DESCRIPTION("NAND ECC function test module");
110MODULE_AUTHOR("Akinobu Mita");
111MODULE_LICENSE("GPL");