mtd/drivers/mtd/nand nand_base.c,1.161,1.162

Vitaly Wool vwool at ru.mvista.com
Tue Dec 13 10:39:11 EST 2005


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv31751/drivers/mtd/nand

Modified Files:
	nand_base.c 
Log Message:
[MTD] NAND: restoring the default behaviour when layout is not specified

struct nand_oobinfo is in a way ambiguous: it doesn't specify in any 
way how the data is laid out across the NAND page. Both ECC bytes and 
OOB free chunks are defined as relative to start of the OOB data. 
Therefore it's silently presumed that data and oob are contiguous for 
the page which may be true and may be false.
I. e. for SanDisk MLC it's false. This NAND controller is used on
PNX4008 and AFAIK on some Freescale's.
So, there's a conclusion. fill_autooob_layout attempts to create a
layout basing on nand_oobinfo provided. It can be done only assuming
something -- either assuming that the data is contiguous and then
follows oob, or assuming that the data starts at sub-block boundaries
and is spread across the page. The former implementation followed the 
latter way, but now it's been changed to work in the former way to
provide backward-compatibility.
This rework resulted in slight ideological change: layouts are now
describing the full page not the page divided by eccsteps.

Conclusion: now HW ECC mode is transparently backward-compatible, though
some fixes will be necessary for 16-bit mode, which are the subject of the 
next patches



Index: nand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_base.c,v
retrieving revision 1.161
retrieving revision 1.162
diff -u -r1.161 -r1.162
--- nand_base.c	9 Dec 2005 10:58:29 -0000	1.161
+++ nand_base.c	13 Dec 2005 15:39:07 -0000	1.162
@@ -117,42 +117,7 @@
 #define FFCHARS_SIZE		2048
 static u_char ffchars[FFCHARS_SIZE];
 
-static struct page_layout_item hw3_256_layout[] = {
-	{ .length = 256, .type = ITEM_TYPE_DATA, },
-	{ .length = 3, .type = ITEM_TYPE_ECC, },
-	{ .length = 5, .type = ITEM_TYPE_OOB, },
-	{ .length = 0, },
-};
-
-static struct page_layout_item hw3_512_layout[] = {
-	{ .length = 512, .type = ITEM_TYPE_DATA, },
-	{ .length = 3, .type = ITEM_TYPE_ECC, },
-	{ .length = 13, .type = ITEM_TYPE_OOB, },
-	{ .length = 0, },
-};
-
-static struct page_layout_item hw6_512_layout[] = {
-	{ .length = 512, .type = ITEM_TYPE_DATA, },
-	{ .length = 6, .type = ITEM_TYPE_ECC, },
-	{ .length = 10, .type = ITEM_TYPE_OOB, },
-	{ .length = 0, },
-};
-
-static struct page_layout_item hw8_512_layout[] = {
-	{ .length = 512, .type = ITEM_TYPE_DATA, },
-	{ .length = 8, .type = ITEM_TYPE_ECC, },
-	{ .length = 8, .type = ITEM_TYPE_OOB, },
-	{ .length = 0, },
-};
-
-static struct page_layout_item hw12_2048_layout[] = {
-	{ .length = 2048, .type = ITEM_TYPE_DATA, },
-	{ .length = 12, .type = ITEM_TYPE_ECC, },
-	{ .length = 52, .type = ITEM_TYPE_OOB, },
-	{ .length = 0, },
-};
-
-#define HW_AUTOOOB_LAYOUT_SIZE		8 /* should be enough */
+#define HW_AUTOOOB_LAYOUT_SIZE		32 /* should be enough */
 
 /*
  * NAND low-level MTD interface functions
@@ -893,11 +858,12 @@
 static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page,
 	u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
 {
-	int 	i, oobidx, status;
+	int 	i = 0, j = 0, oobidx = 0, status;
 	u_char	ecc_code[40];
 	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
 	int  	*oob_config = oobsel->eccpos;
-	int	datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
+	int	datidx = 0, last_datidx = 0, last_oobidx = 0, eccidx = 0;
+	int	eccsteps = this->eccsteps;
 	int	eccbytes = 0;
 
 	/* FIXME: Enable cached programming */
@@ -927,30 +893,26 @@
 		break;
 	default:
 		eccbytes = this->eccbytes;
-		for (oobidx = 0; eccsteps; eccsteps--) {
-			int j = 0, last_datidx = datidx, last_oobidx;
-			for (; this->layout[j].length; j++) {
-				switch (this->layout[j].type) {
-				case ITEM_TYPE_DATA:
-					this->enable_hwecc(mtd, NAND_ECC_WRITE);
-					this->write_buf(mtd, &this->data_poi[datidx], this->layout[j].length);
-					datidx += this->layout[j].length;
-					break;
-				case ITEM_TYPE_ECC:
-					this->enable_hwecc(mtd, NAND_ECC_WRITESYN);
-					this->calculate_ecc(mtd, &this->data_poi[last_datidx], &ecc_code[eccidx]);
-					for (last_oobidx = oobidx; oobidx < last_oobidx + this->layout[j].length; oobidx++, eccidx++)
-						oob_buf[oobidx] = ecc_code[eccidx];
-					this->write_buf(mtd, ecc_code, this->layout[j].length);
-					break;
-				case ITEM_TYPE_OOB:
-					this->enable_hwecc(mtd, NAND_ECC_WRITEOOB);
-					this->write_buf(mtd, &oob_buf[oobidx], this->layout[j].length);
-					oobidx += this->layout[j].length;
-					break;
-				}
-			}
-
+		for (; this->layout[j].length; j++) {
+			switch (this->layout[j].type) {
+			case ITEM_TYPE_DATA:
+				this->enable_hwecc(mtd, NAND_ECC_WRITE);
+				this->write_buf(mtd, &this->data_poi[datidx], this->layout[j].length);
+				datidx += this->layout[j].length;
+				break;
+			case ITEM_TYPE_ECC:
+				this->enable_hwecc(mtd, NAND_ECC_WRITESYN);
+				this->calculate_ecc(mtd, &this->data_poi[last_datidx], &ecc_code[eccidx]);
+				for (last_oobidx = oobidx; oobidx < last_oobidx + this->layout[j].length; oobidx++, eccidx++)
+					oob_buf[oobidx] = ecc_code[eccidx];
+				this->write_buf(mtd, ecc_code, this->layout[j].length);
+				break;
+			case ITEM_TYPE_OOB:
+				this->enable_hwecc(mtd, NAND_ECC_WRITEOOB);
+				this->write_buf(mtd, &oob_buf[oobidx], this->layout[j].length);
+				oobidx += this->layout[j].length;
+				break;
+ 			}
 		}
 		break;
 	}
@@ -1154,6 +1116,7 @@
 
 	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
 	int read = 0, oob = 0, oobidx, ecc_status = 0, ecc_failed = 0, eccidx;
+	int last_datidx, last_oobidx;
 	struct nand_chip *this = mtd->priv;
 	u_char *data_poi, *oob_data = oob_buf;
 	u_char ecc_calc[32];
@@ -1265,45 +1228,47 @@
 			break;
 
 		default:
-			for (oobidx = 0, datidx = 0, eccidx = 0; eccsteps; eccsteps--) {
-				int last_datidx = datidx, last_oobidx = oobidx;
-				for (j = 0; this->layout[j].length; j++) {
-					switch (this->layout[j].type) {
-					case ITEM_TYPE_DATA:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d bytes of data\n", __FUNCTION__, this->layout[j].length);
-						this->enable_hwecc(mtd, NAND_ECC_READ);
-						this->read_buf(mtd, &data_poi[datidx], this->layout[j].length);
-						datidx += this->layout[j].length;
-						break;
-
-					case ITEM_TYPE_ECC:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d ecc bytes\n", __FUNCTION__, this->layout[j].length);
-						/* let the particular driver decide whether to read ECC */
-						this->enable_hwecc(mtd, NAND_ECC_READSYN);
-						this->read_buf(mtd, &oob_data[oobidx], this->layout[j].length);
-						if (!compareecc) {
-							/* We calc error correction directly, it checks the hw
-							 * generator for an error, reads back the syndrome and
-							 * does the error correction on the fly */
-							ecc_status = this->correct_data(mtd, &data_poi[last_datidx], &oob_data[last_oobidx], &ecc_code[eccidx]);
-							if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
-								DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
-									"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
-								ecc_failed++;
-							}
-						} else
-							this->calculate_ecc(mtd, &data_poi[last_datidx], &ecc_calc[eccidx]);
-						oobidx += this->layout[j].length;
-						eccidx += this->layout[j].length;
-						break;
-					case ITEM_TYPE_OOB:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d free oob bytes\n", __FUNCTION__, this->layout[j].length);
-						this->enable_hwecc(mtd, NAND_ECC_READOOB);
+			oobidx = 0;
+			datidx = 0;
+			eccidx = 0;
+			last_datidx = datidx;
+			last_oobidx = oobidx;
+			for (j = 0; this->layout[j].length; j++) {
+				switch (this->layout[j].type) {
+				case ITEM_TYPE_DATA:
+					DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d bytes of data\n", __FUNCTION__, this->layout[j].length);
+					this->enable_hwecc(mtd, NAND_ECC_READ);
+					this->read_buf(mtd, &data_poi[datidx], this->layout[j].length);
+					datidx += this->layout[j].length;
+					break;
 
-						this->read_buf(mtd, &oob_data[oobidx], this->layout[j].length);
-						oobidx += this->layout[j].length;
-						break;
-					}
+				case ITEM_TYPE_ECC:
+					DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d ecc bytes\n", __FUNCTION__, this->layout[j].length);
+					/* let the particular driver decide whether to read ECC */
+					this->enable_hwecc(mtd, NAND_ECC_READSYN);
+					this->read_buf(mtd, &oob_data[oobidx], this->layout[j].length);
+					if (!compareecc) {
+						/* We calc error correction directly, it checks the hw
+						 * generator for an error, reads back the syndrome and
+						 * does the error correction on the fly */
+						ecc_status = this->correct_data(mtd, &data_poi[last_datidx], &oob_data[last_oobidx], &ecc_code[eccidx]);
+						if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
+							DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
+								"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
+							ecc_failed++;
+						}
+					} else
+						this->calculate_ecc(mtd, &data_poi[last_datidx], &ecc_calc[eccidx]);
+					oobidx += this->layout[j].length;
+					eccidx += this->layout[j].length;
+					break;
+				case ITEM_TYPE_OOB:
+					DEBUG (MTD_DEBUG_LEVEL3, "%s: reading %d free oob bytes\n", __FUNCTION__, this->layout[j].length);
+					this->enable_hwecc(mtd, NAND_ECC_READOOB);
+
+					this->read_buf(mtd, &oob_data[oobidx], this->layout[j].length);
+					oobidx += this->layout[j].length;
+					break;
 				}
 			}
 			break;
@@ -1481,81 +1446,52 @@
 			}
 
 			eccsteps = this->eccsteps;
+			for (j = 0; this->layout[j].length; j++) {
+				i = 0;
+				switch (this->layout[j].type) {
+				case ITEM_TYPE_DATA:
+					DEBUG (MTD_DEBUG_LEVEL3, "%s: dummy data read\n", __FUNCTION__);
+					reallen += this->layout[j].length;
+					if (this->options & NAND_BUSWIDTH_16)
+						this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);
+					else
+						this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);
+					break;
 
