aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-12-08 06:34:16 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-12-08 06:56:14 -0500
commite73f217439c7f3e49f9c0048bd04cb77ba656e66 (patch)
tree367b1e7758c95f0d3655fd654f574c105fbad3e9 /drivers/mtd
parente3644da7563d844e94b186a468e480c5575a6572 (diff)
MTD: tests: add mtd_pagetest
This test checks that NAND pages read/write work fine. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/tests/mtd_pagetest.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
new file mode 100644
index 000000000000..9648818b9e2c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -0,0 +1,632 @@
1/*
2 * Copyright (C) 2006-2008 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 page read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <asm/div64.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/err.h>
27#include <linux/mtd/mtd.h>
28#include <linux/sched.h>
29
30#define PRINT_PREF KERN_INFO "mtd_pagetest: "
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 *twopages;
38static unsigned char *writebuf;
39static unsigned char *boundary;
40static unsigned char *bbt;
41
42static int pgsize;
43static int bufsize;
44static int ebcnt;
45static int pgcnt;
46static int errcnt;
47static unsigned long next = 1;
48
49static inline unsigned int simple_rand(void)
50{
51 next = next * 1103515245 + 12345;
52 return (unsigned int)((next / 65536) % 32768);
53}
54
55static inline void simple_srand(unsigned long seed)
56{
57 next = seed;
58}
59
60static void set_random_data(unsigned char *buf, size_t len)
61{
62 size_t i;
63
64 for (i = 0; i < len; ++i)
65 buf[i] = simple_rand();
66}
67
68static int erase_eraseblock(int ebnum)
69{
70 int err;
71 struct erase_info ei;
72 loff_t addr = ebnum * mtd->erasesize;
73
74 memset(&ei, 0, sizeof(struct erase_info));
75 ei.mtd = mtd;
76 ei.addr = addr;
77 ei.len = mtd->erasesize;
78
79 err = mtd->erase(mtd, &ei);
80 if (err) {
81 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
82 return err;
83 }
84
85 if (ei.state == MTD_ERASE_FAILED) {
86 printk(PRINT_PREF "some erase error occurred at EB %d\n",
87 ebnum);
88 return -EIO;
89 }
90
91 return 0;
92}
93
94static int write_eraseblock(int ebnum)
95{
96 int err = 0;
97 size_t written = 0;
98 loff_t addr = ebnum * mtd->erasesize;
99
100 set_random_data(writebuf, mtd->erasesize);
101 cond_resched();
102 err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
103 if (err || written != mtd->erasesize)
104 printk(PRINT_PREF "error: write failed at %#llx\n",
105 (long long)addr);
106
107 return err;
108}
109
110static int verify_eraseblock(int ebnum)
111{
112 uint32_t j;
113 size_t read = 0;
114 int err = 0, i;
115 loff_t addr0, addrn;
116 loff_t addr = ebnum * mtd->erasesize;
117
118 addr0 = 0;
119 for (i = 0; bbt[i] && i < ebcnt; ++i)
120 addr0 += mtd->erasesize;
121
122 addrn = mtd->size;
123 for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
124 addrn -= mtd->erasesize;
125
126 set_random_data(writebuf, mtd->erasesize);
127 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
128 /* Do a read to set the internal dataRAMs to different data */
129 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
130 if (err == -EUCLEAN)
131 err = 0;
132 if (err || read != bufsize) {
133 printk(PRINT_PREF "error: read failed at %#llx\n",
134 (long long)addr0);
135 return err;
136 }
137 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
138 if (err == -EUCLEAN)
139 err = 0;
140 if (err || read != bufsize) {
141 printk(PRINT_PREF "error: read failed at %#llx\n",
142 (long long)(addrn - bufsize));
143 return err;
144 }
145 memset(twopages, 0, bufsize);
146 read = 0;
147 err = mtd->read(mtd, addr, bufsize, &read, twopages);
148 if (err == -EUCLEAN)
149 err = 0;
150 if (err || read != bufsize) {
151 printk(PRINT_PREF "error: read failed at %#llx\n",
152 (long long)addr);
153 break;
154 }
155 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
156 printk(PRINT_PREF "error: verify failed at %#llx\n",
157 (long long)addr);
158 errcnt += 1;
159 }
160 }
161 /* Check boundary between eraseblocks */
162 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
163 unsigned long oldnext = next;
164 /* Do a read to set the internal dataRAMs to different data */
165 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
166 if (err == -EUCLEAN)
167 err = 0;
168 if (err || read != bufsize) {
169 printk(PRINT_PREF "error: read failed at %#llx\n",
170 (long long)addr0);
171 return err;
172 }
173 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
174 if (err == -EUCLEAN)
175 err = 0;
176 if (err || read != bufsize) {
177 printk(PRINT_PREF "error: read failed at %#llx\n",
178 (long long)(addrn - bufsize));
179 return err;
180 }
181 memset(twopages, 0, bufsize);
182 read = 0;
183 err = mtd->read(mtd, addr, bufsize, &read, twopages);
184 if (err == -EUCLEAN)
185 err = 0;
186 if (err || read != bufsize) {
187 printk(PRINT_PREF "error: read failed at %#llx\n",
188 (long long)addr);
189 return err;
190 }
191 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);