[JFFS2] Add support for JFFS2-on-Dataflash devices.
authorAndrew Victor <andrew@sanpeople.com>
Wed, 9 Feb 2005 09:17:45 +0000 (09:17 +0000)
committerThomas Gleixner <tglx@mtd.linutronix.de>
Mon, 23 May 2005 10:28:03 +0000 (12:28 +0200)
For Dataflash, can_mark_obsolete = false and the NAND write buffering
code (wbuf.c) is used.

Since the DataFlash chip will automatically erase pages when writing,
the cleanmarkers are not needed - so cleanmarker_oob = false and
cleanmarker_size = 0

DataFlash page-sizes are not a power of two (they're multiples of 528
bytes).  The SECTOR_ADDR macro (added in the previous core patch) is
replaced with a (slower) div/mod version if CONFIG_JFFS2_FS_DATAFLASH is
selected.

Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
fs/Kconfig
fs/jffs2/Makefile
fs/jffs2/erase.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jffs2/scan.c
fs/jffs2/wbuf.c
include/linux/jffs2_fs_sb.h
include/mtd/mtd-abi.h

index 6a4ad4bb7a54e836e039484d684f66e66f23c334..07835d24c78539a1a47da49ab39c517ac76d6987 100644 (file)
@@ -1084,6 +1084,13 @@ config JFFS2_FS_NOR_ECC
           ECC for JFFS2. This type of flash chip is not common, however it is
           available from ST Microelectronics.
 
+config JFFS2_FS_DATAFLASH
+       bool "JFFS2 support for DataFlash (EXPERIMENTAL)"
+       depends on JFFS2_FS && EXPERIMENTAL
+       default n
+       help
+         This enables the experimental support for JFFS2 on DataFlash devices.
+
 config JFFS2_COMPRESSION_OPTIONS
        bool "Advanced compression options for JFFS2"
        depends on JFFS2_FS
index e3c38ccf9c7d86fe9b9b503c25937ff2e1ffee31..6c2ebe176b4092dea14b6e4d705ea154c270232b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
+# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -13,6 +13,7 @@ jffs2-y       += super.o
 
 jffs2-$(CONFIG_JFFS2_FS_NAND)  += wbuf.o
 jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN)    += compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
index ae858f8788751fe9dea1e5af0b2a24fbd384fdbb..a3c6cc1504972a2b5d0abb52558b78a0949fe44f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $
+ * $Id: erase.c,v 1.71 2005/02/09 09:17:40 pavlov Exp $
  *
  */
 
@@ -310,7 +310,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
        int ret;
        uint32_t bad_offset;
 
-       if (!jffs2_cleanmarker_oob(c)) {
+       if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
                marker_ref = jffs2_alloc_raw_node_ref();
                if (!marker_ref) {
                        printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
@@ -351,7 +351,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                                        bad_offset += i;
                                        printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
                                bad: 
-                                       if (!jffs2_cleanmarker_oob(c))
+                                       if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
                                                jffs2_free_raw_node_ref(marker_ref);
                                        kfree(ebuf);
                                bad2:
@@ -383,6 +383,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                        
                jeb->first_node = jeb->last_node = NULL;
 
+               jeb->free_size = c->sector_size;
+               jeb->used_size = 0;
+               jeb->dirty_size = 0;
+               jeb->wasted_size = 0;
+       } else if (c->cleanmarker_size == 0) {
+               jeb->first_node = jeb->last_node = NULL;
+
                jeb->free_size = c->sector_size;
                jeb->used_size = 0;
                jeb->dirty_size = 0;
index 30ab233fe423010abcb7504796e56985ca565e93..5b7c960a047502ff6c6ea66fea377d47740b813b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
+ * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $
  *
  */
 
@@ -456,6 +456,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
                return -EINVAL;
        }
 #endif
+#ifndef CONFIG_JFFS2_FS_DATAFLASH
+       if (c->mtd->type == MTD_DATAFLASH) {
+               printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
+               return -EINVAL;
+       }
+#endif
 
        c->flash_size = c->mtd->size;
 
@@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
                if (ret)
                        return ret;
        }
+       
+       /* and Dataflash */
+       if (jffs2_dataflash(c)) {
+               ret = jffs2_dataflash_setup(c);
+               if (ret)
+                       return ret;
+       }
+       
        return ret;
 }
 
@@ -674,4 +688,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
        if (jffs2_nor_ecc(c)) {
                jffs2_nor_ecc_flash_cleanup(c);
        }
+       
+       /* and DataFlash */
+       if (jffs2_dataflash(c)) {
+               jffs2_dataflash_cleanup(c);
+       }
 }
index 0412416d1f2d026b5183a9de43caaf4ef96b18e5..af27b84007a1f5eceb040ada5f97117f58373a15 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $
+ * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $
  *
  */
 
@@ -97,12 +97,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #endif
 }
 