-			for (; eccsteps; eccsteps--) {
-				for (j = 0; this->layout[j].length; j++) {
-					i = 0;
-					switch (this->layout[j].type) {
-					case ITEM_TYPE_DATA:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: dummy data read\n", __FUNCTION__);
-						reallen += this->layout[j].length;
+				case ITEM_TYPE_ECC:
+				case ITEM_TYPE_OOB:
+					DEBUG (MTD_DEBUG_LEVEL3, "%s: %s bytes read\n", __FUNCTION__, this->layout[j].type == ITEM_TYPE_ECC ? "ecc" : "oob");
+					i = min_t(int, col, this->layout[j].length);
+					if (i) {
+						reallen += i;
 						if (this->options & NAND_BUSWIDTH_16)
 							this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);
 						else
 							this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);
-						break;
+					}
+					col -= i;
 
-					case ITEM_TYPE_ECC:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: ecc bytes read\n", __FUNCTION__);
-						i = min_t(int, col, this->layout[j].length);
-						if (i) {
-							reallen += i;
-							if (this->options & NAND_BUSWIDTH_16)
-								this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);
-							else
-								this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);
-						}
-						col -= i;
-						i = min_t(int, len - read, this->layout[j].length - i);
+					if (this->layout[j].type == ITEM_TYPE_ECC)
 						this->enable_hwecc(mtd, NAND_ECC_READSYN);
-						if (i) {
-							if (this->options & NAND_BUSWIDTH_16 && reallen & 1) {
-								oob_data[0] = cpu_to_le16(this->read_word(mtd)) >> 8;
-								oob_data++; i--; reallen++;
-							}
-
-							this->read_buf(mtd, oob_data, i);
-							reallen += i;
-						}
-						if (oob_buf + len == oob_data + i) {
-							read += i;
-							goto out;
-						}
-						break;
-					case ITEM_TYPE_OOB:
-						DEBUG (MTD_DEBUG_LEVEL3, "%s: free oob bytes read\n", __FUNCTION__);
-						i = min_t(int, col, this->layout[j].length);
-						if (i) {
-							reallen += i;
-							if (this->options & NAND_BUSWIDTH_16)
-								this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);
-							else
-								this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);
-						}
-						col -= i;
-
+					else
 						this->enable_hwecc(mtd, NAND_ECC_READOOB);
-						i = min_t(int, len - read, this->layout[j].length - i);
-						if (i) {
-							if (this->options & NAND_BUSWIDTH_16 && reallen & 1) {
-								oob_data[0] = cpu_to_le16(this->read_word(mtd)) >> 8;
-								oob_data++; i--; reallen++;
-							}
-
-							this->read_buf(mtd, oob_data, i);
-							reallen += i;
-						}
-						if (oob_buf + len == oob_data + i) {
-							read += i;
-							goto out;
-						}
-
-						break;
+					i = min_t(int, len - read, this->layout[j].length - i);
+					if (i) {
+						if (this->options & NAND_BUSWIDTH_16 && reallen & 1) {
+							oob_data[0] = cpu_to_le16(this->read_word(mtd)) >> 8;
+							oob_data++; i--; reallen++;
+ 						}
+						this->read_buf(mtd, oob_data, i);
+						reallen += i;
 					}
-					read += i;
-					oob_data += i;
-
-				}
+					if (oob_buf + len == oob_data + i) {
+						read += i;
+						goto out;
+	 				}
+					break;
+ 				}
+				read += i;
+				oob_data += i;
 			}
 		}
 out:
