最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

[patch] add support for ECC’d NOR chips to JFFS2

工作和技术 crifan 1784浏览 0评论

[patch] add support for ECC’d NOR chips to JFFS2



Hi all,

Below is a patch that adds support to JFFS2 for the ECC'd NOR flash
chips from STMicro.  These specific chips use the cfi_cmdset_0020.c
driver that's been in the MTD tree for a couple years now.

Basically, these chips are NOR flash that has transparent ECC.  Because
of the ECC, an erase needs to be done before a page can be written to
again, very similar to NAND flash.  In order to accomplish this, a wbuf
type mechanism is needed.

The patch adds a new config option, CONFIG_JFFS2_FS_NOR_ECC.  I'm not
too fond of this, but in the interest of not differing from the current
MTD code for now, that is what was done.  I'm always open for discussion
:).

Please consider accepting the patch for inclusion into CVS. 
Questions/comments are welcome.

Thanks,
josh

Signed-off-by: Josh Boyer <[email protected]>

diff -Naur -x CVS mtd/fs/jffs2/erase.c mtd.cvs/fs/jffs2/erase.c
--- mtd/fs/jffs2/erase.c 2004-10-21 13:15:09.000000000 -0500
+++ mtd.cvs/fs/jffs2/erase.c 2004-10-22 08:50:17.000000000 -0500
@@ -395,7 +395,15 @@
   marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
 
   /* We only write the header; the rest was noise or padding anyway */
-  ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
+  /* Q: why can't we use jffs2_flash_write?
+     A: because we aren't holding alloc_sem here...  which is worse,
+     grabbing alloc_sem to write out the marker, or just writing it...
+     i think grabbing alloc_sem, so we just write it */
+  if (jffs2_nor_ecc(c))
+   ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
+  else
+   ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
+  
   if (ret) {
    printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %dn",
           jeb->offset, ret);
diff -Naur -x CVS mtd/fs/jffs2/fs.c mtd.cvs/fs/jffs2/fs.c
--- mtd/fs/jffs2/fs.c 2004-07-13 03:56:54.000000000 -0500
+++ mtd.cvs/fs/jffs2/fs.c 2004-08-16 08:41:48.000000000 -0500
@@ -649,6 +649,11 @@
  }
 
  /* add setups for other bizarre flashes here... */
+ if (jffs2_nor_ecc(c)) {
+  ret = jffs2_nor_ecc_flash_setup(c);
+  if (ret)
+   return ret;
+ }
  return ret;
 }
 
@@ -659,4 +664,7 @@
  }
 
  /* add cleanups for other bizarre flashes here... */
+ if (jffs2_nor_ecc(c)) {
+  jffs2_nor_ecc_flash_cleanup(c);
+ }
 }
diff -Naur -x CVS mtd/fs/jffs2/Makefile.common mtd.cvs/fs/jffs2/Makefile.common
--- mtd/fs/jffs2/Makefile.common 2004-07-16 10:17:57.000000000 -0500
+++ mtd.cvs/fs/jffs2/Makefile.common 2004-08-16 08:41:48.000000000 -0500
@@ -12,6 +12,7 @@
 jffs2-y += super.o
 
 jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
diff -Naur -x CVS mtd/fs/jffs2/os-linux.h mtd.cvs/fs/jffs2/os-linux.h
--- mtd/fs/jffs2/os-linux.h 2004-07-14 08:20:23.000000000 -0500
+++ mtd.cvs/fs/jffs2/os-linux.h 2004-08-16 08:41:48.000000000 -0500
@@ -99,7 +99,7 @@
 
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
-#ifndef CONFIG_JFFS2_FS_NAND
+#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
 #define jffs2_can_mark_obsolete(c) (1)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -116,9 +116,9 @@
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
 
-#else /* NAND support present */
+#else /* NAND and/or ECC'd NOR support present */
 
-#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
+#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
@@ -135,8 +135,19 @@
 int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 void jffs2_wbuf_timeout(unsigned long data);
 void jffs2_wbuf_process(void *data);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
+#ifdef CONFIG_JFFS2_FS_NOR_ECC
+#define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
+#else
+#define jffs2_nor_ecc(c) (0)
+#define jffs2_nor_ecc_flash_setup (0)
+#define jffs2_nor_ecc_flash_cleanup do {} while (0)
+#endif /* NOR ECC */
 #endif /* NAND */
 
 /* erase.c */
diff -Naur -x CVS mtd/fs/jffs2/scan.c mtd.cvs/fs/jffs2/scan.c
--- mtd/fs/jffs2/scan.c 2004-09-12 04:56:13.000000000 -0500
+++ mtd.cvs/fs/jffs2/scan.c 2004-09-13 14:13:57.000000000 -0500
@@ -68,7 +68,7 @@
 static inline int min_free(struct jffs2_sb_info *c)
 {
  uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
  if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
   return c->wbuf_pagesize;
 #endif
@@ -223,7 +223,7 @@
   c->dirty_size -= c->nextblock->dirty_size;
   c->nextblock->dirty_size = 0;
  }
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
  if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
   /* If we're going to start writing into a block which already 
      contains data, and the end of the data isn't page-aligned,
diff -Naur -x CVS mtd/fs/jffs2/wbuf.c mtd.cvs/fs/jffs2/wbuf.c
--- mtd/fs/jffs2/wbuf.c 2004-09-11 14:22:43.000000000 -0500
+++ mtd.cvs/fs/jffs2/wbuf.c 2004-09-13 14:16:40.000000000 -0500
@@ -224,7 +224,11 @@
   }
 
   /* Do the read... */
