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>
This commit is contained in:
parent
e9195edc59
commit
c46f6483d2
@ -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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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 {
|
|||||||
* @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 {
|
|||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user