[MTD] Remove read/write _ecc variants
MTD clients are agnostic of FLASH which needs ECC suppport. Remove the functions and fixup the callers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
2528e8cdf3
commit
9223a456da
15 changed files with 209 additions and 404 deletions
|
@ -584,8 +584,6 @@ void DoC2k_init(struct mtd_info *mtd)
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
mtd->read = doc_read;
|
mtd->read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->write = doc_write;
|
||||||
mtd->read_ecc = doc_read_ecc;
|
|
||||||
mtd->write_ecc = doc_write_ecc;
|
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->write_oob = doc_write_oob;
|
||||||
mtd->sync = NULL;
|
mtd->sync = NULL;
|
||||||
|
|
|
@ -369,8 +369,6 @@ void DoCMil_init(struct mtd_info *mtd)
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
mtd->read = doc_read;
|
mtd->read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->write = doc_write;
|
||||||
mtd->read_ecc = doc_read_ecc;
|
|
||||||
mtd->write_ecc = doc_write_ecc;
|
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->write_oob = doc_write_oob;
|
||||||
mtd->sync = NULL;
|
mtd->sync = NULL;
|
||||||
|
|
|
@ -491,8 +491,6 @@ void DoCMilPlus_init(struct mtd_info *mtd)
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
mtd->read = doc_read;
|
mtd->read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->write = doc_write;
|
||||||
mtd->read_ecc = doc_read_ecc;
|
|
||||||
mtd->write_ecc = doc_write_ecc;
|
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->write_oob = doc_write_oob;
|
||||||
mtd->sync = NULL;
|
mtd->sync = NULL;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/mtd/nftl.h>
|
#include <linux/mtd/nftl.h>
|
||||||
#include <linux/mtd/inftl.h>
|
#include <linux/mtd/inftl.h>
|
||||||
|
#include <linux/mtd/nand.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
@ -79,14 +80,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
inftl->mbd.devnum = -1;
|
inftl->mbd.devnum = -1;
|
||||||
inftl->mbd.blksize = 512;
|
inftl->mbd.blksize = 512;
|
||||||
inftl->mbd.tr = tr;
|
inftl->mbd.tr = tr;
|
||||||
memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
|
|
||||||
inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
|
|
||||||
|
|
||||||
if (INFTL_mount(inftl) < 0) {
|
if (INFTL_mount(inftl) < 0) {
|
||||||
printk(KERN_WARNING "INFTL: could not mount device\n");
|
printk(KERN_WARNING "INFTL: could not mount device\n");
|
||||||
kfree(inftl);
|
kfree(inftl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, it's a new one. Set up all the data structures. */
|
/* OK, it's a new one. Set up all the data structures. */
|
||||||
|
|
||||||
|
@ -221,7 +220,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
* Scan to find the Erase Unit which holds the actual data for each
|
* Scan to find the Erase Unit which holds the actual data for each
|
||||||
* 512-byte block within the Chain.
|
* 512-byte block within the Chain.
|
||||||
*/
|
*/
|
||||||
silly = MAX_LOOPS;
|
silly = MAX_LOOPS;
|
||||||
while (thisEUN < inftl->nb_blocks) {
|
while (thisEUN < inftl->nb_blocks) {
|
||||||
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
|
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
|
||||||
if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
|
if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
|
||||||
|
@ -232,7 +231,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
(char *)&oob) < 0)
|
(char *)&oob) < 0)
|
||||||
status = SECTOR_IGNORE;
|
status = SECTOR_IGNORE;
|
||||||
else
|
else
|
||||||
status = oob.b.Status | oob.b.Status1;
|
status = oob.b.Status | oob.b.Status1;
|
||||||
|
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case SECTOR_FREE:
|
case SECTOR_FREE:
|
||||||
|
@ -282,29 +281,30 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy only in non free block (free blocks can only
|
* Copy only in non free block (free blocks can only
|
||||||
* happen in case of media errors or deleted blocks).
|
* happen in case of media errors or deleted blocks).
|
||||||
*/
|
*/
|
||||||
if (BlockMap[block] == BLOCK_NIL)
|
if (BlockMap[block] == BLOCK_NIL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
||||||
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
|
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
|
||||||
&retlen, movebuf);
|
&retlen, movebuf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
||||||
BlockMap[block]) + (block * SECTORSIZE),
|
BlockMap[block]) + (block * SECTORSIZE),
|
||||||
SECTORSIZE, &retlen, movebuf);
|
SECTORSIZE, &retlen, movebuf);
|
||||||
if (ret != -EIO)
|
if (ret != -EIO)
|
||||||
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
|
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
|
||||||
"away on retry?\n");
|
"away on retry?\n");
|
||||||
}
|
}
|
||||||
memset(&oob, 0xff, sizeof(struct inftl_oob));
|
memset(&oob, 0xff, sizeof(struct inftl_oob));
|
||||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||||
MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
|
|
||||||
(block * SECTORSIZE), SECTORSIZE, &retlen,
|
nand_write_raw(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
|
||||||
movebuf, (char *)&oob, &inftl->oobinfo);
|
(block * SECTORSIZE), SECTORSIZE, &retlen,
|
||||||
|
movebuf, (char *)&oob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -329,17 +329,17 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
if (thisEUN == targetEUN)
|
if (thisEUN == targetEUN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (INFTL_formatblock(inftl, thisEUN) < 0) {
|
if (INFTL_formatblock(inftl, thisEUN) < 0) {
|
||||||
/*
|
/*
|
||||||
* Could not erase : mark block as reserved.
|
* Could not erase : mark block as reserved.
|
||||||
*/
|
*/
|
||||||
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
|
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
|
||||||
} else {
|
} else {
|
||||||
/* Correctly erased : mark it as free */
|
/* Correctly erased : mark it as free */
|
||||||
inftl->PUtable[thisEUN] = BLOCK_FREE;
|
inftl->PUtable[thisEUN] = BLOCK_FREE;
|
||||||
inftl->PUtable[prevEUN] = BLOCK_NIL;
|
inftl->PUtable[prevEUN] = BLOCK_NIL;
|
||||||
inftl->numfreeEUNs++;
|
inftl->numfreeEUNs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return targetEUN;
|
return targetEUN;
|
||||||
|
@ -437,7 +437,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
|
||||||
MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
|
MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
|
||||||
blockofs, 8, &retlen, (char *)&bci);
|
blockofs, 8, &retlen, (char *)&bci);
|
||||||
|
|
||||||
status = bci.Status | bci.Status1;
|
status = bci.Status | bci.Status1;
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
|
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
|
||||||
"EUN %d is %x\n", block , writeEUN, status);
|
"EUN %d is %x\n", block , writeEUN, status);
|
||||||
|
|
||||||
|
@ -670,12 +670,12 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
|
DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
|
||||||
thisEUN, thisVUC);
|
thisEUN, thisVUC);
|
||||||
|
|
||||||
if (INFTL_formatblock(inftl, thisEUN) < 0) {
|
if (INFTL_formatblock(inftl, thisEUN) < 0) {
|
||||||
/*
|
/*
|
||||||
* Could not erase : mark block as reserved.
|
* Could not erase : mark block as reserved.
|
||||||
*/
|
*/
|
||||||
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
|
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
|
||||||
} else {
|
} else {
|
||||||
/* Correctly erased : mark it as free */
|
/* Correctly erased : mark it as free */
|
||||||
inftl->PUtable[thisEUN] = BLOCK_FREE;
|
inftl->PUtable[thisEUN] = BLOCK_FREE;
|
||||||
inftl->numfreeEUNs++;
|
inftl->numfreeEUNs++;
|
||||||
|
@ -784,9 +784,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
||||||
|
|
||||||
memset(&oob, 0xff, sizeof(struct inftl_oob));
|
memset(&oob, 0xff, sizeof(struct inftl_oob));
|
||||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||||
MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
|
|
||||||
blockofs, SECTORSIZE, &retlen, (char *)buffer,
|
nand_write_raw(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
|
||||||
(char *)&oob, &inftl->oobinfo);
|
blockofs, SECTORSIZE, &retlen, (char *)buffer,
|
||||||
|
(char *)&oob);
|
||||||
/*
|
/*
|
||||||
* need to write SECTOR_USED flags since they are not written
|
* need to write SECTOR_USED flags since they are not written
|
||||||
* in mtd_writeecc
|
* in mtd_writeecc
|
||||||
|
@ -804,9 +805,9 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
||||||
struct INFTLrecord *inftl = (void *)mbd;
|
struct INFTLrecord *inftl = (void *)mbd;
|
||||||
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
|
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
|
||||||
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
|
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
int silly = MAX_LOOPS;
|
int silly = MAX_LOOPS;
|
||||||
struct inftl_bci bci;
|
struct inftl_bci bci;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
|
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
|
||||||
|
@ -850,7 +851,7 @@ foundit:
|
||||||
/* The requested block is not on the media, return all 0x00 */
|
/* The requested block is not on the media, return all 0x00 */
|
||||||
memset(buffer, 0, SECTORSIZE);
|
memset(buffer, 0, SECTORSIZE);
|
||||||
} else {
|
} else {
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
|
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
|
||||||
if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
|
if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
|
||||||
buffer))
|
buffer))
|
||||||
|
|
|
@ -350,21 +350,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
|
||||||
int len, int check_oob)
|
int len, int check_oob)
|
||||||
{
|
{
|
||||||
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
|
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
|
||||||
|
struct mtd_info *mtd = inftl->mbd.mtd;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
|
|
||||||
"address=0x%x,len=%d,check_oob=%d)\n", inftl,
|
|
||||||
address, len, check_oob);
|
|
||||||
|
|
||||||
for (i = 0; i < len; i += SECTORSIZE) {
|
for (i = 0; i < len; i += SECTORSIZE) {
|
||||||
if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
|
if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
|
||||||
return -1;
|
return -1;
|
||||||
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
|
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_oob) {
|
if (check_oob) {
|
||||||
if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
|
if(mtd->read_oob(mtd, address, mtd->oobsize,
|
||||||
|
&retlen, &buf[SECTORSIZE]) < 0)
|
||||||
|
return -1;
|
||||||
|
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
address += SECTORSIZE;
|
address += SECTORSIZE;
|
||||||
|
|
|
@ -142,116 +142,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t * retlen, u_char * buf, u_char * eccbuf,
|
|
||||||
struct nand_oobinfo *oobsel)
|
|
||||||
{
|
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
|
||||||
int err = -EINVAL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
|
||||||
size_t size, retsize;
|
|
||||||
|
|
||||||
if (from >= subdev->size) {
|
|
||||||
/* Not destined for this subdev */
|
|
||||||
size = 0;
|
|
||||||
from -= subdev->size;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from + len > subdev->size)
|
|
||||||
/* First part goes into this subdev */
|
|
||||||
size = subdev->size - from;
|
|
||||||
else
|
|
||||||
/* Entire transaction goes into this subdev */
|
|
||||||
size = len;
|
|
||||||
|
|
||||||
if (subdev->read_ecc)
|
|
||||||
err = subdev->read_ecc(subdev, from, size,
|
|
||||||
&retsize, buf, eccbuf, oobsel);
|
|
||||||
else
|
|
||||||
err = -EINVAL;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
break;
|
|
||||||
|
|
||||||
*retlen += retsize;
|
|
||||||
len -= size;
|
|
||||||
if (len == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
err = -EINVAL;
|
|
||||||
buf += size;
|
|
||||||
if (eccbuf) {
|
|
||||||
eccbuf += subdev->oobsize;
|
|
||||||
/* in nand.c at least, eccbufs are
|
|
||||||
tagged with 2 (int)eccstatus'; we
|
|
||||||
must account for these */
|
|
||||||
eccbuf += 2 * (sizeof (int));
|
|
||||||
}
|
|
||||||
from = 0;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
|
||||||
size_t * retlen, const u_char * buf, u_char * eccbuf,
|
|
||||||
struct nand_oobinfo *oobsel)
|
|
||||||
{
|
|
||||||
struct mtd_concat *concat = CONCAT(mtd);
|
|
||||||
int err = -EINVAL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
|
||||||
size_t size, retsize;
|
|
||||||
|
|
||||||
if (to >= subdev->size) {
|
|
||||||
size = 0;
|
|
||||||
to -= subdev->size;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (to + len > subdev->size)
|
|
||||||
size = subdev->size - to;
|
|
||||||
else
|
|
||||||
size = len;
|
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE))
|
|
||||||
err = -EROFS;
|
|
||||||
else if (subdev->write_ecc)
|
|
||||||
err = subdev->write_ecc(subdev, to, size,
|
|
||||||
&retsize, buf, eccbuf, oobsel);
|
|
||||||
else
|
|
||||||
err = -EINVAL;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
break;
|
|
||||||
|
|
||||||
*retlen += retsize;
|
|
||||||
len -= size;
|
|
||||||
if (len == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
err = -EINVAL;
|
|
||||||
buf += size;
|
|
||||||
if (eccbuf)
|
|
||||||
eccbuf += subdev->oobsize;
|
|
||||||
to = 0;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||||
unsigned long count, loff_t to, size_t * retlen)
|
unsigned long count, loff_t to, size_t * retlen)
|
||||||
|
@ -823,10 +713,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
concat->mtd.oobsize = subdev[0]->oobsize;
|
concat->mtd.oobsize = subdev[0]->oobsize;
|
||||||
concat->mtd.ecctype = subdev[0]->ecctype;
|
concat->mtd.ecctype = subdev[0]->ecctype;
|
||||||
concat->mtd.eccsize = subdev[0]->eccsize;
|
concat->mtd.eccsize = subdev[0]->eccsize;
|
||||||
if (subdev[0]->read_ecc)
|
|
||||||
concat->mtd.read_ecc = concat_read_ecc;
|
|
||||||
if (subdev[0]->write_ecc)
|
|
||||||
concat->mtd.write_ecc = concat_write_ecc;
|
|
||||||
if (subdev[0]->writev)
|
if (subdev[0]->writev)
|
||||||
concat->mtd.writev = concat_writev;
|
concat->mtd.writev = concat_writev;
|
||||||
if (subdev[0]->read_oob)
|
if (subdev[0]->read_oob)
|
||||||
|
@ -869,8 +755,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
concat->mtd.oobsize != subdev[i]->oobsize ||
|
concat->mtd.oobsize != subdev[i]->oobsize ||
|
||||||
concat->mtd.ecctype != subdev[i]->ecctype ||
|
concat->mtd.ecctype != subdev[i]->ecctype ||
|
||||||
concat->mtd.eccsize != subdev[i]->eccsize ||
|
concat->mtd.eccsize != subdev[i]->eccsize ||
|
||||||
!concat->mtd.read_ecc != !subdev[i]->read_ecc ||
|
|
||||||
!concat->mtd.write_ecc != !subdev[i]->write_ecc ||
|
|
||||||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
|
!concat->mtd.read_oob != !subdev[i]->read_oob ||
|
||||||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
|
!concat->mtd.write_oob != !subdev[i]->write_oob) {
|
||||||
kfree(concat);
|
kfree(concat);
|
||||||
|
|
|
@ -55,12 +55,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (from + len > mtd->size)
|
else if (from + len > mtd->size)
|
||||||
len = mtd->size - from;
|
len = mtd->size - from;
|
||||||
if (part->master->read_ecc == NULL)
|
return part->master->read (part->master, from + part->offset,
|
||||||
return part->master->read (part->master, from + part->offset,
|
len, retlen, buf);
|
||||||
len, retlen, buf);
|
|
||||||
else
|
|
||||||
return part->master->read_ecc (part->master, from + part->offset,
|
|
||||||
len, retlen, buf, NULL, &mtd->oobinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
@ -74,6 +70,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
return part->master->point (part->master, from + part->offset,
|
return part->master->point (part->master, from + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
|
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
@ -81,21 +78,6 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
|
||||||
part->master->unpoint (part->master, addr, from + part->offset, len);
|
part->master->unpoint (part->master, addr, from + part->offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
|
|
||||||
{
|
|
||||||
struct mtd_part *part = PART(mtd);
|
|
||||||
if (oobsel == NULL)
|
|
||||||
oobsel = &mtd->oobinfo;
|
|
||||||
if (from >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (from + len > mtd->size)
|
|
||||||
len = mtd->size - from;
|
|
||||||
return part->master->read_ecc (part->master, from + part->offset,
|
|
||||||
len, retlen, buf, eccbuf, oobsel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
|
@ -148,30 +130,8 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (to + len > mtd->size)
|
else if (to + len > mtd->size)
|
||||||
len = mtd->size - to;
|
len = mtd->size - to;
|
||||||
if (part->master->write_ecc == NULL)
|
return part->master->write (part->master, to + part->offset,
|
||||||
return part->master->write (part->master, to + part->offset,
|
len, retlen, buf);
|
||||||
len, retlen, buf);
|
|
||||||
else
|
|
||||||
return part->master->write_ecc (part->master, to + part->offset,
|
|
||||||
len, retlen, buf, NULL, &mtd->oobinfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
|
||||||
size_t *retlen, const u_char *buf,
|
|
||||||
u_char *eccbuf, struct nand_oobinfo *oobsel)
|
|
||||||
{
|
|
||||||
struct mtd_part *part = PART(mtd);
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (oobsel == NULL)
|
|
||||||
oobsel = &mtd->oobinfo;
|
|
||||||
if (to >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
return part->master->write_ecc (part->master, to + part->offset,
|
|
||||||
len, retlen, buf, eccbuf, oobsel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
|
static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
@ -372,10 +332,6 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
slave->mtd.unpoint = part_unpoint;
|
slave->mtd.unpoint = part_unpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (master->read_ecc)
|
|
||||||
slave->mtd.read_ecc = part_read_ecc;
|
|
||||||
if (master->write_ecc)
|
|
||||||
slave->mtd.write_ecc = part_write_ecc;
|
|
||||||
if (master->read_oob)
|
if (master->read_oob)
|
||||||
slave->mtd.read_oob = part_read_oob;
|
slave->mtd.read_oob = part_read_oob;
|
||||||
if (master->write_oob)
|
if (master->write_oob)
|
||||||
|
|
|
@ -139,16 +139,10 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
|
||||||
|
|
||||||
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, uint8_t *buf);
|
size_t *retlen, uint8_t *buf);
|
||||||
static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t *retlen, uint8_t *buf, uint8_t *eccbuf,
|
|
||||||
struct nand_oobinfo *oobsel);
|
|
||||||
static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
|
static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, uint8_t *buf);
|
size_t *retlen, uint8_t *buf);
|
||||||
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const uint8_t *buf);
|
size_t *retlen, const uint8_t *buf);
|
||||||
static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
|
||||||
size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
|
|
||||||
struct nand_oobinfo *oobsel);
|
|
||||||
static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
|
static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const uint8_t *buf);
|
size_t *retlen, const uint8_t *buf);
|
||||||
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
|
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||||
|
@ -1079,27 +1073,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl
|
||||||
return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
|
return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
|
|
||||||
* @mtd: MTD device structure
|
|
||||||
* @from: offset to read from
|
|
||||||
* @len: number of bytes to read
|
|
||||||
* @retlen: pointer to variable to store the number of read bytes
|
|
||||||
* @buf: the databuffer to put data
|
|
||||||
* @oob_buf: filesystem supplied oob data buffer
|
|
||||||
* @oobsel: oob selection structure
|
|
||||||
*
|
|
||||||
* This function simply calls nand_do_read_ecc with flags = 0xff
|
|
||||||
*/
|
|
||||||
static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel)
|
|
||||||
{
|
|
||||||
/* use userspace supplied oobinfo, if zero */
|
|
||||||
if (oobsel == NULL)
|
|
||||||
oobsel = &mtd->oobinfo;
|
|
||||||
return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_do_read_ecc - [MTD Interface] Read data with ECC
|
* nand_do_read_ecc - [MTD Interface] Read data with ECC
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -1523,6 +1496,55 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_write_raw - [GENERIC] Write raw data including oob
|
||||||
|
* @mtd: MTD device structure
|
||||||
|
* @buf: source buffer
|
||||||
|
* @to: offset to write to
|
||||||
|
* @len: number of bytes to write
|
||||||
|
* @buf: source buffer
|
||||||
|
* @oob: oob buffer
|
||||||
|
*
|
||||||
|
* Write raw data including oob
|
||||||
|
*/
|
||||||
|
int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
uint8_t *buf, uint8_t *oob)
|
||||||
|
{
|
||||||
|
struct nand_chip *this = mtd->priv;
|
||||||
|
int page = (int)(to >> this->page_shift);
|
||||||
|
int chip = (int)(to >> this->chip_shift);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
*retlen = 0;
|
||||||
|
|
||||||
|
/* Do not allow writes past end of device */
|
||||||
|
if ((to + len) > mtd->size) {
|
||||||
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
|
||||||
|
"beyond end of device\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab the lock and see if the device is available */
|
||||||
|
nand_get_device(this, mtd, FL_WRITING);
|
||||||
|
|
||||||
|
this->select_chip(mtd, chip);
|
||||||
|
this->data_poi = buf;
|
||||||
|
|
||||||
|
while (len != *retlen) {
|
||||||
|
ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
page++;
|
||||||
|
*retlen += mtd->writesize;
|
||||||
|
this->data_poi += mtd->writesize;
|
||||||
|
oob += mtd->oobsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deselect and wake up anyone waiting on the device */
|
||||||
|
nand_release_device(mtd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
|
* nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -1585,57 +1607,39 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct
|
||||||
#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
|
#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_write - [MTD Interface] compability function for nand_write_ecc
|
* nand_write - [MTD Interface] NAND write with ECC
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @to: offset to write to
|
* @to: offset to write to
|
||||||
* @len: number of bytes to write
|
* @len: number of bytes to write
|
||||||
* @retlen: pointer to variable to store the number of written bytes
|
* @retlen: pointer to variable to store the number of written bytes
|
||||||
* @buf: the data to write
|
* @buf: the data to write
|
||||||
*
|
*
|
||||||
* This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
|
|
||||||
{
|
|
||||||
return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* nand_write_ecc - [MTD Interface] NAND write with ECC
|
|
||||||
* @mtd: MTD device structure
|
|
||||||
* @to: offset to write to
|
|
||||||
* @len: number of bytes to write
|
|
||||||
* @retlen: pointer to variable to store the number of written bytes
|
|
||||||
* @buf: the data to write
|
|
||||||
* @eccbuf: filesystem supplied oob data buffer
|
|
||||||
* @oobsel: oob selection structure
|
|
||||||
*
|
|
||||||
* NAND write with ECC
|
* NAND write with ECC
|
||||||
*/
|
*/
|
||||||
static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
|
size_t *retlen, const uint8_t *buf)
|
||||||
struct nand_oobinfo *oobsel)
|
|
||||||
{
|
{
|
||||||
int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
|
int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
|
||||||
int autoplace = 0, numpages, totalpages;
|
int autoplace = 0, numpages, totalpages;
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
uint8_t *oobbuf, *bufstart;
|
uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
|
||||||
int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
|
int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
|
||||||
|
struct nand_oobinfo *oobsel = &mtd->oobinfo;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
|
DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
|
||||||
|
|
||||||
/* Initialize retlen, in case of early exit */
|
/* Initialize retlen, in case of early exit */
|
||||||
*retlen = 0;
|
*retlen = 0;
|
||||||
|
|
||||||
/* Do not allow write past end of device */
|
/* Do not allow write past end of device */
|
||||||
if ((to + len) > mtd->size) {
|
if ((to + len) > mtd->size) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reject writes, which are not page aligned */
|
/* reject writes, which are not page aligned */
|
||||||
if (NOTALIGNED(to) || NOTALIGNED(len)) {
|
if (NOTALIGNED(to) || NOTALIGNED(len)) {
|
||||||
printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
|
printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1651,10 +1655,6 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
if (nand_check_wp(mtd))
|
if (nand_check_wp(mtd))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* if oobsel is NULL, use chip defaults */
|
|
||||||
if (oobsel == NULL)
|
|
||||||
oobsel = &mtd->oobinfo;
|
|
||||||
|
|
||||||
/* Autoplace of oob data ? Use the default placement scheme */
|
/* Autoplace of oob data ? Use the default placement scheme */
|
||||||
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
|
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
|
||||||
oobsel = this->autooob;
|
oobsel = this->autooob;
|
||||||
|
@ -1689,7 +1689,7 @@ 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));
|
ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/* Next oob page */
|
/* Next oob page */
|
||||||
|
@ -1712,7 +1712,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
ret = nand_verify_pages(mtd, this, startpage, page - startpage,
|
ret = nand_verify_pages(mtd, this, startpage, page - startpage,
|
||||||
oobbuf, oobsel, chipnr, (eccbuf != NULL));
|
oobbuf, oobsel, chipnr, (eccbuf != NULL));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
*retlen = written;
|
*retlen = written;
|
||||||
|
@ -1741,7 +1741,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
*retlen = written;
|
*retlen = written;
|
||||||
else
|
else
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* Deselect and wake up anyone waiting on the device */
|
/* Deselect and wake up anyone waiting on the device */
|
||||||
|
@ -2527,8 +2527,6 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
mtd->read = nand_read;
|
mtd->read = nand_read;
|
||||||
mtd->write = nand_write;
|
mtd->write = nand_write;
|
||||||
mtd->read_ecc = nand_read_ecc;
|
|
||||||
mtd->write_ecc = nand_write_ecc;
|
|
||||||
mtd->read_oob = nand_read_oob;
|
mtd->read_oob = nand_read_oob;
|
||||||
mtd->write_oob = nand_write_oob;
|
mtd->write_oob = nand_write_oob;
|
||||||
mtd->sync = nand_sync;
|
mtd->sync = nand_sync;
|
||||||
|
|
|
@ -156,7 +156,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||||
|
|
||||||
while (totlen) {
|
while (totlen) {
|
||||||
len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
|
len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
|
||||||
res = mtd->read_ecc(mtd, from, len, &retlen, buf, NULL, this->autooob);
|
res = mtd->read(mtd, from, len, &retlen, buf);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (retlen != len) {
|
if (retlen != len) {
|
||||||
printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
|
printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
|
||||||
|
@ -471,17 +471,17 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
|
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
|
||||||
|
int chipsel)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
struct nand_oobinfo oobinfo;
|
|
||||||
struct erase_info einfo;
|
struct erase_info einfo;
|
||||||
int i, j, res, chip = 0;
|
int i, j, res, chip = 0;
|
||||||
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
|
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
|
||||||
int nrchips, bbtoffs, pageoffs;
|
int nrchips, bbtoffs, pageoffs, ooboffs;
|
||||||
uint8_t msk[4];
|
uint8_t msk[4];
|
||||||
uint8_t rcode = td->reserved_block_code;
|
uint8_t rcode = td->reserved_block_code;
|
||||||
size_t retlen, len = 0;
|
size_t retlen, len = 0, ooblen;
|
||||||
loff_t to;
|
loff_t to;
|
||||||
|
|
||||||
if (!rcode)
|
if (!rcode)
|
||||||
|
@ -526,12 +526,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
for (i = 0; i < td->maxblocks; i++) {
|
for (i = 0; i < td->maxblocks; i++) {
|
||||||
int block = startblock + dir * i;
|
int block = startblock + dir * i;
|
||||||
/* Check, if the block is bad */
|
/* Check, if the block is bad */
|
||||||
switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
|
switch ((this->bbt[block >> 2] >>
|
||||||
|
(2 * (block & 0x03))) & 0x03) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
case 0x03:
|
case 0x03:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
page = block << (this->bbt_erase_shift - this->page_shift);
|
page = block <<
|
||||||
|
(this->bbt_erase_shift - this->page_shift);
|
||||||
/* Check, if the block is used by the mirror table */
|
/* Check, if the block is used by the mirror table */
|
||||||
if (!md || md->pages[chip] != page)
|
if (!md || md->pages[chip] != page)
|
||||||
goto write;
|
goto write;
|
||||||
|
@ -542,11 +544,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
|
|
||||||
/* Set up shift count and masks for the flash table */
|
/* Set up shift count and masks for the flash table */
|
||||||
bits = td->options & NAND_BBT_NRBITS_MSK;
|
bits = td->options & NAND_BBT_NRBITS_MSK;
|
||||||
|
msk[2] = ~rcode;
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
|
case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
|
||||||
case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
|
msk[3] = 0x01;
|
||||||
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
|
break;
|
||||||
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
|
case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
|
||||||
|
msk[3] = 0x03;
|
||||||
|
break;
|
||||||
|
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
|
||||||
|
msk[3] = 0x0f;
|
||||||
|
break;
|
||||||
|
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
|
||||||
|
msk[3] = 0xff;
|
||||||
|
break;
|
||||||
default: return -EINVAL;
|
default: return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,49 +565,55 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
|
|
||||||
to = ((loff_t) page) << this->page_shift;
|
to = ((loff_t) page) << this->page_shift;
|
||||||
|
|
||||||
memcpy(&oobinfo, this->autooob, sizeof(oobinfo));
|
|
||||||
oobinfo.useecc = MTD_NANDECC_PLACEONLY;
|
|
||||||
|
|
||||||
/* Must we save the block contents ? */
|
/* Must we save the block contents ? */
|
||||||
if (td->options & NAND_BBT_SAVECONTENT) {
|
if (td->options & NAND_BBT_SAVECONTENT) {
|
||||||
/* Make it block aligned */
|
/* Make it block aligned */
|
||||||
to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
|
to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
|
||||||
len = 1 << this->bbt_erase_shift;
|
len = 1 << this->bbt_erase_shift;
|
||||||
res = mtd->read_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
|
res = mtd->read(mtd, to, len, &retlen, buf);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (retlen != len) {
|
if (retlen != len) {
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO "nand_bbt: Error "
|
||||||
"nand_bbt: Error reading block for writing the bad block table\n");
|
"reading block for writing "
|
||||||
|
"the bad block table\n");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
printk(KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
|
printk(KERN_WARNING "nand_bbt: ECC error "
|
||||||
|
"while reading block for writing "
|
||||||
|
"bad block table\n");
|
||||||
}
|
}
|
||||||
|
/* Read oob data */
|
||||||
|
ooblen = (len >> this->page_shift) * mtd->oobsize;
|
||||||
|
res = mtd->read_oob(mtd, to + mtd->writesize, ooblen,
|
||||||
|
&retlen, &buf[len]);
|
||||||
|
if (res < 0 || retlen != ooblen)
|
||||||
|
goto outerr;
|
||||||
|
|
||||||
/* Calc the byte offset in the buffer */
|
/* Calc the byte offset in the buffer */
|
||||||
pageoffs = page - (int)(to >> this->page_shift);
|
pageoffs = page - (int)(to >> this->page_shift);
|
||||||
offs = pageoffs << this->page_shift;
|
offs = pageoffs << this->page_shift;
|
||||||
/* Preset the bbt area with 0xff */
|
/* Preset the bbt area with 0xff */
|
||||||
memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
|
memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
|
||||||
/* Preset the bbt's oob area with 0xff */
|
ooboffs = len + (pageoffs * mtd->oobsize);
|
||||||
memset(&buf[len + pageoffs * mtd->oobsize], 0xff,
|
|
||||||
((len >> this->page_shift) - pageoffs) * mtd->oobsize);
|
|
||||||
if (td->options & NAND_BBT_VERSION) {
|
|
||||||
buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* Calc length */
|
/* Calc length */
|
||||||
len = (size_t) (numblocks >> sft);
|
len = (size_t) (numblocks >> sft);
|
||||||
/* Make it page aligned ! */
|
/* Make it page aligned ! */
|
||||||
len = (len + (mtd->writesize - 1)) & ~(mtd->writesize - 1);
|
len = (len + (mtd->writesize - 1)) &
|
||||||
|
~(mtd->writesize - 1);
|
||||||
/* Preset the buffer with 0xff */
|
/* Preset the buffer with 0xff */
|
||||||
memset(buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
|
memset(buf, 0xff, len +
|
||||||
|
(len >> this->page_shift)* mtd->oobsize);
|
||||||
offs = 0;
|
offs = 0;
|
||||||
|
ooboffs = len;
|
||||||
/* Pattern is located in oob area of first page */
|
/* Pattern is located in oob area of first page */
|
||||||
memcpy(&buf[len + td->offs], td->pattern, td->len);
|
memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
|
||||||
if (td->options & NAND_BBT_VERSION) {
|
|
||||||
buf[len + td->veroffs] = td->version[chip];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (td->options & NAND_BBT_VERSION)
|
||||||
|
buf[ooboffs + td->veroffs] = td->version[chip];
|
||||||
|
|
||||||
/* walk through the memory table */
|
/* walk through the memory table */
|
||||||
for (i = 0; i < numblocks;) {
|
for (i = 0; i < numblocks;) {
|
||||||
uint8_t dat;
|
uint8_t dat;
|
||||||
|
@ -604,7 +621,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
for (j = 0; j < 4; j++, i++) {
|
for (j = 0; j < 4; j++, i++) {
|
||||||
int sftcnt = (i << (3 - sft)) & sftmsk;
|
int sftcnt = (i << (3 - sft)) & sftmsk;
|
||||||
/* Do not store the reserved bbt blocks ! */
|
/* Do not store the reserved bbt blocks ! */
|
||||||
buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
|
buf[offs + (i >> sft)] &=
|
||||||
|
~(msk[dat & 0x03] << sftcnt);
|
||||||
dat >>= 2;
|
dat >>= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -614,23 +632,25 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
einfo.addr = (unsigned long)to;
|
einfo.addr = (unsigned long)to;
|
||||||
einfo.len = 1 << this->bbt_erase_shift;
|
einfo.len = 1 << this->bbt_erase_shift;
|
||||||
res = nand_erase_nand(mtd, &einfo, 1);
|
res = nand_erase_nand(mtd, &einfo, 1);
|
||||||
if (res < 0) {
|
if (res < 0)
|
||||||
printk(KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
|
goto outerr;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mtd->write_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
|
res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]);
|
||||||
if (res < 0) {
|
if (res < 0)
|
||||||
printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
|
goto outerr;
|
||||||
return res;
|
|
||||||
}
|
printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
|
||||||
printk(KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
|
"0x%02X\n", (unsigned int)to, td->version[chip]);
|
||||||
(unsigned int)to, td->version[chip]);
|
|
||||||
|
|
||||||
/* Mark it as used */
|
/* Mark it as used */
|
||||||
td->pages[chip] = page;
|
td->pages[chip] = page;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
outerr:
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"nand_bbt: Error while writing bad block table %d\n", res);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -70,8 +70,6 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
nftl->mbd.devnum = -1;
|
nftl->mbd.devnum = -1;
|
||||||
nftl->mbd.blksize = 512;
|
nftl->mbd.blksize = 512;
|
||||||
nftl->mbd.tr = tr;
|
nftl->mbd.tr = tr;
|
||||||
memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
|
|
||||||
nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
|
|
||||||
|
|
||||||
if (NFTL_mount(nftl) < 0) {
|
if (NFTL_mount(nftl) < 0) {
|
||||||
printk(KERN_WARNING "NFTL: could not mount device\n");
|
printk(KERN_WARNING "NFTL: could not mount device\n");
|
||||||
|
@ -369,8 +367,11 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
}
|
}
|
||||||
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
||||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||||
MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
|
|
||||||
512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
|
nand_write_raw(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
|
||||||
|
(block * 512), 512, &retlen, movebuf,
|
||||||
|
(char *)&oob);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add the header so that it is now a valid chain */
|
/* add the header so that it is now a valid chain */
|
||||||
|
@ -639,10 +640,10 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
||||||
|
|
||||||
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
||||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||||
MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
|
|
||||||
512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
|
|
||||||
/* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
|
|
||||||
|
|
||||||
|
nand_write_raw(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) +
|
||||||
|
blockofs, 512, &retlen, (char *)buffer,
|
||||||
|
(char *)&oob);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NFTL_RW */
|
#endif /* CONFIG_NFTL_RW */
|
||||||
|
|
|
@ -268,18 +268,22 @@ static int memcmpb(void *a, int c, int n)
|
||||||
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
|
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
|
||||||
int check_oob)
|
int check_oob)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
size_t retlen;
|
|
||||||
u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
|
u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
|
||||||
|
struct mtd_info *mtd = nftl->mbd.mtd;
|
||||||
|
size_t retlen;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < len; i += SECTORSIZE) {
|
for (i = 0; i < len; i += SECTORSIZE) {
|
||||||
if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
|
if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
|
||||||
return -1;
|
return -1;
|
||||||
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
|
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_oob) {
|
if (check_oob) {
|
||||||
if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
|
if(mtd->read_oob(mtd, address, mtd->oobsize,
|
||||||
|
&retlen, &buf[SECTORSIZE]) < 0)
|
||||||
|
return -1;
|
||||||
|
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
address += SECTORSIZE;
|
address += SECTORSIZE;
|
||||||
|
|
|
@ -597,31 +597,28 @@ static void onenand_release_device(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_read_ecc - [MTD Interface] Read data with ECC
|
* onenand_read - [MTD Interface] Read data from flash
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
* @param from offset to read from
|
* @param from offset to read from
|
||||||
* @param len number of bytes to read
|
* @param len number of bytes to read
|
||||||
* @param retlen pointer to variable to store the number of read bytes
|
* @param retlen pointer to variable to store the number of read bytes
|
||||||
* @param buf the databuffer to put data
|
* @param buf the databuffer to put data
|
||||||
* @param oob_buf filesystem supplied oob data buffer
|
|
||||||
* @param oobsel oob selection structure
|
|
||||||
*
|
*
|
||||||
* OneNAND read with ECC
|
* Read with ecc
|
||||||
*/
|
*/
|
||||||
static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf,
|
size_t *retlen, u_char *buf)
|
||||||
u_char *oob_buf, struct nand_oobinfo *oobsel)
|
|
||||||
{
|
{
|
||||||
struct onenand_chip *this = mtd->priv;
|
struct onenand_chip *this = mtd->priv;
|
||||||
int read = 0, column;
|
int read = 0, column;
|
||||||
int thislen;
|
int thislen;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
||||||
|
|
||||||
/* Do not allow reads past end of device */
|
/* Do not allow reads past end of device */
|
||||||
if ((from + len) > mtd->size) {
|
if ((from + len) > mtd->size) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n");
|
||||||
*retlen = 0;
|
*retlen = 0;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -654,7 +651,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,22 +672,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
|
|
||||||
* @param mtd MTD device structure
|
|
||||||
* @param from offset to read from
|
|
||||||
* @param len number of bytes to read
|
|
||||||
* @param retlen pointer to variable to store the number of read bytes
|
|
||||||
* @param buf the databuffer to put data
|
|
||||||
*
|
|
||||||
* This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
|
|
||||||
*/
|
|
||||||
static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
||||||
size_t *retlen, u_char *buf)
|
|
||||||
{
|
|
||||||
return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_read_oob - [MTD Interface] OneNAND read out-of-band
|
* onenand_read_oob - [MTD Interface] OneNAND read out-of-band
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
|
@ -834,39 +815,36 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
|
||||||
#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
|
#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_write_ecc - [MTD Interface] OneNAND write with ECC
|
* onenand_write - [MTD Interface] write buffer to FLASH
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
* @param to offset to write to
|
* @param to offset to write to
|
||||||
* @param len number of bytes to write
|
* @param len number of bytes to write
|
||||||
* @param retlen pointer to variable to store the number of written bytes
|
* @param retlen pointer to variable to store the number of written bytes
|
||||||
* @param buf the data to write
|
* @param buf the data to write
|
||||||
* @param eccbuf filesystem supplied oob data buffer
|
|
||||||
* @param oobsel oob selection structure
|
|
||||||
*
|
*
|
||||||
* OneNAND write with ECC
|
* Write with ECC
|
||||||
*/
|
*/
|
||||||
static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf,
|
size_t *retlen, const u_char *buf)
|
||||||
u_char *eccbuf, struct nand_oobinfo *oobsel)
|
|
||||||
{
|
{
|
||||||
struct onenand_chip *this = mtd->priv;
|
struct onenand_chip *this = mtd->priv;
|
||||||
int written = 0;
|
int written = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
|
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
|
||||||
|
|
||||||
/* Initialize retlen, in case of early exit */
|
/* Initialize retlen, in case of early exit */
|
||||||
*retlen = 0;
|
*retlen = 0;
|
||||||
|
|
||||||
/* Do not allow writes past end of device */
|
/* Do not allow writes past end of device */
|
||||||
if (unlikely((to + len) > mtd->size)) {
|
if (unlikely((to + len) > mtd->size)) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reject writes, which are not page aligned */
|
/* Reject writes, which are not page aligned */
|
||||||
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
|
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,7 +866,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
|
||||||
ret = this->wait(mtd, FL_WRITING);
|
ret = this->wait(mtd, FL_WRITING);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,7 +875,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
/* Only check verify write turn on */
|
/* Only check verify write turn on */
|
||||||
ret = onenand_verify_page(mtd, (u_char *) buf, to);
|
ret = onenand_verify_page(mtd, (u_char *) buf, to);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret);
|
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,23 +895,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* onenand_write - [MTD Interface] compability function for onenand_write_ecc
|
|
||||||
* @param mtd MTD device structure
|
|
||||||
* @param to offset to write to
|
|
||||||
* @param len number of bytes to write
|
|
||||||
* @param retlen pointer to variable to store the number of written bytes
|
|
||||||
* @param buf the data to write
|
|
||||||
*
|
|
||||||
* This function simply calls onenand_write_ecc
|
|
||||||
* with oob buffer and oobsel = NULL
|
|
||||||
*/
|
|
||||||
static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
||||||
size_t *retlen, const u_char *buf)
|
|
||||||
{
|
|
||||||
return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onenand_write_oob - [MTD Interface] OneNAND write out-of-band
|
* onenand_write_oob - [MTD Interface] OneNAND write out-of-band
|
||||||
* @param mtd MTD device structure
|
* @param mtd MTD device structure
|
||||||
|
@ -1812,8 +1773,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
mtd->read = onenand_read;
|
mtd->read = onenand_read;
|
||||||
mtd->write = onenand_write;
|
mtd->write = onenand_write;
|
||||||
mtd->read_ecc = onenand_read_ecc;
|
|
||||||
mtd->write_ecc = onenand_write_ecc;
|
|
||||||
mtd->read_oob = onenand_read_oob;
|
mtd->read_oob = onenand_read_oob;
|
||||||
mtd->write_oob = onenand_write_oob;
|
mtd->write_oob = onenand_write_oob;
|
||||||
#ifdef CONFIG_MTD_ONENAND_OTP
|
#ifdef CONFIG_MTD_ONENAND_OTP
|
||||||
|
|
|
@ -233,10 +233,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the read... */
|
/* Do the read... */
|
||||||
if (jffs2_cleanmarker_oob(c))
|
ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
|
||||||
ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
|
|
||||||
else
|
|
||||||
ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
|
|
||||||
|
|
||||||
if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
|
if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
|
||||||
/* ECC recovered */
|
/* ECC recovered */
|
||||||
|
@ -290,16 +287,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
||||||
if (breakme++ == 20) {
|
if (breakme++ == 20) {
|
||||||
printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
|
printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
|
||||||
breakme = 0;
|
breakme = 0;
|
||||||
c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
|
c->mtd->write(c->mtd, ofs, towrite, &retlen,
|
||||||
brokenbuf, NULL, c->oobinfo);
|
brokenbuf);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (jffs2_cleanmarker_oob(c))
|
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
|
||||||
ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
|
rewrite_buf);
|
||||||
rewrite_buf, NULL, c->oobinfo);
|
|
||||||
else
|
|
||||||
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
|
|
||||||
|
|
||||||
if (ret || retlen != towrite) {
|
if (ret || retlen != towrite) {
|
||||||
/* Argh. We tried. Really we did. */
|
/* Argh. We tried. Really we did. */
|
||||||
|
@ -457,15 +451,12 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
||||||
if (breakme++ == 20) {
|
if (breakme++ == 20) {
|
||||||
printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
|
printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
|
||||||
breakme = 0;
|
breakme = 0;
|
||||||
c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
|
c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
|
||||||
&retlen, brokenbuf, NULL, c->oobinfo);
|
brokenbuf);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (jffs2_cleanmarker_oob(c))
|
|
||||||
ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
|
|
||||||
else
|
|
||||||
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
|
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
|
||||||
|
|
||||||
if (ret || retlen != c->wbuf_pagesize) {
|
if (ret || retlen != c->wbuf_pagesize) {
|
||||||
|
@ -800,10 +791,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
|
||||||
|
|
||||||
/* Read flash */
|
/* Read flash */
|
||||||
down_read(&c->wbuf_sem);
|
down_read(&c->wbuf_sem);
|
||||||
if (jffs2_cleanmarker_oob(c))
|
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||||
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
|
|
||||||
else
|
|
||||||
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
|
||||||
|
|
||||||
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
||||||
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
||||||
|
|
|
@ -115,9 +115,6 @@ struct mtd_info {
|
||||||
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||||
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||||
|
|
||||||
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
|
|
||||||
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
|
|
||||||
|
|
||||||
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||||
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
|
||||||
size_t len, size_t ooblen);
|
size_t len, size_t ooblen);
|
||||||
|
|
||||||
|
|
||||||
|
extern int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, uint8_t *buf, uint8_t *oob);
|
||||||
|
|
||||||
/* The maximum number of NAND chips in an array */
|
/* The maximum number of NAND chips in an array */
|
||||||
#define NAND_MAX_CHIPS 8
|
#define NAND_MAX_CHIPS 8
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue