[PATCH 1/2] [MTD] [JFFS2] MLC NAND support

apgmoorthy moorthy.apg at samsung.com
Tue Sep 23 12:50:38 EDT 2008


Hi,

Kyungmin Park wrote:

>> Currently JFFS2 writes twice to the first page of the block,
>> cleanmarker in OOB area and data in main area, which prevents
>> JFFS2 from being used on MLC devices which have NOP count 1.
>> This patch reserves the first page only for the cleanmarker.

>Is it reasonable to waste the first page at each blocks?
>It wastes 1/128 storages e.g., 512MiB/128 = 4MiB.
>How about to unuse the oob cleanmarker at previous email sent by me?

        - I will look into this.
     
>And small coding synmatic problem at patche. See below.

         - corrected those in the new patch 

 
Signed-off-by: Rajshekar H Payagond <rajshekar.hp at samsung.com>
---
--- a/fs/jffs2/build.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/build.c	2008-09-19 17:07:48.000000000 +0530
@@ -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);
--- a/fs/jffs2/debug.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/debug.c	2008-09-19 17:07:48.000000000 +0530
@@ -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);
 
--- a/fs/jffs2/erase.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/erase.c	2008-09-19 17:07:48.000000000 +0530
@@ -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))
--- a/fs/jffs2/gc.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/gc.c	2008-09-23 21:36:56.000000000 +0530
@@ -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);
 
--- a/fs/jffs2/nodelist.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/nodelist.c	2008-09-19 17:07:48.000000000 +0530
@@ -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);
 
--- a/fs/jffs2/nodemgmt.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/nodemgmt.c	2008-09-19 17:07:48.000000000 +0530
@@ -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
--- a/fs/jffs2/scan.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/scan.c	2008-09-19 17:07:48.000000000 +0530
@@ -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;
 
--- a/fs/jffs2/wbuf.c	2008-09-16 20:48:12.000000000 +0530
+++ b/fs/jffs2/wbuf.c	2008-09-19 17:07:48.000000000 +0530
@@ -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;
 		}
--- a/include/mtd/mtd-abi.h	2008-09-16 20:48:12.000000000 +0530
+++ b/include/mtd/mtd-abi.h	2008-09-23 22:09:18.000000000 +0530
@@ -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 */
 #define MTD_NANDECC_OFF		0	// Switch off ECC (Not
recommended)




More information about the linux-mtd mailing list