1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-27 19:33:08 +02:00

[xburst] Improve mounttime.

This patchset optimizes nand read access and reduces the ubi attach time by ~2/3
Credits go to dvdk for having the idea.
This commit is contained in:
Lars-Peter Clausen 2011-02-26 18:40:02 +01:00 committed by Xiangfu Liu
parent 44fe4794bb
commit 5629baf0c4
4 changed files with 265 additions and 0 deletions

View File

@ -0,0 +1,21 @@
From 2b0db7309cf386899741b355efb12ab2742f178c Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 26 Feb 2011 15:19:11 +0100
Subject: [PATCH 1/4] ubi: Read only the vid header instead of the whole page
Improves ubi attach time by ~1/2
---
drivers/mtd/ubi/io.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -979,7 +979,7 @@ int ubi_io_read_vid_hdr(struct ubi_devic
p = (char *)vid_hdr - ubi->vid_hdr_shift;
err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
- ubi->vid_hdr_alsize);
+ UBI_VID_HDR_SIZE + ubi->vid_hdr_shift);
if (err) {
if (err != UBI_IO_BITFLIPS && err != -EBADMSG)
return err;

View File

@ -0,0 +1,41 @@
From 93ad1a19872dfa2f4b9aa7b8d20581bda3057622 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 26 Feb 2011 15:30:07 +0100
Subject: [PATCH 2/4] NAND: Optimize NAND_ECC_HW_OOB_FIRST read
Avoid sending unnecessary READ commands to the chip.
---
drivers/mtd/nand/nand_base.c | 15 +++++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1008,9 +1008,16 @@ static int nand_read_page_hwecc_oob_firs
uint8_t *ecc_calc = chip->buffers->ecccalc;
/* Read the OOB area first */
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ /* Read the OOB area first */
+ if (mtd->writesize > 512) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ }
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1177,7 +1184,7 @@ static int nand_do_read_ops(struct mtd_i
if (realpage != chip->pagebuf || oob) {
bufpoi = aligned ? buf : chip->buffers->databuf;
- if (likely(sndcmd)) {
+ if (likely(sndcmd) && chip->ecc.mode != NAND_ECC_HW_OOB_FIRST) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
sndcmd = 0;
}

View File

@ -0,0 +1,145 @@
From 117f87de607a65e8e1cd155acd12a7cd201de7d0 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 26 Feb 2011 15:26:55 +0100
Subject: [PATCH 3/4] NAND: Add support for subpage reads for NAND_ECC_HW_OOB_FIRST
---
drivers/mtd/nand/nand_base.c | 84 ++++++++++++++++++++++++++++++++++++++++--
include/linux/mtd/nand.h | 8 ++--
2 files changed, 84 insertions(+), 8 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -864,7 +864,8 @@ static int nand_read_page_swecc(struct m
* @readlen: data length
* @bufpoi: buffer to store read data
*/
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
{
int start_step, end_step, num_steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -1039,6 +1040,76 @@ static int nand_read_page_hwecc_oob_firs
}
/**
+ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
+ * @page: page number to read
+ *
+ * Hardware ECC for large page chips, require OOB to be read first.
+ * For this ECC mode, the write_page method is re-used from ECC_HW.
+ * These methods read/write ECC from the OOB area, unlike the
+ * ECC_HW_SYNDROME support with multiple ECC steps, follows the
+ * "infix ECC" scheme and reads/writes ECC from the data area, by
+ * overwriting the NAND manufacturer bad block markings.
+ */
+static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
+{
+ int start_step, end_step, num_steps;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *p;
+ int data_col_addr;
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ int i;
+
+ /* Column address wihin the page aligned to ECC size */
+ start_step = data_offs / chip->ecc.size;
+ end_step = (data_offs + readlen - 1) / chip->ecc.size;
+ num_steps = end_step - start_step + 1;
+
+ data_col_addr = start_step * chip->ecc.size;
+
+ /* Read the OOB area first */
+ if (mtd->writesize > 512) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
+ }
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ p = bufpoi + data_col_addr;
+
+ for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+
+ return 0;
+}
+
+
+/**
* nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
@@ -1194,7 +1265,7 @@ static int nand_do_read_ops(struct mtd_i
ret = chip->ecc.read_page_raw(mtd, chip,
bufpoi, page);
else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
- ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
+ ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi, page);
else
ret = chip->ecc.read_page(mtd, chip, bufpoi,
page);
@@ -2742,8 +2813,11 @@ int nand_scan_tail(struct mtd_info *mtd)
"Hardware ECC not possible\n");
BUG();
}
- if (!chip->ecc.read_page)
+ if (!chip->ecc.read_page) {
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
+ if (!chip->ecc.read_subpage)
+ chip->ecc.read_subpage = nand_read_subpage_hwecc_oob_first;
+ }
case NAND_ECC_HW:
/* Use standard hwecc read page function ? */
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -178,9 +178,9 @@ typedef enum {
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
-/* Large page NAND with SOFT_ECC should support subpage reads */
-#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
- && (chip->page_shift > 9))
+/* Large page NAND with read_subpage set should support subpage reads */
+#define NAND_SUBPAGE_READ(chip) (((chip)->ecc.read_subpage) \
+ && ((chip)->page_shift > 9))
/* Mask to zero out the chip options, which come from the id table */
#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
@@ -282,7 +282,7 @@ struct nand_ecc_ctrl {
int (*read_subpage)(struct mtd_info *mtd,
struct nand_chip *chip,
uint32_t offs, uint32_t len,
- uint8_t *buf);
+ uint8_t *buf, int page);
void (*write_page)(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf);

View File

@ -0,0 +1,58 @@
From 3eeeee7302a9b25de1eeabd901d3bb678d9983d9 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 26 Feb 2011 15:32:30 +0100
Subject: [PATCH 4/4] NAND: Optimize reading the eec data for the JZ4740 (evil hack)
We know that the ecc data is continuous, this allows us to only read the ecc
data instead of the whole oob section, which slightly improves performance.
Note that this is an evil hack, which will break platforms where the ecc data is
non-continuous.
---
drivers/mtd/nand/nand_base.c | 16 +++++-----------
1 files changed, 5 insertions(+), 11 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1011,8 +1011,8 @@ static int nand_read_page_hwecc_oob_firs
/* Read the OOB area first */
/* Read the OOB area first */
if (mtd->writesize > 512) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page);
+ chip->read_buf(mtd, ecc_code, chip->ecc.total);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
@@ -1020,9 +1020,6 @@ static int nand_read_page_hwecc_oob_firs
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
}
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
@@ -1077,8 +1074,8 @@ static int nand_read_subpage_hwecc_oob_f
/* Read the OOB area first */
if (mtd->writesize > 512) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page);
+ chip->read_buf(mtd, ecc_code, chip->ecc.total);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
@@ -1086,9 +1083,6 @@ static int nand_read_subpage_hwecc_oob_f
chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
}
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
p = bufpoi + data_col_addr;
for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {