|
@@ -1066,15 +1066,17 @@ EXPORT_SYMBOL(nand_lock);
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*
|
|
*
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
|
*/
|
|
*/
|
|
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- uint8_t *buf, int page)
|
|
|
|
|
|
+ uint8_t *buf, int oob_required, int page)
|
|
{
|
|
{
|
|
chip->read_buf(mtd, buf, mtd->writesize);
|
|
chip->read_buf(mtd, buf, mtd->writesize);
|
|
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
|
|
+ if (oob_required)
|
|
|
|
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1083,13 +1085,14 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*
|
|
*
|
|
* We need a special oob layout and handling even when OOB isn't used.
|
|
* We need a special oob layout and handling even when OOB isn't used.
|
|
*/
|
|
*/
|
|
static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
|
static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
|
- struct nand_chip *chip,
|
|
|
|
- uint8_t *buf, int page)
|
|
|
|
|
|
+ struct nand_chip *chip, uint8_t *buf,
|
|
|
|
+ int oob_required, int page)
|
|
{
|
|
{
|
|
int eccsize = chip->ecc.size;
|
|
int eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1126,10 +1129,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*/
|
|
*/
|
|
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- uint8_t *buf, int page)
|
|
|
|
|
|
+ uint8_t *buf, int oob_required, int page)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1138,8 +1142,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
- chip->ecc.read_page_raw(mtd, chip, buf, page);
|
|
|
|
|
|
+ chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
@@ -1154,12 +1159,14 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
int stat;
|
|
int stat;
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
- if (stat < 0)
|
|
|
|
|
|
+ if (stat < 0) {
|
|
mtd->ecc_stats.failed++;
|
|
mtd->ecc_stats.failed++;
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
mtd->ecc_stats.corrected += stat;
|
|
mtd->ecc_stats.corrected += stat;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1180,6 +1187,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
|
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
|
|
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
|
|
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
|
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
|
int index = 0;
|
|
int index = 0;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
/* Column address within the page aligned to ECC size (256bytes) */
|
|
/* Column address within the page aligned to ECC size (256bytes) */
|
|
start_step = data_offs / chip->ecc.size;
|
|
start_step = data_offs / chip->ecc.size;
|
|
@@ -1244,12 +1252,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p,
|
|
stat = chip->ecc.correct(mtd, p,
|
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
|
- if (stat < 0)
|
|
|
|
|
|
+ if (stat < 0) {
|
|
mtd->ecc_stats.failed++;
|
|
mtd->ecc_stats.failed++;
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
mtd->ecc_stats.corrected += stat;
|
|
mtd->ecc_stats.corrected += stat;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1257,12 +1267,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*
|
|
*
|
|
* Not for syndrome calculating ECC controllers which need a special oob layout.
|
|
* Not for syndrome calculating ECC controllers which need a special oob layout.
|
|
*/
|
|
*/
|
|
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- uint8_t *buf, int page)
|
|
|
|
|
|
+ uint8_t *buf, int oob_required, int page)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1271,6 +1282,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
@@ -1289,12 +1301,14 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
int stat;
|
|
int stat;
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
- if (stat < 0)
|
|
|
|
|
|
+ if (stat < 0) {
|
|
mtd->ecc_stats.failed++;
|
|
mtd->ecc_stats.failed++;
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
mtd->ecc_stats.corrected += stat;
|
|
mtd->ecc_stats.corrected += stat;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1302,6 +1316,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*
|
|
*
|
|
* Hardware ECC for large page chips, require OOB to be read first. For this
|
|
* Hardware ECC for large page chips, require OOB to be read first. For this
|
|
@@ -1311,7 +1326,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* the data area, by overwriting the NAND manufacturer bad block markings.
|
|
* the data area, by overwriting the NAND manufacturer bad block markings.
|
|
*/
|
|
*/
|
|
static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
|
static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
|
- struct nand_chip *chip, uint8_t *buf, int page)
|
|
|
|
|
|
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1320,6 +1335,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
/* Read the OOB area first */
|
|
/* Read the OOB area first */
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
@@ -1337,12 +1353,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
|
- if (stat < 0)
|
|
|
|
|
|
+ if (stat < 0) {
|
|
mtd->ecc_stats.failed++;
|
|
mtd->ecc_stats.failed++;
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
mtd->ecc_stats.corrected += stat;
|
|
mtd->ecc_stats.corrected += stat;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1350,19 +1368,21 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
* @buf: buffer to store read data
|
|
|
|
+ * @oob_required: caller requires OOB data read to chip->oob_poi
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
*
|
|
*
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
* need a special oob layout and handling.
|
|
* need a special oob layout and handling.
|
|
*/
|
|
*/
|
|
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- uint8_t *buf, int page)
|
|
|
|
|
|
+ uint8_t *buf, int oob_required, int page)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccsteps = chip->ecc.steps;
|
|
int eccsteps = chip->ecc.steps;
|
|
uint8_t *p = buf;
|
|
uint8_t *p = buf;
|
|
uint8_t *oob = chip->oob_poi;
|
|
uint8_t *oob = chip->oob_poi;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
int stat;
|
|
int stat;
|
|
@@ -1379,10 +1399,12 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
chip->read_buf(mtd, oob, eccbytes);
|
|
chip->read_buf(mtd, oob, eccbytes);
|
|
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
|
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
|
|
|
|
|
- if (stat < 0)
|
|
|
|
|
|
+ if (stat < 0) {
|
|
mtd->ecc_stats.failed++;
|
|
mtd->ecc_stats.failed++;
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
mtd->ecc_stats.corrected += stat;
|
|
mtd->ecc_stats.corrected += stat;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
+ }
|
|
|
|
|
|
oob += eccbytes;
|
|
oob += eccbytes;
|
|
|
|
|
|
@@ -1397,7 +1419,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
if (i)
|
|
if (i)
|
|
chip->read_buf(mtd, oob, i);
|
|
chip->read_buf(mtd, oob, i);
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1459,11 +1481,9 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
|
|
static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
struct mtd_oob_ops *ops)
|
|
struct mtd_oob_ops *ops)
|
|
{
|
|
{
|
|
- int chipnr, page, realpage, col, bytes, aligned;
|
|
|
|
|
|
+ int chipnr, page, realpage, col, bytes, aligned, oob_required;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct mtd_ecc_stats stats;
|
|
struct mtd_ecc_stats stats;
|
|
- int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
|
|
|
- int sndcmd = 1;
|
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
uint32_t readlen = ops->len;
|
|
uint32_t readlen = ops->len;
|
|
uint32_t oobreadlen = ops->ooblen;
|
|
uint32_t oobreadlen = ops->ooblen;
|
|
@@ -1471,6 +1491,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
mtd->oobavail : mtd->oobsize;
|
|
mtd->oobavail : mtd->oobsize;
|
|
|
|
|
|
uint8_t *bufpoi, *oob, *buf;
|
|
uint8_t *bufpoi, *oob, *buf;
|
|
|
|
+ unsigned int max_bitflips = 0;
|
|
|
|
|
|
stats = mtd->ecc_stats;
|
|
stats = mtd->ecc_stats;
|
|
|
|
|
|
@@ -1484,6 +1505,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
|
|
|
|
buf = ops->datbuf;
|
|
buf = ops->datbuf;
|
|
oob = ops->oobbuf;
|
|
oob = ops->oobbuf;
|
|
|
|
+ oob_required = oob ? 1 : 0;
|
|
|
|
|
|
while (1) {
|
|
while (1) {
|
|
bytes = min(mtd->writesize - col, readlen);
|
|
bytes = min(mtd->writesize - col, readlen);
|
|
@@ -1493,21 +1515,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
if (realpage != chip->pagebuf || oob) {
|
|
if (realpage != chip->pagebuf || oob) {
|
|
bufpoi = aligned ? buf : chip->buffers->databuf;
|
|
bufpoi = aligned ? buf : chip->buffers->databuf;
|
|
|
|
|
|
- if (likely(sndcmd)) {
|
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
|
|
|
- sndcmd = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
|
|
|
|
|
- /* Now read the page into the buffer */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Now read the page into the buffer. Absent an error,
|
|
|
|
+ * the read methods return max bitflips per ecc step.
|
|
|
|
+ */
|
|
if (unlikely(ops->mode == MTD_OPS_RAW))
|
|
if (unlikely(ops->mode == MTD_OPS_RAW))
|
|
- ret = chip->ecc.read_page_raw(mtd, chip,
|
|
|
|
- bufpoi, page);
|
|
|
|
|
|
+ ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
|
|
|
|
+ oob_required,
|
|
|
|
+ page);
|
|
else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
|
|
else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
|
|
ret = chip->ecc.read_subpage(mtd, chip,
|
|
ret = chip->ecc.read_subpage(mtd, chip,
|
|
col, bytes, bufpoi);
|
|
col, bytes, bufpoi);
|
|
else
|
|
else
|
|
ret = chip->ecc.read_page(mtd, chip, bufpoi,
|
|
ret = chip->ecc.read_page(mtd, chip, bufpoi,
|
|
- page);
|
|
|
|
|
|
+ oob_required, page);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
if (!aligned)
|
|
if (!aligned)
|
|
/* Invalidate page cache */
|
|
/* Invalidate page cache */
|
|
@@ -1515,22 +1538,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, ret);
|
|
|
|
+
|
|
/* Transfer not aligned data */
|
|
/* Transfer not aligned data */
|
|
if (!aligned) {
|
|
if (!aligned) {
|
|
if (!NAND_SUBPAGE_READ(chip) && !oob &&
|
|
if (!NAND_SUBPAGE_READ(chip) && !oob &&
|
|
!(mtd->ecc_stats.failed - stats.failed) &&
|
|
!(mtd->ecc_stats.failed - stats.failed) &&
|
|
- (ops->mode != MTD_OPS_RAW))
|
|
|
|
|
|
+ (ops->mode != MTD_OPS_RAW)) {
|
|
chip->pagebuf = realpage;
|
|
chip->pagebuf = realpage;
|
|
- else
|
|
|
|
|
|
+ chip->pagebuf_bitflips = ret;
|
|
|
|
+ } else {
|
|
/* Invalidate page cache */
|
|
/* Invalidate page cache */
|
|
chip->pagebuf = -1;
|
|
chip->pagebuf = -1;
|
|
|
|
+ }
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
}
|
|
}
|
|
|
|
|
|
buf += bytes;
|
|
buf += bytes;
|
|
|
|
|
|
if (unlikely(oob)) {
|
|
if (unlikely(oob)) {
|
|
-
|
|
|
|
int toread = min(oobreadlen, max_oobsize);
|
|
int toread = min(oobreadlen, max_oobsize);
|
|
|
|
|
|
if (toread) {
|
|
if (toread) {
|
|
@@ -1541,13 +1567,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
}
|
|
}
|
|
|
|
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
- /*
|
|
|
|
- * Apply delay or wait for ready/busy pin. Do
|
|
|
|
- * this before the AUTOINCR check, so no
|
|
|
|
- * problems arise if a chip which does auto
|
|
|
|
- * increment is marked as NOAUTOINCR by the
|
|
|
|
- * board driver.
|
|
|
|
- */
|
|
|
|
|
|
+ /* Apply delay or wait for ready/busy pin */
|
|
if (!chip->dev_ready)
|
|
if (!chip->dev_ready)
|
|
udelay(chip->chip_delay);
|
|
udelay(chip->chip_delay);
|
|
else
|
|
else
|
|
@@ -1556,6 +1576,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
} else {
|
|
} else {
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
buf += bytes;
|
|
buf += bytes;
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips,
|
|
|
|
+ chip->pagebuf_bitflips);
|
|
}
|
|
}
|
|
|
|
|
|
readlen -= bytes;
|
|
readlen -= bytes;
|
|
@@ -1575,26 +1597,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
chip->select_chip(mtd, -1);
|
|
chip->select_chip(mtd, -1);
|
|
chip->select_chip(mtd, chipnr);
|
|
chip->select_chip(mtd, chipnr);
|
|
}
|
|
}
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Check, if the chip supports auto page increment or if we
|
|
|
|
- * have hit a block boundary.
|
|
|
|
- */
|
|
|
|
- if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
|
|
|
|
- sndcmd = 1;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
ops->retlen = ops->len - (size_t) readlen;
|
|
ops->retlen = ops->len - (size_t) readlen;
|
|
if (oob)
|
|
if (oob)
|
|
ops->oobretlen = ops->ooblen - oobreadlen;
|
|
ops->oobretlen = ops->ooblen - oobreadlen;
|
|
|
|
|
|
- if (ret)
|
|
|
|
|
|
+ if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
return -EBADMSG;
|
|
return -EBADMSG;
|
|
|
|
|
|
- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
|
|
|
|
|
+ return max_bitflips;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1630,17 +1645,13 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
- * @sndcmd: flag whether to issue read command or not
|
|
|
|
*/
|
|
*/
|
|
static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- int page, int sndcmd)
|
|
|
|
|
|
+ int page)
|
|
{
|
|
{
|
|
- if (sndcmd) {
|
|
|
|
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
|
|
- sndcmd = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
- return sndcmd;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1649,10 +1660,9 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @page: page number to read
|
|
* @page: page number to read
|
|
- * @sndcmd: flag whether to issue read command or not
|
|
|
|
*/
|
|
*/
|
|
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- int page, int sndcmd)
|
|
|
|
|
|
+ int page)
|
|
{
|
|
{
|
|
uint8_t *buf = chip->oob_poi;
|
|
uint8_t *buf = chip->oob_poi;
|
|
int length = mtd->oobsize;
|
|
int length = mtd->oobsize;
|
|
@@ -1679,7 +1689,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
|
if (length > 0)
|
|
if (length > 0)
|
|
chip->read_buf(mtd, bufpoi, length);
|
|
chip->read_buf(mtd, bufpoi, length);
|
|
|
|
|
|
- return 1;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1775,13 +1785,13 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
|
|
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
struct mtd_oob_ops *ops)
|
|
struct mtd_oob_ops *ops)
|
|
{
|
|
{
|
|
- int page, realpage, chipnr, sndcmd = 1;
|
|
|
|
|
|
+ int page, realpage, chipnr;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct mtd_ecc_stats stats;
|
|
struct mtd_ecc_stats stats;
|
|
- int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
|
|
|
int readlen = ops->ooblen;
|
|
int readlen = ops->ooblen;
|
|
int len;
|
|
int len;
|
|
uint8_t *buf = ops->oobbuf;
|
|
uint8_t *buf = ops->oobbuf;
|
|
|
|
+ int ret = 0;
|
|
|
|
|
|
pr_debug("%s: from = 0x%08Lx, len = %i\n",
|
|
pr_debug("%s: from = 0x%08Lx, len = %i\n",
|
|
__func__, (unsigned long long)from, readlen);
|
|
__func__, (unsigned long long)from, readlen);
|
|
@@ -1817,20 +1827,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
|
|
|
while (1) {
|
|
while (1) {
|
|
if (ops->mode == MTD_OPS_RAW)
|
|
if (ops->mode == MTD_OPS_RAW)
|
|
- sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd);
|
|
|
|
|
|
+ ret = chip->ecc.read_oob_raw(mtd, chip, page);
|
|
else
|
|
else
|
|
- sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
|
|
|
|
|
|
+ ret = chip->ecc.read_oob(mtd, chip, page);
|
|
|
|
+
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ break;
|
|
|
|
|
|
len = min(len, readlen);
|
|
len = min(len, readlen);
|
|
buf = nand_transfer_oob(chip, buf, ops, len);
|
|
buf = nand_transfer_oob(chip, buf, ops, len);
|
|
|
|
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
- /*
|
|
|
|
- * Apply delay or wait for ready/busy pin. Do this
|
|
|
|
- * before the AUTOINCR check, so no problems arise if a
|
|
|
|
- * chip which does auto increment is marked as
|
|
|
|
- * NOAUTOINCR by the board driver.
|
|
|
|
- */
|
|
|
|
|
|
+ /* Apply delay or wait for ready/busy pin */
|
|
if (!chip->dev_ready)
|
|
if (!chip->dev_ready)
|
|
udelay(chip->chip_delay);
|
|
udelay(chip->chip_delay);
|
|
else
|
|
else
|
|
@@ -1851,16 +1859,12 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
chip->select_chip(mtd, -1);
|
|
chip->select_chip(mtd, -1);
|
|
chip->select_chip(mtd, chipnr);
|
|
chip->select_chip(mtd, chipnr);
|
|
}
|
|
}
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Check, if the chip supports auto page increment or if we
|
|
|
|
- * have hit a block boundary.
|
|
|
|
- */
|
|
|
|
- if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
|
|
|
|
- sndcmd = 1;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- ops->oobretlen = ops->ooblen;
|
|
|
|
|
|
+ ops->oobretlen = ops->ooblen - readlen;
|
|
|
|
+
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
return -EBADMSG;
|
|
return -EBADMSG;
|
|
@@ -1919,14 +1923,16 @@ out:
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
* @buf: data buffer
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
*
|
|
*
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
|
*/
|
|
*/
|
|
static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- const uint8_t *buf)
|
|
|
|
|
|
+ const uint8_t *buf, int oob_required)
|
|
{
|
|
{
|
|
chip->write_buf(mtd, buf, mtd->writesize);
|
|
chip->write_buf(mtd, buf, mtd->writesize);
|
|
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
|
|
+ if (oob_required)
|
|
|
|
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1934,12 +1940,13 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
* @buf: data buffer
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
*
|
|
*
|
|
* We need a special oob layout and handling even when ECC isn't checked.
|
|
* We need a special oob layout and handling even when ECC isn't checked.
|
|
*/
|
|
*/
|
|
static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
|
static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
|
struct nand_chip *chip,
|
|
struct nand_chip *chip,
|
|
- const uint8_t *buf)
|
|
|
|
|
|
+ const uint8_t *buf, int oob_required)
|
|
{
|
|
{
|
|
int eccsize = chip->ecc.size;
|
|
int eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1973,9 +1980,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
* @buf: data buffer
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
*/
|
|
*/
|
|
static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- const uint8_t *buf)
|
|
|
|
|
|
+ const uint8_t *buf, int oob_required)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -1991,7 +1999,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
|
|
|
|
- chip->ecc.write_page_raw(mtd, chip, buf);
|
|
|
|
|
|
+ chip->ecc.write_page_raw(mtd, chip, buf, 1);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1999,9 +2007,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
* @buf: data buffer
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
*/
|
|
*/
|
|
static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- const uint8_t *buf)
|
|
|
|
|
|
+ const uint8_t *buf, int oob_required)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -2027,12 +2036,14 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
* @mtd: mtd info structure
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
* @buf: data buffer
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
*
|
|
*
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
* need a special oob layout and handling.
|
|
* need a special oob layout and handling.
|
|
*/
|
|
*/
|
|
static void nand_write_page_syndrome(struct mtd_info *mtd,
|
|
static void nand_write_page_syndrome(struct mtd_info *mtd,
|
|
- struct nand_chip *chip, const uint8_t *buf)
|
|
|
|
|
|
+ struct nand_chip *chip,
|
|
|
|
+ const uint8_t *buf, int oob_required)
|
|
{
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccbytes = chip->ecc.bytes;
|
|
@@ -2071,21 +2082,23 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
|
|
* @mtd: MTD device structure
|
|
* @mtd: MTD device structure
|
|
* @chip: NAND chip descriptor
|
|
* @chip: NAND chip descriptor
|
|
* @buf: the data to write
|
|
* @buf: the data to write
|
|
|
|
+ * @oob_required: must write chip->oob_poi to OOB
|
|
* @page: page number to write
|
|
* @page: page number to write
|
|
* @cached: cached programming
|
|
* @cached: cached programming
|
|
* @raw: use _raw version of write_page
|
|
* @raw: use _raw version of write_page
|
|
*/
|
|
*/
|
|
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|
- const uint8_t *buf, int page, int cached, int raw)
|
|
|
|
|
|
+ const uint8_t *buf, int oob_required, int page,
|
|
|
|
+ int cached, int raw)
|
|
{
|
|
{
|
|
int status;
|
|
int status;
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
|
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
|
|
|
|
|
if (unlikely(raw))
|
|
if (unlikely(raw))
|
|
- chip->ecc.write_page_raw(mtd, chip, buf);
|
|
|
|
|
|
+ chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
|
|
else
|
|
else
|
|
- chip->ecc.write_page(mtd, chip, buf);
|
|
|
|
|
|
+ chip->ecc.write_page(mtd, chip, buf, oob_required);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Cached progamming disabled for now. Not sure if it's worth the
|
|
* Cached progamming disabled for now. Not sure if it's worth the
|
|
@@ -2118,6 +2131,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
|
|
if (chip->verify_buf(mtd, buf, mtd->writesize))
|
|
if (chip->verify_buf(mtd, buf, mtd->writesize))
|
|
return -EIO;
|
|
return -EIO;
|
|
|
|
+
|
|
|
|
+ /* Make sure the next page prog is preceded by a status read */
|
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -2202,6 +2218,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
|
uint8_t *oob = ops->oobbuf;
|
|
uint8_t *oob = ops->oobbuf;
|
|
uint8_t *buf = ops->datbuf;
|
|
uint8_t *buf = ops->datbuf;
|
|
int ret, subpage;
|
|
int ret, subpage;
|
|
|
|
+ int oob_required = oob ? 1 : 0;
|
|
|
|
|
|
ops->retlen = 0;
|
|
ops->retlen = 0;
|
|
if (!writelen)
|
|
if (!writelen)
|
|
@@ -2264,8 +2281,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
|
}
|
|
}
|
|
|
|
|
|
- ret = chip->write_page(mtd, chip, wbuf, page, cached,
|
|
|
|
- (ops->mode == MTD_OPS_RAW));
|
|
|
|
|
|
+ ret = chip->write_page(mtd, chip, wbuf, oob_required, page,
|
|
|
|
+ cached, (ops->mode == MTD_OPS_RAW));
|
|
if (ret)
|
|
if (ret)
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -2898,8 +2915,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|
*busw = NAND_BUSWIDTH_16;
|
|
*busw = NAND_BUSWIDTH_16;
|
|
|
|
|
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
- chip->options |= (NAND_NO_READRDY |
|
|
|
|
- NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
|
|
|
|
|
+ chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
|
|
|
|
|
|
pr_info("ONFI flash detected\n");
|
|
pr_info("ONFI flash detected\n");
|
|
return 1;
|
|
return 1;
|
|
@@ -3076,11 +3092,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
|
ident_done:
|
|
ident_done:
|
|
|
|
|
|
- /*
|
|
|
|
- * Set chip as a default. Board drivers can override it, if necessary.
|
|
|
|
- */
|
|
|
|
- chip->options |= NAND_NO_AUTOINCR;
|
|
|
|
-
|
|
|
|
/* Try to identify manufacturer */
|
|
/* Try to identify manufacturer */
|
|
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
|
|
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
|
|
if (nand_manuf_ids[maf_idx].id == *maf_id)
|
|
if (nand_manuf_ids[maf_idx].id == *maf_id)
|
|
@@ -3154,10 +3165,11 @@ ident_done:
|
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
|
chip->cmdfunc = nand_command_lp;
|
|
chip->cmdfunc = nand_command_lp;
|
|
|
|
|
|
- pr_info("NAND device: Manufacturer ID:"
|
|
|
|
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
|
|
|
|
- nand_manuf_ids[maf_idx].name,
|
|
|
|
- chip->onfi_version ? chip->onfi_params.model : type->name);
|
|
|
|
|
|
+ pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
|
|
|
|
+ " page size: %d, OOB size: %d\n",
|
|
|
|
+ *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
|
|
|
|
+ chip->onfi_version ? chip->onfi_params.model : type->name,
|
|
|
|
+ mtd->writesize, mtd->oobsize);
|
|
|
|
|
|
return type;
|
|
return type;
|
|
}
|
|
}
|
|
@@ -3329,8 +3341,13 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|
if (!chip->ecc.write_oob)
|
|
if (!chip->ecc.write_oob)
|
|
chip->ecc.write_oob = nand_write_oob_syndrome;
|
|
chip->ecc.write_oob = nand_write_oob_syndrome;
|
|
|
|
|
|
- if (mtd->writesize >= chip->ecc.size)
|
|
|
|
|
|
+ if (mtd->writesize >= chip->ecc.size) {
|
|
|
|
+ if (!chip->ecc.strength) {
|
|
|
|
+ pr_warn("Driver must set ecc.strength when using hardware ECC\n");
|
|
|
|
+ BUG();
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
pr_warn("%d byte HW ECC not possible on "
|
|
pr_warn("%d byte HW ECC not possible on "
|
|
"%d byte page size, fallback to SW ECC\n",
|
|
"%d byte page size, fallback to SW ECC\n",
|
|
chip->ecc.size, mtd->writesize);
|
|
chip->ecc.size, mtd->writesize);
|
|
@@ -3385,7 +3402,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|
BUG();
|
|
BUG();
|
|
}
|
|
}
|
|
chip->ecc.strength =
|
|
chip->ecc.strength =
|
|
- chip->ecc.bytes*8 / fls(8*chip->ecc.size);
|
|
|
|
|
|
+ chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
|
|
break;
|
|
break;
|
|
|
|
|
|
case NAND_ECC_NONE:
|
|
case NAND_ECC_NONE:
|
|
@@ -3483,7 +3500,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|
|
|
|
|
/* propagate ecc info to mtd_info */
|
|
/* propagate ecc info to mtd_info */
|
|
mtd->ecclayout = chip->ecc.layout;
|
|
mtd->ecclayout = chip->ecc.layout;
|
|
- mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps;
|
|
|
|
|
|
+ mtd->ecc_strength = chip->ecc.strength;
|
|
|
|
|
|
/* Check, if we should skip the bad block table scan */
|
|
/* Check, if we should skip the bad block table scan */
|
|
if (chip->options & NAND_SKIP_BBTSCAN)
|
|
if (chip->options & NAND_SKIP_BBTSCAN)
|