Merge branch 'drm-ttm-unmappable' into drm-core-next
[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 = kmalloc(ebcnt, GFP_KERNEL);
358         if (!bbt) {
359                 printk(PRINT_PREF "error: cannot allocate memory\n");
360                 return -ENOMEM;
361         }
362         memset(bbt, 0 , ebcnt);
363
364         printk(PRINT_PREF "scanning for bad eraseblocks\n");
365         for (i = 0; i < ebcnt; ++i) {
366                 bbt[i] = is_block_bad(i) ? 1 : 0;
367                 if (bbt[i])
368                         bad += 1;
369                 cond_resched();
370         }
371         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
372         return 0;
373 }
374
375 static int __init mtd_subpagetest_init(void)
376 {
377         int err = 0;
378         uint32_t i;
379         uint64_t tmp;
380
381         printk(KERN_INFO "\n");
382         printk(KERN_INFO "=================================================\n");
383         printk(PRINT_PREF "MTD device: %d\n", dev);
384
385         mtd = get_mtd_device(NULL, dev);
386         if (IS_ERR(mtd)) {
387                 err = PTR_ERR(mtd);
388                 printk(PRINT_PREF "error: cannot get MTD device\n");
389                 return err;
390         }
391
392         if (mtd->type != MTD_NANDFLASH) {
393                 printk(PRINT_PREF "this test requires NAND flash\n");
394                 goto out;
395         }
396
397         subpgsize = mtd->writesize >> mtd->subpage_sft;
398         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
399                "page size %u, subpage size %u, count of eraseblocks %u, "
400                "pages per eraseblock %u, OOB size %u\n",
401                (unsigned long long)mtd->size, mtd->erasesize,
402                mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
403
404         err = -ENOMEM;
405         bufsize = subpgsize * 32;
406         writebuf = kmalloc(bufsize, GFP_KERNEL);
407         if (!writebuf) {
408                 printk(PRINT_PREF "error: cannot allocate memory\n");
409                 goto out;
410         }
411         readbuf = kmalloc(bufsize, GFP_KERNEL);
412         if (!readbuf) {
413                 printk(PRINT_PREF "error: cannot allocate memory\n");
414                 goto out;
415         }
416
417         tmp = mtd->size;
418         do_div(tmp, mtd->erasesize);
419         ebcnt = tmp;
420         pgcnt = mtd->erasesize / mtd->writesize;
421
422         err = scan_for_bad_eraseblocks();
423         if (err)
424                 goto out;
425
426         err = erase_whole_device();
427         if (err)
428                 goto out;
429
430         printk(PRINT_PREF "writing whole device\n");
431         simple_srand(1);
432         for (i = 0; i < ebcnt; ++i) {
433                 if (bbt[i])
434                         continue;
435                 err = write_eraseblock(i);
436                 if (unlikely(err))
437                         goto out;
438                 if (i % 256 == 0)
439                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
440                 cond_resched();
441         }
442         printk(PRINT_PREF "written %u eraseblocks\n", i);
443
444         simple_srand(1);
445         printk(PRINT_PREF "verifying all eraseblocks\n");
446         for (i = 0; i < ebcnt; ++i) {
447                 if (bbt[i])
448                         continue;
449                 err = verify_eraseblock(i);
450                 if (unlikely(err))
451                         goto out;
452                 if (i % 256 == 0)
453                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
454                 cond_resched();
455         }
456         printk(PRINT_PREF "verified %u eraseblocks\n", i);
457
458         err = erase_whole_device();
459         if (err)
460                 goto out;
461
462         err = verify_all_eraseblocks_ff();
463         if (err)
464                 goto out;
465
466         /* Write all eraseblocks */
467         simple_srand(3);
468         printk(PRINT_PREF "writing whole device\n");
469         for (i = 0; i < ebcnt; ++i) {
470                 if (bbt[i])
471                         continue;
472                 err = write_eraseblock2(i);
473                 if (unlikely(err))
474                         goto out;
475                 if (i % 256 == 0)
476                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
477                 cond_resched();
478         }
479         printk(PRINT_PREF "written %u eraseblocks\n", i);
480
481         /* Check all eraseblocks */
482         simple_srand(3);
483         printk(PRINT_PREF "verifying all eraseblocks\n");
484         for (i = 0; i < ebcnt; ++i) {
485                 if (bbt[i])
486                         continue;
487                 err = verify_eraseblock2(i);
488                 if (unlikely(err))
489                         goto out;
490                 if (i % 256 == 0)
491                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
492                 cond_resched();
493         }
494         printk(PRINT_PREF "verified %u eraseblocks\n", i);
495
496         err = erase_whole_device();
497         if (err)
498                 goto out;
499
500         err = verify_all_eraseblocks_ff();
501         if (err)
502                 goto out;
503
504         printk(PRINT_PREF "finished with %d errors\n", errcnt);
505
506 out:
507         kfree(bbt);
508         kfree(readbuf);
509         kfree(writebuf);
510         put_mtd_device(mtd);
511         if (err)
512                 printk(PRINT_PREF "error %d occurred\n", err);
513         printk(KERN_INFO "=================================================\n");
514         return err;
515 }
516 module_init(mtd_subpagetest_init);
517
518 static void __exit mtd_subpagetest_exit(void)
519 {
520         return;
521 }
522 module_exit(mtd_subpagetest_exit);
523
524 MODULE_DESCRIPTION("Subpage test module");
525 MODULE_AUTHOR("Adrian Hunter");
526 MODULE_LICENSE("GPL");