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

Vitaly Wool vwool at ru.mvista.com
Wed Dec 14 07:29:46 EST 2005


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

Modified Files:
	nand_base.c 
Log Message:
[MTD] NAND: Restoring support for chips with 16-bit access for HW ECC

Layout-based handling of NAND flash pages for hardware ECC made it
somehow more complicated to deal with chips with 16-bit access. A length
of a layout item may well be odd, thus making it necessary for the 
accessing routine to process this case separately. This patch implements
such processing in 'read odd-1 and keep it in mind' manner.
The asumption however is that the data block will always be starting from
even position and will be of even length, which is true for all the chips/
controllers I'm aware of.


Index: nand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_base.c,v
retrieving revision 1.162
retrieving revision 1.163
diff -u -r1.162 -r1.163
--- nand_base.c	13 Dec 2005 15:39:07 -0000	1.162
+++ nand_base.c	14 Dec 2005 12:29:42 -0000	1.163
@@ -894,23 +894,41 @@
 	default:
 		eccbytes = this->eccbytes;
 		for (; this->layout[j].length; j++) {
+			int len = this->layout[j].length;
+			int oidx = oobidx;
 			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;
+				this->write_buf(mtd, &this->data_poi[datidx], len);
+				datidx += len;
 				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++)
+				for (last_oobidx = oobidx; oobidx < last_oobidx + len; oobidx++, eccidx++)
 					oob_buf[oobidx] = ecc_code[eccidx];
-				this->write_buf(mtd, ecc_code, this->layout[j].length);
+				if (this->options & NAND_BUSWIDTH_16) {
+					if (oidx & 1) {
+						oidx--;
+						len++;
+					}
+					if (len & 1)
+						len--;
+				}
+				this->write_buf(mtd, &oob_buf[oidx], len);
 				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;
+				if (this->options & NAND_BUSWIDTH_16) {
+					if (oidx & 1) {
+						oidx--;
+						len++;
+					}
+					if (len & 1)
+						len--;
+				}
+				this->write_buf(mtd, &oob_buf[oidx], len);
+				oobidx += len;
 				break;
  			}
 		}
@@ -1234,11 +1252,13 @@
 			last_datidx = datidx;
 			last_oobidx = oobidx;
 			for (j = 0; this->layout[j].length; j++) {
+				int len = this->layout[j].length;
+				int oidx = oobidx;
 				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);
+					this->read_buf(mtd, &data_poi[datidx], len);
 					datidx += this->layout[j].length;
 					break;
 
@@ -1246,7 +1266,16 @@
 					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 (this->options & NAND_BUSWIDTH_16) {
+						if (oidx & 1) {
+							oidx--;
+							len++;
+						}
+						if (len & 1)
+							len--;
+					}
+						
+					this->read_buf(mtd, &oob_data[oidx], len);
 					if (!compareecc) {
 						/* We calc error correction directly, it checks the hw
 						 * generator for an error, reads back the syndrome and
@@ -1265,8 +1294,16 @@
 				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);
+					if (this->options & NAND_BUSWIDTH_16) {
+						if (oidx & 1) {
+							oidx--;
+							len++;
+						}
+						if (len & 1)
+							len--;
+					}
 
-					this->read_buf(mtd, &oob_data[oobidx], this->layout[j].length);
+					this->read_buf(mtd, &oob_data[oidx], len);
 					oobidx += this->layout[j].length;
 					break;
 				}
@@ -1477,11 +1514,18 @@
 						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++;
+						if (this->options & NAND_BUSWIDTH_16) {
+							if (reallen & 1) {
+								oob_data[0] = cpu_to_le16(this->read_word(mtd)) >> 8;
+								oob_data++; i--; reallen++;
+							}
+							if (i & 1)
+								this->read_buf(mtd, oob_data, i - 1);
+							else
+								this->read_buf(mtd, oob_data, i);
  						}
-						this->read_buf(mtd, oob_data, i);
+						else
+							this->read_buf(mtd, oob_data, i);
 						reallen += i;
 					}
 					if (oob_buf + len == oob_data + i) {
@@ -1925,15 +1969,35 @@
 				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);
+				if (i) {
+					if (this->options & NAND_BUSWIDTH_16 && i & 1)
+						i--;
+					if (i == 0) {
+						this->write_word(mtd, cpu_to_le16((oob_buf[0] >> 8) || 0xff));
+						i++;
+						ooblen++;
+					} else
+						this->write_buf(mtd, ffchars, i);
+				}
 				column -= i;
 				fflen += i;
 				i = min_t(int, len + column - ooblen, this->layout[j].length - i);
-				if (i)
+				if (i) {
+					if (column) {
+						this->write_word(mtd, cpu_to_le16((oob_buf[0] >> 8) || 0xff));
+						i--;
+						ooblen++;
+					}
+					if (i & 1)
+						i--;
 					this->write_buf(mtd, &oob_buf[ooblen], i);
+				}
 				ooblen += i;
-				if (ooblen == len) {
+				if (ooblen == len - 1) {
+					this->write_word(mtd, cpu_to_le16(oob_buf[ooblen]) || 0xff00);
+					ooblen += 2;
+				}
+				if (ooblen >= len) {
 					if (NAND_MUST_PAD(this))
 						this->write_buf(mtd, ffchars, mtd->oobsize + mtd->oobblock - fflen - ooblen);
 					goto finish;





More information about the linux-mtd-cvs mailing list