Skip to contentSkip to conversation

Write-while-program support

PATCH In review Kyungmin Park 3 participants 8 messages Nov 14, 2008 – Nov 17, 2008 Memory technology devices (MTD)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Write-while-program support

This is from Adrian hunter and modified for write_ops operation.

It's similar with load-while-read method. but it's write side performance improvement.

Here's brief performance results.
Note: Measured from OMAP3 with async OneNAND mode. (not sync mode)

=================================================================
speedtest: dev = 3
speedtest: Size=16777216 EB size=131072 Write size=2048 EB count=128

		Pages per EB=64  Page size=2048

speedtest: scanning for bad blocks
speedtest: scanned 0
speedtest: scanned 128, found 0 bad
speedtest: erasing
speedtest: erased 0
speedtest: erased 128
speedtest: Testing eraseblock write speed eraseblock write speed is 2424 KiB/s
speedtest: Testing eraseblock read speed eraseblock read speed is 11985 KiB/s
speedtest: Testing page write speed page write speed is 2493 KiB/s
speedtest: Testing page read speed page read speed is 11586 KiB/s
speedtest: Testing 2 page write speed 2 page write speed is 2681 KiB/s
speedtest: Testing 2 page read speed 2 page read speed is 10922 KiB/s
speedtest: Testing erase speed erase speed is 192752 KiB/s
speedtest: speedtest finished
=================================================================

Also it's passed all nand-tests.

---

drivers/mtd/onenand/onenand_base.c +64 -49
index aaf3504..bc9b420 100644
@@ -1455,7 +1455,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
 				struct mtd_oob_ops *ops)
 {
 	struct onenand_chip *this = mtd->priv;
-	int written = 0, column, thislen, subpage;
+	int written = 0, column, thislen = 0, subpage = 0;
+	int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
 	int oobwritten = 0, oobcolumn, thisooblen, oobsize;
 	size_t len = ops->len;
 	size_t ooblen = ops->ooblen;
@@ -1492,76 +1493,90 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
 	column = to & (mtd->writesize - 1);
 
 	/* Loop until all data write */
-	while (written < len) {
-		u_char *wbuf = (u_char *) buf;
+	while (1) {
+		if (written < len) {
+			u_char *wbuf = (u_char *) buf;
 
-		thislen = min_t(int, mtd->writesize - column, len - written);
-		thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
+			thislen = min_t(int, mtd->writesize - column, len - written);
+			thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
 
-		cond_resched();
+			cond_resched();
 
-		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
+			this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
 
-		/* Partial page write */
-		subpage = thislen < mtd->writesize;
-		if (subpage) {
-			memset(this->page_buf, 0xff, mtd->writesize);
-			memcpy(this->page_buf + column, buf, thislen);
-			wbuf = this->page_buf;
-		}
+			/* Partial page write */
+			subpage = thislen < mtd->writesize;
+			if (subpage) {
+				memset(this->page_buf, 0xff, mtd->writesize);
+				memcpy(this->page_buf + column, buf, thislen);
+				wbuf = this->page_buf;
+			}
 
-		this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
+			this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
 
-		if (oob) {
-			oobbuf = this->oob_buf;
+			if (oob) {
+				oobbuf = this->oob_buf;
 
-			/* We send data to spare ram with oobsize
-			 * to prevent byte access */
-			memset(oobbuf, 0xff, mtd->oobsize);
-			if (ops->mode == MTD_OOB_AUTO)
-				onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
-			else
-				memcpy(oobbuf + oobcolumn, oob, thisooblen);
+				/* We send data to spare ram with oobsize
+				 * to prevent byte access */
+				memset(oobbuf, 0xff, mtd->oobsize);
+				if (ops->mode == MTD_OOB_AUTO)
+					onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
+				else
+					memcpy(oobbuf + oobcolumn, oob, thisooblen);
 
-			oobwritten += thisooblen;
-			oob += thisooblen;
-			oobcolumn = 0;
+				oobwritten += thisooblen;
+				oob += thisooblen;
+				oobcolumn = 0;
+			} else
+				oobbuf = (u_char *) ffchars;
+
+			this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
 		} else
-			oobbuf = (u_char *) ffchars;
+			ONENAND_SET_NEXT_BUFFERRAM(this);
 
-		this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
+		if (!first) {
+			ONENAND_SET_PREV_BUFFERRAM(this);
 
-		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+			ret = this->wait(mtd, FL_WRITING);
 
-		ret = this->wait(mtd, FL_WRITING);
+			/* In partial page write we don't update bufferram */
+			onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
+			if (ONENAND_IS_2PLANE(this)) {
+				ONENAND_SET_BUFFERRAM1(this);
+				onenand_update_bufferram(mtd, prev + this->writesize, !ret && !prev_subpage);
+			}
 
-		/* In partial page write we don't update bufferram */
-		onenand_update_bufferram(mtd, to, !ret && !subpage);
-		if (ONENAND_IS_2PLANE(this)) {
-			ONENAND_SET_BUFFERRAM1(this);
-			onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
-		}
+			if (ret) {
+				printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
+				break;
+			}
 
-		if (ret) {
-			printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
-			break;
-		}
+			if (written == len) {
+				/* Only check verify write turn on */
+				ret = onenand_verify(mtd, buf - len, to - len, len);
+				if (ret) {
+					printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
+					break;
+				}
+			}
+			ONENAND_SET_NEXT_BUFFERRAM(this);
 
-		/* Only check verify write turn on */
-		ret = onenand_verify(mtd, buf, to, thislen);
-		if (ret) {
-			printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
-			break;
+			if (written == len)
+				break;
 		}
 
-		written += thislen;
+		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
 
-		if (written == len)
-			break;
+		written += thislen;
 
 		column = 0;
+		prev_subpage = subpage;
+		prev = to;
+		prevlen = thislen;
 		to += thislen;
 		buf += thislen;
+		first = 0;
 	}
 
 	ops->retlen = written;
#1 lore raw
Quoted 1 line · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though. I have copied the whole function below because the diff is too confusing:

Quoted 31 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param ops oob operation description structure
*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
	struct onenand_chip *this = mtd->priv;
	int written = 0, column, thislen = 0, subpage = 0;
	int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
	int oobwritten = 0, oobcolumn, thisooblen, oobsize;
	size_t len = ops->len;
	size_t ooblen = ops->ooblen;
	const u_char *buf = ops->datbuf;
	const u_char *oob = ops->oobbuf;
	u_char *oobbuf;
	int ret = 0;

	DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);

	/* Initialize retlen, in case of early exit */
	ops->retlen = 0;
	ops->oobretlen = 0;

	/* Do not allow writes past end of device */
	if (unlikely((to + len) > mtd->size)) {
		printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
Quoted 9 lines
		return -EINVAL;
	}

	/* Reject writes, which are not page aligned */
        if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
                printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
                return -EINVAL;
        }

The loop cannot handle the case when len is zero so I had:

	if (!len)
		return 0;
Quoted 52 lines
	if (ops->mode == MTD_OOB_AUTO)
		oobsize = this->ecclayout->oobavail;
	else
		oobsize = mtd->oobsize;

	oobcolumn = to & (mtd->oobsize - 1);

	column = to & (mtd->writesize - 1);

	/* Loop until all data write */
	while (1) {
		if (written < len) {
			u_char *wbuf = (u_char *) buf;

			thislen = min_t(int, mtd->writesize - column, len - written);
			thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);

			cond_resched();

			this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);

			/* Partial page write */
			subpage = thislen < mtd->writesize;
			if (subpage) {
				memset(this->page_buf, 0xff, mtd->writesize);
				memcpy(this->page_buf + column, buf, thislen);
				wbuf = this->page_buf;
			}

			this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);

			if (oob) {
				oobbuf = this->oob_buf;

				/* We send data to spare ram with oobsize
				 * to prevent byte access */
				memset(oobbuf, 0xff, mtd->oobsize);
				if (ops->mode == MTD_OOB_AUTO)
					onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
				else
					memcpy(oobbuf + oobcolumn, oob, thisooblen);

				oobwritten += thisooblen;
				oob += thisooblen;
				oobcolumn = 0;
			} else
				oobbuf = (u_char *) ffchars;

			this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
		} else
			ONENAND_SET_NEXT_BUFFERRAM(this);
Quoted 8 lines
		if (!first) {
			ONENAND_SET_PREV_BUFFERRAM(this);

			ret = this->wait(mtd, FL_WRITING);

			/* In partial page write we don't update bufferram */
			onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
			if (ONENAND_IS_2PLANE(this)) {

I do not understand how 2PLANE is compatible with write-while-program because 2PLANE uses both buffers so we cannot start transferring to the second buffer while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Quoted 5 lines
				ONENAND_SET_BUFFERRAM1(this);
				onenand_update_bufferram(mtd, prev + this->writesize, !ret && !prev_subpage);
			}

			if (ret) {

My original patch had "written -= prevlen" here.

Quoted 11 lines
				printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
				break;
			}

			if (written == len) {
				/* Only check verify write turn on */
				ret = onenand_verify(mtd, buf - len, to - len, len);
				if (ret) {
					printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
					break;
				}

Why not just break here?

Quoted 13 lines
			}
			ONENAND_SET_NEXT_BUFFERRAM(this);

			if (written == len)
				break;
		}

		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);

		written += thislen;

		column = 0;
		prev_subpage = subpage;
Quoted 8 lines
		prev = to;
		prevlen = thislen;
		to += thislen;
		buf += thislen;
		first = 0;
	}

	ops->retlen = written;

Is ops->oobretlen needed here also?

Quoted 3 lines
	return ret;
}
#2 lore raw

Hi Adrian

FlexOneNand read dual data ram buffer and so we can not use ----- Original Message -----
From: "Adrian Hunter" <[email protected]>
To: "Kyungmin Park" <[email protected]>
Cc: <[email protected]>
Sent: Friday, November 14, 2008 4:02 PM
Subject: Re: [PATCH][OneNAND] Write-while-program support

Quoted 129 lines
Quoted 2 lines · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though.
I have copied the whole function below because the diff is too confusing:

