From ad75f39dc303438a2033b6b7e31433ac838fea30 Mon Sep 17 00:00:00 2001 From: Dennis Groenen Date: Fri, 28 Jan 2011 21:35:34 +0100 Subject: [PATCH] add nandsim patch to make the nandsim module useful --- .../patches/mtd-nandsim-add-cache_file-option.diff | 324 ++++++++++++++++++++ kernel-bfs-2.6.28/debian/patches/series | 1 + 2 files changed, 325 insertions(+) create mode 100644 kernel-bfs-2.6.28/debian/patches/mtd-nandsim-add-cache_file-option.diff diff --git a/kernel-bfs-2.6.28/debian/patches/mtd-nandsim-add-cache_file-option.diff b/kernel-bfs-2.6.28/debian/patches/mtd-nandsim-add-cache_file-option.diff new file mode 100644 index 0000000..3d4dc0e --- /dev/null +++ b/kernel-bfs-2.6.28/debian/patches/mtd-nandsim-add-cache_file-option.diff @@ -0,0 +1,324 @@ +--- linux-2.6.28.orig/drivers/mtd/nand/nandsim.c 2008-12-25 00:26:37.000000000 +0100 ++++ linux-2.6.28/drivers/mtd/nand/nandsim.c 2011-01-28 15:36:55.284094498 +0100 +@@ -38,6 +38,9 @@ + #include + #include + #include ++#include ++ ++#include + + /* Default simulator parameters values */ + #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ +@@ -100,6 +103,7 @@ static unsigned int bitflips = 0; + static char *gravepages = NULL; + static unsigned int rptwear = 0; + static unsigned int overridesize = 0; ++static char *cache_file = NULL; + + module_param(first_id_byte, uint, 0400); + module_param(second_id_byte, uint, 0400); +@@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400) + module_param(gravepages, charp, 0400); + module_param(rptwear, uint, 0400); + module_param(overridesize, uint, 0400); ++module_param(cache_file, charp, 0400); + + MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); + MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); + MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); + MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); +-MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); ++MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); + MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); + MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); + MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); +@@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number + MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " + "The size is specified in erase blocks and as the exponent of a power of two" + " e.g. 5 means a size of 32 erase blocks"); ++MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); + + /* The largest possible page size */ + #define NS_LARGEST_PAGE_SIZE 2048 +@@ -335,6 +341,11 @@ struct nandsim { + int ale; /* address Latch Enable */ + int wp; /* write Protect */ + } lines; ++ ++ /* Fields needed when using a cache file */ ++ struct file *cfile; /* Open file */ ++ unsigned char *pages_written; /* Which pages have been written */ ++ void *file_buf; + }; + + /* +@@ -427,11 +438,43 @@ static u_char ns_verify_buf[NS_LARGEST_P + */ + static int alloc_device(struct nandsim *ns) + { +- int i; ++ struct file *cfile; ++ int i, err; ++ ++ if (cache_file) { ++ cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0640); ++ if (IS_ERR(cfile)) ++ return PTR_ERR(cfile); ++ if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { ++ NS_ERR("alloc_device: cache file not readable\n"); ++ err = -EINVAL; ++ goto err_close; ++ } ++ if (!cfile->f_op->write && !cfile->f_op->aio_write) { ++ NS_ERR("alloc_device: cache file not writeable\n"); ++ err = -EINVAL; ++ goto err_close; ++ } ++ ns->pages_written = vmalloc(ns->geom.pgnum); ++ if (!ns->pages_written) { ++ NS_ERR("alloc_device: unable to allocate pages written array\n"); ++ err = -ENOMEM; ++ goto err_close; ++ } ++ ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); ++ if (!ns->file_buf) { ++ NS_ERR("alloc_device: unable to allocate file buf\n"); ++ err = -ENOMEM; ++ goto err_free; ++ } ++ ns->cfile = cfile; ++ memset(ns->pages_written, 0, ns->geom.pgnum); ++ return 0; ++ } + + ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); + if (!ns->pages) { +- NS_ERR("alloc_map: unable to allocate page array\n"); ++ NS_ERR("alloc_device: unable to allocate page array\n"); + return -ENOMEM; + } + for (i = 0; i < ns->geom.pgnum; i++) { +@@ -439,6 +482,12 @@ static int alloc_device(struct nandsim * + } + + return 0; ++ ++err_free: ++ vfree(ns->pages_written); ++err_close: ++ filp_close(cfile, NULL); ++ return err; + } + + /* +@@ -448,6 +497,13 @@ static void free_device(struct nandsim * + { + int i; + ++ if (ns->cfile) { ++ kfree(ns->file_buf); ++ vfree(ns->pages_written); ++ filp_close(ns->cfile, NULL); ++ return; ++ } ++ + if (ns->pages) { + for (i = 0; i < ns->geom.pgnum; i++) { + if (ns->pages[i].byte) +@@ -1211,6 +1267,30 @@ static int find_operation(struct nandsim + return -1; + } + ++static ssize_t read_file(struct file *file, void *buf, size_t count, loff_t *pos) ++{ ++ mm_segment_t old_fs; ++ ssize_t tx; ++ ++ old_fs = get_fs(); ++ set_fs(get_ds()); ++ tx = vfs_read(file, (char __user *)buf, count, pos); ++ set_fs(old_fs); ++ return tx; ++} ++ ++static ssize_t write_file(struct file *file, void *buf, size_t count, loff_t *pos) ++{ ++ mm_segment_t old_fs; ++ ssize_t tx; ++ ++ old_fs = get_fs(); ++ set_fs(get_ds()); ++ tx = vfs_write(file, (char __user *)buf, count, pos); ++ set_fs(old_fs); ++ return tx; ++} ++ + /* + * Returns a pointer to the current page. + */ +@@ -1227,6 +1307,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(s + return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; + } + ++int do_read_error(struct nandsim *ns, int num) ++{ ++ unsigned int page_no = ns->regs.row; ++ ++ if (read_error(page_no)) { ++ int i; ++ memset(ns->buf.byte, 0xFF, num); ++ for (i = 0; i < num; ++i) ++ ns->buf.byte[i] = random32(); ++ NS_WARN("simulating read error in page %u\n", page_no); ++ return 1; ++ } ++ return 0; ++} ++ ++void do_bit_flips(struct nandsim *ns, int num) ++{ ++ if (bitflips && random32() < (1 << 22)) { ++ int flips = 1; ++ if (bitflips > 1) ++ flips = (random32() % (int) bitflips) + 1; ++ while (flips--) { ++ int pos = random32() % (num * 8); ++ ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); ++ NS_WARN("read_page: flipping bit %d in page %d " ++ "reading from %d ecc: corrected=%u failed=%u\n", ++ pos, ns->regs.row, ns->regs.column + ns->regs.off, ++ nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); ++ } ++ } ++} ++ + /* + * Fill the NAND buffer with data read from the specified page. + */ +@@ -1234,36 +1346,40 @@ static void read_page(struct nandsim *ns + { + union ns_mem *mypage; + ++ if (ns->cfile) { ++ if (!ns->pages_written[ns->regs.row]) { ++ NS_DBG("read_page: page %d not written\n", ns->regs.row); ++ memset(ns->buf.byte, 0xFF, num); ++ } else { ++ loff_t pos; ++ ssize_t tx; ++ ++ NS_DBG("read_page: page %d written, reading from %d\n", ++ ns->regs.row, ns->regs.column + ns->regs.off); ++ if (do_read_error(ns, num)) ++ return; ++ pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; ++ tx = read_file(ns->cfile, ns->buf.byte, num, &pos); ++ if (tx != num) { ++ NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); ++ return; ++ } ++ do_bit_flips(ns, num); ++ } ++ return; ++ } ++ + mypage = NS_GET_PAGE(ns); + if (mypage->byte == NULL) { + NS_DBG("read_page: page %d not allocated\n", ns->regs.row); + memset(ns->buf.byte, 0xFF, num); + } else { +- unsigned int page_no = ns->regs.row; + NS_DBG("read_page: page %d allocated, reading from %d\n", + ns->regs.row, ns->regs.column + ns->regs.off); +- if (read_error(page_no)) { +- int i; +- memset(ns->buf.byte, 0xFF, num); +- for (i = 0; i < num; ++i) +- ns->buf.byte[i] = random32(); +- NS_WARN("simulating read error in page %u\n", page_no); ++ if (do_read_error(ns, num)) + return; +- } + memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); +- if (bitflips && random32() < (1 << 22)) { +- int flips = 1; +- if (bitflips > 1) +- flips = (random32() % (int) bitflips) + 1; +- while (flips--) { +- int pos = random32() % (num * 8); +- ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); +- NS_WARN("read_page: flipping bit %d in page %d " +- "reading from %d ecc: corrected=%u failed=%u\n", +- pos, ns->regs.row, ns->regs.column + ns->regs.off, +- nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); +- } +- } ++ do_bit_flips(ns, num); + } + } + +@@ -1275,6 +1391,15 @@ static void erase_sector(struct nandsim + union ns_mem *mypage; + int i; + ++ if (ns->cfile) { ++ for (i = 0; i < ns->geom.pgsec; i++) ++ if (ns->pages_written[ns->regs.row + i]) { ++ NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); ++ ns->pages_written[ns->regs.row + i] = 0; ++ } ++ return; ++ } ++ + mypage = NS_GET_PAGE(ns); + for (i = 0; i < ns->geom.pgsec; i++) { + if (mypage->byte != NULL) { +@@ -1295,6 +1420,47 @@ static int prog_page(struct nandsim *ns, + union ns_mem *mypage; + u_char *pg_off; + ++ if (ns->cfile) { ++ loff_t off, pos; ++ ssize_t tx; ++ int all; ++ ++ NS_DBG("prog_page: writing page %d\n", ns->regs.row); ++ pg_off = ns->file_buf + ns->regs.column + ns->regs.off; ++ off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; ++ if (!ns->pages_written[ns->regs.row]) { ++ all = 1; ++ memset(ns->file_buf, 0xff, ns->geom.pgszoob); ++ } else { ++ all = 0; ++ pos = off; ++ tx = read_file(ns->cfile, pg_off, num, &pos); ++ if (tx != num) { ++ NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); ++ return -1; ++ } ++ } ++ for (i = 0; i < num; i++) ++ pg_off[i] &= ns->buf.byte[i]; ++ if (all) { ++ pos = (loff_t)ns->regs.row * ns->geom.pgszoob; ++ tx = write_file(ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); ++ if (tx != ns->geom.pgszoob) { ++ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); ++ return -1; ++ } ++ ns->pages_written[ns->regs.row] = 1; ++ } else { ++ pos = off; ++ tx = write_file(ns->cfile, pg_off, num, &pos); ++ if (tx != num) { ++ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); ++ return -1; ++ } ++ } ++ return 0; ++ } ++ + mypage = NS_GET_PAGE(ns); + if (mypage->byte == NULL) { + NS_DBG("prog_page: allocating page %d\n", ns->regs.row); diff --git a/kernel-bfs-2.6.28/debian/patches/series b/kernel-bfs-2.6.28/debian/patches/series index 8af8cba..7f92140 100644 --- a/kernel-bfs-2.6.28/debian/patches/series +++ b/kernel-bfs-2.6.28/debian/patches/series @@ -47,3 +47,4 @@ i2c-battery.diff usbhostmode.diff bt-mice.diff #vanilla-2.6.28-anti-io-stalling.patch +mtd-nandsim-add-cache_file-option.diff -- 1.7.9.5