public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
@ 2008-09-19 12:37 AYYANARPONNUSAMY GANGHEYAMOORTHY
  2008-09-19 14:50 ` Jason Liu
  2008-09-22  6:33 ` Kyungmin Park
  0 siblings, 2 replies; 11+ messages in thread
From: AYYANARPONNUSAMY GANGHEYAMOORTHY @ 2008-09-19 12:37 UTC (permalink / raw)
  To: linux-mtd; +Cc: David.Woodhouse

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.

Note : With robustness testing, one test board out six has
given a BUG. We are looking into it.

Signed-off-by: Rajshekar H Payagond <rajshekar.hp@samsung.com>
---
--- a/fs/jffs2/build.c	2008-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/build.c	2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/debug.c	2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/erase.c	2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/gc.c	2008-09-01 13:39:56.000000000 +0530
@@ -237,9 +237,19 @@ 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 +439,32 @@ 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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/nodelist.c	2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/nodemgmt.c	2008-09-01 16:15:47.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/scan.c	2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
+++ b/fs/jffs2/wbuf.c	2008-09-01 13:39:56.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-02 13:51:09.000000000 +0530
+++ b/include/mtd/mtd-abi.h	2008-09-02 13:51:42.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_WRITABLE_ONCE	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_WRITABLE_ONCE)
 
 /* ECC byte placement */
 #define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)



 
 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-19 12:37 [PATCH 1/2] [MTD] [JFFS2] MLC NAND support AYYANARPONNUSAMY GANGHEYAMOORTHY
@ 2008-09-19 14:50 ` Jason Liu
  2008-09-22  6:33 ` Kyungmin Park
  1 sibling, 0 replies; 11+ messages in thread
From: Jason Liu @ 2008-09-19 14:50 UTC (permalink / raw)
  To: moorthy.apg; +Cc: linux-mtd, David.Woodhouse

Could you send out the panic log? How do you perform the robustness test.
Currently, I found the jffs2 filesystem can't support MLC well. Not
long time ago,
I use the patch JFFS2 doesn't use OOB at MLC NAND/OneNAND from
Kyungmin Park <kyungmin.park at samsung.com> on Sumsung MLC nand flash
K9LAG08U0M, but sometimes i will meet BUG() on the jffs2 file system. I suspect
that that patch does not completely handle MLC nand flash well. How
about this patch?

2008/9/19 AYYANARPONNUSAMY GANGHEYAMOORTHY <moorthy.apg@samsung.com>:
> 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.
>
> Note : With robustness testing, one test board out six has
> given a BUG. We are looking into it.
>
> Signed-off-by: Rajshekar H Payagond <rajshekar.hp@samsung.com>
> ---
> --- a/fs/jffs2/build.c  2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/build.c  2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/debug.c  2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/erase.c  2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/gc.c     2008-09-01 13:39:56.000000000 +0530
> @@ -237,9 +237,19 @@ 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 +439,32 @@ 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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/nodelist.c       2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/nodemgmt.c       2008-09-01 16:15:47.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/scan.c   2008-09-01 13:39:56.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-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/wbuf.c   2008-09-01 13:39:56.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-02 13:51:09.000000000 +0530
> +++ b/include/mtd/mtd-abi.h     2008-09-02 13:51:42.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_WRITABLE_ONCE      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_WRITABLE_ONCE)
>
>  /* ECC byte placement */
>  #define MTD_NANDECC_OFF                0       // Switch off ECC (Not recommended)
>
>
>
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-19 12:37 [PATCH 1/2] [MTD] [JFFS2] MLC NAND support AYYANARPONNUSAMY GANGHEYAMOORTHY
  2008-09-19 14:50 ` Jason Liu
@ 2008-09-22  6:33 ` Kyungmin Park
  2008-09-23 16:50   ` apgmoorthy
  2008-09-29 12:22   ` apgmoorthy
  1 sibling, 2 replies; 11+ messages in thread
From: Kyungmin Park @ 2008-09-22  6:33 UTC (permalink / raw)
  To: moorthy.apg; +Cc: linux-mtd, David.Woodhouse

Hi,

On Fri, Sep 19, 2008 at 9:37 PM, AYYANARPONNUSAMY GANGHEYAMOORTHY
<moorthy.apg@samsung.com> 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'm not sure why the oob cleanmaker makes a problem at runtime?

And small coding synmatic problem at patche. See below.

