All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] mtd: nand: optimize subpage writes
@ 2014-06-30 10:33 Pekon Gupta
  2014-06-30 10:34 ` [RFC PATCH 1/2] mtd: nand: clean nand_write_subpage_hwecc to reduce local variables Pekon Gupta
  2014-06-30 10:34 ` [RFC PATCH 2/2] mtd: nand: refactor nand_write_subpage_hwecc to write only relevant subpage data Pekon Gupta
  0 siblings, 2 replies; 3+ messages in thread
From: Pekon Gupta @ 2014-06-30 10:33 UTC (permalink / raw)
  To: Brian Norris; +Cc: linux-mtd, Pekon Gupta, Ezequiel Garcia, Artem Bityutskiy

This patch cleans and fixes nand_write_subpage_hwecc() for devices supporting
subpages. Devices supporting subpage write must support NAND_CMD_RNDIN(0x80)

As per datasheet following devices support above command
Macronix	MX30LF1G08	Figure 13. AC Waveforms for Random Data In (For Page Program)
Samsung		K9F1G08U0E	Figure 4.9 Page Program Operation with Random Data Input
Micron		MT29F[2G|4G]xx	Section RANDOM DATA INPUT 85h
Spansion	S34ML[xx]G2	Figure 6.11 Page Program Operation with Random Data Input
Toshiba		TC58NVG1S3ETAI0	Section: Random Column Address Change in Auto Page Program Operation

- This series needs testing with multiple drivers and above devices to check
  full compliance and working of subpage writes.
- Use 'ubiformat -s <subpage-size>' option to format a UBIFS image on subpages
  supporting device

Pekon Gupta (2):
  mtd: nand: clean nand_write_subpage_hwecc to reduce local variables
  mtd: nand: refactor nand_write_subpage_hwecc to write only relevant
    subpage data

 drivers/mtd/nand/nand_base.c | 51 +++++++++++++++++++-------------------------
 1 file changed, 22 insertions(+), 29 deletions(-)

-- 
1.8.5.1.163.gd7aced9

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH 1/2] mtd: nand: clean nand_write_subpage_hwecc to reduce local variables
  2014-06-30 10:33 [RFC PATCH 0/2] mtd: nand: optimize subpage writes Pekon Gupta
@ 2014-06-30 10:34 ` Pekon Gupta
  2014-06-30 10:34 ` [RFC PATCH 2/2] mtd: nand: refactor nand_write_subpage_hwecc to write only relevant subpage data Pekon Gupta
  1 sibling, 0 replies; 3+ messages in thread
From: Pekon Gupta @ 2014-06-30 10:34 UTC (permalink / raw)
  To: Brian Norris; +Cc: linux-mtd, Pekon Gupta, Ezequiel Garcia, Artem Bityutskiy

Use 'struct nand_ecc_ctrl *' instead of 'struct nand_chip *' for de-referenceing
ECC variables.

