diff options
Diffstat (limited to 'drivers/mtd/tests/mtd_nandecctest.c')
-rw-r--r-- | drivers/mtd/tests/mtd_nandecctest.c | 93 |
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index d90daf879c46..204f796ed3e7 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c | |||
@@ -7,8 +7,24 @@ | |||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/mtd/nand_ecc.h> | 8 | #include <linux/mtd/nand_ecc.h> |
9 | 9 | ||
10 | /* | ||
11 | * Test the implementation for software ECC | ||
12 | * | ||
13 | * No actual MTD device is needed, So we don't need to warry about losing | ||
14 | * important data by human error. | ||
15 | * | ||
16 | * This covers possible patterns of corruption which can be reliably corrected | ||
17 | * or detected. | ||
18 | */ | ||
19 | |||
10 | #if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE) | 20 | #if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE) |
11 | 21 | ||
22 | struct nand_ecc_test { | ||
23 | const char *name; | ||
24 | void (*prepare)(void *, void *, void *, void *, const size_t); | ||
25 | int (*verify)(void *, void *, void *, const size_t); | ||
26 | }; | ||
27 | |||
12 | /* | 28 | /* |
13 | * The reason for this __change_bit_le() instead of __change_bit() is to inject | 29 | * 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 | 30 | * bit error properly within the region which is not a multiple of |
@@ -23,13 +39,44 @@ | |||
23 | #error "Unknown byte order" | 39 | #error "Unknown byte order" |
24 | #endif | 40 | #endif |
25 | 41 | ||
26 | static void inject_single_bit_error(void *data, size_t size) | 42 | static void single_bit_error_data(void *error_data, void *correct_data, |
43 | size_t size) | ||
27 | { | 44 | { |
28 | unsigned int offset = random32() % (size * BITS_PER_BYTE); | 45 | unsigned int offset = random32() % (size * BITS_PER_BYTE); |
29 | 46 | ||
30 | __change_bit_le(offset, data); | 47 | memcpy(error_data, correct_data, size); |
48 | __change_bit_le(offset, error_data); | ||
49 | } | ||
50 | |||
51 | static void single_bit_error_in_data(void *error_data, void *error_ecc, | ||
52 | void *correct_data, void *correct_ecc, const size_t size) | ||
53 | { | ||
54 | single_bit_error_data(error_data, correct_data, size); | ||
55 | memcpy(error_ecc, correct_ecc, 3); | ||
56 | } | ||
57 | |||
58 | static int single_bit_error_correct(void *error_data, void *error_ecc, | ||
59 | void *correct_data, const size_t size) | ||
60 | { | ||
61 | unsigned char calc_ecc[3]; | ||
62 | int ret; | ||
63 | |||
64 | __nand_calculate_ecc(error_data, size, calc_ecc); | ||
65 | ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size); | ||
66 | if (ret == 1 && !memcmp(correct_data, error_data, size)) | ||
67 | return 0; | ||
68 | |||
69 | return -EINVAL; | ||
31 | } | 70 | } |
32 | 71 | ||
72 | static const struct nand_ecc_test nand_ecc_test[] = { | ||
73 | { | ||
74 | .name = "single-bit-error-in-data-correct", | ||
75 | .prepare = single_bit_error_in_data, | ||
76 | .verify = single_bit_error_correct, | ||
77 | }, | ||
78 | }; | ||
79 | |||
33 | static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data, | 80 | static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data, |
34 | void *correct_ecc, const size_t size) | 81 | void *correct_ecc, const size_t size) |
35 | { | 82 | { |
@@ -46,14 +93,14 @@ static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data, | |||
46 | DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false); | 93 | DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false); |
47 | } | 94 | } |
48 | 95 | ||
49 | static int nand_ecc_test(const size_t size) | 96 | static int nand_ecc_test_run(const size_t size) |
50 | { | 97 | { |
98 | int i; | ||
51 | int err = 0; | 99 | int err = 0; |
52 | void *error_data; | 100 | void *error_data; |
53 | void *error_ecc; | 101 | void *error_ecc; |
54 | void *correct_data; | 102 | void *correct_data; |
55 | void *correct_ecc; | 103 | void *correct_ecc; |
56 | char testname[30]; | ||
57 | 104 | ||
58 | error_data = kmalloc(size, GFP_KERNEL); | 105 | error_data = kmalloc(size, GFP_KERNEL); |
59 | error_ecc = kmalloc(3, GFP_KERNEL); | 106 | error_ecc = kmalloc(3, GFP_KERNEL); |
@@ -65,25 +112,25 @@ static int nand_ecc_test(const size_t size) | |||
65 | goto error; | 112 | goto error; |
66 | } | 113 | } |
67 | 114 | ||
68 | sprintf(testname, "nand-ecc-%zu", size); | ||
69 | |||
70 | get_random_bytes(correct_data, size); | 115 | get_random_bytes(correct_data, size); |
71 | |||
72 | memcpy(error_data, correct_data, size); | ||
73 | inject_single_bit_error(error_data, size); | ||
74 | |||
75 | __nand_calculate_ecc(correct_data, size, correct_ecc); | 116 | __nand_calculate_ecc(correct_data, size, correct_ecc); |
76 | __nand_calculate_ecc(error_data, size, error_ecc); | 117 | |
77 | __nand_correct_data(error_data, correct_ecc, error_ecc, size); | 118 | for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) { |
78 | 119 | nand_ecc_test[i].prepare(error_data, error_ecc, | |
79 | if (memcmp(correct_data, error_data, size)) { | 120 | correct_data, correct_ecc, size); |
80 | pr_err("mtd_nandecctest: not ok - %s\n", testname); | 121 | err = nand_ecc_test[i].verify(error_data, error_ecc, |
81 | dump_data_ecc(error_data, error_ecc, correct_data, correct_ecc, | 122 | correct_data, size); |
82 | size); | 123 | |
83 | err = -EINVAL; | 124 | if (err) { |
84 | goto error; | 125 | pr_err("mtd_nandecctest: not ok - %s-%zd\n", |
126 | nand_ecc_test[i].name, size); | ||
127 | dump_data_ecc(error_data, error_ecc, | ||
128 | correct_data, correct_ecc, size); | ||
129 | break; | ||
130 | } | ||
131 | pr_info("mtd_nandecctest: ok - %s-%zd\n", | ||
132 | nand_ecc_test[i].name, size); | ||
85 | } | 133 | } |
86 | pr_info("mtd_nandecctest: ok - %s\n", testname); | ||
87 | error: | 134 | error: |
88 | kfree(error_data); | 135 | kfree(error_data); |
89 | kfree(error_ecc); | 136 | kfree(error_ecc); |
@@ -95,7 +142,7 @@ error: | |||
95 | 142 | ||
96 | #else | 143 | #else |
97 | 144 | ||
98 | static int nand_ecc_test(const size_t size) | 145 | static int nand_ecc_test_run(const size_t size) |
99 | { | 146 | { |
100 | return 0; | 147 | return 0; |
101 | } | 148 | } |
@@ -106,11 +153,11 @@ static int __init ecc_test_init(void) | |||
106 | { | 153 | { |
107 | int err; | 154 | int err; |
108 | 155 | ||
109 | err = nand_ecc_test(256); | 156 | err = nand_ecc_test_run(256); |
110 | if (err) | 157 | if (err) |
111 | return err; | 158 | return err; |
112 | 159 | ||
113 | return nand_ecc_test(512); | 160 | return nand_ecc_test_run(512); |
114 | } | 161 | } |
115 | 162 | ||
116 | static void __exit ecc_test_exit(void) | 163 | static void __exit ecc_test_exit(void) |