aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2011-08-30 21:45:38 -0400
committerArtem Bityutskiy <artem.bityutskiy@intel.com>2011-09-11 08:13:38 -0400
commitc46f6483d21e93400e4a110de7902830173d53b0 (patch)
treebac45575c58963f4bc35d13b188c8ff5a32c9823 /drivers/mtd
parente9195edc59f33e9cabdd32a2959e927806670f45 (diff)
mtd: support reading OOB without ECC
This fixes issues with `nanddump -n' and the MEMREADOOB[64] ioctls on hardware that performs error correction when reading only OOB data. A driver for such hardware needs to know when we're doing a RAW vs. a normal write, but mtd_do_read_oob does not pass such information to the lower layers (e.g., NAND). We should pass MTD_OOB_RAW or MTD_OOB_PLACE based on the MTD file mode. For now, most drivers can get away with just setting: chip->ecc.read_oob_raw = chip->ecc.read_oob This is done by default; but for systems that behave as described above, you must supply your own replacement function. This was tested with nandsim as well as on actual SLC NAND. Signed-off-by: Brian Norris <computersforpeace@gmail.com> Cc: Jim Quinlan <jim2101024@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/mtdchar.c14
-rw-r--r--drivers/mtd/nand/nand_base.c7
2 files changed, 14 insertions, 7 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index bcb7f05fd27b..d0eaef67b9bb 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -435,9 +435,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
435 return ret; 435 return ret;
436} 436}
437 437
438static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, 438static int mtd_do_readoob(struct file *file, struct mtd_info *mtd,
439 uint32_t length, void __user *ptr, uint32_t __user *retp) 439 uint64_t start, uint32_t length, void __user *ptr,
440 uint32_t __user *retp)
440{ 441{
442 struct mtd_file_info *mfi = file->private_data;
441 struct mtd_oob_ops ops; 443 struct mtd_oob_ops ops;
442 int ret = 0; 444 int ret = 0;
443 445
@@ -455,7 +457,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
455 ops.ooblen = length; 457 ops.ooblen = length;
456 ops.ooboffs = start & (mtd->writesize - 1); 458 ops.ooboffs = start & (mtd->writesize - 1);
457 ops.datbuf = NULL; 459 ops.datbuf = NULL;
458 ops.mode = MTD_OOB_PLACE; 460 ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE;
459 461
460 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) 462 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
461 return -EINVAL; 463 return -EINVAL;
@@ -716,7 +718,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
716 if (copy_from_user(&buf, argp, sizeof(buf))) 718 if (copy_from_user(&buf, argp, sizeof(buf)))
717 ret = -EFAULT; 719 ret = -EFAULT;
718 else 720 else
719 ret = mtd_do_readoob(mtd, buf.start, buf.length, 721 ret = mtd_do_readoob(file, mtd, buf.start, buf.length,
720 buf.ptr, &buf_user->start); 722 buf.ptr, &buf_user->start);
721 break; 723 break;
722 } 724 }
@@ -743,7 +745,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
743 if (copy_from_user(&buf, argp, sizeof(buf))) 745 if (copy_from_user(&buf, argp, sizeof(buf)))
744 ret = -EFAULT; 746 ret = -EFAULT;
745 else 747 else
746 ret = mtd_do_readoob(mtd, buf.start, buf.length, 748 ret = mtd_do_readoob(file, mtd, buf.start, buf.length,
747 (void __user *)(uintptr_t)buf.usr_ptr, 749 (void __user *)(uintptr_t)buf.usr_ptr,
748 &buf_user->length); 750 &buf_user->length);
749 break; 751 break;
@@ -1029,7 +1031,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
1029 if (copy_from_user(&buf, argp, sizeof(buf))) 1031 if (copy_from_user(&buf, argp, sizeof(buf)))
1030 ret = -EFAULT; 1032 ret = -EFAULT;
1031 else 1033 else
1032 ret = mtd_do_readoob(mtd, buf.start, 1034 ret = mtd_do_readoob(file, mtd, buf.start,
1033 buf.length, compat_ptr(buf.ptr), 1035 buf.length, compat_ptr(buf.ptr),
1034 &buf_user->start); 1036 &buf_user->start);
1035 break; 1037 break;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index b61a7c7bd097..ad40607f5f24 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1787,7 +1787,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1787 page = realpage & chip->pagemask; 1787 page = realpage & chip->pagemask;
1788 1788
1789 while (1) { 1789 while (1) {
1790 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); 1790 if (ops->mode == MTD_OOB_RAW)
1791 sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd);
1792 else
1793 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
1791 1794
1792 len = min(len, readlen); 1795 len = min(len, readlen);
1793 buf = nand_transfer_oob(chip, buf, ops, len); 1796 buf = nand_transfer_oob(chip, buf, ops, len);
@@ -3385,6 +3388,8 @@ int nand_scan_tail(struct mtd_info *mtd)
3385 } 3388 }
3386 3389
3387 /* For many systems, the standard OOB write also works for raw */ 3390 /* For many systems, the standard OOB write also works for raw */
3391 if (!chip->ecc.read_oob_raw)
3392 chip->ecc.read_oob_raw = chip->ecc.read_oob;
3388 if (!chip->ecc.write_oob_raw) 3393 if (!chip->ecc.write_oob_raw)
3389 chip->ecc.write_oob_raw = chip->ecc.write_oob; 3394 chip->ecc.write_oob_raw = chip->ecc.write_oob;
3390 3395