+#ifdef CONFIG_JFFS2_FS_DATAFLASH
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
+#else
 #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+#endif
 
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 #define jffs2_is_writebuffered(c) (c->wbuf != NULL)
 
-#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
+#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH)
 #define jffs2_can_mark_obsolete(c) (1)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -119,6 +123,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
 #define jffs2_nor_ecc(c) (0)
+#define jffs2_dataflash(c) (0)
 #define jffs2_nor_ecc_flash_setup(c) (0)
 #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
 
@@ -154,6 +159,15 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
 #define jffs2_nor_ecc_flash_setup(c) (0)
 #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
 #endif /* NOR ECC */
+#ifdef CONFIG_JFFS2_FS_DATAFLASH
+#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+#else
+#define jffs2_dataflash(c) (0)
+#define jffs2_dataflash_setup(c) (0)
+#define jffs2_dataflash_cleanup(c) do {} while (0)
+#endif /* DATAFLASH */
 #endif /* NAND */
 
 /* erase.c */
index 76859ff5343717049cb407d7f8de0ac3f9d1c466..e8c43746c82e42267184d59ef1d9dd52a724c90c 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $
+ * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $
  *
  */
 #include <linux/kernel.h>
@@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
 static inline int min_free(struct jffs2_sb_info *c)
 {
        uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
        if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
                return c->wbuf_pagesize;
 #endif
@@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                c->dirty_size -= c->nextblock->dirty_size;
                c->nextblock->dirty_size = 0;
        }
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
        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,
@@ -351,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                }
 #endif
                D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
-               return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
+               if (c->cleanmarker_size == 0)
+                       return BLK_STATE_CLEANMARKER;   /* don't bother with re-erase */
+               else
+                       return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
        }
        if (ofs) {
                D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
index 894dea88678dd8a9406c29a8c5a5950c2b079d81..a35e007e5bf84103106d37aa5163ac585b74f440 100644 (file)
@@ -9,7 +9,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $
+ * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $
  *
  */
 
@@ -435,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
           if we have a switch to next page, we will not have
           enough remaining space for this. 
        */
-       if (pad) {
+       if (pad && !jffs2_dataflash(c)) {
                c->wbuf_len = PAD(c->wbuf_len);
 
                /* Pad with JFFS2_DIRTY_BITMASK initially.  this helps out ECC'd NOR
@@ -486,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        spin_lock(&c->erase_completion_lock);
 
        /* Adjust free size of the block if we padded. */
-       if (pad) {
+       if (pad && !jffs2_dataflash(c)) {
                struct jffs2_eraseblock *jeb;
 
                jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -604,8 +604,14 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
        return ret;
 }
 
+#ifdef CONFIG_JFFS2_FS_DATAFLASH
+#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
+#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
+#else
 #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
 #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
+#endif
+
 int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
 {
        struct kvec outvecs[3];
@@ -1192,6 +1198,29 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
        kfree(c->wbuf);
 }
 
+#ifdef CONFIG_JFFS2_FS_DATAFLASH
+int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
+       c->cleanmarker_size = 0;                /* No cleanmarkers needed */
+       
+       /* Initialize write buffer */
+       init_rwsem(&c->wbuf_sem);
+       c->wbuf_pagesize = c->sector_size;
+       c->wbuf_ofs = 0xFFFFFFFF;
+
+       c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+       if (!c->wbuf)
+               return -ENOMEM;
+
+       printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
+
+       return 0;
+}
+
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
+       kfree(c->wbuf);
+}
+#endif
+
 #ifdef CONFIG_JFFS2_FS_NOR_ECC
 int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
        /* Cleanmarker is actually larger on the flashes */
index 4afc8d8c2e9e11d0e57ea176989ce30783c9ed78..faec29559fed5f9cbe6d62573e7ef5eb3bc312ef 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.49 2005/02/09 09:17:41 pavlov Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -94,7 +94,7 @@ struct jffs2_sb_info {
           to an obsoleted node. I don't like this. Alternatives welcomed. */
        struct semaphore erase_free_sem;
 
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
        /* Write-behind buffer for NAND flash */
        unsigned char *wbuf;
        uint32_t wbuf_ofs;
index c984cb2c9413b2ce3d5733c49a7d91cc76314eb3..cacb9842b19509b62d5c29844b0c6c0b8b7969c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd-abi.h,v 1.9 2005/02/08 17:45:52 nico Exp $
+ * $Id: mtd-abi.h,v 1.10 2005/02/09 09:17:42 pavlov Exp $
  *
  * Portions of MTD ABI definition which are shared by kernel and user space 
  */
@@ -29,6 +29,7 @@ struct mtd_oob_buf {
 #define MTD_NORFLASH           3
 #define MTD_NANDFLASH          4
 #define MTD_PEROM              5
+#define MTD_DATAFLASH          6
 #define MTD_OTHER              14
 #define MTD_UNKNOWN            15