[From nobody Sun May 17 03:26:20 2009
X-Account-Key: account2
X-Mozilla-Keys: 
Received: from mx04.mfg.onr.siteprotect.com (unknown [192.168.33.225])
	by mf29.mfg.onr.chicago.hostway (Postfix) with ESMTP id C5EFD12001E
	for &lt;troy.kisky@boundarydevices.com&gt;;
	Wed, 13 May 2009 22:00:17 -0500 (CDT)
Received: from mpls-qmqp-05.inet.qwest.net (mpls-qmqp-05.inet.qwest.net
	[63.231.195.116])
	by mx04.mfg.onr.siteprotect.com (Postfix) with ESMTP id ADCE420B4068
	for &lt;troy.kisky@boundarydevices.com&gt;;
	Wed, 13 May 2009 22:00:17 -0500 (CDT)
Received: from localhost (unknown [67.42.45.38])
	by mpls-qmqp-05.inet.qwest.net (Postfix) with ESMTP id 112516278AA;
	Thu, 14 May 2009 03:00:15 +0000 (UTC)
Received: by localhost (Postfix, from userid 1002)
	id 6BD3E588192; Wed, 13 May 2009 20:00:09 -0700 (MST)
From: Troy Kisky &lt;troy.kisky@boundarydevices.com&gt;
To: linux-mtd@lists.infradead.org
Cc: david-b@pacbell.net, Troy Kisky &lt;troy.kisky@boundarydevices.com&gt;
Subject: [PATCH 2/5] mtd: nand: Calculate better default ecc layout
Date: Wed, 13 May 2009 20:00:05 -0700
Message-Id: &lt;1242270008-1552-2-git-send-email-troy.kisky@boundarydevices.com&gt;
X-Mailer: git-send-email 1.5.4.3
In-Reply-To: &lt;1242270008-1552-1-git-send-email-troy.kisky@boundarydevices.com&gt;
References: &lt;&gt;
	&lt;1242270008-1552-1-git-send-email-troy.kisky@boundarydevices.com&gt;
Mail-Filter-Gateway: Found to be Virus Free
X-Mail-Filter-Gateway-SpamDetectionEngine: NOT SPAM,
	MailFilterGateway Engine (Not Cached, Score=-1, Score Required 3,
	autolearn=disabled, CTASD_SPAM_UNKNOWN -1.00)
X-Mail-Filter-Gateway-From: tkisky@boundarydevices.com
X-Mail-Filter-Gateway-To: troy.kisky@boundarydevices.com
X-Spam-Status: No

This saves lines of code by having nand_base
calculate oob_free entries.

Boards that don't specify a layout and don't
use all ecc bytes in the current default layout
could have their ecc position changed.

Looking through the code, I can only see that
Davinci is effected this way. It has its ecc
bytes moved to the end of the oob data, which
is why I want this patch. Before, it was wasting
a lot of oob bytes.

Some boards will print warning messages. i.e.
mxc_nand which specifies ecc.bytes = 3, but
eccbytes = 5 (not a multiple of 3).

I may have missed other boards being affected
so it needs through testing.

Signed-off-by: Troy Kisky &lt;troy.kisky@boundarydevices.com&gt;
---
 drivers/mtd/nand/nand_base.c |  186 ++++++++++++++++++++++++++----------------
 1 files changed, 114 insertions(+), 72 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 2780a9b..6505d87 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -52,50 +52,6 @@
 #include &lt;linux/mtd/partitions.h&gt;
 #endif
 
-/* Define default oob placement schemes for large and small page devices */
-static struct nand_ecclayout nand_oob_8 = {
-	.eccbytes = 3,
-	.eccpos = {0, 1, 2},
-	.oobfree = {
-		{.offset = 3,
-		 .length = 2},
-		{.offset = 6,
-		 .length = 2}}
-};
-
-static struct nand_ecclayout nand_oob_16 = {
-	.eccbytes = 6,
-	.eccpos = {0, 1, 2, 3, 6, 7},
-	.oobfree = {
-		{.offset = 8,
-		 . length = 8}}
-};
-
-static struct nand_ecclayout nand_oob_64 = {
-	.eccbytes = 24,
-	.eccpos = {
-		   40, 41, 42, 43, 44, 45, 46, 47,
-		   48, 49, 50, 51, 52, 53, 54, 55,
-		   56, 57, 58, 59, 60, 61, 62, 63},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 38}}
-};
-
-static struct nand_ecclayout nand_oob_128 = {
-	.eccbytes = 48,
-	.eccpos = {
-		   80, 81, 82, 83, 84, 85, 86, 87,
-		   88, 89, 90, 91, 92, 93, 94, 95,
-		   96, 97, 98, 99, 100, 101, 102, 103,
-		   104, 105, 106, 107, 108, 109, 110, 111,
-		   112, 113, 114, 115, 116, 117, 118, 119,
-		   120, 121, 122, 123, 124, 125, 126, 127},
-	.oobfree = {
-		{.offset = 2,
-		 .length = 78}}
-};
-
 static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
 			   int new_state);
 