Thank you,
Kyungmin Park

> Signed-off-by: Rajshekar H Payagond <rajshekar.hp@samsung.com>
> ---


> --- a/fs/jffs2/gc.c     2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/gc.c     2008-09-01 13:39:56.000000000 +0530
> @@ -237,9 +237,19 @@ 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;
> +               }
>        }

Please add 'else' after curly braces .

>
>        raw = jeb->gc_node;
> @@ -429,13 +439,32 @@ 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);

Ditto.



> --- a/include/mtd/mtd-abi.h     2008-09-02 13:51:09.000000000 +0530
> +++ b/include/mtd/mtd-abi.h     2008-09-02 13:51:42.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_WRITABLE_ONCE      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_WRITABLE_ONCE)
>

As previously, define MTD_OOB_WRITEABLE instead of WRITABLE_ONCE.
SLC NAND has WRITEABLE | OOB_WRITEABLE, but MLC NAND has WRITEABLE only

^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-22  6:33 ` Kyungmin Park
@ 2008-09-23 16:50   ` apgmoorthy
  2008-09-29 12:22   ` apgmoorthy
  1 sibling, 0 replies; 11+ messages in thread
From: apgmoorthy @ 2008-09-23 16:50 UTC (permalink / raw)
  To: 'Kyungmin Park'; +Cc: linux-mtd, David.Woodhouse

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@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)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-22  6:33 ` Kyungmin Park
  2008-09-23 16:50   ` apgmoorthy
@ 2008-09-29 12:22   ` apgmoorthy
  2008-09-30 12:07     ` Jason Liu
  1 sibling, 1 reply; 11+ messages in thread
From: apgmoorthy @ 2008-09-29 12:22 UTC (permalink / raw)
  To: 'Kyungmin Park'; +Cc: linux-mtd, David.Woodhouse

Hi,

In the earlier patch there was a typo , have rectified it and posting it
back.


Signed-off-by: Rajshekar H Payagond <rajshekar.hp@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 | MTD_OOB_WRITEABLE)
+#define MTD_CAP_MLCNANDFLASH	(MTD_WRITEABLE)
 
 /* ECC byte placement */
 #define MTD_NANDECC_OFF		0	// Switch off ECC (Not
recommended)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-29 12:22   ` apgmoorthy
@ 2008-09-30 12:07     ` Jason Liu
  2008-10-01  3:37       ` Amit Kumar Sharma
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Liu @ 2008-09-30 12:07 UTC (permalink / raw)
  To: apgmoorthy; +Cc: linux-mtd, Kyungmin Park, David.Woodhouse

Hi,
    I have looked into the log file. I notice the oops in the log
file is the same i often meet with MLC nand after apply  the patch
JFFS2 doesn't use OOB at MLC NAND/OneNAND from Kyungmin Park, it seems
that jffs2 file system may have serious issues. I have strong feeling
that jffs2 files system is far from production level at least for MLC
nand flash. David, do you have any comments?

