Skip to content

Commit

Permalink
[MTD] [NAND] remove len/ooblen confusion.
Browse files Browse the repository at this point in the history
As was discussed between Ricard Wanderlöf, David Woodhouse, Artem 
Bityutskiy and me, the current API for reading/writing OOB is confusing. 

The thing that introduces confusion is the need to specify ops.len 
together with ops.ooblen for reads/writes that concern only OOB not data 
area. So, ops.len is overloaded: when ops.datbuf != NULL it serves to 
specify the length of the data read, and when ops.datbuf == NULL, it 
serves to specify the full OOB read length.

The patch inlined below is the slightly updated version of the previous 
patch serving the same purpose, but with the new Artem's comments taken 
into account.

Artem, BTW, thanks a lot for your valuable input!

Signed-off-by: Vitaly Wool <vwool@ru.mvista.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
Vitaly Wool authored and dwmw2 committed Nov 28, 2006
1 parent 1918767 commit 7014568
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 73 deletions.
6 changes: 2 additions & 4 deletions drivers/mtd/inftlcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,9 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;

res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}

Expand All @@ -184,10 +183,9 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;

res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}

Expand Down
12 changes: 5 additions & 7 deletions drivers/mtd/mtdchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,13 +499,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;

ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;

if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
return -EINVAL;

ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
Expand All @@ -520,7 +519,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->write_oob(mtd, buf.start, &ops);

if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen,
sizeof(uint32_t)))
ret = -EFAULT;

Expand Down Expand Up @@ -548,7 +547,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;

ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
Expand All @@ -564,10 +562,10 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->read_oob(mtd, buf.start, &ops);

if (put_user(ops.retlen, (uint32_t __user *)argp))
if (put_user(ops.oobretlen, (uint32_t __user *)argp))
ret = -EFAULT;
else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
ops.retlen))
else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,
ops.oobretlen))
ret = -EFAULT;

kfree(ops.oobbuf);
Expand Down
39 changes: 24 additions & 15 deletions drivers/mtd/mtdconcat.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
struct mtd_oob_ops devops = *ops;
int i, err, ret = 0;

ops->retlen = 0;
ops->retlen = ops->oobretlen = 0;

for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
Expand All @@ -263,6 +263,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)

err = subdev->read_oob(subdev, from, &devops);
ops->retlen += devops.retlen;
ops->oobretlen += devops.oobretlen;

/* Save information about bitflips! */
if (unlikely(err)) {
Expand All @@ -278,14 +279,18 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
return err;
}

devops.len = ops->len - ops->retlen;
if (!devops.len)
return ret;

if (devops.datbuf)
if (devops.datbuf) {
devops.len = ops->len - ops->retlen;
if (!devops.len)
return ret;
devops.datbuf += devops.retlen;
if (devops.oobbuf)
devops.oobbuf += devops.ooblen;
}
if (devops.oobbuf) {
devops.ooblen = ops->ooblen - ops->oobretlen;
if (!devops.ooblen)
return ret;
devops.oobbuf += ops->oobretlen;
}

from = 0;
}
Expand Down Expand Up @@ -321,14 +326,18 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
if (err)
return err;

devops.len = ops->len - ops->retlen;
if (!devops.len)
return 0;

if (devops.datbuf)
if (devops.datbuf) {
devops.len = ops->len - ops->retlen;
if (!devops.len)
return 0;
devops.datbuf += devops.retlen;
if (devops.oobbuf)
devops.oobbuf += devops.ooblen;
}
if (devops.oobbuf) {
devops.ooblen = ops->ooblen - ops->oobretlen;
if (!devops.ooblen)
return 0;
devops.oobbuf += devops.oobretlen;
}
to = 0;
}
return -EINVAL;
Expand Down
4 changes: 2 additions & 2 deletions drivers/mtd/mtdpart.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,

if (from >= mtd->size)
return -EINVAL;
if (from + ops->len > mtd->size)
if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL;
res = part->master->read_oob(part->master, from + part->offset, ops);

Expand Down Expand Up @@ -161,7 +161,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,