Signed-off-by: Pekon Gupta <pekon@ti.com>
---
 drivers/mtd/nand/nand_base.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c5c1b1f..fdbd8c6 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2106,25 +2106,23 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 {
 	uint8_t *oob_buf  = chip->oob_poi;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
-	int ecc_size      = chip->ecc.size;
-	int ecc_bytes     = chip->ecc.bytes;
-	int ecc_steps     = chip->ecc.steps;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
 	uint32_t *eccpos  = chip->ecc.layout->eccpos;
-	uint32_t start_step = offset / ecc_size;
-	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
-	int oob_bytes       = mtd->oobsize / ecc_steps;
+	uint32_t start_step = offset / ecc->size;
+	uint32_t end_step   = (offset + data_len - 1) / ecc->size;
+	int oob_bytes       = mtd->oobsize / ecc->steps;
 	int step, i;
 
-	for (step = 0; step < ecc_steps; step++) {
+	for (step = 0; step < ecc->steps; step++) {
 		/* configure controller for WRITE access */
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 
 		/* write data (untouched subpages already masked by 0xFF) */
-		chip->write_buf(mtd, buf, ecc_size);
+		chip->write_buf(mtd, buf, ecc->size);
 
 		/* mask ECC of un-touched subpages by padding 0xFF */
 		if ((step < start_step) || (step > end_step))
-			memset(ecc_calc, 0xff, ecc_bytes);
+			memset(ecc_calc, 0xff, ecc->bytes);
 		else
 			chip->ecc.calculate(mtd, buf, ecc_calc);
 
@@ -2133,9 +2131,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 		if (!oob_required || (step < start_step) || (step > end_step))
 			memset(oob_buf, 0xff, oob_bytes);
 
-		buf += ecc_size;
-		ecc_calc += ecc_bytes;
-		oob_buf  += oob_bytes;
+		buf		+= ecc->size;
+		ecc_calc	+= ecc->bytes;
+		oob_buf		+= oob_bytes;
 	}
 
 	/* copy calculated ECC for whole page to chip->buffer->oob */
-- 
1.8.5.1.163.gd7aced9

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH 2/2] mtd: nand: refactor nand_write_subpage_hwecc to write only relevant subpage data
  2014-06-30 10:33 [RFC PATCH 0/2] mtd: nand: optimize subpage writes Pekon Gupta
  2014-06-30 10:34 ` [RFC PATCH 1/2] mtd: nand: clean nand_write_subpage_hwecc to reduce local variables Pekon Gupta
@ 2014-06-30 10:34 ` Pekon Gupta
  1 sibling, 0 replies; 3+ messages in thread
From: Pekon Gupta @ 2014-06-30 10:34 UTC (permalink / raw)
  To: Brian Norris; +Cc: linux-mtd, Pekon Gupta, Ezequiel Garcia, Artem Bityutskiy

Current nand_write_subpage_hwecc() code extends the subpage data to page-sized
one by padding it with 0xff. And then whole chunk is written to NAND device
using normal PAGE_PROGRAM sequence as below.
  <NAND_CMD_SEQIN(0x80)>
       <row-addr>
       <column-addr>
       <data1>
       <data2>
       ...
       <dataN>
       <OOB-data>
  <NAND_CMD_PAGEPROG(0x10)>

However many NAND devices support NAND_CMD_RNDIN(0x85) 'Random Input' command
which allows changing the column-address during PAGE_PROGRAM operation and write
only relevant data to NAND device, thereby avoiding the need for padding. This
patch uses below sequence to optimizes data writes for devices supporting subpages.
  <NAND_CMD_SEQIN(0x80)>
       <row-addr>
    <NAND_CMD_RNDIN(0x85)>
       <column-addr = subpageX>
       <data1>
       <data2>
       ...
       <dataN>
    <NAND_CMD_RNDIN(0x85)>
       <column-addr = subpageY>
       <data1>
       <data2>
       ...
       <dataM>
       ...
    <NAND_CMD_RNDIN(0x85)>
       <column-addr = oob-offset>
       <OOB-data>
  <NAND_CMD_PAGEPROG(0x10)>

*Note*
 nand_chip-ecc->size may be different from nand_chip->subpagesize. That means
 a single subpage can be further divided into more than one ECC sectors, as per
 capacity of ECC engine. nand_chip->ecc->size is an attribute of ECC engine and
 not NAND device. However same is not take care for reads in nand_read_subpage()

Signed-off-by: Pekon Gupta <pekon@ti.com>
---
 drivers/mtd/nand/nand_base.c | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index fdbd8c6..41b844d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2110,40 +2110,35 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 	uint32_t *eccpos  = chip->ecc.layout->eccpos;
 	uint32_t start_step = offset / ecc->size;
 	uint32_t end_step   = (offset + data_len - 1) / ecc->size;
-	int oob_bytes       = mtd->oobsize / ecc->steps;
 	int step, i;
 
-	for (step = 0; step < ecc->steps; step++) {
+	buf		+= (start_step * ecc->size);
+	ecc_calc	+= (start_step * ecc->bytes);
+	eccpos		+= (start_step * ecc->bytes);
+	for (step = start_step; step < end_step; step++) {
 		/* configure controller for WRITE access */
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 
-		/* write data (untouched subpages already masked by 0xFF) */
+		/* write data */
+		chip->cmdfunc(mtd, NAND_CMD_RNDIN, (step * ecc->size), -1);
 		chip->write_buf(mtd, buf, ecc->size);
 
-		/* mask ECC of un-touched subpages by padding 0xFF */
-		if ((step < start_step) || (step > end_step))
-			memset(ecc_calc, 0xff, ecc->bytes);
-		else
-			chip->ecc.calculate(mtd, buf, ecc_calc);
+		/* calculate ECC */
+		chip->ecc.calculate(mtd, buf, ecc_calc);
 
-		/* mask OOB of un-touched subpages by padding 0xFF */
-		/* if oob_required, preserve OOB metadata of written subpage */
-		if (!oob_required || (step < start_step) || (step > end_step))
-			memset(oob_buf, 0xff, oob_bytes);
+		/* copy calculated ECC to OOB buffer as per ecc-layout */
+		for (i = 0; i < ecc->bytes; i++)
+			oob_buf[eccpos[i]] = ecc_calc[i];
 
 		buf		+= ecc->size;
 		ecc_calc	+= ecc->bytes;
-		oob_buf		+= oob_bytes;
+		eccpos		+= ecc->bytes;
 	}
 
-	/* copy calculated ECC for whole page to chip->buffer->oob */
-	/* this include masked-value(0xFF) for unwritten subpages */
-	ecc_calc = chip->buffers->ecccalc;
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
-	/* write OOB buffer to NAND device */
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+	/* write _complete_ OOB buffer to NAND device,
+	 * unused OOB bytes are already padded with 0xFF */
+	chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
+	chip->write_buf(mtd, oob_buf, mtd->oobsize);
 
 	return 0;
 }
-- 
1.8.5.1.163.gd7aced9

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-06-30 10:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-30 10:33 [RFC PATCH 0/2] mtd: nand: optimize subpage writes Pekon Gupta
2014-06-30 10:34 ` [RFC PATCH 1/2] mtd: nand: clean nand_write_subpage_hwecc to reduce local variables Pekon Gupta
2014-06-30 10:34 ` [RFC PATCH 2/2] mtd: nand: refactor nand_write_subpage_hwecc to write only relevant subpage data Pekon Gupta

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.