blob: d90daf879c46b28a7c99e349a79dfb261766ebc0 [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
Akinobu Mitac092b432012-09-08 01:48:06 +090012/*
13 * The reason for this __change_bit_le() instead of __change_bit() is to inject
14 * bit error properly within the region which is not a multiple of
15 * sizeof(unsigned long) on big-endian systems
16 */
17#ifdef __LITTLE_ENDIAN
18#define __change_bit_le(nr, addr) __change_bit(nr, addr)
19#elif defined(__BIG_ENDIAN)
20#define __change_bit_le(nr, addr) \
21 __change_bit((nr) ^ ((BITS_PER_LONG - 1) & ~0x7), addr)
22#else
23#error "Unknown byte order"
24#endif
25
Akinobu Mita7126bd82009-10-22 16:53:33 +090026static void inject_single_bit_error(void *data, size_t size)
27{
Akinobu Mitac092b432012-09-08 01:48:06 +090028 unsigned int offset = random32() % (size * BITS_PER_BYTE);
Akinobu Mita7126bd82009-10-22 16:53:33 +090029
Akinobu Mitac092b432012-09-08 01:48:06 +090030 __change_bit_le(offset, data);
Akinobu Mita7126bd82009-10-22 16:53:33 +090031}
32
Akinobu Mitac5b83842012-09-03 22:00:00 +090033static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data,
34 void *correct_ecc, const size_t size)
35{
36 pr_info("hexdump of error data:\n");
37 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
38 error_data, size, false);
39 print_hex_dump(KERN_INFO, "hexdump of error ecc: ",
40 DUMP_PREFIX_NONE, 16, 1, error_ecc, 3, false);
41
42 pr_info("hexdump of correct data:\n");
43 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
44 correct_data, size, false);
45 print_hex_dump(KERN_INFO, "hexdump of correct ecc: ",
46 DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false);
47}
48
Akinobu Mita7126bd82009-10-22 16:53:33 +090049static int nand_ecc_test(const size_t size)
50{
Akinobu Mita1749c002012-09-03 22:00:01 +090051 int err = 0;
52 void *error_data;
53 void *error_ecc;
54 void *correct_data;
55 void *correct_ecc;
Akinobu Mita7126bd82009-10-22 16:53:33 +090056 char testname[30];
57
Akinobu Mita1749c002012-09-03 22:00:01 +090058 error_data = kmalloc(size, GFP_KERNEL);
59 error_ecc = kmalloc(3, GFP_KERNEL);
60 correct_data = kmalloc(size, GFP_KERNEL);
61 correct_ecc = kmalloc(3, GFP_KERNEL);
62
63 if (!error_data || !error_ecc || !correct_data || !correct_ecc) {
64 err = -ENOMEM;
65 goto error;
66 }
Akinobu Mita7126bd82009-10-22 16:53:33 +090067
68 sprintf(testname, "nand-ecc-%zu", size);
69
Akinobu Mitac5b83842012-09-03 22:00:00 +090070 get_random_bytes(correct_data, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090071
Akinobu Mitac5b83842012-09-03 22:00:00 +090072 memcpy(error_data, correct_data, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090073 inject_single_bit_error(error_data, size);
74
Akinobu Mitac5b83842012-09-03 22:00:00 +090075 __nand_calculate_ecc(correct_data, size, correct_ecc);
76 __nand_calculate_ecc(error_data, size, error_ecc);
77 __nand_correct_data(error_data, correct_ecc, error_ecc, size);
Akinobu Mita7126bd82009-10-22 16:53:33 +090078
Akinobu Mita1749c002012-09-03 22:00:01 +090079 if (memcmp(correct_data, error_data, size)) {
80 pr_err("mtd_nandecctest: not ok - %s\n", testname);
81 dump_data_ecc(error_data, error_ecc, correct_data, correct_ecc,
82 size);
83 err = -EINVAL;
84 goto error;
Akinobu Mita7126bd82009-10-22 16:53:33 +090085 }
Akinobu Mita1749c002012-09-03 22:00:01 +090086 pr_info("mtd_nandecctest: ok - %s\n", testname);
87error:
88 kfree(error_data);
89 kfree(error_ecc);
90 kfree(correct_data);
91 kfree(correct_ecc);
Akinobu Mita7126bd82009-10-22 16:53:33 +090092
Akinobu Mita1749c002012-09-03 22:00:01 +090093 return err;
Akinobu Mita7126bd82009-10-22 16:53:33 +090094}
95
96#else
97
98static int nand_ecc_test(const size_t size)
99{
100 return 0;
101}
102
103#endif
104
105static int __init ecc_test_init(void)
106{
Akinobu Mitaf45c2992012-08-26 21:06:44 +0900107 int err;
Akinobu Mita7126bd82009-10-22 16:53:33 +0900108
Akinobu Mitaf45c2992012-08-26 21:06:44 +0900109 err = nand_ecc_test(256);
110 if (err)
111 return err;
112
113 return nand_ecc_test(512);
Akinobu Mita7126bd82009-10-22 16:53:33 +0900114}
115
116static void __exit ecc_test_exit(void)
117{
118}
119
120module_init(ecc_test_init);
121module_exit(ecc_test_exit);
122
123MODULE_DESCRIPTION("NAND ECC function test module");
124MODULE_AUTHOR("Akinobu Mita");
125MODULE_LICENSE("GPL");