[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 6a4ad4b..07835d2 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.
 
           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
 config JFFS2_COMPRESSION_OPTIONS
        bool "Advanced compression options for JFFS2"
        depends on JFFS2_FS
index e3c38cc..6c2ebe1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
 #
 # 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
 #
 
 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_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
 jffs2-$(CONFIG_JFFS2_RUBIN)    += compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
index ae858f8..a3c6cc1 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  *
  * 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;
 
        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");
                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: 
                                        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:
                                                jffs2_free_raw_node_ref(marker_ref);
                                        kfree(ebuf);
                                bad2:
@@ -387,6 +387,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                jeb->used_size = 0;
                jeb->dirty_size = 0;
                jeb->wasted_size = 0;
                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;
+               jeb->wasted_size = 0;
        } else {
                struct kvec vecs[1];
                struct jffs2_unknown_node marker = {
        } else {
                struct kvec vecs[1];
                struct jffs2_unknown_node marker = {
index 30ab233..5b7c960 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  *
  * 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
                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;
 
 
        c->flash_size = c->mtd->size;
 
@@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
                if (ret)
                        return ret;
        }
                if (ret)
                        return ret;
        }
+       
+       /* and Dataflash */
+       if (jffs2_dataflash(c)) {
+               ret = jffs2_dataflash_setup(c);
+               if (ret)
+                       return 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);
        }
        if (jffs2_nor_ecc(c)) {
                jffs2_nor_ecc_flash_cleanup(c);
        }
+       
+       /* and DataFlash */
+       if (jffs2_dataflash(c)) {
+               jffs2_dataflash_cleanup(c);
+       }
 }
 }
index 0412416..af27b84 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  *
  * 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
 }
 
 #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)) )
 #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)
 
 
 #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)
 #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_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)
 
 #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 */
 #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 */
 #endif /* NAND */
 
 /* erase.c */
index 76859ff..e8c4374 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  *
  * 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>
  *
  */
 #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);
 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
        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;
        }
                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,
        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));
                }
 #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,
        }
        if (ofs) {
                D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
index 894dea8..a35e007 100644 (file)
@@ -9,7 +9,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  *
  * 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 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
                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. */
        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];
                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;
 }
 
        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) )
 #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];
 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);
 }
 
        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 */
 #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 4afc8d8..faec295 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
 
 #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;
 
           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;
        /* Write-behind buffer for NAND flash */
        unsigned char *wbuf;
        uint32_t wbuf_ofs;
index c984cb2..cacb984 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 
  */
  *
  * 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_NORFLASH           3
 #define MTD_NANDFLASH          4
 #define MTD_PEROM              5
+#define MTD_DATAFLASH          6
 #define MTD_OTHER              14
 #define MTD_UNKNOWN            15
 
 #define MTD_OTHER              14
 #define MTD_UNKNOWN            15