Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvar...
[pandora-kernel.git] / drivers / mtd / tests / mtd_subpagetest.c
1 /*
2  * Copyright (C) 2006-2007 Nokia Corporation
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; see the file COPYING. If not, write to the Free Software
15  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16  *
17  * Test sub-page read and write on MTD device.
18  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
19  *
20  */
21
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/err.h>
26 #include <linux/mtd/mtd.h>
27 #include <linux/slab.h>
28 #include <linux/sched.h>
29
30 #define PRINT_PREF KERN_INFO "mtd_subpagetest: "
31
32 static int dev;
33 module_param(dev, int, S_IRUGO);
34 MODULE_PARM_DESC(dev, "MTD device number to use");
35
36 static struct mtd_info *mtd;
37 static unsigned char *writebuf;
38 static unsigned char *readbuf;
39 static unsigned char *bbt;
40
41 static int subpgsize;
42 static int bufsize;
43 static int ebcnt;
44 static int pgcnt;
45 static int errcnt;
46 static unsigned long next = 1;
47
48 static inline unsigned int simple_rand(void)
49 {
50         next = next * 1103515245 + 12345;
51         return (unsigned int)((next / 65536) % 32768);
52 }
53
54 static inline void simple_srand(unsigned long seed)
55 {
56         next = seed;
57 }
58
59 static void set_random_data(unsigned char *buf, size_t len)
60 {
61         size_t i;
62
63         for (i = 0; i < len; ++i)
64                 buf[i] = simple_rand();
65 }
66
67 static inline void clear_data(unsigned char *buf, size_t len)
68 {
69         memset(buf, 0, len);
70 }
71
72 static int erase_eraseblock(int ebnum)
73 {
74         int err;
75         struct erase_info ei;
76         loff_t addr = ebnum * mtd->erasesize;
77
78         memset(&ei, 0, sizeof(struct erase_info));
79         ei.mtd  = mtd;
80         ei.addr = addr;
81         ei.len  = mtd->erasesize;
82
83         err = mtd->erase(mtd, &ei);
84         if (err) {
85                 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
86                 return err;
87         }
88
89         if (ei.state == MTD_ERASE_FAILED) {
90                 printk(PRINT_PREF "some erase error occurred at EB %d\n",
91                        ebnum);
92                 return -EIO;
93         }
94
95         return 0;
96 }
97
98 static int erase_whole_device(void)
99 {
100         int err;
101         unsigned int i;
102
103         printk(PRINT_PREF "erasing whole device\n");
104         for (i = 0; i < ebcnt; ++i) {
105                 if (bbt[i])
106                         continue;
107                 err = erase_eraseblock(i);
108                 if (err)
109                         return err;
110                 cond_resched();
111         }
112         printk(PRINT_PREF "erased %u eraseblocks\n", i);
113         return 0;
114 }
115
116 static int write_eraseblock(int ebnum)
117 {
118         size_t written = 0;
119         int err = 0;
120         loff_t addr = ebnum * mtd->erasesize;
121
122         set_random_data(writebuf, subpgsize);
123         err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
124         if (unlikely(err || written != subpgsize)) {
125                 printk(PRINT_PREF "error: write failed at %#llx\n",
126                        (long long)addr);
127                 if (written != subpgsize) {
128                         printk(PRINT_PREF "  write size: %#x\n", subpgsize);
129                         printk(PRINT_PREF "  written: %#zx\n", written);
130                 }
131                 return err ? err : -1;
132         }
133
134         addr += subpgsize;
135
136         set_random_data(writebuf, subpgsize);
137         err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
138         if (unlikely(err || written != subpgsize)) {
139                 printk(PRINT_PREF "error: write failed at %#llx\n",
140                        (long long)addr);
141                 if (written != subpgsize) {
142                         printk(PRINT_PREF "  write size: %#x\n", subpgsize);
143                         printk(PRINT_PREF "  written: %#zx\n", written);
144                 }
145                 return err ? err : -1;
146         }
147
148         return err;
149 }
150
151 static int write_eraseblock2(int ebnum)
152 {
153         size_t written = 0;
154         int err = 0, k;
155         loff_t addr = ebnum * mtd->erasesize;
156
157         for (k = 1; k < 33; ++k) {
158                 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
159                         break;
160                 set_random_data(writebuf, subpgsize * k);
161                 err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf);
162                 if (unlikely(err || written != subpgsize * k)) {
163                         printk(PRINT_PREF "error: write failed at %#llx\n",
164                                (long long)addr);
165                         if (written != subpgsize) {
166                                 printk(PRINT_PREF "  write size: %#x\n",
167                                        subpgsize * k);
168                                 printk(PRINT_PREF "  written: %#08zx\n",
169                                        written);
170                         }
171                         return err ? err : -1;
172                 }
173                 addr += subpgsize * k;
174         }
175
176         return err;
177 }
178
179 static void print_subpage(unsigned char *p)
180 {
181         int i, j;
182
183         for (i = 0; i < subpgsize; ) {
184                 for (j = 0; i < subpgsize && j < 32; ++i, ++j)
185                         printk("%02x", *p++);
186                 printk("\n");
187         }
188 }
189
190 static int verify_eraseblock(int ebnum)
191 {
192         size_t read = 0;
193         int err = 0;
194         loff_t addr = ebnum * mtd->erasesize;
195
196         set_random_data(writebuf, subpgsize);
197         clear_data(readbuf, subpgsize);
198         read = 0;
199         err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
200         if (unlikely(err || read != subpgsize)) {
201                 if (err == -EUCLEAN && read == subpgsize) {
202                         printk(PRINT_PREF "ECC correction at %#llx\n",
203                                (long long)addr);
204                         err = 0;
205                 } else {
206                         printk(PRINT_PREF "error: read failed at %#llx\n",
207                                (long long)addr);
208                         return err ? err : -1;
209                 }
210         }
211         if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
212                 printk(PRINT_PREF "error: verify failed at %#llx\n",
213                        (long long)addr);
214                 printk(PRINT_PREF "------------- written----------------\n");
215                 print_subpage(writebuf);
216                 printk(PRINT_PREF "------------- read ------------------\n");
217                 print_subpage(readbuf);
218                 printk(PRINT_PREF "-------------------------------------\n");
219                 errcnt += 1;
220         }
221
222         addr += subpgsize;
223
224         set_random_data(writebuf, subpgsize);
225         clear_data(readbuf, subpgsize);
226         read = 0;
227         err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
228         if (unlikely(err || read != subpgsize)) {
229                 if (err == -EUCLEAN && read == subpgsize) {
230                         printk(PRINT_PREF "ECC correction at %#llx\n",
231                                (long long)addr);
232                         err = 0;
233                 } else {
234                         printk(PRINT_PREF "error: read failed at %#llx\n",
235                                (long long)addr);
236                         return err ? err : -1;
237                 }
238         }
239         if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
240                 printk(PRINT_PREF "error: verify failed at %#llx\n",
241                        (long long)addr);
242                 printk(PRINT_PREF "------------- written----------------\n");
243                 print_subpage(writebuf);
244                 printk(PRINT_PREF "------------- read ------------------\n");
245                 print_subpage(readbuf);
246                 printk(PRINT_PREF "-------------------------------------\n");
247                 errcnt += 1;
248         }
249
250         return err;
251 }
252
253 static int verify_eraseblock2(int ebnum)
254 {
255         size_t read = 0;
256         int err = 0, k;
257         loff_t addr = ebnum * mtd->erasesize;
258
259         for (k = 1; k < 33; ++k) {
260                 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
261                         break;
262                 set_random_data(writebuf, subpgsize * k);
263                 clear_data(readbuf, subpgsize * k);
264                 read = 0;
265                 err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
266                 if (unlikely(err || read != subpgsize * k)) {
267                         if (err == -EUCLEAN && read == subpgsize * k) {
268                                 printk(PRINT_PREF "ECC correction at %#llx\n",
269                                        (long long)addr);
270                                 err = 0;
271                         } else {
272                                 printk(PRINT_PREF "error: read failed at "
273                                        "%#llx\n", (long long)addr);
274                                 return err ? err : -1;
275                         }
276                 }
277                 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
278                         printk(PRINT_PREF "error: verify failed at %#llx\n",
279                                (long long)addr);
280                         errcnt += 1;
281                 }
282                 addr += subpgsize * k;
283         }
284
285         return err;
286 }
287
288 static int verify_eraseblock_ff(int ebnum)
289 {
290         uint32_t j;
291         size_t read = 0;
292         int err = 0;
293         loff_t addr = ebnum * mtd->erasesize;
294
295         memset(writebuf, 0xff, subpgsize);
296         for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
297                 clear_data(readbuf, subpgsize);
298                 read = 0;
299                 err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
300                 if (unlikely(err || read != subpgsize)) {
301                         if (err == -EUCLEAN && read == subpgsize) {
302                                 printk(PRINT_PREF "ECC correction at %#llx\n",
303                                        (long long)addr);
304                                 err = 0;
305                         } else {
306                                 printk(PRINT_PREF "error: read failed at "
307                                        "%#llx\n", (long long)addr);
308                                 return err ? err : -1;
309                         }
310                 }
311                 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
312                         printk(PRINT_PREF "error: verify 0xff failed at "
313                                "%#llx\n", (long long)addr);
314                         errcnt += 1;
315                 }
316                 addr += subpgsize;
317         }
318
319         return err;
320 }
321
322 static int verify_all_eraseblocks_ff(void)
323 {
324         int err;
325         unsigned int i;
326
327         printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
328         for (i = 0; i < ebcnt; ++i) {
329                 if (bbt[i])
330                         continue;
331                 err = verify_eraseblock_ff(i);
332                 if (err)
333                         return err;
334                 if (i % 256 == 0)
335                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
336                 cond_resched();
337         }
338         printk(PRINT_PREF "verified %u eraseblocks\n", i);
339         return 0;
340 }
341
342 static int is_block_bad(int ebnum)
343 {
344         loff_t addr = ebnum * mtd->erasesize;
345         int ret;
346
347         ret = mtd->block_isbad(mtd, addr);
348         if (ret)
349                 printk(PRINT_PREF "block %d is bad\n", ebnum);
350         return ret;
351 }
352
353 static int scan_for_bad_eraseblocks(void)
354 {
355         int i, bad = 0;
356
357         bbt = kzalloc(ebcnt, GFP_KERNEL);
358         if (!bbt) {
359                 printk(PRINT_PREF "error: cannot allocate memory\n");
360                 return -ENOMEM;
361         }
362
363         printk(PRINT_PREF "scanning for bad eraseblocks\n");
364         for (i = 0; i < ebcnt; ++i) {
365                 bbt[i] = is_block_bad(i) ? 1 : 0;
366                 if (bbt[i])
367                         bad += 1;
368                 cond_resched();
369         }
370         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
371         return 0;
372 }
373
374 static int __init mtd_subpagetest_init(void)
375 {
376         int err = 0;
377         uint32_t i;
378         uint64_t tmp;
379
380         printk(KERN_INFO "\n");
381         printk(KERN_INFO "=================================================\n");
382         printk(PRINT_PREF "MTD device: %d\n", dev);
383
384         mtd = get_mtd_device(NULL, dev);
385         if (IS_ERR(mtd)) {
386                 err = PTR_ERR(mtd);
387                 printk(PRINT_PREF "error: cannot get MTD device\n");
388                 return err;
389         }
390
391         if (mtd->type != MTD_NANDFLASH) {
392                 printk(PRINT_PREF "this test requires NAND flash\n");
393                 goto out;
394         }
395
396         subpgsize = mtd->writesize >> mtd->subpage_sft;
397         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
398                "page size %u, subpage size %u, count of eraseblocks %u, "
399                "pages per eraseblock %u, OOB size %u\n",
400                (unsigned long long)mtd->size, mtd->erasesize,
401                mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
402
403         err = -ENOMEM;
404         bufsize = subpgsize * 32;
405         writebuf = kmalloc(bufsize, GFP_KERNEL);
406         if (!writebuf) {
407                 printk(PRINT_PREF "error: cannot allocate memory\n");
408                 goto out;
409         }
410         readbuf = kmalloc(bufsize, GFP_KERNEL);
411         if (!readbuf) {
412                 printk(PRINT_PREF "error: cannot allocate memory\n");
413                 goto out;
414         }
415
416         tmp = mtd->size;
417         do_div(tmp, mtd->erasesize);
418         ebcnt = tmp;
419         pgcnt = mtd->erasesize / mtd->writesize;
420
421         err = scan_for_bad_eraseblocks();
422         if (err)
423                 goto out;
424
425         err = erase_whole_device();
426         if (err)
427                 goto out;
428
429         printk(PRINT_PREF "writing whole device\n");
430         simple_srand(1);
431         for (i = 0; i < ebcnt; ++i) {
432                 if (bbt[i])
433                         continue;
434                 err = write_eraseblock(i);
435                 if (unlikely(err))
436                         goto out;
437                 if (i % 256 == 0)
438                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
439                 cond_resched();
440         }
441         printk(PRINT_PREF "written %u eraseblocks\n", i);
442
443         simple_srand(1);
444         printk(PRINT_PREF "verifying all eraseblocks\n");
445         for (i = 0; i < ebcnt; ++i) {
446                 if (bbt[i])
447                         continue;
448                 err = verify_eraseblock(i);
449                 if (unlikely(err))
450                         goto out;
451                 if (i % 256 == 0)
452                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
453                 cond_resched();
454         }
455         printk(PRINT_PREF "verified %u eraseblocks\n", i);
456
457         err = erase_whole_device();
458         if (err)
459                 goto out;
460
461         err = verify_all_eraseblocks_ff();
462         if (err)
463                 goto out;
464
465         /* Write all eraseblocks */
466         simple_srand(3);
467         printk(PRINT_PREF "writing whole device\n");
468         for (i = 0; i < ebcnt; ++i) {
469                 if (bbt[i])
470                         continue;
471                 err = write_eraseblock2(i);
472                 if (unlikely(err))
473                         goto out;
474                 if (i % 256 == 0)
475                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
476                 cond_resched();
477         }
478         printk(PRINT_PREF "written %u eraseblocks\n", i);
479
480         /* Check all eraseblocks */
481         simple_srand(3);
482         printk(PRINT_PREF "verifying all eraseblocks\n");
483         for (i = 0; i < ebcnt; ++i) {
484                 if (bbt[i])
485                         continue;
486                 err = verify_eraseblock2(i);
487                 if (unlikely(err))
488                         goto out;
489                 if (i % 256 == 0)
490                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
491                 cond_resched();
492         }
493         printk(PRINT_PREF "verified %u eraseblocks\n", i);
494
495         err = erase_whole_device();
496         if (err)
497                 goto out;
498
499         err = verify_all_eraseblocks_ff();
500         if (err)
501                 goto out;
502
503         printk(PRINT_PREF "finished with %d errors\n", errcnt);
504
505 out:
506         kfree(bbt);
507         kfree(readbuf);
508         kfree(writebuf);
509         put_mtd_device(mtd);
510         if (err)
511                 printk(PRINT_PREF "error %d occurred\n", err);
512         printk(KERN_INFO "=================================================\n");
513         return err;
514 }
515 module_init(mtd_subpagetest_init);
516
517 static void __exit mtd_subpagetest_exit(void)
518 {
519         return;
520 }
521 module_exit(mtd_subpagetest_exit);
522
523 MODULE_DESCRIPTION("Subpage test module");
524 MODULE_AUTHOR("Adrian Hunter");
525 MODULE_LICENSE("GPL");