@@ -2627,7 +2583,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
  */
 int nand_scan_tail(struct mtd_info *mtd)
 {
-	int i;
+	int i, len, bit, next_bit;
+	int bad_block_marker_offset;
+	int bad_block_marker_length;
+	DECLARE_BITMAP(in_use, 256);
 	struct nand_chip *chip = mtd-&gt;priv;
 
 	if (!(chip-&gt;options &amp; NAND_OWN_BUFFERS))
@@ -2737,42 +2696,125 @@ int nand_scan_tail(struct mtd_info *mtd)
 		BUG();
 	}
 	chip-&gt;ecc.total = chip-&gt;ecc.steps * chip-&gt;ecc.bytes;
+	pr_info(&quot;%s ecc.total = %d, ecc.steps = %d, ecc.bytes = %d, &quot;
+		&quot;ecc.size = %d, writesize = %d\n&quot;,
+		__func__, chip-&gt;ecc.total, chip-&gt;ecc.steps, chip-&gt;ecc.bytes,
+		chip-&gt;ecc.size, mtd-&gt;writesize);
+try_again:
+	bad_block_marker_offset = 0;
+	bad_block_marker_length = 2;
+	if (mtd-&gt;oobsize == 8) {
+		bad_block_marker_offset = 5;
+		bad_block_marker_length = 1;
+	} else if (mtd-&gt;oobsize == 16) {
+		bad_block_marker_offset = 4;	/* length still 2 */
+	}
+	if (chip-&gt;bbt_td) {
+		bad_block_marker_offset = chip-&gt;bbt_td-&gt;offs;
+		bad_block_marker_length = chip-&gt;bbt_td-&gt;len;
+	}
+	if (chip-&gt;badblock_pattern) {
+		bad_block_marker_offset = chip-&gt;badblock_pattern-&gt;offs;
+		bad_block_marker_length = chip-&gt;badblock_pattern-&gt;len;
+	}
+	memset(in_use, 0, 256/8);
+	while (bad_block_marker_length--)
+		__set_bit(bad_block_marker_offset++, in_use);
 
 	/*
-	 * If no default placement scheme is given, select an appropriate one
+	 * The number of bytes available for a client to place data into
+	 * the out of band area
 	 */
