|
|
|
@ -962,7 +962,9 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa |
|
|
|
|
status = this->waitfunc (mtd, this, FL_WRITING); |
|
|
|
|
/* See if device thinks it succeeded */ |
|
|
|
|
if (status & 0x01) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"%s: Failed write, page 0x%08x, ", |
|
|
|
|
__FUNCTION__, page); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
@ -1010,7 +1012,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int |
|
|
|
|
for (j = 0; j < eccsteps; j++) { |
|
|
|
|
/* Loop through and verify the data */ |
|
|
|
|
if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " |
|
|
|
|
"Failed write verify, page 0x%08x ", |
|
|
|
|
__FUNCTION__, page); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
datidx += mtd->eccsize; |
|
|
|
@ -1018,7 +1022,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int |
|
|
|
|
if (!hweccbytes) |
|
|
|
|
continue; |
|
|
|
|
if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " |
|
|
|
|
"Failed write verify, page 0x%08x ", |
|
|
|
|
__FUNCTION__, page); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
oobofs += hweccbytes; |
|
|
|
@ -1029,7 +1035,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int |
|
|
|
|
*/ |
|
|
|
|
if (oobmode) { |
|
|
|
|
if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " |
|
|
|
|
"Failed write verify, page 0x%08x ", |
|
|
|
|
__FUNCTION__, page); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
@ -1042,9 +1050,11 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int |
|
|
|
|
for (i = 0; i < ecccnt; i++) { |
|
|
|
|
int idx = oobsel->eccpos[i]; |
|
|
|
|
if (oobdata[idx] != oob_buf[oobofs + idx] ) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"%s: Failed ECC write " |
|
|
|
|
"verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); |
|
|
|
|
"verify, page 0x%08x, " |
|
|
|
|
"%6i bytes were succesful\n", |
|
|
|
|
__FUNCTION__, page, i); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1131,11 +1141,13 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
|
|
|
|
int oobreadlen; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", |
|
|
|
|
(unsigned int) from, (int) len); |
|
|
|
|
|
|
|
|
|
/* Do not allow reads past end of device */ |
|
|
|
|
if ((from + len) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_read_ecc: Attempt read beyond end of device\n"); |
|
|
|
|
*retlen = 0; |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
@ -1252,7 +1264,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
|
|
|
|
* generator for an error, reads back the syndrome and |
|
|
|
|
* does the error correction on the fly */ |
|
|
|
|
if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
|
|
|
|
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); |
|
|
|
|
ecc_failed++; |
|
|
|
|
} |
|
|
|
@ -1291,7 +1303,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ecc_status == -1) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
|
|
|
|
"Failed ECC read, page 0x%08x\n", |
|
|
|
|
page); |
|
|
|
|
ecc_failed++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1388,7 +1402,8 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", |
|
|
|
|
(unsigned int) from, (int) len); |
|
|
|
|
|
|
|
|
|
/* Shift to get page */ |
|
|
|
|
page = (int)(from >> this->page_shift); |
|
|
|
@ -1402,7 +1417,8 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t |
|
|
|
|
|
|
|
|
|
/* Do not allow reads past end of device */ |
|
|
|
|
if ((from + len) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_read_oob: Attempt read beyond end of device\n"); |
|
|
|
|
*retlen = 0; |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
@ -1488,7 +1504,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, |
|
|
|
|
|
|
|
|
|
/* Do not allow reads past end of device */ |
|
|
|
|
if ((from + len) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_read_raw: Attempt read beyond end of device\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1626,14 +1643,16 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, |
|
|
|
|
u_char *oobbuf, *bufstart; |
|
|
|
|
int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", |
|
|
|
|
(unsigned int) to, (int) len); |
|
|
|
|
|
|
|
|
|
/* Initialize retlen, in case of early exit */ |
|
|
|
|
*retlen = 0; |
|
|
|
|
|
|
|
|
|
/* Do not allow write past end of device */ |
|
|
|
|
if ((to + len) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_write_ecc: Attempt to write past end of page\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1695,7 +1714,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, |
|
|
|
|
*/ |
|
|
|
|
ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); |
|
|
|
|
if (ret) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_write_ecc: write_page failed %d\n", ret); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
/* Next oob page */ |
|
|
|
@ -1719,7 +1739,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, |
|
|
|
|
page - startpage, |
|
|
|
|
oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
|
|
|
|
if (ret) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: " |
|
|
|
|
"verify_pages failed %d\n", ret); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
*retlen = written; |
|
|
|
@ -1752,7 +1773,8 @@ cmp: |
|
|
|
|
if (!ret) |
|
|
|
|
*retlen = written; |
|
|
|
|
else |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_write_ecc: verify_pages failed %d\n", ret); |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
/* Deselect and wake up anyone waiting on the device */ |
|
|
|
@ -1777,7 +1799,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * |
|
|
|
|
int column, page, status, ret = -EIO, chipnr; |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", |
|
|
|
|
(unsigned int) to, (int) len); |
|
|
|
|
|
|
|
|
|
/* Shift to get page */ |
|
|
|
|
page = (int) (to >> this->page_shift); |
|
|
|
@ -1791,7 +1814,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * |
|
|
|
|
|
|
|
|
|
/* Do not allow write past end of page */ |
|
|
|
|
if ((column + len) > mtd->oobsize) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " |
|
|
|
|
"Attempt to write past end of page\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1821,8 +1845,9 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * |
|
|
|
|
this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); |
|
|
|
|
if (!ffchars) { |
|
|
|
|
if (!(ffchars = kmalloc (mtd->oobsize, GFP_KERNEL))) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " |
|
|
|
|
"No memory for padding array, need %d bytes", mtd->oobsize); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " |
|
|
|
|
"No memory for padding array, " |
|
|
|
|
"need %d bytes", mtd->oobsize); |
|
|
|
|
ret = -ENOMEM; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
@ -1847,7 +1872,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * |
|
|
|
|
|
|
|
|
|
/* See if device thinks it succeeded */ |
|
|
|
|
if (status & 0x01) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " |
|
|
|
|
"Failed write, page 0x%08x\n", page); |
|
|
|
|
ret = -EIO; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
@ -1859,7 +1885,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * |
|
|
|
|
this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask); |
|
|
|
|
|
|
|
|
|
if (this->verify_buf(mtd, buf, len)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " |
|
|
|
|
"Failed write verify, page 0x%08x\n", page); |
|
|
|
|
ret = -EIO; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
@ -1919,12 +1946,14 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig |
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
|
total_len += (int) vecs[i].iov_len; |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, |
|
|
|
|
"nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, |
|
|
|
|
"nand_writev: to = 0x%08x, len = %i, count = %ld\n", |
|
|
|
|
(unsigned int) to, (unsigned int) total_len, count); |
|
|
|
|
|
|
|
|
|
/* Do not allow write past end of page */ |
|
|
|
|
if ((to + total_len) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_writev: Attempted write past end of device\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2117,24 +2146,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb |
|
|
|
|
int page, len, status, pages_per_block, ret, chipnr; |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, |
|
|
|
|
"nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", |
|
|
|
|
(unsigned int) instr->addr, (unsigned int) instr->len); |
|
|
|
|
|
|
|
|
|
/* Start address must align on block boundary */ |
|
|
|
|
if (instr->addr & ((1 << this->phys_erase_shift) - 1)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Length must align on block boundary */ |
|
|
|
|
if (instr->len & ((1 << this->phys_erase_shift) - 1)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_erase: Length not block aligned\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Do not allow erase past end of device */ |
|
|
|
|
if ((instr->len + instr->addr) > mtd->size) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_erase: Erase past end of device\n"); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2156,7 +2187,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb |
|
|
|
|
/* Check the WP bit */ |
|
|
|
|
/* Check, if it is write protected */ |
|
|
|
|
if (nand_check_wp(mtd)) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, |
|
|
|
|
"nand_erase: Device is write protected!!!\n"); |
|
|
|
|
instr->state = MTD_ERASE_FAILED; |
|
|
|
|
goto erase_exit; |
|
|
|
|
} |
|
|
|
@ -2186,7 +2218,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb |
|
|
|
|
|
|
|
|
|
/* See if block erase succeeded */ |
|
|
|
|
if (status & 0x01) { |
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " |
|
|
|
|
"Failed erase, page 0x%08x\n", page); |
|
|
|
|
instr->state = MTD_ERASE_FAILED; |
|
|
|
|
instr->fail_addr = (page << this->page_shift); |
|
|
|
|
goto erase_exit; |
|
|
|
@ -2229,7 +2262,7 @@ static void nand_sync (struct mtd_info *mtd) |
|
|
|
|
{ |
|
|
|
|
struct nand_chip *this = mtd->priv; |
|
|
|
|
|
|
|
|
|
DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); |
|
|
|
|
MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); |
|
|
|
|
|
|
|
|
|
/* Grab the lock and see if the device is available */ |
|
|
|
|
nand_get_device (this, mtd, FL_SYNCING); |
|
|
|
|