• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/mtd/tests/
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
32static int dev;
33module_param(dev, int, S_IRUGO);
34MODULE_PARM_DESC(dev, "MTD device number to use");
35
36static struct mtd_info *mtd;
37static unsigned char *writebuf;
38static unsigned char *readbuf;
39static unsigned char *bbt;
40
41static int subpgsize;
42static int bufsize;
43static int ebcnt;
44static int pgcnt;
45static int errcnt;
46static unsigned long next = 1;
47
48static inline unsigned int simple_rand(void)
49{
50	next = next * 1103515245 + 12345;
51	return (unsigned int)((next / 65536) % 32768);
52}
53
54static inline void simple_srand(unsigned long seed)
55{
56	next = seed;
57}
58
59static 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
67static inline void clear_data(unsigned char *buf, size_t len)
68{
69	memset(buf, 0, len);
70}
71
72static 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
98static 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
116static 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
151static 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
179static 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
190static 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
253static 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
288static 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
322static 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
342static 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
353static 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
374static 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
505out:
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}
515module_init(mtd_subpagetest_init);
516
517static void __exit mtd_subpagetest_exit(void)
518{
519	return;
520}
521module_exit(mtd_subpagetest_exit);
522
523MODULE_DESCRIPTION("Subpage test module");
524MODULE_AUTHOR("Adrian Hunter");
525MODULE_LICENSE("GPL");
526