-  ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
+  if (jffs2_cleanmarker_oob(c))
+   ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
+  else
+   ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
+  
   if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
    /* ECC recovered */
    ret = 0;
@@ -281,8 +285,11 @@
    ret = -EIO;
   } else
 #endif
+  if (jffs2_cleanmarker_oob(c))
    ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
       buf, NULL, c->oobinfo);
+  else
+   ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
 
   if (ret || retlen != towrite) {
    /* Argh. We tried. Really we did. */
@@ -419,6 +426,10 @@
  */
  if (pad) {
   c->wbuf_len = PAD(c->wbuf_len);
+
+  /* Pad with JFFS2_DIRTY_BITMASK initially.  this helps out ECC'd NOR
+     with 8 byte page size */
+  memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
   
   if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
    struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
@@ -426,9 +437,6 @@
    padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
    padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
    padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
-  } else {
-   /* Pad with JFFS2_DIRTY_BITMASK */
-   memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
   }
  }
  /* else jffs2_flash_writev has actually filled in the rest of the
@@ -444,8 +452,11 @@
   ret = -EIO;
  } else 
 #endif
- ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
-
+ 
+ if (jffs2_cleanmarker_oob(c))
+  ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
+ else
+  ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
 
  if (ret || retlen != c->wbuf_pagesize) {
   if (ret)
@@ -582,6 +593,17 @@
   memset(c->wbuf,0xff,c->wbuf_pagesize);
  }
 
+ /* Fixup the wbuf if we are moving to a new eraseblock.  The checks below
+    fail for ECC'd NOR because cleanmarker == 16, so a block starts at
+    xxx0010.  */
+ if (jffs2_nor_ecc(c)) {
+  if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) {
+   c->wbuf_ofs = PAGE_DIV(to);
+   c->wbuf_len = PAGE_MOD(to);
+   memset(c->wbuf,0xff,c->wbuf_pagesize);
+  }
+ }
+ 
  /* Sanity checks on target address. 
     It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 
     and it's permitted to write at the beginning of a new 
@@ -715,7 +737,11 @@
   outvecs[splitvec].iov_len = split_ofs;
 
   /* We did cross a page boundary, so we write some now */
-  ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
+  if (jffs2_cleanmarker_oob(c))
+   ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
+  else
+   ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
+  
   if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
    /* At this point we have no problem,
       c->wbuf is empty. 
@@ -789,7 +815,10 @@
 
  /* Read flash */
  if (!jffs2_can_mark_obsolete(c)) {
-  ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+  if (jffs2_cleanmarker_oob(c))
+   ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+  else
+   ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
 
   if ( (ret == -EBADMSG) && (*retlen == len) ) {
    printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC errorn",
@@ -1105,3 +1134,22 @@
 {
  kfree(c->wbuf);
 }
+
+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
+ /* Cleanmarker is actually larger on the flashes */
+ c->cleanmarker_size = 16;
+
+ /* Initialize write buffer */
+ c->wbuf_pagesize = c->mtd->eccsize;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+  return -ENOMEM;
+
+ return 0;
+}
+
+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
+ kfree(c->wbuf);
+}
diff -Naur -x CVS mtd/fs/Kconfig mtd.cvs/fs/Kconfig
--- mtd/fs/Kconfig 2004-07-16 10:20:59.000000000 -0500
+++ mtd.cvs/fs/Kconfig 2004-08-16 08:41:48.000000000 -0500
@@ -68,6 +68,15 @@
    Say 'N' unless you have NAND flash and you are willing to test and
    develop JFFS2 support for it.
 
+config JFFS2_FS_NOR_ECC
+ bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)"
+    depends on JFFS2_FS && EXPERIMENTAL
+    default n
+    help
+      This enables the experimental support for NOR flash with transparent
+   ECC for JFFS2.  This type of flash chip is not common, however it is
+   available from STMicro.
+
 config JFFS2_COMPRESSION_OPTIONS
  bool "Advanced compression options for JFFS2"
  default n
diff -Naur -x CVS mtd/include/linux/jffs2_fs_sb.h mtd.cvs/include/linux/jffs2_fs_sb.h
--- mtd/include/linux/jffs2_fs_sb.h 2003-10-08 06:46:27.000000000 -0500
+++ mtd.cvs/include/linux/jffs2_fs_sb.h 2004-08-16 08:41:48.000000000 -0500
@@ -95,7 +95,7 @@
     to an obsoleted node. I don't like this. Alternatives welcomed. */
  struct semaphore erase_free_sem;
 
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
  /* Write-behind buffer for NAND flash */
  unsigned char *wbuf;
  uint32_t wbuf_ofs;

To unsubscribe from this list: send the line "unsubscribe jffs-dev" in
the body of a message to [email protected]

转载请注明:在路上 » [patch] add support for ECC’d NOR chips to JFFS2

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
79 queries in 0.178 seconds, using 22.11MB memory