summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-10 13:15:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-10 13:15:17 -0700
commit6f51ab9440d131ae424cce27e3170746219f5142 (patch)
treee198f70fb53214ca67db8ffb76cafc29852c05df /drivers/mtd
parent6f630784cc0d92fb58ea326e2bc01aa056279ecb (diff)
parent5788ccf3c84f5587418a80128a3653aa35abf00b (diff)
Merge tag 'mtd/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Richard Weinberger: "MTD core changes: - partition parser: Support MTD names containing one or more colons. - mtdblock: clear cache_state to avoid writing to bad blocks repeatedly. Raw NAND core changes: - Stop using nand_release(), patched all drivers. - Give more information about the ECC weakness when not matching the chip's requirement. - MAINTAINERS updates. - Support emulated SLC mode on MLC NANDs. - Support "constrained" controllers, adapt the core and ONFI/JEDEC table parsing and Micron's code. - Take check_only into account. - Add an invalid ECC mode to discriminate with valid ones. - Return an enum from of_get_nand_ecc_algo(). - Drop OOB_FIRST placement scheme. - Introduce nand_extract_bits(). - Ensure a consistent bitflips numbering. - BCH lib: - Allow easy bit swapping. - Rework a little bit the exported function names. - Fix nand_gpio_waitrdy(). - Propage CS selection to sub operations. - Add a NAND_NO_BBM_QUIRK flag. - Give the possibility to verify a read operation is supported. - Add a helper to check supported operations. - Avoid indirect access to ->data_buf(). - Rename the use_bufpoi variables. - Fix comments about the use of bufpoi. - Rename a NAND chip option. - Reorder the nand_chip->options flags. - Translate obscure bitfields into readable macros. - Timings: - Fix default values. - Add mode information to the timings structure. Raw NAND controller driver changes: - Fixed many error paths. - Arasan - New driver - Au1550nd: - Various cleanups - Migration to ->exec_op() - brcmnand: - Misc cleanup. - Support v2.1-v2.2 controllers. - Remove unused including <linux/version.h>. - Correctly verify erased pages. - Fix Hamming OOB layout. - Cadence - Make cadence_nand_attach_chip static. - Cafe: - Set the NAND_NO_BBM_QUIRK flag - cmx270: - Remove this controller driver. - cs553x: - Misc cleanup - Migration to ->exec_op() - Davinci: - Misc cleanup. - Migration to ->exec_op() - Denali: - Add more delays before latching incoming data - Diskonchip: - Misc cleanup - Migration to ->exec_op() - Fsmc: - Change to non-atomic bit operations. - GPMI: - Use nand_extract_bits() - Fix runtime PM imbalance. - Ingenic: - Migration to exec_op() - Fix the RB gpio active-high property on qi, lb60 - Make qi_lb60_ooblayout_ops static. - Marvell: - Misc cleanup and small fixes - Nandsim: - Fix the error paths, driver wide. - Omap_elm: - Fix runtime PM imbalance. - STM32_FMC2: - Misc cleanups (error cases, comments, timeout valus, cosmetic changes). SPI NOR core changes: - Add, update support and fix few flashes. - Prepare BFPT parsing for JESD216 rev D. - Kernel doc fixes. CFI changes: - Support the absence of protection registers for Intel CFI flashes. - Replace zero-length array with flexible-arrays" * tag 'mtd/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (208 commits) mtd: clear cache_state to avoid writing to bad blocks repeatedly mtd: parser: cmdline: Support MTD names containing one or more colons mtd: physmap_of_gemini: remove defined but not used symbol 'syscon_match' mtd: rawnand: Add an invalid ECC mode to discriminate with valid ones mtd: rawnand: Return an enum from of_get_nand_ecc_algo() mtd: rawnand: Drop OOB_FIRST placement scheme mtd: rawnand: Avoid a typedef mtd: Fix typo in mtd_ooblayout_set_databytes() description mtd: rawnand: Stop using nand_release() mtd: rawnand: nandsim: Reorganize ns_cleanup_module() mtd: rawnand: nandsim: Rename a label in ns_init_module() mtd: rawnand: nandsim: Manage lists on error in ns_init_module() mtd: rawnand: nandsim: Fix the label pointing on nand_cleanup() mtd: rawnand: nandsim: Free erase_block_wear on error mtd: rawnand: nandsim: Use an additional label when freeing the nandsim object mtd: rawnand: nandsim: Stop using nand_release() mtd: rawnand: nandsim: Free the partition names in ns_free() mtd: rawnand: nandsim: Free the allocated device on error in ns_init() mtd: rawnand: nandsim: Free partition names on error in ns_init() mtd: rawnand: nandsim: Fix the two ns_alloc_device() error paths ...
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c13
-rw-r--r--drivers/mtd/devices/docg3.c10
-rw-r--r--drivers/mtd/maps/physmap-gemini.c5
-rw-r--r--drivers/mtd/mtdblock.c11
-rw-r--r--drivers/mtd/mtdcore.c191
-rw-r--r--drivers/mtd/mtdpart.c54
-rw-r--r--drivers/mtd/nand/raw/Kconfig12
-rw-r--r--drivers/mtd/nand/raw/Makefile2
-rw-r--r--drivers/mtd/nand/raw/ams-delta.c5
-rw-r--r--drivers/mtd/nand/raw/arasan-nand-controller.c1297
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c2
-rw-r--r--drivers/mtd/nand/raw/au1550nd.c403
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/main.c6
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c164
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c17
-rw-r--r--drivers/mtd/nand/raw/cafe_nand.c16
-rw-r--r--drivers/mtd/nand/raw/cmx270_nand.c236
-rw-r--r--drivers/mtd/nand/raw/cs553x_nand.c199
-rw-r--r--drivers/mtd/nand/raw/davinci_nand.c312
-rw-r--r--drivers/mtd/nand/raw/denali.c60
-rw-r--r--drivers/mtd/nand/raw/diskonchip.c487
-rw-r--r--drivers/mtd/nand/raw/fsl_elbc_nand.c7
-rw-r--r--drivers/mtd/nand/raw/fsl_ifc_nand.c7
-rw-r--r--drivers/mtd/nand/raw/fsl_upm.c9
-rw-r--r--drivers/mtd/nand/raw/fsmc_nand.c19
-rw-r--r--drivers/mtd/nand/raw/gpio.c6
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c189
-rw-r--r--drivers/mtd/nand/raw/hisi504_nand.c6
-rw-r--r--drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c170
-rw-r--r--drivers/mtd/nand/raw/internals.h12
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_mlc.c7
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_slc.c6
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c68
-rw-r--r--drivers/mtd/nand/raw/meson_nand.c5
-rw-r--r--drivers/mtd/nand/raw/mpc5121_nfc.c5
-rw-r--r--drivers/mtd/nand/raw/mtk_nand.c19
-rw-r--r--drivers/mtd/nand/raw/mxc_nand.c6
-rw-r--r--drivers/mtd/nand/raw/mxic_nand.c10
-rw-r--r--drivers/mtd/nand/raw/nand_base.c445
-rw-r--r--drivers/mtd/nand/raw/nand_bch.c10
-rw-r--r--drivers/mtd/nand/raw/nand_jedec.c32
-rw-r--r--drivers/mtd/nand/raw/nand_legacy.c8
-rw-r--r--drivers/mtd/nand/raw/nand_micron.c65
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c71
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c11
-rw-r--r--drivers/mtd/nand/raw/nand_toshiba.c14
-rw-r--r--drivers/mtd/nand/raw/nandsim.c438
-rw-r--r--drivers/mtd/nand/raw/ndfc.c8
-rw-r--r--drivers/mtd/nand/raw/omap2.c8
-rw-r--r--drivers/mtd/nand/raw/omap_elm.c1
-rw-r--r--drivers/mtd/nand/raw/orion_nand.c8
-rw-r--r--drivers/mtd/nand/raw/oxnas_nand.c33
-rw-r--r--drivers/mtd/nand/raw/pasemi_nand.c9
-rw-r--r--drivers/mtd/nand/raw/plat_nand.c8
-rw-r--r--drivers/mtd/nand/raw/qcom_nandc.c13
-rw-r--r--drivers/mtd/nand/raw/r852.c6
-rw-r--r--drivers/mtd/nand/raw/s3c2410.c3
-rw-r--r--drivers/mtd/nand/raw/sh_flctl.c6
-rw-r--r--drivers/mtd/nand/raw/sharpsl.c14
-rw-r--r--drivers/mtd/nand/raw/socrates_nand.c8
-rw-r--r--drivers/mtd/nand/raw/stm32_fmc2_nand.c1067
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c16
-rw-r--r--drivers/mtd/nand/raw/tango_nand.c13
-rw-r--r--drivers/mtd/nand/raw/tegra_nand.c6
-rw-r--r--drivers/mtd/nand/raw/tmio_nand.c8
-rw-r--r--drivers/mtd/nand/raw/txx9ndfmc.c6
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c10
-rw-r--r--drivers/mtd/nand/raw/xway_nand.c8
-rw-r--r--drivers/mtd/parsers/cmdlinepart.c35
-rw-r--r--drivers/mtd/parsers/ofpart.c3
-rw-r--r--drivers/mtd/spi-nor/Kconfig4
-rw-r--r--drivers/mtd/spi-nor/controllers/Kconfig4
-rw-r--r--drivers/mtd/spi-nor/controllers/aspeed-smc.c2
-rw-r--r--drivers/mtd/spi-nor/controllers/hisi-sfc.c2
-rw-r--r--drivers/mtd/spi-nor/controllers/nxp-spifi.c2
-rw-r--r--drivers/mtd/spi-nor/core.c22
-rw-r--r--drivers/mtd/spi-nor/macronix.c6
-rw-r--r--drivers/mtd/spi-nor/micron-st.c6
-rw-r--r--drivers/mtd/spi-nor/sfdp.c34
-rw-r--r--drivers/mtd/spi-nor/sfdp.h11
-rw-r--r--drivers/mtd/spi-nor/spansion.c44
-rw-r--r--drivers/mtd/spi-nor/winbond.c29
-rw-r--r--drivers/mtd/ubi/build.c5
83 files changed, 4131 insertions, 2484 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 142c0f9485fe..42001c49833b 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -420,8 +420,9 @@ read_pri_intelext(struct map_info *map, __u16 adr)
extra_size = 0;
/* Protection Register info */
- extra_size += (extp->NumProtectionFields - 1) *
- sizeof(struct cfi_intelext_otpinfo);
+ if (extp->NumProtectionFields)
+ extra_size += (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
}
if (extp->MinorVersion >= '1') {
@@ -695,14 +696,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
*/
if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
&& extp->FeatureSupport & (1 << 9)) {
+ int offs = 0;
struct cfi_private *newcfi;
struct flchip *chip;
struct flchip_shared *shared;
- int offs, numregions, numparts, partshift, numvirtchips, i, j;
+ int numregions, numparts, partshift, numvirtchips, i, j;
/* Protection Register info */
- offs = (extp->NumProtectionFields - 1) *
- sizeof(struct cfi_intelext_otpinfo);
+ if (extp->NumProtectionFields)
+ offs = (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
offs += extp->extra[offs+1]+2;
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index eb0f4600efd1..a030792115bc 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -647,7 +647,7 @@ static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc)
for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
ecc[i] = bitrev8(hwecc[i]);
- numerrs = decode_bch(docg3->cascade->bch, NULL,
+ numerrs = bch_decode(docg3->cascade->bch, NULL,
DOC_ECC_BCH_COVERED_BYTES,
NULL, ecc, NULL, errorpos);
BUG_ON(numerrs == -EINVAL);
@@ -1984,8 +1984,8 @@ static int __init docg3_probe(struct platform_device *pdev)
return ret;
cascade->base = base;
mutex_init(&cascade->lock);
- cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
- DOC_ECC_BCH_PRIMPOLY);
+ cascade->bch = bch_init(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
+ DOC_ECC_BCH_PRIMPOLY, false);
if (!cascade->bch)
return ret;
@@ -2021,7 +2021,7 @@ notfound:
ret = -ENODEV;
dev_info(dev, "No supported DiskOnChip found\n");
err_probe:
- free_bch(cascade->bch);
+ bch_free(cascade->bch);
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
if (cascade->floors[floor])
doc_release_device(cascade->floors[floor]);
@@ -2045,7 +2045,7 @@ static int docg3_release(struct platform_device *pdev)
if (cascade->floors[floor])
doc_release_device(cascade->floors[floor]);
- free_bch(docg3->cascade->bch);
+ bch_free(docg3->cascade->bch);
return 0;
}
diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c
index a289c8b5cabf..d4a46e159d38 100644
--- a/drivers/mtd/maps/physmap-gemini.c
+++ b/drivers/mtd/maps/physmap-gemini.c
@@ -46,11 +46,6 @@
#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
-static const struct of_device_id syscon_match[] = {
- { .compatible = "cortina,gemini-syscon" },
- { },
-};
-
struct gemini_flash {
struct device *dev;
struct pinctrl *p;
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 078e0f67377d..32e52d83b961 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -89,8 +89,6 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
ret = erase_write (mtd, mtdblk->cache_offset,
mtdblk->cache_size, mtdblk->cache_data);
- if (ret)
- return ret;
/*
* Here we could arguably set the cache state to STATE_CLEAN.
@@ -98,9 +96,14 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
* be notified if this content is altered on the flash by other
* means. Let's declare it empty and leave buffering tasks to
* the buffer cache instead.
+ *
+ * If this cache_offset points to a bad block, data cannot be
+ * written to the device. Clear cache_state to avoid writing to
+ * bad blocks repeatedly.
*/
- mtdblk->cache_state = STATE_EMPTY;
- return 0;
+ if (ret == 0 || ret == -EIO)
+ mtdblk->cache_state = STATE_EMPTY;
+ return ret;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index b47691e1b81c..76d832a88e0c 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -617,6 +617,19 @@ int add_mtd_device(struct mtd_info *mtd)
!(mtd->flags & MTD_NO_ERASE)))
return -EINVAL;
+ /*
+ * MTD_SLC_ON_MLC_EMULATION can only be set on partitions, when the
+ * master is an MLC NAND and has a proper pairing scheme defined.
+ * We also reject masters that implement ->_writev() for now, because
+ * NAND controller drivers don't implement this hook, and adding the
+ * SLC -> MLC address/length conversion to this path is useless if we
+ * don't have a user.
+ */
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION &&
+ (!mtd_is_partition(mtd) || master->type != MTD_MLCNANDFLASH ||
+ !master->pairing || master->_writev))
+ return -EINVAL;
+
mutex_lock(&mtd_table_mutex);
i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
@@ -632,6 +645,14 @@ int add_mtd_device(struct mtd_info *mtd)
if (mtd->bitflip_threshold == 0)
mtd->bitflip_threshold = mtd->ecc_strength;
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
+ int ngroups = mtd_pairing_groups(master);
+
+ mtd->erasesize /= ngroups;
+ mtd->size = (u64)mtd_div_by_eb(mtd->size, master) *
+ mtd->erasesize;
+ }
+
if (is_power_of_2(mtd->erasesize))
mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
else
@@ -1074,9 +1095,11 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct mtd_info *master = mtd_get_master(mtd);
u64 mst_ofs = mtd_get_master_ofs(mtd, 0);
+ struct erase_info adjinstr;
int ret;
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ adjinstr = *instr;
if (!mtd->erasesize || !master->_erase)
return -ENOTSUPP;
@@ -1091,12 +1114,27 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
ledtrig_mtd_activity();
- instr->addr += mst_ofs;
- ret = master->_erase(master, instr);
- if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
- instr->fail_addr -= mst_ofs;
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
+ adjinstr.addr = (loff_t)mtd_div_by_eb(instr->addr, mtd) *
+ master->erasesize;
+ adjinstr.len = ((u64)mtd_div_by_eb(instr->addr + instr->len, mtd) *
+ master->erasesize) -
+ adjinstr.addr;
+ }
+
+ adjinstr.addr += mst_ofs;
+
+ ret = master->_erase(master, &adjinstr);
+
+ if (adjinstr.fail_addr != MTD_FAIL_ADDR_UNKNOWN) {
+ instr->fail_addr = adjinstr.fail_addr - mst_ofs;
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
+ instr->fail_addr = mtd_div_by_eb(instr->fail_addr,
+ master);
+ instr->fail_addr *= mtd->erasesize;
+ }
+ }
- instr->addr -= mst_ofs;
return ret;
}
EXPORT_SYMBOL_GPL(mtd_erase);
@@ -1276,6 +1314,101 @@ static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
return 0;
}
+static int mtd_read_oob_std(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_info *master = mtd_get_master(mtd);
+ int ret;
+
+ from = mtd_get_master_ofs(mtd, from);
+ if (master->_read_oob)
+ ret = master->_read_oob(master, from, ops);
+ else
+ ret = master->_read(master, from, ops->len, &ops->retlen,
+ ops->datbuf);
+
+ return ret;
+}
+
+static int mtd_write_oob_std(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_info *master = mtd_get_master(mtd);
+ int ret;
+
+ to = mtd_get_master_ofs(mtd, to);
+ if (master->_write_oob)
+ ret = master->_write_oob(master, to, ops);
+ else
+ ret = master->_write(master, to, ops->len, &ops->retlen,
+ ops->datbuf);
+
+ return ret;
+}
+
+static int mtd_io_emulated_slc(struct mtd_info *mtd, loff_t start, bool read,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_info *master = mtd_get_master(mtd);
+ int ngroups = mtd_pairing_groups(master);
+ int npairs = mtd_wunit_per_eb(master) / ngroups;
+ struct mtd_oob_ops adjops = *ops;
+ unsigned int wunit, oobavail;
+ struct mtd_pairing_info info;
+ int max_bitflips = 0;
+ u32 ebofs, pageofs;
+ loff_t base, pos;
+
+ ebofs = mtd_mod_by_eb(start, mtd);
+ base = (loff_t)mtd_div_by_eb(start, mtd) * master->erasesize;
+ info.group = 0;
+ info.pair = mtd_div_by_ws(ebofs, mtd);
+ pageofs = mtd_mod_by_ws(ebofs, mtd);
+ oobavail = mtd_oobavail(mtd, ops);
+
+ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) {
+ int ret;
+
+ if (info.pair >= npairs) {
+ info.pair = 0;
+ base += master->erasesize;
+ }
+
+ wunit = mtd_pairing_info_to_wunit(master, &info);
+ pos = mtd_wunit_to_offset(mtd, base, wunit);
+
+ adjops.len = ops->len - ops->retlen;
+ if (adjops.len > mtd->writesize - pageofs)
+ adjops.len = mtd->writesize - pageofs;
+
+ adjops.ooblen = ops->ooblen - ops->oobretlen;
+ if (adjops.ooblen > oobavail - adjops.ooboffs)
+ adjops.ooblen = oobavail - adjops.ooboffs;
+
+ if (read) {
+ ret = mtd_read_oob_std(mtd, pos + pageofs, &adjops);
+ if (ret > 0)
+ max_bitflips = max(max_bitflips, ret);
+ } else {
+ ret = mtd_write_oob_std(mtd, pos + pageofs, &adjops);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ max_bitflips = max(max_bitflips, ret);
+ ops->retlen += adjops.retlen;
+ ops->oobretlen += adjops.oobretlen;
+ adjops.datbuf += adjops.retlen;
+ adjops.oobbuf += adjops.oobretlen;
+ adjops.ooboffs = 0;
+ pageofs = 0;
+ info.pair++;
+ }
+
+ return max_bitflips;
+}
+
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
struct mtd_info *master = mtd_get_master(mtd);
@@ -1294,12 +1427,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
if (!master->_read_oob && (!master->_read || ops->oobbuf))
return -EOPNOTSUPP;
- from = mtd_get_master_ofs(mtd, from);
- if (master->_read_oob)
- ret_code = master->_read_oob(master, from, ops);
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
+ ret_code = mtd_io_emulated_slc(mtd, from, true, ops);
else
- ret_code = master->_read(master, from, ops->len, &ops->retlen,
- ops->datbuf);
+ ret_code = mtd_read_oob_std(mtd, from, ops);
mtd_update_ecc_stats(mtd, master, &old_stats);
@@ -1338,13 +1469,10 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
if (!master->_write_oob && (!master->_write || ops->oobbuf))
return -EOPNOTSUPP;
- to = mtd_get_master_ofs(mtd, to);
+ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
+ return mtd_io_emulated_slc(mtd, to, false, ops);
- if (master->_write_oob)
- return master->_write_oob(master, to, ops);
- else
- return master->_write(master, to, ops->len, &ops->retlen,
- ops->datbuf);
+ return mtd_write_oob_std(mtd, to, ops);
}