-	if (!chip-&gt;ecc.layout.eccbytes) {
-		const struct nand_ecclayout *layout = NULL;
-		switch (mtd-&gt;oobsize) {
-		case 8:
-			layout = &amp;nand_oob_8;
-			break;
-		case 16:
-			layout = &amp;nand_oob_16;
-			break;
-		case 64:
-			layout = &amp;nand_oob_64;
-			break;
-		case 128:
-			layout = &amp;nand_oob_128;
+	chip-&gt;ecc.layout.oobavail = 0;
+	i = 0;
+	do {
+		len = chip-&gt;ecc.layout.oobfree[i].length;
+		if (!len)
 			break;
-		default:
-			printk(KERN_WARNING &quot;No oob scheme defined for &quot;
-			       &quot;oobsize %d\n&quot;, mtd-&gt;oobsize);
-			BUG();
+		bit = chip-&gt;ecc.layout.oobfree[i].offset;
+		if (bit + len &gt; mtd-&gt;oobsize) {
+			pr_warning(&quot;oob byte(%d) &gt;= oobsize(%d)\n&quot;,
+					bit + len - 1, mtd-&gt;oobsize);
+			len = mtd-&gt;oobsize - bit;
+			if (len &lt; 0)
+				len = 0;
+			chip-&gt;ecc.layout.oobfree[i].length = len;
+			if (!len)
+				break;
 		}
-		if (layout)
-			memcpy(&amp;chip-&gt;ecc.layout, layout, sizeof(*layout));
-	}
+		chip-&gt;ecc.layout.oobavail += len;
+		while (len) {
+			if (test_and_set_bit(bit, in_use))
+				pr_warning(&quot;free oob byte(%d) in use\n&quot;, bit);
+			bit++;
+			len--;
+		}
+		i++;
+	} while (i &lt; MTD_MAX_OOBFREE_ENTRIES);
 
 	/*
-	 * The number of bytes available for a client to place data into
-	 * the out of band area
+	 * If no ecc placement scheme is given, select an appropriate one
 	 */
-	chip-&gt;ecc.layout.oobavail = 0;
-	for (i = 0; chip-&gt;ecc.layout.oobfree[i].length; i++)
+	if (chip-&gt;ecc.layout.eccbytes &gt;= chip-&gt;ecc.total) {
+		int j = 0;
+		if (chip-&gt;ecc.layout.eccbytes &gt; chip-&gt;ecc.total)
+			pr_warning(&quot;%s: layout.eccbytes(%d) &gt; ecc.total(%d),&quot;
+				&quot; some oob space will be wasted\n&quot;, __func__,
+				chip-&gt;ecc.layout.eccbytes, chip-&gt;ecc.total);
+		for (len = chip-&gt;ecc.layout.eccbytes; len; len--) {
+			bit = chip-&gt;ecc.layout.eccpos[j++];
+			if (bit &gt;= mtd-&gt;oobsize) {
+				pr_warning(&quot;%s: eccpos(%d) too big, &quot;
+						&quot;defaulting\n&quot;, __func__, bit);
+				chip-&gt;ecc.layout.eccbytes = 0;
+				goto try_again;
+			} else if (test_and_set_bit(bit, in_use))
+				pr_warning(&quot;%s: eccpos(%d) in use\n&quot;, __func__,
+					bit);
+		}
+	} else {
+		int j = 0;
+		if (chip-&gt;ecc.layout.eccbytes)
+			pr_warning(&quot;%s: layout.eccbytes(%d) &lt; ecc.total(%d),&quot;
+				&quot; eccpos will default\n&quot;, __func__,
+				chip-&gt;ecc.layout.eccbytes, chip-&gt;ecc.total);
+		bit = 0;
+		bit = find_next_zero_bit(in_use, mtd-&gt;oobsize, bit);
+		if (bit)
+			bit = mtd-&gt;oobsize - chip-&gt;ecc.total;
+		while (j &lt; chip-&gt;ecc.total) {
+			bit = find_next_zero_bit(in_use, mtd-&gt;oobsize, bit);
+			if (bit == mtd-&gt;oobsize) {
+				bit = find_next_zero_bit(in_use, mtd-&gt;oobsize,
+						0);
+				if (bit == mtd-&gt;oobsize) {
+					pr_warning(&quot;%s: oobfull\n&quot;, __func__);
+					break;
+				}
+			}
+			__set_bit(bit, in_use);
+			chip-&gt;ecc.layout.eccpos[j++] = bit++;
+		}
+		chip-&gt;ecc.layout.eccbytes = j;
+	}
+
+	next_bit = 0;
+	while (i &lt; MTD_MAX_OOBFREE_ENTRIES) {
+		bit = find_next_zero_bit(in_use, mtd-&gt;oobsize, next_bit);
+		if (bit == mtd-&gt;oobsize)
+			break;
+		next_bit = find_next_bit(in_use, mtd-&gt;oobsize, bit);
+		pr_info(&quot;%s oobfree[%d].offset=%d, .length=%d\n&quot;, __func__, i,
+				bit, next_bit - bit);
+		chip-&gt;ecc.layout.oobfree[i].offset = bit;
 		chip-&gt;ecc.layout.oobavail +=
-			chip-&gt;ecc.layout.oobfree[i].length;
+			chip-&gt;ecc.layout.oobfree[i++].length = next_bit - bit;
+	}
+
+	if (i &lt; MTD_MAX_OOBFREE_ENTRIES) {
+		chip-&gt;ecc.layout.oobfree[i].offset = 0;
+		chip-&gt;ecc.layout.oobfree[i].length = 0;
+	}
 	mtd-&gt;oobavail = chip-&gt;ecc.layout.oobavail;
 
 	/*
-- 
1.5.4.3


]