@@ -330,7 +330,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
int i;
int size;
- c->free_size = c->flash_size;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
+ c->free_size = 0;
+ else
+ c->free_size = c->flash_size;
+
c->nr_blocks = c->flash_size / c->sector_size;
size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
#ifndef __ECOS
@@ -346,7 +350,14 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
for (i=0; i<c->nr_blocks; i++) {
INIT_LIST_HEAD(&c->blocks[i].list);
c->blocks[i].offset = i * c->sector_size;
- c->blocks[i].free_size = c->sector_size;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ c->blocks[i].free_size =
+ c->sector_size - c->wbuf_pagesize;
+ c->blocks[i].used_size = c->wbuf_pagesize;
+ c->free_size += c->blocks[i].free_size;
+ c->used_size += c->blocks[i].used_size;
+ } else
+ c->blocks[i].free_size = c->sector_size;
}
INIT_LIST_HEAD(&c->clean_list);
@@ -307,6 +307,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(s
uint32_t my_dirty_size = 0;
struct jffs2_raw_node_ref *ref2 = jeb->first_node;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
+ my_used_size = c->wbuf_pagesize;
+
while (ref2) {
uint32_t totlen = ref_totlen(c, jeb, ref2);
@@ -454,13 +454,21 @@ static void jffs2_mark_erased_block(stru
}
}
/* Everything else got zeroed before the erase */
- jeb->free_size = c->sector_size;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ jeb->free_size = c->sector_size - c->wbuf_pagesize;
+ jeb->used_size = c->wbuf_pagesize;
+ } else
+ jeb->free_size = c->sector_size;
mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
c->erasing_size -= c->sector_size;
- c->free_size += c->sector_size;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ c->free_size += c->sector_size - c->wbuf_pagesize;
+ c->used_size += c->wbuf_pagesize;
+ } else
+ c->free_size += c->sector_size;
/* Account for cleanmarker now, if it's in-band */
if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c))
@@ -237,9 +237,17 @@ int jffs2_garbage_collect_pass(struct jf
D1(if (c->nextblock)
printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size
%08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset,
c->nextblock->used_size, c->nextblock->dirty_size,
c->nextblock->wasted_size, c->nextblock->free_size));
- if (!jeb->used_size) {
- mutex_unlock(&c->alloc_sem);
- goto eraseit;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ if (jeb->used_size <= c->wbuf_pagesize) {
+ mutex_unlock(&c->alloc_sem);
+ goto eraseit;
+ }
+
+ } else{
+ if (!jeb->used_size) {
+ mutex_unlock(&c->alloc_sem);
+ goto eraseit;
+ }
}
raw = jeb->gc_node;
@@ -429,13 +437,30 @@ int jffs2_garbage_collect_pass(struct jf
spin_lock(&c->erase_completion_lock);
eraseit:
- if (c->gcblock && !c->gcblock->used_size) {
- D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted
by GC. Moving to erase_pending_list\n", c->gcblock->offset));
- /* We're GC'ing an empty block? */
- list_add_tail(&c->gcblock->list, &c->erase_pending_list);
- c->gcblock = NULL;
- c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ if (c->gcblock && (c->gcblock->used_size <=
c->wbuf_pagesize)) {
+ D1(printk(KERN_DEBUG "Block at 0x%08x completely"
+ " obsoleted by GC. Moving to
erase_pending_list\n"
+ , c->gcblock->offset));
+ /* We're GC'ing an empty block? */
+ list_add_tail(&c->gcblock->list,
+ &c->erase_pending_list);
+ c->gcblock = NULL;
+ c->nr_erasing_blocks++;
+ jffs2_erase_pending_trigger(c);
+ }
+ } else{
+ if (c->gcblock && !c->gcblock->used_size) {
+ D1(printk(KERN_DEBUG "Block at 0x%08x completely"
+ " obsoleted by GC. Moving to
erase_pending_list\n"
+ , c->gcblock->offset));
+ /* We're GC'ing an empty block? */
+ list_add_tail(&c->gcblock->list,
+ &c->erase_pending_list);
+ c->gcblock = NULL;
+ c->nr_erasing_blocks++;
+ jffs2_erase_pending_trigger(c);
+ }
}
spin_unlock(&c->erase_completion_lock);
@@ -634,7 +634,11 @@ struct jffs2_raw_node_ref *jffs2_link_no
if (!jeb->first_node) {
jeb->first_node = ref;
- BUG_ON(ref_offset(ref) != jeb->offset);
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
+ BUG_ON(ref_offset(ref) !=
+ jeb->offset +
c->wbuf_pagesize);
+ else
+ BUG_ON(ref_offset(ref) != jeb->offset);
} else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size
- jeb->free_size)) {
uint32_t last_len = ref_totlen(c, jeb, jeb->last_node);
@@ -362,16 +362,25 @@ static int jffs2_do_reserve_space(struct
}
if (!jeb) {
-
ret = jffs2_find_nextblock(c);
if (ret)
return ret;
jeb = c->nextblock;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ if (jeb->free_size != c->sector_size -
+ c->cleanmarker_size - c->wbuf_pagesize) {
+ printk(KERN_WARNING "Eep. Block 0x%08x taken
from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
+ goto restart;
+ }
+ }
- if (jeb->free_size != c->sector_size - c->cleanmarker_size)
{
- printk(KERN_WARNING "Eep. Block 0x%08x taken from
free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
- goto restart;
+ else{
+ if (jeb->free_size != c->sector_size -
+ c->cleanmarker_size) {
+ printk(KERN_WARNING "Eep. Block 0x%08x taken
from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
+ goto restart;
+ }
}
}
/* OK, jeb (==c->nextblock) is now pointing at a block which
definitely has
@@ -534,7 +534,10 @@ static int jffs2_scan_eraseblock (struct
}
}
- buf_ofs = jeb->offset;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
+ buf_ofs = jeb->offset + c->wbuf_pagesize;
+ else
+ buf_ofs = jeb->offset;
if (!buf_size) {
/* This is the XIP case -- we're reading _directly_ from the
flash chip */
@@ -582,7 +585,10 @@ static int jffs2_scan_eraseblock (struct
}
/* Now ofs is a complete physical flash offset as it always was...
*/
- ofs += jeb->offset;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
+ ofs += jeb->offset + c->wbuf_pagesize;
+ else
+ ofs += jeb->offset;
noise = 10;
@@ -873,6 +873,13 @@ int jffs2_flash_writev(struct jffs2_sb_i
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
c->wbuf_ofs = outvec_to;
+ if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
+ /* adjust write buffer offset,
+ * else we get a non contiguous write bug
+ */
+ if (!(c->wbuf_ofs % c->sector_size))
+ c->wbuf_ofs = 0xffffffff;
+ }
donelen += wbuf_retlen;
v += wbuf_retlen;
}
@@ -28,12 +28,14 @@ struct mtd_oob_buf {
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
+#define MTD_OOB_WRITEABLE 0x4000
// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE |
MTD_NO_ERASE)
#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
+#define MTD_CAP_MLCNANDFLASH (MTD_WRITEABLE | MTD_OOB_WRITEABLE)
/* ECC byte placement */