2008/9/29 apgmoorthy <moorthy.apg@samsung.com>:
> Hi,
>
> In the earlier patch there was a typo , have rectified it and posting it
> back.
>
>
> Signed-off-by: Rajshekar H Payagond <rajshekar.hp@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 | MTD_OOB_WRITEABLE)
> +#define MTD_CAP_MLCNANDFLASH   (MTD_WRITEABLE)
>
>  /* ECC byte placement */
>  #define MTD_NANDECC_OFF                0       // Switch off ECC (Not
> recommended)
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-09-30 12:07     ` Jason Liu
@ 2008-10-01  3:37       ` Amit Kumar Sharma
  2008-10-01  5:52         ` Artem Bityutskiy
  0 siblings, 1 reply; 11+ messages in thread
From: Amit Kumar Sharma @ 2008-10-01  3:37 UTC (permalink / raw)
  To: Jason Liu, apgmoorthy; +Cc: Kyungmin Park, linux-mtd, David.Woodhouse

We are also facing many difficulty in robustness and 
reliability test with Jffs2 not only this we have tested our 
MLC patches on kernel 2.6.22 their Jffs2 stability was 
little bit higher as compare to  2.6.27 , not only this LTP 
file tests and rw test fails with Jffs2 and same driver 
works fine with yaffs2 but yaffs2 also has issue with 
Symlink operation  we are working for that.

Rgs
Amit
----- Original Message ----- 
From: "Jason Liu" <liu.h.jason@gmail.com>
To: "apgmoorthy" <moorthy.apg@samsung.com>
Cc: <linux-mtd@lists.infradead.org>; "Kyungmin Park" 
<kmpark@infradead.org>; <David.Woodhouse@intel.com>
Sent: Tuesday, September 30, 2008 5:37 PM
Subject: Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support


> Hi,
>    I have looked into the log file. I notice the oops in 
> the log
> file is the same i often meet with MLC nand after apply 
> the patch
> JFFS2 doesn't use OOB at MLC NAND/OneNAND from Kyungmin 
> Park, it seems
> that jffs2 file system may have serious issues. I have 
> strong feeling
> that jffs2 files system is far from production level at 
> least for MLC
> nand flash. David, do you have any comments?
>
> 2008/9/29 apgmoorthy <moorthy.apg@samsung.com>:
>> Hi,
>>
>> In the earlier patch there was a typo , have rectified it 
>> and posting it
>> back.
>>
>>
>> Signed-off-by: Rajshekar H Payagond 
>> <rajshekar.hp@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 | 
>> MTD_OOB_WRITEABLE)
>> +#define MTD_CAP_MLCNANDFLASH   (MTD_WRITEABLE)
>>
>>  /* ECC byte placement */
>>  #define MTD_NANDECC_OFF                0       // Switch 
>> off ECC (Not
>> recommended)
>>
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/ 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-10-01  3:37       ` Amit Kumar Sharma
@ 2008-10-01  5:52         ` Artem Bityutskiy
  2008-10-01  9:44           ` Amit Kumar Sharma
  0 siblings, 1 reply; 11+ messages in thread
From: Artem Bityutskiy @ 2008-10-01  5:52 UTC (permalink / raw)
  To: Amit Kumar Sharma
  Cc: Jason Liu, apgmoorthy, Kyungmin Park, David.Woodhouse, linux-mtd

Hi,

On Wed, 2008-10-01 at 09:07 +0530, Amit Kumar Sharma wrote:
> We are also facing many difficulty in robustness and 
> reliability test with Jffs2 not only this we have tested our 
> MLC patches on kernel 2.6.22 their Jffs2 stability was 
> little bit higher as compare to  2.6.27 , not only this LTP 
> file tests and rw test fails with Jffs2 and same driver 
> works fine with yaffs2 but yaffs2 also has issue with 
> Symlink operation  we are working for that.

Have you tries UBIFS?

-- 
Best regards,
Artem Bityutskiy (Битюцкий Артём)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-10-01  5:52         ` Artem Bityutskiy
@ 2008-10-01  9:44           ` Amit Kumar Sharma
  2008-10-01  9:52             ` Artem Bityutskiy
  0 siblings, 1 reply; 11+ messages in thread
From: Amit Kumar Sharma @ 2008-10-01  9:44 UTC (permalink / raw)
  To: dedekind; +Cc: Jason Liu, apgmoorthy, Kyungmin Park, David.Woodhouse, linux-mtd

no we have started working for UBIFS , very soon we will 
start working for UBIFS , let u know results.
----- Original Message ----- 
From: "Artem Bityutskiy" <dedekind@infradead.org>
To: "Amit Kumar Sharma" <amitsharma.9@samsung.com>
Cc: "Jason Liu" <liu.h.jason@gmail.com>; "apgmoorthy" 
<moorthy.apg@samsung.com>; "Kyungmin Park" 
<kmpark@infradead.org>; <David.Woodhouse@intel.com>; 
<linux-mtd@lists.infradead.org>
Sent: Wednesday, October 01, 2008 11:22 AM
Subject: Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support


> Hi,
>
> On Wed, 2008-10-01 at 09:07 +0530, Amit Kumar Sharma 
> wrote:
>> We are also facing many difficulty in robustness and
>> reliability test with Jffs2 not only this we have tested 
>> our
>> MLC patches on kernel 2.6.22 their Jffs2 stability was
>> little bit higher as compare to  2.6.27 , not only this 
>> LTP
>> file tests and rw test fails with Jffs2 and same driver
>> works fine with yaffs2 but yaffs2 also has issue with
>> Symlink operation  we are working for that.
>
> Have you tries UBIFS?
>
> -- 
> Best regards,
> Artem Bityutskiy (???????? ?????)
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-10-01  9:44           ` Amit Kumar Sharma
@ 2008-10-01  9:52             ` Artem Bityutskiy
  2008-10-03  5:59               ` Amit Kumar Sharma
  0 siblings, 1 reply; 11+ messages in thread
