diff options
author | Roger Quadros <rogerq@ti.com> | 2014-10-21 09:53:28 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-11-20 02:25:49 -0500 |
commit | afc0ea1b8e1e27b2cb77e7023d917f3aa5971d17 (patch) | |
tree | f9d775ea06825e101ad82258fa8cf61e4ab56ff2 /drivers/mtd | |
parent | 5a66088bffd9a5251e96ca5d0d46456ab9196287 (diff) |
mtd: mtd_oobtest: add bitflip_limit parameter
It is common for NAND devices to have bitflip errors.
Add a bitflip_limit parameter to specify how many bitflips per
page we can tolerate without flagging an error.
By default zero bitflips are tolerated.
Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/tests/oobtest.c | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index edd859d96d85..1fd2cdad85f0 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c | |||
@@ -34,8 +34,11 @@ | |||
34 | #include "mtd_test.h" | 34 | #include "mtd_test.h" |
35 | 35 | ||
36 | static int dev = -EINVAL; | 36 | static int dev = -EINVAL; |
37 | static int bitflip_limit; | ||
37 | module_param(dev, int, S_IRUGO); | 38 | module_param(dev, int, S_IRUGO); |
38 | MODULE_PARM_DESC(dev, "MTD device number to use"); | 39 | MODULE_PARM_DESC(dev, "MTD device number to use"); |
40 | module_param(bitflip_limit, int, S_IRUGO); | ||
41 | MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page"); | ||
39 | 42 | ||
40 | static struct mtd_info *mtd; | 43 | static struct mtd_info *mtd; |
41 | static unsigned char *readbuf; | 44 | static unsigned char *readbuf; |
@@ -115,24 +118,27 @@ static int write_whole_device(void) | |||
115 | return 0; | 118 | return 0; |
116 | } | 119 | } |
117 | 120 | ||
118 | /* Display the address, offset and data bytes at comparison failure */ | 121 | /* |
119 | static int memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count) | 122 | * Display the address, offset and data bytes at comparison failure. |
123 | * Return number of bitflips encountered. | ||
124 | */ | ||
125 | static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count) | ||
120 | { | 126 | { |
121 | const unsigned char *su1, *su2; | 127 | const unsigned char *su1, *su2; |
122 | int res; | 128 | int res; |
123 | int ret = 0; | ||
124 | size_t i = 0; | 129 | size_t i = 0; |
130 | size_t bitflips = 0; | ||
125 | 131 | ||
126 | for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { | 132 | for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { |
127 | res = *su1 ^ *su2; | 133 | res = *su1 ^ *su2; |
128 | if (res) { | 134 | if (res) { |
129 | pr_info("error @addr[0x%lx:0x%x] 0x%x -> 0x%x diff 0x%x\n", | 135 | pr_info("error @addr[0x%lx:0x%x] 0x%x -> 0x%x diff 0x%x\n", |
130 | (unsigned long)addr, i, *su1, *su2, res); | 136 | (unsigned long)addr, i, *su1, *su2, res); |
131 | ret = 1; | 137 | bitflips += hweight8(res); |
132 | } | 138 | } |
133 | } | 139 | } |
134 | 140 | ||
135 | return ret; | 141 | return bitflips; |
136 | } | 142 | } |
137 | 143 | ||
138 | static int verify_eraseblock(int ebnum) | 144 | static int verify_eraseblock(int ebnum) |
@@ -141,6 +147,7 @@ static int verify_eraseblock(int ebnum) | |||
141 | struct mtd_oob_ops ops; | 147 | struct mtd_oob_ops ops; |
142 | int err = 0; | 148 | int err = 0; |
143 | loff_t addr = (loff_t)ebnum * mtd->erasesize; | 149 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
150 | size_t bitflips; | ||
144 | 151 | ||
145 | prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); | 152 | prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); |
146 | for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { | 153 | for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { |
@@ -159,9 +166,11 @@ static int verify_eraseblock(int ebnum) | |||
159 | errcnt += 1; | 166 | errcnt += 1; |
160 | return err ? err : -1; | 167 | return err ? err : -1; |
161 | } | 168 | } |
162 | if (memcmpshow(addr, readbuf, | 169 | |
163 | writebuf + (use_len_max * i) + use_offset, | 170 | bitflips = memcmpshow(addr, readbuf, |
164 | use_len)) { | 171 | writebuf + (use_len_max * i) + use_offset, |
172 | use_len); | ||
173 | if (bitflips > bitflip_limit) { | ||
165 | pr_err("error: verify failed at %#llx\n", | 174 | pr_err("error: verify failed at %#llx\n", |
166 | (long long)addr); | 175 | (long long)addr); |
167 | errcnt += 1; | 176 | errcnt += 1; |
@@ -169,7 +178,10 @@ static int verify_eraseblock(int ebnum) | |||
169 | pr_err("error: too many errors\n"); | 178 | pr_err("error: too many errors\n"); |
170 | return -1; | 179 | return -1; |
171 | } | 180 | } |
181 | } else if (bitflips) { | ||
182 | pr_info("ignoring error as within bitflip_limit\n"); | ||
172 | } | 183 | } |
184 | |||
173 | if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { | 185 | if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { |
174 | int k; | 186 | int k; |
175 | 187 | ||
@@ -188,9 +200,10 @@ static int verify_eraseblock(int ebnum) | |||
188 | errcnt += 1; | 200 | errcnt += 1; |
189 | return err ? err : -1; | 201 | return err ? err : -1; |
190 | } | 202 | } |
191 | if (memcmpshow(addr, readbuf + use_offset, | 203 | bitflips = memcmpshow(addr, readbuf + use_offset, |
192 | writebuf + (use_len_max * i) + use_offset, | 204 | writebuf + (use_len_max * i) + use_offset, |
193 | use_len)) { | 205 | use_len); |
206 | if (bitflips > bitflip_limit) { | ||
194 | pr_err("error: verify failed at %#llx\n", | 207 | pr_err("error: verify failed at %#llx\n", |
195 | (long long)addr); | 208 | (long long)addr); |
196 | errcnt += 1; | 209 | errcnt += 1; |
@@ -198,7 +211,10 @@ static int verify_eraseblock(int ebnum) | |||
198 | pr_err("error: too many errors\n"); | 211 | pr_err("error: too many errors\n"); |
199 | return -1; | 212 | return -1; |
200 | } | 213 | } |
214 | } else if (bitflips) { | ||
215 | pr_info("ignoring error as within bitflip_limit\n"); | ||
201 | } | 216 | } |
217 | |||
202 | for (k = 0; k < use_offset; ++k) | 218 | for (k = 0; k < use_offset; ++k) |
203 | if (readbuf[k] != 0xff) { | 219 | if (readbuf[k] != 0xff) { |
204 | pr_err("error: verify 0xff " | 220 | pr_err("error: verify 0xff " |
@@ -237,6 +253,9 @@ static int verify_eraseblock_in_one_go(int ebnum) | |||
237 | int err = 0; | 253 | int err = 0; |
238 | loff_t addr = (loff_t)ebnum * mtd->erasesize; | 254 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
239 | size_t len = mtd->ecclayout->oobavail * pgcnt; | 255 | size_t len = mtd->ecclayout->oobavail * pgcnt; |
256 | size_t oobavail = mtd->ecclayout->oobavail; | ||
257 | size_t bitflips; | ||
258 | int i; | ||
240 | 259 | ||
241 | prandom_bytes_state(&rnd_state, writebuf, len); | 260 | prandom_bytes_state(&rnd_state, writebuf, len); |
242 | ops.mode = MTD_OPS_AUTO_OOB; | 261 | ops.mode = MTD_OPS_AUTO_OOB; |
@@ -247,6 +266,8 @@ static int verify_eraseblock_in_one_go(int ebnum) | |||
247 | ops.ooboffs = 0; | 266 | ops.ooboffs = 0; |
248 | ops.datbuf = NULL; | 267 | ops.datbuf = NULL; |
249 | ops.oobbuf = readbuf; | 268 | ops.oobbuf = readbuf; |
269 | |||
270 | /* read entire block's OOB at one go */ | ||
250 | err = mtd_read_oob(mtd, addr, &ops); | 271 | err = mtd_read_oob(mtd, addr, &ops); |
251 | if (err || ops.oobretlen != len) { | 272 | if (err || ops.oobretlen != len) { |
252 | pr_err("error: readoob failed at %#llx\n", | 273 | pr_err("error: readoob failed at %#llx\n", |
@@ -254,13 +275,21 @@ static int verify_eraseblock_in_one_go(int ebnum) | |||
254 | errcnt += 1; | 275 | errcnt += 1; |
255 | return err ? err : -1; | 276 | return err ? err : -1; |
256 | } | 277 | } |
257 | if (memcmpshow(addr, readbuf, writebuf, len)) { | 278 | |
258 | pr_err("error: verify failed at %#llx\n", | 279 | /* verify one page OOB at a time for bitflip per page limit check */ |
259 | (long long)addr); | 280 | for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { |
260 | errcnt += 1; | 281 | bitflips = memcmpshow(addr, readbuf + (i * oobavail), |
261 | if (errcnt > 1000) { | 282 | writebuf + (i * oobavail), oobavail); |
262 | pr_err("error: too many errors\n"); | 283 | if (bitflips > bitflip_limit) { |
263 | return -1; | 284 | pr_err("error: verify failed at %#llx\n", |
285 | (long long)addr); | ||
286 | errcnt += 1; | ||
287 | if (errcnt > 1000) { | ||
288 | pr_err("error: too many errors\n"); | ||
289 | return -1; | ||
290 | } | ||
291 | } else if (bitflips) { | ||
292 | pr_info("ignoring error as within bitflip_limit\n"); | ||
264 | } | 293 | } |
265 | } | 294 | } |
266 | 295 | ||