Quoted 38 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write
main and/or out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param ops oob operation description structure *
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
int written = 0, column, thislen = 0, subpage = 0; int prev = 0, prevlen = 0, prev_subpage = 0, first = 1; int oobwritten = 0, oobcolumn, thisooblen, oobsize; size_t len = ops->len;
size_t ooblen = ops->ooblen;
const u_char *buf = ops->datbuf;
const u_char *oob = ops->oobbuf;
u_char *oobbuf;
int ret = 0;

DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);

/* Initialize retlen, in case of early exit */
ops->retlen = 0;
ops->oobretlen = 0;

/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) { printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
return -EINVAL;
}

Quoted 9 lines

/* Reject writes, which are not page aligned */

        if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) 
{
                printk(KERN_ERR 
"onenand_write_ops_nolock: Attempt to write not page 
aligned data\n");
                return -EINVAL;
        }

The loop cannot handle the case when len is zero so I had:

if (!len)
return 0;

Quoted 60 lines

if (ops->mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
else
oobsize = mtd->oobsize;

oobcolumn = to & (mtd->oobsize - 1);

column = to & (mtd->writesize - 1);

/* Loop until all data write */
while (1) {
if (written < len) {
u_char *wbuf = (u_char *) buf;

thislen = min_t(int, mtd->writesize - column, len - written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);

cond_resched();

this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);

/* Partial page write */
subpage = thislen < mtd->writesize;
if (subpage) {
memset(this->page_buf, 0xff, mtd->writesize);
memcpy(this->page_buf + column, buf, thislen);
wbuf = this->page_buf;
}

this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);

if (oob) {
oobbuf = this->oob_buf;

/* We send data to spare ram with oobsize
* to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob, thisooblen);

oobwritten += thisooblen;
oob += thisooblen;
oobcolumn = 0;
} else
oobbuf = (u_char *) ffchars;

this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
} else
ONENAND_SET_NEXT_BUFFERRAM(this);

if (!first) {
ONENAND_SET_PREV_BUFFERRAM(this);

Quoted 6 lines

ret = this->wait(mtd, FL_WRITING);

/* In partial page write we don't update bufferram */ onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
if (ONENAND_IS_2PLANE(this)) {

Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Amit : FlexOneNand use dual data ram buffer and so we can not use it and other point is for OneNand we have a plan to use dual buufer
because OneNand page size will increase to 4k.

Quoted 24 lines
Quoted 7 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev + this->writesize, !ret && !prev_subpage);
}

if (ret) {

My original patch had "written -= prevlen" here.

Quoted 5 lines

printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
}

Quoted 8 lines

if (written == len) {
/* Only check verify write turn on */
ret = onenand_verify(mtd, buf - len, to - len, len); if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}

Quoted 2 lines

Why not just break here?

Amit : same as kyungmin comment.

Quoted 34 lines
Quoted 20 lines

}
ONENAND_SET_NEXT_BUFFERRAM(this);

if (written == len)
break;
}

this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);

written += thislen;

column = 0;
prev_subpage = subpage;
prev = to;
prevlen = thislen;
to += thislen;
buf += thislen;
first = 0;
}

Quoted 1 line

ops->retlen = written;

Is ops->oobretlen needed here also?

Quoted 3 lines

return ret;
}

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

#3 lore raw
In reply to Adrian Hunter

HI,

Quoted 52 lines · Adrian Hunter
Quoted 2 lines · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though. I have copied the whole function below because the diff is too confusing:

Quoted 35 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or
out-of-band

 * @param mtd           MTD device structure
 * @param to            offset to write to
 * @param ops           oob operation description structure

*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
       struct onenand_chip *this = mtd->priv;
       int written = 0, column, thislen = 0, subpage = 0;
       int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
       int oobwritten = 0, oobcolumn, thisooblen, oobsize;
       size_t len = ops->len;
       size_t ooblen = ops->ooblen;
       const u_char *buf = ops->datbuf;
       const u_char *oob = ops->oobbuf;
       u_char *oobbuf;
       int ret = 0;

       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len

= %i\n", (unsigned int) to, (int) len);

       /* Initialize retlen, in case of early exit */
       ops->retlen = 0;
       ops->oobretlen = 0;

       /* Do not allow writes past end of device */
       if (unlikely((to + len) > mtd->size)) {
               printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to
past end of device\n");
               return -EINVAL;
Quoted 9 lines
       }

       /* Reject writes, which are not page aligned */
       if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
               printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write
not page aligned data\n");
               return -EINVAL;
       }
Quoted 4 lines

The loop cannot handle the case when len is zero so I had:

       if (!len)
               return 0;

Yes there's length check. I wonder is it possible to write with zero? Is it handle at driver level or upper level such as filesystem? But no problem to just add length check here at this time.

