1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/list.h>
4 #include <linux/random.h>
5 #include <linux/string.h>
6 #include <linux/bitops.h>
7 #include <linux/slab.h>
8 #include <linux/mtd/nand_ecc.h>
9 
10 #if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
11 
12 static 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 
19 static 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 
35 static int nand_ecc_test(const size_t size)
36 {
37 	int err = 0;
38 	void *error_data;
39 	void *error_ecc;
40 	void *correct_data;
41 	void *correct_ecc;
42 	char testname[30];
43 
44 	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 	}
53 
54 	sprintf(testname, "nand-ecc-%zu", size);
55 
56 	get_random_bytes(correct_data, size);
57 
58 	memcpy(error_data, correct_data, size);
59 	inject_single_bit_error(error_data, size);
60 
61 	__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);
64 
65 	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;
71 	}
72 	pr_info("mtd_nandecctest: ok - %s\n", testname);
73 error:
74 	kfree(error_data);
75 	kfree(error_ecc);
76 	kfree(correct_data);
77 	kfree(correct_ecc);
78 
79 	return err;
80 }
81 
82 #else
83 
84 static int nand_ecc_test(const size_t size)
85 {
86 	return 0;
87 }
88 
89 #endif
90 
91 static int __init ecc_test_init(void)
92 {
93 	int err;
94 
95 	err = nand_ecc_test(256);
96 	if (err)
97 		return err;
98 
99 	return nand_ecc_test(512);
100 }
101 
102 static void __exit ecc_test_exit(void)
103 {
104 }
105 
106 module_init(ecc_test_init);
107 module_exit(ecc_test_exit);
108 
109 MODULE_DESCRIPTION("NAND ECC function test module");
110 MODULE_AUTHOR("Akinobu Mita");
111 MODULE_LICENSE("GPL");
112