1 --- linux-2.6.28.orig/drivers/mtd/nand/nandsim.c 2008-12-25 00:26:37.000000000 +0100
2 +++ linux-2.6.28/drivers/mtd/nand/nandsim.c 2011-01-28 15:36:55.284094498 +0100
4 #include <linux/delay.h>
5 #include <linux/list.h>
6 #include <linux/random.h>
9 +#include <asm/uaccess.h>
11 /* Default simulator parameters values */
12 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
13 @@ -100,6 +103,7 @@ static unsigned int bitflips = 0;
14 static char *gravepages = NULL;
15 static unsigned int rptwear = 0;
16 static unsigned int overridesize = 0;
17 +static char *cache_file = NULL;
19 module_param(first_id_byte, uint, 0400);
20 module_param(second_id_byte, uint, 0400);
21 @@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400)
22 module_param(gravepages, charp, 0400);
23 module_param(rptwear, uint, 0400);
24 module_param(overridesize, uint, 0400);
25 +module_param(cache_file, charp, 0400);
27 MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
28 MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
29 MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
30 MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
31 -MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)");
32 +MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)");
33 MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
34 MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
35 MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)");
36 @@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number
37 MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
38 "The size is specified in erase blocks and as the exponent of a power of two"
39 " e.g. 5 means a size of 32 erase blocks");
40 +MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
42 /* The largest possible page size */
43 #define NS_LARGEST_PAGE_SIZE 2048
44 @@ -335,6 +341,11 @@ struct nandsim {
45 int ale; /* address Latch Enable */
46 int wp; /* write Protect */
49 + /* Fields needed when using a cache file */
50 + struct file *cfile; /* Open file */
51 + unsigned char *pages_written; /* Which pages have been written */
56 @@ -427,11 +438,43 @@ static u_char ns_verify_buf[NS_LARGEST_P
58 static int alloc_device(struct nandsim *ns)
65 + cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0640);
67 + return PTR_ERR(cfile);
68 + if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) {
69 + NS_ERR("alloc_device: cache file not readable\n");
73 + if (!cfile->f_op->write && !cfile->f_op->aio_write) {
74 + NS_ERR("alloc_device: cache file not writeable\n");
78 + ns->pages_written = vmalloc(ns->geom.pgnum);
79 + if (!ns->pages_written) {
80 + NS_ERR("alloc_device: unable to allocate pages written array\n");
84 + ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
85 + if (!ns->file_buf) {
86 + NS_ERR("alloc_device: unable to allocate file buf\n");
91 + memset(ns->pages_written, 0, ns->geom.pgnum);
95 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
97 - NS_ERR("alloc_map: unable to allocate page array\n");
98 + NS_ERR("alloc_device: unable to allocate page array\n");
101 for (i = 0; i < ns->geom.pgnum; i++) {
102 @@ -439,6 +482,12 @@ static int alloc_device(struct nandsim *
108 + vfree(ns->pages_written);
110 + filp_close(cfile, NULL);
115 @@ -448,6 +497,13 @@ static void free_device(struct nandsim *
120 + kfree(ns->file_buf);
121 + vfree(ns->pages_written);
122 + filp_close(ns->cfile, NULL);
127 for (i = 0; i < ns->geom.pgnum; i++) {
128 if (ns->pages[i].byte)
129 @@ -1211,6 +1267,30 @@ static int find_operation(struct nandsim
133 +static ssize_t read_file(struct file *file, void *buf, size_t count, loff_t *pos)
135 + mm_segment_t old_fs;
140 + tx = vfs_read(file, (char __user *)buf, count, pos);
145 +static ssize_t write_file(struct file *file, void *buf, size_t count, loff_t *pos)
147 + mm_segment_t old_fs;
152 + tx = vfs_write(file, (char __user *)buf, count, pos);
158 * Returns a pointer to the current page.
160 @@ -1227,6 +1307,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(s
161 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
164 +int do_read_error(struct nandsim *ns, int num)
166 + unsigned int page_no = ns->regs.row;
168 + if (read_error(page_no)) {
170 + memset(ns->buf.byte, 0xFF, num);
171 + for (i = 0; i < num; ++i)
172 + ns->buf.byte[i] = random32();
173 + NS_WARN("simulating read error in page %u\n", page_no);
179 +void do_bit_flips(struct nandsim *ns, int num)
181 + if (bitflips && random32() < (1 << 22)) {
184 + flips = (random32() % (int) bitflips) + 1;
186 + int pos = random32() % (num * 8);
187 + ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
188 + NS_WARN("read_page: flipping bit %d in page %d "
189 + "reading from %d ecc: corrected=%u failed=%u\n",
190 + pos, ns->regs.row, ns->regs.column + ns->regs.off,
191 + nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
197 * Fill the NAND buffer with data read from the specified page.
199 @@ -1234,36 +1346,40 @@ static void read_page(struct nandsim *ns
201 union ns_mem *mypage;
204 + if (!ns->pages_written[ns->regs.row]) {
205 + NS_DBG("read_page: page %d not written\n", ns->regs.row);
206 + memset(ns->buf.byte, 0xFF, num);
211 + NS_DBG("read_page: page %d written, reading from %d\n",
212 + ns->regs.row, ns->regs.column + ns->regs.off);
213 + if (do_read_error(ns, num))
215 + pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
216 + tx = read_file(ns->cfile, ns->buf.byte, num, &pos);
218 + NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
221 + do_bit_flips(ns, num);
226 mypage = NS_GET_PAGE(ns);
227 if (mypage->byte == NULL) {
228 NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
229 memset(ns->buf.byte, 0xFF, num);
231 - unsigned int page_no = ns->regs.row;
232 NS_DBG("read_page: page %d allocated, reading from %d\n",
233 ns->regs.row, ns->regs.column + ns->regs.off);
234 - if (read_error(page_no)) {
236 - memset(ns->buf.byte, 0xFF, num);
237 - for (i = 0; i < num; ++i)
238 - ns->buf.byte[i] = random32();
239 - NS_WARN("simulating read error in page %u\n", page_no);
240 + if (do_read_error(ns, num))
243 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
244 - if (bitflips && random32() < (1 << 22)) {
247 - flips = (random32() % (int) bitflips) + 1;
249 - int pos = random32() % (num * 8);
250 - ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
251 - NS_WARN("read_page: flipping bit %d in page %d "
252 - "reading from %d ecc: corrected=%u failed=%u\n",
253 - pos, ns->regs.row, ns->regs.column + ns->regs.off,
254 - nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
257 + do_bit_flips(ns, num);
261 @@ -1275,6 +1391,15 @@ static void erase_sector(struct nandsim
262 union ns_mem *mypage;
266 + for (i = 0; i < ns->geom.pgsec; i++)
267 + if (ns->pages_written[ns->regs.row + i]) {
268 + NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
269 + ns->pages_written[ns->regs.row + i] = 0;
274 mypage = NS_GET_PAGE(ns);
275 for (i = 0; i < ns->geom.pgsec; i++) {
276 if (mypage->byte != NULL) {
277 @@ -1295,6 +1420,47 @@ static int prog_page(struct nandsim *ns,
278 union ns_mem *mypage;
286 + NS_DBG("prog_page: writing page %d\n", ns->regs.row);
287 + pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
288 + off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
289 + if (!ns->pages_written[ns->regs.row]) {
291 + memset(ns->file_buf, 0xff, ns->geom.pgszoob);
295 + tx = read_file(ns->cfile, pg_off, num, &pos);
297 + NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
301 + for (i = 0; i < num; i++)
302 + pg_off[i] &= ns->buf.byte[i];
304 + pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
305 + tx = write_file(ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos);
306 + if (tx != ns->geom.pgszoob) {
307 + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
310 + ns->pages_written[ns->regs.row] = 1;
313 + tx = write_file(ns->cfile, pg_off, num, &pos);
315 + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
322 mypage = NS_GET_PAGE(ns);
323 if (mypage->byte == NULL) {
324 NS_DBG("prog_page: allocating page %d\n", ns->regs.row);