Quoted 73 lines
Quoted 65 lines
       if (ops->mode == MTD_OOB_AUTO)
               oobsize = this->ecclayout->oobavail;
       else
               oobsize = mtd->oobsize;

       oobcolumn = to & (mtd->oobsize - 1);

       column = to & (mtd->writesize - 1);

       /* Loop until all data write */
       while (1) {
               if (written < len) {
                       u_char *wbuf = (u_char *) buf;

                       thislen = min_t(int, mtd->writesize - column, len -

written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen
- oobwritten);

                       cond_resched();

                       this->command(mtd, ONENAND_CMD_BUFFERRAM, to,

thislen);

                       /* Partial page write */
                       subpage = thislen < mtd->writesize;
                       if (subpage) {
                               memset(this->page_buf, 0xff,
mtd->writesize);
                               memcpy(this->page_buf + column, buf,
thislen);
                               wbuf = this->page_buf;
                       }

                       this->write_bufferram(mtd, ONENAND_DATARAM, wbuf,

0, mtd->writesize);

                       if (oob) {
                               oobbuf = this->oob_buf;

                               /* We send data to spare ram with oobsize
                                * to prevent byte access */
                               memset(oobbuf, 0xff, mtd->oobsize);
                               if (ops->mode == MTD_OOB_AUTO)
                                       onenand_fill_auto_oob(mtd, oobbuf,

oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob,
thisooblen);

                               oobwritten += thisooblen;
                               oob += thisooblen;
                               oobcolumn = 0;
                       } else
                               oobbuf = (u_char *) ffchars;

                       this->write_bufferram(mtd, ONENAND_SPARERAM,
oobbuf, 0, mtd->oobsize);
               } else
                       ONENAND_SET_NEXT_BUFFERRAM(this);

               if (!first) {
                       ONENAND_SET_PREV_BUFFERRAM(this);
Quoted 7 lines
                       ret = this->wait(mtd, FL_WRITING);

                       /* In partial page write we don't update bufferram
*/
                       onenand_update_bufferram(mtd, prev, !ret &&
!prev_subpage);
                       if (ONENAND_IS_2PLANE(this)) {
Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Agree, I'm not yet tested the 2PLANE features and it doesn't support write-while-program.
If the 2plane and flex-onenand, it used the previous one.

Quoted 9 lines
Quoted 7 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev +

this->writesize, !ret && !prev_subpage);
                       }

                       if (ret) {

My original patch had "written -= prevlen" here.

Agreed.

Quoted 16 lines
Quoted 15 lines

printk(KERN_ERR "onenand_write_ops_nolock:

write filaed %d\n", ret);
                               break;
                       }

                       if (written == len) {
                               /* Only check verify write turn on */
                               ret = onenand_verify(mtd, buf - len, to -
len, len);
                               if (ret) {
                                       printk(KERN_ERR
"onenand_write_ops_nolock: verify failed %d\n", ret);
                                       break;
                               }
Quoted 1 line

Why not just break here?

E.g., In original version, write bufferram 0 and it changes bufferam 1 automatically.
Same as if break here, it points out the previous bufferram.

Quoted 21 lines
Quoted 21 lines
                       }
                       ONENAND_SET_NEXT_BUFFERRAM(this);

                       if (written == len)
                               break;
               }

               this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);

               written += thislen;

               column = 0;
               prev_subpage = subpage;
               prev = to;
               prevlen = thislen;
               to += thislen;
               buf += thislen;
               first = 0;
       }
Quoted 3 lines
Quoted 1 line
       ops->retlen = written;

Is ops->oobretlen needed here also?

Okay I will added. I'm not sure YAFFS handle this one correctly. Maybe it used the retlen in ops operation (data + spare).

Quoted 4 lines
Quoted 4 lines

       return ret;
}

Thank you,
Kyungmin Park

#4 lore raw
Quoted 148 lines · Kyungmin Park
Quoted 49 lines · Adrian Hunter
Quoted 1 line · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though. I have copied the whole function below because the diff is too confusing:

Quoted 35 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or
out-of-band

 * @param mtd           MTD device structure
 * @param to            offset to write to
 * @param ops           oob operation description structure

*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
       struct onenand_chip *this = mtd->priv;
       int written = 0, column, thislen = 0, subpage = 0;
       int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
       int oobwritten = 0, oobcolumn, thisooblen, oobsize;
       size_t len = ops->len;
       size_t ooblen = ops->ooblen;
       const u_char *buf = ops->datbuf;
       const u_char *oob = ops->oobbuf;
       u_char *oobbuf;
       int ret = 0;

       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len

= %i\n", (unsigned int) to, (int) len);

       /* Initialize retlen, in case of early exit */
       ops->retlen = 0;
       ops->oobretlen = 0;

       /* Do not allow writes past end of device */
       if (unlikely((to + len) > mtd->size)) {
               printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to
past end of device\n");
               return -EINVAL;
Quoted 9 lines
       }

       /* Reject writes, which are not page aligned */
       if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
               printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write
not page aligned data\n");
               return -EINVAL;
       }
Quoted 4 lines

The loop cannot handle the case when len is zero so I had:

       if (!len)
               return 0;

Yes there's length check. I wonder is it possible to write with zero? Is it handle at driver level or upper level such as filesystem? But no problem to just add length check here at this time.

