Commit c46f6483 authored by Brian Norris's avatar Brian Norris Committed by Artem Bityutskiy

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: default avatarBrian Norris <computersforpeace@gmail.com>
Cc: Jim Quinlan <jim2101024@gmail.com>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@intel.com>
parent e9195edc
...@@ -435,9 +435,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, ...@@ -435,9 +435,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
return ret; return ret;
} }
static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, static int mtd_do_readoob(struct file *file, struct mtd_info *mtd,
uint32_t length, void __user *ptr, uint32_t __user *retp) uint64_t start, uint32_t length, void __user *ptr,
uint32_t __user *retp)
{ {
struct mtd_file_info *mfi = file->private_data;
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int ret = 0; int ret = 0;
...@@ -455,7 +457,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, ...@@ -455,7 +457,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
ops.ooblen = length; ops.ooblen = length;
ops.ooboffs = start & (mtd->writesize - 1); ops.ooboffs = start & (mtd->writesize - 1);
ops.datbuf = NULL; ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE; ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE;
if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
return -EINVAL; return -EINVAL;
...@@ -716,7 +718,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -716,7 +718,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
if (copy_from_user(&buf, argp, sizeof(buf))) if (copy_from_user(&buf, argp, sizeof(buf)))
ret = -EFAULT; ret = -EFAULT;
else else
ret = mtd_do_readoob(mtd, buf.start, buf.length, ret = mtd_do_readoob(file, mtd, buf.start, buf.length,
buf.ptr, &buf_user->start); buf.ptr, &buf_user->start);
break; break;
} }
...@@ -743,7 +745,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -743,7 +745,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
if (copy_from_user(&buf, argp, sizeof(buf))) if (copy_from_user(&buf, argp, sizeof(buf)))
ret = -EFAULT; ret = -EFAULT;
else else
ret = mtd_do_readoob(mtd, buf.start, buf.length, ret = mtd_do_readoob(file, mtd, buf.start, buf.length,
(void __user *)(uintptr_t)buf.usr_ptr, (void __user *)(uintptr_t)buf.usr_ptr,
&buf_user->length); &buf_user->length);
break; break;
...@@ -1029,7 +1031,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, ...@@ -1029,7 +1031,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
if (copy_from_user(&buf, argp, sizeof(buf))) if (copy_from_user(&buf, argp, sizeof(buf)))
ret = -EFAULT; ret = -EFAULT;
else else
ret = mtd_do_readoob(mtd, buf.start, ret = mtd_do_readoob(file, mtd, buf.start,
buf.length, compat_ptr(buf.ptr), buf.length, compat_ptr(buf.ptr),
&buf_user->start); &buf_user->start);
break; break;
......
...@@ -1787,7 +1787,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -1787,7 +1787,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
page = realpage & chip->pagemask; page = realpage & chip->pagemask;
while (1) { while (1) {
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); if (ops->mode == MTD_OOB_RAW)
sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd);
else
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
len = min(len, readlen); len = min(len, readlen);
buf = nand_transfer_oob(chip, buf, ops, len); buf = nand_transfer_oob(chip, buf, ops, len);
...@@ -3385,6 +3388,8 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -3385,6 +3388,8 @@ int nand_scan_tail(struct mtd_info *mtd)
} }
/* For many systems, the standard OOB write also works for raw */ /* For many systems, the standard OOB write also works for raw */
if (!chip->ecc.read_oob_raw)
chip->ecc.read_oob_raw = chip->ecc.read_oob;
if (!chip->ecc.write_oob_raw) if (!chip->ecc.write_oob_raw)
chip->ecc.write_oob_raw = chip->ecc.write_oob; chip->ecc.write_oob_raw = chip->ecc.write_oob;
......
...@@ -341,6 +341,7 @@ struct nand_hw_control { ...@@ -341,6 +341,7 @@ struct nand_hw_control {
* @write_page: function to write a page according to the ECC generator * @write_page: function to write a page according to the ECC generator
* requirements. * requirements.
* @write_oob_raw: function to write chip OOB data without ECC * @write_oob_raw: function to write chip OOB data without ECC
* @read_oob_raw: function to read chip OOB data without ECC
* @read_oob: function to read chip OOB data * @read_oob: function to read chip OOB data
* @write_oob: function to write chip OOB data * @write_oob: function to write chip OOB data
*/ */
...@@ -371,6 +372,8 @@ struct nand_ecc_ctrl { ...@@ -371,6 +372,8 @@ struct nand_ecc_ctrl {
const uint8_t *buf); const uint8_t *buf);
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
int page); int page);
int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd);
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
int sndcmd); int sndcmd);
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment