From patchwork Tue Sep 23 16:50:38 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AYYANARPONNUSAMY GANGHEYAMOORTHY X-Patchwork-Id: 1132 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DE95FDE10D for ; Wed, 24 Sep 2008 02:49:23 +1000 (EST) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.68 #1 (Red Hat Linux)) id 1KiB3h-0000xy-UO; Tue, 23 Sep 2008 16:48:17 +0000 Received: from mailout2.samsung.com ([203.254.224.25]) by bombadil.infradead.org with esmtp (Exim 4.68 #1 (Red Hat Linux)) id 1KiB3g-0000xi-72 for linux-mtd@lists.infradead.org; Tue, 23 Sep 2008 16:48:16 +0000 Received: from epmmp2 (mailout2.samsung.com [203.254.224.25]) by mailout2.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTP id <0K7N000U0QOCB1@mailout2.samsung.com> for linux-mtd@lists.infradead.org; Wed, 24 Sep 2008 01:48:12 +0900 (KST) Received: from apgmoorthy ([107.108.214.61]) by mmp2.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTPA id <0K7N00E9RQOA56@mmp2.samsung.com> for linux-mtd@lists.infradead.org; Wed, 24 Sep 2008 01:48:12 +0900 (KST) Date: Tue, 23 Sep 2008 22:20:38 +0530 From: apgmoorthy Subject: RE: [PATCH 1/2] [MTD] [JFFS2] MLC NAND support In-reply-to: <9c9fda240809212333n76fa6cc6jbf1025f4f272d3f4@mail.gmail.com> To: 'Kyungmin Park' Message-id: <000001c91d9c$827a3300$3dd66c6b@sisodomain.com> MIME-version: 1.0 X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2900.3198 X-Mailer: Microsoft Office Outlook 11 Thread-index: AckcfRvRpHjbJTYxSBOldgVA0Q46NgBHtJlg References: <30508484.52991221827822859.JavaMail.weblogic@epml16> <9c9fda240809212333n76fa6cc6jbf1025f4f272d3f4@mail.gmail.com> X-Spam-Score: -4.0 (----) X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary: Content analysis details: (-4.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -4.0 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [203.254.224.25 listed in list.dnswl.org] Cc: linux-mtd@lists.infradead.org, David.Woodhouse@intel.com X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- #define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) --- 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; inr_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 */