if (to >= mtd->size)
return -EINVAL;
if (to + ops->len > mtd->size)
if (ops->datbuf && to + ops->len > mtd->size)
return -EINVAL;
return part->master->write_oob(part->master, to + part->offset, ops);
}
Expand Down
51 changes: 35 additions & 16 deletions drivers/mtd/nand/nand_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
* @len: size of oob to transfer
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops)
struct mtd_oob_ops *ops, size_t len)
{
size_t len = ops->ooblen;

switch(ops->mode) {

case MTD_OOB_PLACE:
Expand Down Expand Up @@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
int sndcmd = 1;
int ret = 0;
uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen;
uint8_t *bufpoi, *oob, *buf;

stats = mtd->ecc_stats;
Expand Down Expand Up @@ -1006,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,

if (unlikely(oob)) {
/* Raw mode does data:oob:data:oob */
if (ops->mode != MTD_OOB_RAW)
oob = nand_transfer_oob(chip, oob, ops);
else
buf = nand_transfer_oob(chip, buf, ops);
if (ops->mode != MTD_OOB_RAW) {
int toread = min(oobreadlen,
chip->ecc.layout->oobavail);
if (toread) {
oob = nand_transfer_oob(chip,
oob, ops, toread);
oobreadlen -= toread;
}
} else
buf = nand_transfer_oob(chip,
buf, ops, mtd->oobsize);
}

if (!(chip->options & NAND_NO_READRDY)) {
Expand Down Expand Up @@ -1056,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}

ops->retlen = ops->len - (size_t) readlen;
if (oob)
ops->oobretlen = ops->ooblen - oobreadlen;

if (ret)
return ret;
Expand Down Expand Up @@ -1256,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
int page, realpage, chipnr, sndcmd = 1;
struct nand_chip *chip = mtd->priv;
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
int readlen = ops->len;
int readlen = ops->ooblen;
int len;
uint8_t *buf = ops->oobbuf;

DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
(unsigned long long)from, readlen);

if (ops->mode == MTD_OOB_RAW)
len = mtd->oobsize;
else
len = chip->ecc.layout->oobavail;

chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);

Expand All @@ -1271,7 +1286,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,

while(1) {
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
buf = nand_transfer_oob(chip, buf, ops);

len = min(len, readlen);
buf = nand_transfer_oob(chip, buf, ops, len);

if (!(chip->options & NAND_NO_READRDY)) {
/*
Expand All @@ -1286,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
nand_wait_ready(mtd);
}

readlen -= ops->ooblen;
readlen -= len;
if (!readlen)
break;

Expand All @@ -1308,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
sndcmd = 1;
}

ops->retlen = ops->len;
ops->oobretlen = ops->ooblen;
return 0;
}

Expand All @@ -1329,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->retlen = 0;

/* Do not allow reads past end of device */
if ((from + ops->len) > mtd->size) {
if (ops->datbuf && (from + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
Expand Down Expand Up @@ -1654,6 +1671,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
}

ops->retlen = ops->len - writelen;
if (unlikely(oob))
ops->oobretlen = ops->ooblen;
return ret;
}

Expand Down Expand Up @@ -1709,10 +1728,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct nand_chip *chip = mtd->priv;

DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
(unsigned int)to, (int)ops->len);
(unsigned int)to, (int)ops->ooblen);

/* Do not allow write past end of page */
if ((ops->ooboffs + ops->len) > mtd->oobsize) {
if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
Expand Down Expand Up @@ -1748,7 +1767,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
if (status)
return status;

ops->retlen = ops->len;
ops->oobretlen = ops->ooblen;

return 0;
}
Expand All @@ -1768,7 +1787,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0;

/* Do not allow writes past end of device */
if ((to + ops->len) > mtd->size) {
if (ops->datbuf && (to + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
Expand Down
5 changes: 2 additions & 3 deletions drivers/mtd/nand/nand_bbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
struct mtd_oob_ops ops;
int j, ret;

ops.len = mtd->oobsize;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
ops.ooboffs = 0;
Expand Down Expand Up @@ -676,10 +675,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
"bad block table\n");
}
/* Read oob data */
ops.len = (len >> this->page_shift) * mtd->oobsize;
ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
ops.oobbuf = &buf[len];
res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
if (res < 0 || ops.retlen != ops.len)
if (res < 0 || ops.oobretlen != ops.ooblen)
goto outerr;

/* Calc the byte offset in the buffer */
Expand Down
6 changes: 2 additions & 4 deletions drivers/mtd/nftlcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,9 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;

res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}

Expand All @@ -168,10 +167,9 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;

res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}

Expand Down
5 changes: 2 additions & 3 deletions drivers/mtd/ssfdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,12 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)

ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.len = OOB_SIZE;
ops.ooblen = OOB_SIZE;
ops.oobbuf = buf;
ops.datbuf = NULL;

ret = mtd->read_oob(mtd, offs, &ops);
if (ret < 0 || ops.retlen != OOB_SIZE)
if (ret < 0 || ops.oobretlen != OOB_SIZE)
return -1;

return 0;
Expand Down
Loading

0 comments on commit 7014568

Please sign in to comment.