Quoted 71 lines
Quoted 64 lines
       if (ops->mode == MTD_OOB_AUTO)
               oobsize = this->ecclayout->oobavail;
       else
               oobsize = mtd->oobsize;

       oobcolumn = to & (mtd->oobsize - 1);

       column = to & (mtd->writesize - 1);

       /* Loop until all data write */
       while (1) {
               if (written < len) {
                       u_char *wbuf = (u_char *) buf;

                       thislen = min_t(int, mtd->writesize - column, len -

written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen
- oobwritten);

                       cond_resched();

                       this->command(mtd, ONENAND_CMD_BUFFERRAM, to,

thislen);

                       /* Partial page write */
                       subpage = thislen < mtd->writesize;
                       if (subpage) {
                               memset(this->page_buf, 0xff,
mtd->writesize);
                               memcpy(this->page_buf + column, buf,
thislen);
                               wbuf = this->page_buf;
                       }

                       this->write_bufferram(mtd, ONENAND_DATARAM, wbuf,

0, mtd->writesize);

                       if (oob) {
                               oobbuf = this->oob_buf;

                               /* We send data to spare ram with oobsize
                                * to prevent byte access */
                               memset(oobbuf, 0xff, mtd->oobsize);
                               if (ops->mode == MTD_OOB_AUTO)
                                       onenand_fill_auto_oob(mtd, oobbuf,

oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob,
thisooblen);

                               oobwritten += thisooblen;
                               oob += thisooblen;
                               oobcolumn = 0;
                       } else
                               oobbuf = (u_char *) ffchars;

                       this->write_bufferram(mtd, ONENAND_SPARERAM,
oobbuf, 0, mtd->oobsize);
               } else
                       ONENAND_SET_NEXT_BUFFERRAM(this);

               if (!first) {
                       ONENAND_SET_PREV_BUFFERRAM(this);
Quoted 7 lines
                       ret = this->wait(mtd, FL_WRITING);

                       /* In partial page write we don't update bufferram
*/
                       onenand_update_bufferram(mtd, prev, !ret &&
!prev_subpage);
                       if (ONENAND_IS_2PLANE(this)) {
Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Agree, I'm not yet tested the 2PLANE features and it doesn't support write-while-program.
If the 2plane and flex-onenand, it used the previous one.

Quoted 5 lines
Quoted 5 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev +

this->writesize, !ret && !prev_subpage);
                       }
Quoted 5 lines
Quoted 2 lines
Quoted 1 line
                       if (ret) {

My original patch had "written -= prevlen" here.

Agreed.

Also we need to invalidate the other bufferram because we transferred the data but did not write it. i.e.

	if (written < len)
		onenand_update_bufferram(mtd, to, 0);
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines

printk(KERN_ERR "onenand_write_ops_nolock:

write filaed %d\n", ret);
                               break;
                       }

                       if (written == len) {
                               /* Only check verify write turn on */
                               ret = onenand_verify(mtd, buf - len, to -
len, len);
                               if (ret) {
                                       printk(KERN_ERR
"onenand_write_ops_nolock: verify failed %d\n", ret);
                                       break;
                               }
Quoted 5 lines
Quoted 1 line

Why not just break here?

E.g., In original version, write bufferram 0 and it changes bufferam 1 automatically.
Same as if break here, it points out the previous bufferram.

The previous bufferram is the last one that was used, so it should point to the previous one.

Quoted 32 lines
Quoted 20 lines
Quoted 20 lines
                       }
                       ONENAND_SET_NEXT_BUFFERRAM(this);

                       if (written == len)
                               break;
               }

               this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);

               written += thislen;

               column = 0;
               prev_subpage = subpage;
               prev = to;
               prevlen = thislen;
               to += thislen;
               buf += thislen;
               first = 0;
       }
Quoted 2 lines
Quoted 1 line
       ops->retlen = written;

Is ops->oobretlen needed here also?

Okay I will added. I'm not sure YAFFS handle this one correctly. Maybe it used the retlen in ops operation (data + spare).

Quoted 2 lines
Quoted 2 lines
       return ret;
}

Thank you,
Kyungmin Park

#5 lore raw
Quoted 164 lines · Adrian Hunter
Quoted 163 lines · Kyungmin Park
Quoted 56 lines · Adrian Hunter
Quoted 2 lines · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though.
I have copied the whole function below because the diff is too confusing:

Quoted 39 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or
out-of-band

 * @param mtd           MTD device structure
 * @param to            offset to write to
 * @param ops           oob operation description structure

*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
      struct onenand_chip *this = mtd->priv;
      int written = 0, column, thislen = 0, subpage = 0;
      int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
      int oobwritten = 0, oobcolumn, thisooblen, oobsize;
      size_t len = ops->len;
      size_t ooblen = ops->ooblen;
      const u_char *buf = ops->datbuf;
      const u_char *oob = ops->oobbuf;
      u_char *oobbuf;
      int ret = 0;

      DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x,