@@ -1908,7 +1844,7 @@
  */
 static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * oob_buf)
 {
-	int column, page, status, ret = -EIO, chipnr, eccsteps, fflen, ooblen;
+	int column, page, status, ret = -EIO, chipnr, eccsteps; 
 	struct nand_chip *this = mtd->priv;
 
 	DEBUG (MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __FUNCTION__, (unsigned int) to, (int) len);
@@ -1967,46 +1903,42 @@
 			this->write_buf(mtd, oob_buf, len);
 		}
 	} else {
+		int i = 0, j = 0;
+		int fflen = 0, ooblen = 0;
+
 		/* Write out desired data */
 		this->cmdfunc (mtd, NAND_CMD_SEQIN, 0, page & this->pagemask);
 
 		eccsteps = this->eccsteps;
+		for (j = 0; this->layout[j].length; j++) {
+			switch (this->layout[j].type) {
+			case ITEM_TYPE_DATA:
+				this->enable_hwecc(mtd, NAND_ECC_WRITE);
+				this->write_buf(mtd, ffchars, this->layout[j].length);
+				fflen += this->layout[j].length;
+				break;
 
-		for (fflen = 0, ooblen = 0; eccsteps; eccsteps--) {
-			int i, j;
-			for (j = 0; this->layout[j].length; j++) {
-				switch (this->layout[j].type) {
-				case ITEM_TYPE_DATA:
-					this->enable_hwecc(mtd, NAND_ECC_WRITE);
-					this->write_buf(mtd, ffchars, this->layout[j].length);
-					fflen += this->layout[j].length;
-					break;
-
-				case ITEM_TYPE_ECC:
+			case ITEM_TYPE_ECC:
+			case ITEM_TYPE_OOB:
+				if (this->layout[j].type == ITEM_TYPE_ECC)
 					this->enable_hwecc(mtd, NAND_ECC_WRITESYN);
-					this->write_buf(mtd, ffchars, this->layout[j].length);
-					ooblen += this->layout[j].length;
-					break;
-
-				case ITEM_TYPE_OOB:
+				else
 					this->enable_hwecc(mtd, NAND_ECC_WRITEOOB);
-					i = min_t(int, column, this->layout[j].length);
-					if (i)
-						this->write_buf(mtd, ffchars, i);
-					column -= i;
-					fflen += i;
-					i = min_t(int, len + column - ooblen, this->layout[j].length - i);
-
-					if (i)
-						this->write_buf(mtd, &oob_buf[ooblen], i);
-					ooblen += i;
-					if (ooblen == len) {
-						if (NAND_MUST_PAD(this))
-							this->write_buf(mtd, ffchars, mtd->oobsize + mtd->oobblock - fflen - ooblen);
-						goto finish;
-					}
-					break;
+				i = min_t(int, column, this->layout[j].length);
+				if (i)
+					this->write_buf(mtd, ffchars, i);
+				column -= i;
+				fflen += i;
+				i = min_t(int, len + column - ooblen, this->layout[j].length - i);
+				if (i)
+					this->write_buf(mtd, &oob_buf[ooblen], i);
+				ooblen += i;
+				if (ooblen == len) {
+					if (NAND_MUST_PAD(this))
+						this->write_buf(mtd, ffchars, mtd->oobsize + mtd->oobblock - fflen - ooblen);
+					goto finish;
 				}
+				break;
 			}
 		}
 	}
@@ -2513,13 +2445,21 @@
 
 }
 
+/**
+ * fill_autooob_layout - [NAND Interface] build the layout for hardware ECC case
+ * @mtd:	MTD device structure
+ * @eccbytes:	Number of ECC bytes per page
+ *
+ * Build the page_layout array for NAND page handling for hardware ECC
+ * handling basing on the nand_oobinfo structure supplied for the chip
+ */
 static int fill_autooob_layout(struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_oobinfo *oob = this->autooob;
-	int datasize = mtd->oobblock / this->eccsteps;
-	int i = 0, res = 0;
-	int eccpos = 0, eccbytes = 0, cur = 0;
+	int oobfreesize = 0;
+	int i = 1, res = 0;
+	int eccpos = 0, eccbytes = 0, cur = 0, oobcur = 0;
 
 	this->layout = kmalloc(HW_AUTOOOB_LAYOUT_SIZE * sizeof (struct page_layout_item), GFP_KERNEL);
 
@@ -2528,34 +2468,67 @@
 	else
 		this->layout_allocated = 1;
 
-	while (i < HW_AUTOOOB_LAYOUT_SIZE - 1 &&
-		cur < (mtd->oobsize + mtd->oobblock) / this->eccsteps - 1) {
-		if (cur == 0) {
-			this->layout[i].type = ITEM_TYPE_DATA;
-			this->layout[i].length = datasize;
-		} else if (oob->eccpos[eccpos] == cur - datasize) {
+	memset(this->layout, 0, HW_AUTOOOB_LAYOUT_SIZE * sizeof (struct page_layout_item));
+
+
+	this->layout[0].type = ITEM_TYPE_DATA;
+	this->layout[0].length = mtd->oobblock;
+	DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: data type, length %d\n", this->layout[0].length);
+
+	while (i < HW_AUTOOOB_LAYOUT_SIZE / this->eccsteps - 1 && cur < mtd->oobsize / this->eccsteps) {
+		if (oob->oobfree[oobcur][0] == cur) {
+			int len = oob->oobfree[oobcur][1];
+			oobfreesize += this->layout[i].length;
+			oobcur++;
+			if (i > 0 && this->layout[i-1].type == ITEM_TYPE_OOB) {
+				i--;
+				cur -= this->layout[i].length;
+				this->layout[i].length += len;
+				DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: oob concatenated, aggregate length %d\n", this->layout[i].length);
+			} else {
+				this->layout[i].type = ITEM_TYPE_OOB;
+				this->layout[i].length = len;
+				DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: oob type, length %d\n", this->layout[i].length);
+			}
+		} else if (oob->eccpos[eccpos] == cur) {
 			int eccpos_cur = eccpos;
 			do  {
 				eccpos++;
 				eccbytes++;
-			} while (eccbytes < oob->eccbytes / this->eccsteps && oob->eccpos[eccpos] == oob->eccpos[eccpos+1] - 1);
+			} while (eccbytes < oob->eccbytes && oob->eccpos[eccpos] == oob->eccpos[eccpos+1] - 1);
 			eccpos++;
 			eccbytes++;
 			this->layout[i].type = ITEM_TYPE_ECC;
 			this->layout[i].length = eccpos - eccpos_cur;
+			DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: ecc type, length %d\n", this->layout[i].length);
 		} else {
-			this->layout[i].type = ITEM_TYPE_OOB;
-			if (eccbytes < oob->eccbytes / this->eccsteps)
-				this->layout[i].length = datasize - cur + oob->eccpos[eccpos];
-			else
-				this->layout[i].length = mtd->oobsize / this->eccsteps - (cur - datasize);
+			int len = min_t(int, oob->eccpos[eccpos], oob->oobfree[oobcur][0]);
+			if (i > 0 && this->layout[i-1].type == ITEM_TYPE_OOB) {
+				i--;
+				cur -= this->layout[i].length;
+				this->layout[i].length += len;
+				DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: oob concatenated, aggregate length %d\n", this->layout[i].length);
+			} else {
+				this->layout[i].type = ITEM_TYPE_OOB;
+				this->layout[i].length = len;
+				DEBUG (MTD_DEBUG_LEVEL3, "fill_autooob_layout: oob type, length %d\n", this->layout[i].length);
+			}
 		}
 		cur += this->layout[i].length;
 		i++;
 	}
-	if (cur < (mtd->oobsize + mtd->oobblock) / this->eccsteps - 1)
+	if (cur < mtd->oobsize / this->eccsteps - 1) {
+		kfree(this->layout);
 		res = -1;
-
+	} else if (this->eccsteps > 1) {
+		int j = i;
+		i--;
+		while (j < this->eccsteps * i + 1) {
+			this->layout[j].length = this->layout[j-i].length;
+			this->layout[j].type = this->layout[j-i].type;
+			j++;
+		}
+	}
 	return res;
 }
 
@@ -2910,29 +2883,9 @@
 
 	/* We consider only layout allocation performed in nand_base */
 	this->layout_allocated = 0;
-	if (!this->layout) {
-		if (this->autooob)
-			fill_autooob_layout(mtd);
-		else {
-			switch (this->eccmode) {
-			case NAND_ECC_HW12_2048:
-				this->layout = hw12_2048_layout;
-				break;
-			case NAND_ECC_HW3_512:
-				this->layout = hw3_512_layout;
-				break;
-			case NAND_ECC_HW6_512:
-				this->layout = hw6_512_layout;
-				break;
-			case NAND_ECC_HW8_512:
-				this->layout = hw8_512_layout;
-				break;
-			case NAND_ECC_HW3_256:
-				this->layout = hw3_256_layout;
-				break;
-			}
-		}
-	}
+	if (!this->layout && this->autooob)
+		if (fill_autooob_layout(mtd) < 0)
+			BUG();
 
 	/* Initialize state, waitqueue and spinlock */
 	this->state = FL_READY;





More information about the linux-mtd-cvs mailing list