[JFFS2] Add support for JFFS2-on-Dataflash devices.

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>
This commit is contained in:
Andrew Victor 2005-02-09 09:17:45 +00:00 committed by Thomas Gleixner
parent 3be36675d4
commit 8f15fd55f9
9 changed files with 98 additions and 17 deletions

View File

@ -1084,6 +1084,13 @@ config JFFS2_FS_NOR_ECC
ECC for JFFS2. This type of flash chip is not common, however it is ECC for JFFS2. This type of flash chip is not common, however it is
available from ST Microelectronics. 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 config JFFS2_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2" bool "Advanced compression options for JFFS2"
depends on JFFS2_FS depends on JFFS2_FS

View 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_NAND) += wbuf.o
jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += 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_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o

View 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; int ret;
uint32_t bad_offset; 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(); marker_ref = jffs2_alloc_raw_node_ref();
if (!marker_ref) { if (!marker_ref) {
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); 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; bad_offset += i;
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
bad: bad:
if (!jffs2_cleanmarker_oob(c)) if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
jffs2_free_raw_node_ref(marker_ref); jffs2_free_raw_node_ref(marker_ref);
kfree(ebuf); kfree(ebuf);
bad2: 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->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->free_size = c->sector_size;
jeb->used_size = 0; jeb->used_size = 0;
jeb->dirty_size = 0; jeb->dirty_size = 0;

View 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; return -EINVAL;
} }
#endif #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) if (ret)
return 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)) { if (jffs2_nor_ecc(c)) {
jffs2_nor_ecc_flash_cleanup(c); jffs2_nor_ecc_flash_cleanup(c);
} }
/* and DataFlash */
if (jffs2_dataflash(c)) {
jffs2_dataflash_cleanup(c);
}
} }

View 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_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
#define jffs2_is_writebuffered(c) (c->wbuf != NULL) #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_can_mark_obsolete(c) (1)
#define jffs2_cleanmarker_oob(c) (0) #define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) #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_timeout NULL
#define jffs2_wbuf_process NULL #define jffs2_wbuf_process NULL
#define jffs2_nor_ecc(c) (0) #define jffs2_nor_ecc(c) (0)
#define jffs2_dataflash(c) (0)
#define jffs2_nor_ecc_flash_setup(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_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_setup(c) (0)
#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
#endif /* NOR ECC */ #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 */ #endif /* NAND */
/* erase.c */ /* erase.c */

View 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) static inline int min_free(struct jffs2_sb_info *c)
{ {
uint32_t min = 2 * sizeof(struct jffs2_raw_inode); 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) if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
return c->wbuf_pagesize; return c->wbuf_pagesize;
#endif #endif
@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->dirty_size -= c->nextblock->dirty_size; c->dirty_size -= c->nextblock->dirty_size;
c->nextblock->dirty_size = 0; 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 (!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 /* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned, 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 #endif
D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); 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) { if (ofs) {
D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,

View 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 if we have a switch to next page, we will not have
enough remaining space for this. enough remaining space for this.
*/ */
if (pad) { if (pad && !jffs2_dataflash(c)) {
c->wbuf_len = PAD(c->wbuf_len); c->wbuf_len = PAD(c->wbuf_len);
/* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR /* 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); spin_lock(&c->erase_completion_lock);
/* Adjust free size of the block if we padded. */ /* Adjust free size of the block if we padded. */
if (pad) { if (pad && !jffs2_dataflash(c)) {
struct jffs2_eraseblock *jeb; struct jffs2_eraseblock *jeb;
jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; 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_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
#define PAGE_MOD(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) 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]; 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 #ifdef CONFIG_JFFS2_FS_NOR_ECC
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
/* Cleanmarker is actually larger on the flashes */ /* Cleanmarker is actually larger on the flashes */

View 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 #ifndef _JFFS2_FS_SB
#define _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. */ to an obsoleted node. I don't like this. Alternatives welcomed. */
struct semaphore erase_free_sem; 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 */ /* Write-behind buffer for NAND flash */
unsigned char *wbuf; unsigned char *wbuf;
uint32_t wbuf_ofs; uint32_t wbuf_ofs;

View 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_NORFLASH 3
#define MTD_NANDFLASH 4 #define MTD_NANDFLASH 4
#define MTD_PEROM 5 #define MTD_PEROM 5
#define MTD_DATAFLASH 6
#define MTD_OTHER 14 #define MTD_OTHER 14
#define MTD_UNKNOWN 15 #define MTD_UNKNOWN 15