len
= %i\n", (unsigned int) to, (int) len);

      /* Initialize retlen, in case of early exit */
      ops->retlen = 0;
      ops->oobretlen = 0;

      /* Do not allow writes past end of device */
      if (unlikely((to + len) > mtd->size)) {
              printk(KERN_ERR "onenand_write_ops_nolock: Attempt write
to
past end of device\n");
              return -EINVAL;
      }
Quoted 8 lines
      /* Reject writes, which are not page aligned */
      if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
              printk(KERN_ERR "onenand_write_ops_nolock: Attempt to
write
not page aligned data\n");
              return -EINVAL;
      }
Quoted 4 lines

The loop cannot handle the case when len is zero so I had:

      if (!len)
              return 0;

Yes there's length check. I wonder is it possible to write with zero? Is it handle at driver level or upper level such as filesystem? But no problem to just add length check here at this time.

Quoted 74 lines
Quoted 66 lines
      if (ops->mode == MTD_OOB_AUTO)
              oobsize = this->ecclayout->oobavail;
      else
              oobsize = mtd->oobsize;

      oobcolumn = to & (mtd->oobsize - 1);

      column = to & (mtd->writesize - 1);

      /* Loop until all data write */
      while (1) {
              if (written < len) {
                      u_char *wbuf = (u_char *) buf;

                      thislen = min_t(int, mtd->writesize - column, len

-
written);
thisooblen = min_t(int, oobsize - oobcolumn,
ooblen
- oobwritten);

                      cond_resched();

                      this->command(mtd, ONENAND_CMD_BUFFERRAM, to,

thislen);

                      /* Partial page write */
                      subpage = thislen < mtd->writesize;
                      if (subpage) {
                              memset(this->page_buf, 0xff,
mtd->writesize);
                              memcpy(this->page_buf + column, buf,
thislen);
                              wbuf = this->page_buf;
                      }

                      this->write_bufferram(mtd, ONENAND_DATARAM, wbuf,

0, mtd->writesize);

                      if (oob) {
                              oobbuf = this->oob_buf;

                              /* We send data to spare ram with oobsize
                               * to prevent byte access */
                              memset(oobbuf, 0xff, mtd->oobsize);
                              if (ops->mode == MTD_OOB_AUTO)
                                      onenand_fill_auto_oob(mtd, oobbuf,

oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob,
thisooblen);

                              oobwritten += thisooblen;
                              oob += thisooblen;
                              oobcolumn = 0;
                      } else
                              oobbuf = (u_char *) ffchars;

                      this->write_bufferram(mtd, ONENAND_SPARERAM,
oobbuf, 0, mtd->oobsize);
              } else
                      ONENAND_SET_NEXT_BUFFERRAM(this);

              if (!first) {
                      ONENAND_SET_PREV_BUFFERRAM(this);
Quoted 7 lines
                      ret = this->wait(mtd, FL_WRITING);

                      /* In partial page write we don't update bufferram
*/
                      onenand_update_bufferram(mtd, prev, !ret &&
!prev_subpage);
                      if (ONENAND_IS_2PLANE(this)) {
Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Agree, I'm not yet tested the 2PLANE features and it doesn't support write-while-program.
If the 2plane and flex-onenand, it used the previous one.

Quoted 8 lines
Quoted 6 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev +

this->writesize, !ret && !prev_subpage);
                      }

                      if (ret) {

My original patch had "written -= prevlen" here.

Quoted 8 lines
Quoted 2 lines

Agreed.

Also we need to invalidate the other bufferram because we transferred the data but did not write it. i.e.

if (written < len)
onenand_update_bufferram(mtd, to, 0);

For clarity, clear all bufferram at error case.

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines

printk(KERN_ERR "onenand_write_ops_nolock:

write filaed %d\n", ret);
                              break;
                      }

                      if (written == len) {
                              /* Only check verify write turn on */
                              ret = onenand_verify(mtd, buf - len, to -
len, len);
                              if (ret) {
                                      printk(KERN_ERR
"onenand_write_ops_nolock: verify failed %d\n", ret);
                                      break;
                              }
Quoted 9 lines
Quoted 5 lines
Quoted 1 line

Why not just break here?

E.g., In original version, write bufferram 0 and it changes bufferam 1 automatically.
Same as if break here, it points out the previous bufferram.

The previous bufferram is the last one that was used, so it should point to the previous one.

then next time, it overwrite the previous bufferram, but it expects it write next bufferram.

Thank you,
Kyungmin Park

#6 lore raw
Quoted 159 lines · Kyungmin Park
Quoted 157 lines · Adrian Hunter
Quoted 156 lines · Kyungmin Park
Quoted 53 lines · Adrian Hunter
Quoted 1 line · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though.
I have copied the whole function below because the diff is too confusing:

Quoted 39 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or
out-of-band

 * @param mtd           MTD device structure
 * @param to            offset to write to
 * @param ops           oob operation description structure

*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
      struct onenand_chip *this = mtd->priv;
      int written = 0, column, thislen = 0, subpage = 0;
      int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
      int oobwritten = 0, oobcolumn, thisooblen, oobsize;
      size_t len = ops->len;
      size_t ooblen = ops->ooblen;
      const u_char *buf = ops->datbuf;
      const u_char *oob = ops->oobbuf;
      u_char *oobbuf;
      int ret = 0;

      DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x,

len
= %i\n", (unsigned int) to, (int) len);

      /* Initialize retlen, in case of early exit */
      ops->retlen = 0;
      ops->oobretlen = 0;

      /* Do not allow writes past end of device */
      if (unlikely((to + len) > mtd->size)) {
              printk(KERN_ERR "onenand_write_ops_nolock: Attempt write
to
past end of device\n");
              return -EINVAL;
      }
Quoted 8 lines
      /* Reject writes, which are not page aligned */
      if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
              printk(KERN_ERR "onenand_write_ops_nolock: Attempt to
write
not page aligned data\n");
              return -EINVAL;
      }
Quoted 4 lines

The loop cannot handle the case when len is zero so I had:

      if (!len)
              return 0;

Yes there's length check. I wonder is it possible to write with zero? Is it handle at driver level or upper level such as filesystem? But no problem to just add length check here at this time.

Quoted 73 lines
Quoted 66 lines
      if (ops->mode == MTD_OOB_AUTO)
              oobsize = this->ecclayout->oobavail;
      else
              oobsize = mtd->oobsize;

      oobcolumn = to & (mtd->oobsize - 1);

      column = to & (mtd->writesize - 1);

      /* Loop until all data write */
      while (1) {
              if (written < len) {
                      u_char *wbuf = (u_char *) buf;

                      thislen = min_t(int, mtd->writesize - column, len

-
written);
thisooblen = min_t(int, oobsize - oobcolumn,
ooblen
- oobwritten);

                      cond_resched();

                      this->command(mtd, ONENAND_CMD_BUFFERRAM, to,

thislen);

                      /* Partial page write */
                      subpage = thislen < mtd->writesize;
                      if (subpage) {
                              memset(this->page_buf, 0xff,
mtd->writesize);
                              memcpy(this->page_buf + column, buf,
thislen);
                              wbuf = this->page_buf;
                      }

                      this->write_bufferram(mtd, ONENAND_DATARAM, wbuf,

0, mtd->writesize);

                      if (oob) {
                              oobbuf = this->oob_buf;

                              /* We send data to spare ram with oobsize
                               * to prevent byte access */
                              memset(oobbuf, 0xff, mtd->oobsize);
                              if (ops->mode == MTD_OOB_AUTO)
                                      onenand_fill_auto_oob(mtd, oobbuf,

oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob,
thisooblen);

                              oobwritten += thisooblen;
                              oob += thisooblen;
                              oobcolumn = 0;
                      } else
                              oobbuf = (u_char *) ffchars;

                      this->write_bufferram(mtd, ONENAND_SPARERAM,
oobbuf, 0, mtd->oobsize);
              } else
                      ONENAND_SET_NEXT_BUFFERRAM(this);

              if (!first) {
                      ONENAND_SET_PREV_BUFFERRAM(this);
Quoted 7 lines
                      ret = this->wait(mtd, FL_WRITING);

                      /* In partial page write we don't update bufferram
*/
                      onenand_update_bufferram(mtd, prev, !ret &&
!prev_subpage);
                      if (ONENAND_IS_2PLANE(this)) {
Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Agree, I'm not yet tested the 2PLANE features and it doesn't support write-while-program.
If the 2plane and flex-onenand, it used the previous one.

Quoted 7 lines
Quoted 6 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev +

this->writesize, !ret && !prev_subpage);
                      }

                      if (ret) {

My original patch had "written -= prevlen" here.

Agreed.

Quoted 7 lines
Quoted 5 lines

Also we need to invalidate the other bufferram because we transferred the data but did not write it. i.e.

if (written < len)
onenand_update_bufferram(mtd, to, 0);

For clarity, clear all bufferram at error case.

OK

Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 14 lines
Quoted 14 lines

printk(KERN_ERR "onenand_write_ops_nolock:

write filaed %d\n", ret);
                              break;
                      }

                      if (written == len) {
                              /* Only check verify write turn on */
                              ret = onenand_verify(mtd, buf - len, to -
len, len);
                              if (ret) {
                                      printk(KERN_ERR
"onenand_write_ops_nolock: verify failed %d\n", ret);
                                      break;
                              }
Quoted 1 line

Why not just break here?

E.g., In original version, write bufferram 0 and it changes bufferam 1 automatically.
Same as if break here, it points out the previous bufferram.

Quoted 6 lines
Quoted 3 lines

The previous bufferram is the last one that was used, so it should point to the previous one.

then next time, it overwrite the previous bufferram, but it expects it write next bufferram.

The current MTD write is finished because written == len. The next one starts by changing the bufferram with this->command(mtd, ONENAND_CMD_BUFFERRAM, ...)

#7 lore raw
Quoted 210 lines · Adrian Hunter
Quoted 173 lines · Kyungmin Park
Quoted 170 lines · Adrian Hunter
Quoted 168 lines · Kyungmin Park
Quoted 57 lines · Adrian Hunter
Quoted 2 lines · Kyungmin Park

This is from Adrian hunter and modified for write_ops operation.

Thanks for looking at write-while-program. I have a few questions though.
I have copied the whole function below because the diff is too confusing:

Quoted 39 lines

/**
* onenand_write_ops_nolock - [OneNAND Interface] write main and/or
out-of-band

 * @param mtd           MTD device structure
 * @param to            offset to write to
 * @param ops           oob operation description structure

*
* Write main and/or oob with ECC
*/
static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)

{
     struct onenand_chip *this = mtd->priv;
     int written = 0, column, thislen = 0, subpage = 0;
     int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
     int oobwritten = 0, oobcolumn, thisooblen, oobsize;
     size_t len = ops->len;
     size_t ooblen = ops->ooblen;
     const u_char *buf = ops->datbuf;
     const u_char *oob = ops->oobbuf;
     u_char *oobbuf;
     int ret = 0;

     DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x,

len
= %i\n", (unsigned int) to, (int) len);

     /* Initialize retlen, in case of early exit */
     ops->retlen = 0;
     ops->oobretlen = 0;

     /* Do not allow writes past end of device */
     if (unlikely((to + len) > mtd->size)) {
             printk(KERN_ERR "onenand_write_ops_nolock: Attempt write
to
past end of device\n");
             return -EINVAL;
     }
Quoted 8 lines
     /* Reject writes, which are not page aligned */
     if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
             printk(KERN_ERR "onenand_write_ops_nolock: Attempt to
write
not page aligned data\n");
             return -EINVAL;
     }
Quoted 4 lines

The loop cannot handle the case when len is zero so I had:

     if (!len)
             return 0;

Yes there's length check. I wonder is it possible to write with zero? Is it handle at driver level or upper level such as filesystem? But no problem to just add length check here at this time.

Quoted 76 lines
Quoted 67 lines
     if (ops->mode == MTD_OOB_AUTO)
             oobsize = this->ecclayout->oobavail;
     else
             oobsize = mtd->oobsize;

     oobcolumn = to & (mtd->oobsize - 1);

     column = to & (mtd->writesize - 1);

     /* Loop until all data write */
     while (1) {
             if (written < len) {
                     u_char *wbuf = (u_char *) buf;

                     thislen = min_t(int, mtd->writesize - column, len

-
written);
thisooblen = min_t(int, oobsize - oobcolumn,
ooblen
- oobwritten);

                     cond_resched();

                     this->command(mtd, ONENAND_CMD_BUFFERRAM, to,

thislen);

                     /* Partial page write */
                     subpage = thislen < mtd->writesize;
                     if (subpage) {
                             memset(this->page_buf, 0xff,
mtd->writesize);
                             memcpy(this->page_buf + column, buf,
thislen);
                             wbuf = this->page_buf;
                     }

                     this->write_bufferram(mtd, ONENAND_DATARAM, wbuf,

0, mtd->writesize);

                     if (oob) {
                             oobbuf = this->oob_buf;

                             /* We send data to spare ram with oobsize
                              * to prevent byte access */
                             memset(oobbuf, 0xff, mtd->oobsize);
                             if (ops->mode == MTD_OOB_AUTO)
                                     onenand_fill_auto_oob(mtd,

oobbuf,
oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob,
thisooblen);

                             oobwritten += thisooblen;
                             oob += thisooblen;
                             oobcolumn = 0;
                     } else
                             oobbuf = (u_char *) ffchars;

                     this->write_bufferram(mtd, ONENAND_SPARERAM,
oobbuf, 0, mtd->oobsize);
             } else
                     ONENAND_SET_NEXT_BUFFERRAM(this);

             if (!first) {
                     ONENAND_SET_PREV_BUFFERRAM(this);
Quoted 8 lines
                     ret = this->wait(mtd, FL_WRITING);

                     /* In partial page write we don't update
bufferram
*/
                     onenand_update_bufferram(mtd, prev, !ret &&
!prev_subpage);
                     if (ONENAND_IS_2PLANE(this)) {
Quoted 7 lines

I do not understand how 2PLANE is compatible with write-while-program because
2PLANE uses both buffers so we cannot start transferring to the second buffer
while the program is ongoing. Does it work?

Won't MLC and FlexOneNAND have that problem too?

Agree, I'm not yet tested the 2PLANE features and it doesn't support write-while-program.
If the 2plane and flex-onenand, it used the previous one.

Quoted 8 lines
Quoted 6 lines

ONENAND_SET_BUFFERRAM1(this); onenand_update_bufferram(mtd, prev +

this->writesize, !ret && !prev_subpage);
                     }

                     if (ret) {

My original patch had "written -= prevlen" here.

Agreed.

Quoted 7 lines
Quoted 5 lines

Also we need to invalidate the other bufferram because we transferred the data but did not write it. i.e.

if (written < len)
onenand_update_bufferram(mtd, to, 0);

For clarity, clear all bufferram at error case.

OK

Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines

printk(KERN_ERR
"onenand_write_ops_nolock:

write filaed %d\n", ret);
                             break;
                     }

                     if (written == len) {
                             /* Only check verify write turn on */
                             ret = onenand_verify(mtd, buf - len, to -
len, len);
                             if (ret) {
                                     printk(KERN_ERR
"onenand_write_ops_nolock: verify failed %d\n", ret);
                                     break;
                             }
Quoted 5 lines
Quoted 1 line

Why not just break here?

E.g., In original version, write bufferram 0 and it changes bufferam 1 automatically.
Same as if break here, it points out the previous bufferram.

The previous bufferram is the last one that was used, so it should point to the previous one.

Quoted 7 lines
Quoted 2 lines

then next time, it overwrite the previous bufferram, but it expects it write next bufferram.

The current MTD write is finished because written == len. The next one starts by changing the bufferram with this->command(mtd, ONENAND_CMD_BUFFERRAM, ...)

Ah sorry, you're right. I'm confused.

I will repost it.

Thank you,
Kyungmin Park