add nandsim patch to make the nandsim module useful
authorDennis Groenen <dennis_groenen@hotmail.com>
Fri, 28 Jan 2011 20:35:34 +0000 (21:35 +0100)
committerDennis Groenen <dennis_groenen@hotmail.com>
Fri, 28 Jan 2011 20:35:34 +0000 (21:35 +0100)
kernel-bfs-2.6.28/debian/patches/mtd-nandsim-add-cache_file-option.diff [new file with mode: 0644]
kernel-bfs-2.6.28/debian/patches/series

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 (file)
index 0000000..3d4dc0e
--- /dev/null
@@ -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 <linux/delay.h>
+ #include <linux/list.h>
+ #include <linux/random.h>
++#include <linux/fs.h>
++
++#include <asm/uaccess.h>
+ /* 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);
index 8af8cba..7f92140 100644 (file)
@@ -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