From: Artem Bityutskiy @ 2008-10-01  9:52 UTC (permalink / raw)
  To: Amit Kumar Sharma
  Cc: Jason Liu, apgmoorthy, Kyungmin Park, David.Woodhouse, linux-mtd


On Wed, 2008-10-01 at 15:14 +0530, Amit Kumar Sharma wrote:
> no we have started working for UBIFS , very soon we will 
> start working for UBIFS , let u know results.

Note, JFFS2 is not really suitable for MLC because it has
random wear-leveling algorithm, and it may erase one eraseblock
thousands of times, while erasing the other eraseblock only hundreds of
times.

In UBI you may set the WL threshold to control this. Also, JFFS2
does not really help with read-disturb problem, but this is fixable.

UBI refreshes data when it meets a bit-flip.

However, UBIFS is not really ready to handle this paired page problem.
I mean, in MLC, if you interrupt power during write operation, this
may result in corruptions in one of the previous NAND page. The only
simple way to fix this is to make UBIFS assume that min. I/O unit size
is not one NAND page, but several pages, so that both paired NAND pages
were in one min. I/O unit.

-- 
Best regards,
Artem Bityutskiy (Битюцкий Артём)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support
  2008-10-01  9:52             ` Artem Bityutskiy
@ 2008-10-03  5:59               ` Amit Kumar Sharma
  0 siblings, 0 replies; 11+ messages in thread
From: Amit Kumar Sharma @ 2008-10-03  5:59 UTC (permalink / raw)
  To: dedekind; +Cc: Jason Liu, apgmoorthy, Kyungmin Park, David.Woodhouse, linux-mtd

Thanks Artem for pre information , your information I hope 
will be useful for us and we will consider your points 
during UBIFS with OneNAND-FlexOneNAND.
----- Original Message ----- 
From: "Artem Bityutskiy" <dedekind@infradead.org>
To: "Amit Kumar Sharma" <amitsharma.9@samsung.com>
Cc: "Jason Liu" <liu.h.jason@gmail.com>; "apgmoorthy" 
<moorthy.apg@samsung.com>; "Kyungmin Park" 
<kmpark@infradead.org>; <David.Woodhouse@intel.com>; 
<linux-mtd@lists.infradead.org>
Sent: Wednesday, October 01, 2008 3:22 PM
Subject: Re: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support


>
> On Wed, 2008-10-01 at 15:14 +0530, Amit Kumar Sharma 
> wrote:
>> no we have started working for UBIFS , very soon we will
>> start working for UBIFS , let u know results.
>
> Note, JFFS2 is not really suitable for MLC because it has
> random wear-leveling algorithm, and it may erase one 
> eraseblock
> thousands of times, while erasing the other eraseblock 
> only hundreds of
> times.
>
> In UBI you may set the WL threshold to control this. Also, 
> JFFS2
> does not really help with read-disturb problem, but this 
> is fixable.
>
> UBI refreshes data when it meets a bit-flip.
>
> However, UBIFS is not really ready to handle this paired 
> page problem.
> I mean, in MLC, if you interrupt power during write 
> operation, this
> may result in corruptions in one of the previous NAND 
> page. The only
> simple way to fix this is to make UBIFS assume that min. 
> I/O unit size
> is not one NAND page, but several pages, so that both 
> paired NAND pages
> were in one min. I/O unit.
>
> -- 
> Best regards,
> Artem Bityutskiy (???????? ?????)
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-10-03  5:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-19 12:37 [PATCH 1/2] [MTD] [JFFS2] MLC NAND support AYYANARPONNUSAMY GANGHEYAMOORTHY
2008-09-19 14:50 ` Jason Liu
2008-09-22  6:33 ` Kyungmin Park
2008-09-23 16:50   ` apgmoorthy
2008-09-29 12:22   ` apgmoorthy
2008-09-30 12:07     ` Jason Liu
2008-10-01  3:37       ` Amit Kumar Sharma
2008-10-01  5:52         ` Artem Bityutskiy
2008-10-01  9:44           ` Amit Kumar Sharma
2008-10-01  9:52             ` Artem Bityutskiy
2008-10-03  5:59               ` Amit Kumar Sharma

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox