mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
[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:
parent
3be36675d4
commit
8f15fd55f9
9 changed files with 98 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue