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 <troy.kisky@boundarydevices.com>; 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 <troy.kisky@boundarydevices.com>; 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 <troy.kisky@boundarydevices.com>
To: linux-mtd@lists.infradead.org
Cc: david-b@pacbell.net, Troy Kisky <troy.kisky@boundarydevices.com>
Subject: [PATCH 2/5] mtd: nand: Calculate better default ecc layout
Date: Wed, 13 May 2009 20:00:05 -0700
Message-Id: <1242270008-1552-2-git-send-email-troy.kisky@boundarydevices.com>
X-Mailer: git-send-email 1.5.4.3
In-Reply-To: <1242270008-1552-1-git-send-email-troy.kisky@boundarydevices.com>
References: <>
 <1242270008-1552-1-git-send-email-troy.kisky@boundarydevices.com>
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 <troy.kisky@boundarydevices.com>
---
 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 <linux/mtd/partitions.h>
 #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->priv;
 
 	if (!(chip->options & NAND_OWN_BUFFERS))
@@ -2737,42 +2696,125 @@ int nand_scan_tail(struct mtd_info *mtd)
 		BUG();
 	}
 	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
+	pr_info("%s ecc.total = %d, ecc.steps = %d, ecc.bytes = %d, "
+		"ecc.size = %d, writesize = %d\n",
+		__func__, chip->ecc.total, chip->ecc.steps, chip->ecc.bytes,
+		chip->ecc.size, mtd->writesize);
+try_again:
+	bad_block_marker_offset = 0;
+	bad_block_marker_length = 2;
+	if (mtd->oobsize == 8) {
+		bad_block_marker_offset = 5;
+		bad_block_marker_length = 1;
+	} else if (mtd->oobsize == 16) {
+		bad_block_marker_offset = 4;	/* length still 2 */
+	}
+	if (chip->bbt_td) {
+		bad_block_marker_offset = chip->bbt_td->offs;
+		bad_block_marker_length = chip->bbt_td->len;
+	}
+	if (chip->badblock_pattern) {
+		bad_block_marker_offset = chip->badblock_pattern->offs;
+		bad_block_marker_length = chip->badblock_pattern->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->ecc.layout.eccbytes) {
-		const struct nand_ecclayout *layout = NULL;
-		switch (mtd->oobsize) {
-		case 8:
-			layout = &nand_oob_8;
-			break;
-		case 16:
-			layout = &nand_oob_16;
-			break;
-		case 64:
-			layout = &nand_oob_64;
-			break;
-		case 128:
-			layout = &nand_oob_128;
+	chip->ecc.layout.oobavail = 0;
+	i = 0;
+	do {
+		len = chip->ecc.layout.oobfree[i].length;
+		if (!len)
 			break;
-		default:
-			printk(KERN_WARNING "No oob scheme defined for "
-			       "oobsize %d\n", mtd->oobsize);
-			BUG();
+		bit = chip->ecc.layout.oobfree[i].offset;
+		if (bit + len > mtd->oobsize) {
+			pr_warning("oob byte(%d) >= oobsize(%d)\n",
+					bit + len - 1, mtd->oobsize);
+			len = mtd->oobsize - bit;
+			if (len < 0)
+				len = 0;
+			chip->ecc.layout.oobfree[i].length = len;
+			if (!len)
+				break;
 		}
-		if (layout)
-			memcpy(&chip->ecc.layout, layout, sizeof(*layout));
-	}
+		chip->ecc.layout.oobavail += len;
+		while (len) {
+			if (test_and_set_bit(bit, in_use))
+				pr_warning("free oob byte(%d) in use\n", bit);
+			bit++;
+			len--;
+		}
+		i++;
+	} while (i < 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->ecc.layout.oobavail = 0;
-	for (i = 0; chip->ecc.layout.oobfree[i].length; i++)
+	if (chip->ecc.layout.eccbytes >= chip->ecc.total) {
+		int j = 0;
+		if (chip->ecc.layout.eccbytes > chip->ecc.total)
+			pr_warning("%s: layout.eccbytes(%d) > ecc.total(%d),"
+				" some oob space will be wasted\n", __func__,
+				chip->ecc.layout.eccbytes, chip->ecc.total);
+		for (len = chip->ecc.layout.eccbytes; len; len--) {
+			bit = chip->ecc.layout.eccpos[j++];
+			if (bit >= mtd->oobsize) {
+				pr_warning("%s: eccpos(%d) too big, "
+						"defaulting\n", __func__, bit);
+				chip->ecc.layout.eccbytes = 0;
+				goto try_again;
+			} else if (test_and_set_bit(bit, in_use))
+				pr_warning("%s: eccpos(%d) in use\n", __func__,
+					bit);
+		}
+	} else {
+		int j = 0;
+		if (chip->ecc.layout.eccbytes)
+			pr_warning("%s: layout.eccbytes(%d) < ecc.total(%d),"
+				" eccpos will default\n", __func__,
+				chip->ecc.layout.eccbytes, chip->ecc.total);
+		bit = 0;
+		bit = find_next_zero_bit(in_use, mtd->oobsize, bit);
+		if (bit)
+			bit = mtd->oobsize - chip->ecc.total;
+		while (j < chip->ecc.total) {
+			bit = find_next_zero_bit(in_use, mtd->oobsize, bit);
+			if (bit == mtd->oobsize) {
+				bit = find_next_zero_bit(in_use, mtd->oobsize,
+						0);
+				if (bit == mtd->oobsize) {
+					pr_warning("%s: oobfull\n", __func__);
+					break;
+				}
+			}
+			__set_bit(bit, in_use);
+			chip->ecc.layout.eccpos[j++] = bit++;
+		}
+		chip->ecc.layout.eccbytes = j;
+	}
+
+	next_bit = 0;
+	while (i < MTD_MAX_OOBFREE_ENTRIES) {
+		bit = find_next_zero_bit(in_use, mtd->oobsize, next_bit);
+		if (bit == mtd->oobsize)
+			break;
+		next_bit = find_next_bit(in_use, mtd->oobsize, bit);
+		pr_info("%s oobfree[%d].offset=%d, .length=%d\n", __func__, i,
+				bit, next_bit - bit);
+		chip->ecc.layout.oobfree[i].offset = bit;
 		chip->ecc.layout.oobavail +=
-			chip->ecc.layout.oobfree[i].length;
+			chip->ecc.layout.oobfree[i++].length = next_bit - bit;
+	}
+
+	if (i < MTD_MAX_OOBFREE_ENTRIES) {
+		chip->ecc.layout.oobfree[i].offset = 0;
+		chip->ecc.layout.oobfree[i].length = 0;
+	}
 	mtd->oobavail = chip->ecc.layout.oobavail;
 
 	/*
-- 
1.5.4.3


