aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/tests/mtd_nandecctest.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/tests/mtd_nandecctest.c')
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c93
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
22struct 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
26static void inject_single_bit_error(void *data, size_t size) 42static 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
51static 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
58static 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
72static 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
33static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data, 80static 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
49static int nand_ecc_test(const size_t size) 96static 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);
87error: 134error:
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
98static int nand_ecc_test(const size_t size) 145static 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
116static void __exit ecc_test_exit(void) 163static void __exit ecc_test_exit(void)