diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2012-09-07 12:48:07 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-09-29 10:47:37 -0400 |
commit | 6060fb42a0bf93015d05c1a857b94894936f40ee (patch) | |
tree | 4b28d8730eba19b6f61692b520c7529039fd3605 | |
parent | c092b43906098a6879d0fa9f74e5141516b9b856 (diff) |
mtd: mtd_nandecctest: rewrite the test routine
This rewrites the entire test routine in order to make it easy to add more
tests by later changes and minimize duplication of each tests as much as
possible.
Now that each test is described by the members of struct nand_ecc_test:
- name: descriptive testname
- prepare: function to prepare data block and ecc with artifical corruption
- verify: function to verify the result of correcting data block
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-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) |