diff options
15 files changed, 908 insertions, 17 deletions
diff --git a/target/linux/generic/backport-5.15/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch b/target/linux/generic/backport-5.15/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch new file mode 100644 index 0000000000..10e61602c8 --- /dev/null +++ b/target/linux/generic/backport-5.15/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch @@ -0,0 +1,73 @@ +From e237285113963bd1dd2e925770aa8b3aa8a1894c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <kernel@kempniu.pl> +Date: Wed, 29 Jun 2022 14:57:34 +0200 +Subject: [PATCH 1/4] mtd: track maximum number of bitflips for each read + request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mtd_read_oob() callers are currently oblivious to the details of ECC +errors detected during the read operation - they only learn (through the +return value) whether any corrected bitflips or uncorrectable errors +occurred. More detailed ECC information can be useful to user-space +applications for making better-informed choices about moving data +around. + +Extend struct mtd_oob_ops with a pointer to a newly-introduced struct +mtd_req_stats and set its 'max_bitflips' field to the maximum number of +bitflips found in a single ECC step during the read operation performed +by mtd_read_oob(). This is a prerequisite for ultimately passing that +value back to user space. + +Suggested-by: Boris Brezillon <boris.brezillon@collabora.com> +Signed-off-by: Michał Kępień <kernel@kempniu.pl> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-2-kernel@kempniu.pl +--- + drivers/mtd/mtdcore.c | 5 +++++ + include/linux/mtd/mtd.h | 5 +++++ + 2 files changed, 10 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -1669,6 +1669,9 @@ int mtd_read_oob(struct mtd_info *mtd, l + if (!master->_read_oob && (!master->_read || ops->oobbuf)) + return -EOPNOTSUPP; + ++ if (ops->stats) ++ memset(ops->stats, 0, sizeof(*ops->stats)); ++ + if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) + ret_code = mtd_io_emulated_slc(mtd, from, true, ops); + else +@@ -1686,6 +1689,8 @@ int mtd_read_oob(struct mtd_info *mtd, l + return ret_code; + if (mtd->ecc_strength == 0) + return 0; /* device lacks ecc */ ++ if (ops->stats) ++ ops->stats->max_bitflips = ret_code; + return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; + } + EXPORT_SYMBOL_GPL(mtd_read_oob); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -40,6 +40,10 @@ struct mtd_erase_region_info { + unsigned long *lockmap; /* If keeping bitmap of locks */ + }; + ++struct mtd_req_stats { ++ unsigned int max_bitflips; ++}; ++ + /** + * struct mtd_oob_ops - oob operation operands + * @mode: operation mode +@@ -70,6 +74,7 @@ struct mtd_oob_ops { + uint32_t ooboffs; + uint8_t *datbuf; + uint8_t *oobbuf; ++ struct mtd_req_stats *stats; + }; + + #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 diff --git a/target/linux/generic/backport-5.15/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch b/target/linux/generic/backport-5.15/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch new file mode 100644 index 0000000000..1484624e4e --- /dev/null +++ b/target/linux/generic/backport-5.15/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch @@ -0,0 +1,325 @@ +From e97709c9d18903f5acd5fbe2985dd054da0432b1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <kernel@kempniu.pl> +Date: Wed, 29 Jun 2022 14:57:35 +0200 +Subject: [PATCH 2/4] mtd: always initialize 'stats' in struct mtd_oob_ops +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As the 'stats' field in struct mtd_oob_ops is used in conditional +expressions, ensure it is always zero-initialized in all such structures +to prevent random stack garbage from being interpreted as a pointer. + +Strictly speaking, this problem currently only needs to be fixed for +struct mtd_oob_ops structures subsequently passed to mtd_read_oob(). +However, this commit goes a step further and makes all instances of +struct mtd_oob_ops in the tree zero-initialized, in hope of preventing +future problems, e.g. if struct mtd_req_stats gets extended with write +statistics at some point. + +Signed-off-by: Michał Kępień <kernel@kempniu.pl> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-3-kernel@kempniu.pl +--- + drivers/mtd/inftlcore.c | 6 +++--- + drivers/mtd/mtdswap.c | 6 +++--- + drivers/mtd/nand/onenand/onenand_base.c | 4 ++-- + drivers/mtd/nand/onenand/onenand_bbt.c | 2 +- + drivers/mtd/nand/raw/nand_bbt.c | 8 ++++---- + drivers/mtd/nand/raw/sm_common.c | 2 +- + drivers/mtd/nftlcore.c | 6 +++--- + drivers/mtd/sm_ftl.c | 4 ++-- + drivers/mtd/ssfdc.c | 2 +- + drivers/mtd/tests/nandbiterrs.c | 2 +- + drivers/mtd/tests/oobtest.c | 8 ++++---- + drivers/mtd/tests/readtest.c | 2 +- + fs/jffs2/wbuf.c | 6 +++--- + 13 files changed, 29 insertions(+), 29 deletions(-) + +--- a/drivers/mtd/inftlcore.c ++++ b/drivers/mtd/inftlcore.c +@@ -136,7 +136,7 @@ static void inftl_remove_dev(struct mtd_ + int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -156,7 +156,7 @@ int inftl_read_oob(struct mtd_info *mtd, + int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -176,7 +176,7 @@ int inftl_write_oob(struct mtd_info *mtd + static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf, uint8_t *oob) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +--- a/drivers/mtd/mtdswap.c ++++ b/drivers/mtd/mtdswap.c +@@ -323,7 +323,7 @@ static int mtdswap_read_markers(struct m + struct mtdswap_oobdata *data, *data2; + int ret; + loff_t offset; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + offset = mtdswap_eb_offset(d, eb); + +@@ -370,7 +370,7 @@ static int mtdswap_write_marker(struct m + struct mtdswap_oobdata n; + int ret; + loff_t offset; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.ooboffs = 0; + ops.oobbuf = (uint8_t *)&n; +@@ -879,7 +879,7 @@ static unsigned int mtdswap_eblk_passes( + loff_t base, pos; + unsigned int *p1 = (unsigned int *)d->page_buf; + unsigned char *p2 = (unsigned char *)d->oob_buf; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + ops.mode = MTD_OPS_AUTO_OOB; +--- a/drivers/mtd/nand/onenand/onenand_base.c ++++ b/drivers/mtd/nand/onenand/onenand_base.c +@@ -2935,7 +2935,7 @@ static int do_otp_write(struct mtd_info + struct onenand_chip *this = mtd->priv; + unsigned char *pbuf = buf; + int ret; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + /* Force buffer page aligned */ + if (len < mtd->writesize) { +@@ -2977,7 +2977,7 @@ static int do_otp_lock(struct mtd_info * + size_t *retlen, u_char *buf) + { + struct onenand_chip *this = mtd->priv; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + if (FLEXONENAND(this)) { +--- a/drivers/mtd/nand/onenand/onenand_bbt.c ++++ b/drivers/mtd/nand/onenand/onenand_bbt.c +@@ -61,7 +61,7 @@ static int create_bbt(struct mtd_info *m + int startblock; + loff_t from; + size_t readlen, ooblen; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int rgn; + + printk(KERN_INFO "Scanning device for bad blocks\n"); +--- a/drivers/mtd/nand/raw/nand_bbt.c ++++ b/drivers/mtd/nand/raw/nand_bbt.c +@@ -313,7 +313,7 @@ static int scan_read_oob(struct nand_chi + size_t len) + { + struct mtd_info *mtd = nand_to_mtd(this); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res, ret = 0; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -354,7 +354,7 @@ static int scan_write_bbt(struct nand_ch + uint8_t *buf, uint8_t *oob) + { + struct mtd_info *mtd = nand_to_mtd(this); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.ooboffs = 0; +@@ -416,7 +416,7 @@ static int scan_block_fast(struct nand_c + { + struct mtd_info *mtd = nand_to_mtd(this); + +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret, page_offset; + + ops.ooblen = mtd->oobsize; +@@ -756,7 +756,7 @@ static int write_bbt(struct nand_chip *t + uint8_t rcode = td->reserved_block_code; + size_t retlen, len = 0; + loff_t to; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; +--- a/drivers/mtd/nand/raw/sm_common.c ++++ b/drivers/mtd/nand/raw/sm_common.c +@@ -99,7 +99,7 @@ static const struct mtd_ooblayout_ops oo + static int sm_block_markbad(struct nand_chip *chip, loff_t ofs) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct sm_oob oob; + int ret; + +--- a/drivers/mtd/nftlcore.c ++++ b/drivers/mtd/nftlcore.c +@@ -124,7 +124,7 @@ int nftl_read_oob(struct mtd_info *mtd, + size_t *retlen, uint8_t *buf) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -145,7 +145,7 @@ int nftl_write_oob(struct mtd_info *mtd, + size_t *retlen, uint8_t *buf) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -168,7 +168,7 @@ static int nftl_write(struct mtd_info *m + size_t *retlen, uint8_t *buf, uint8_t *oob) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +--- a/drivers/mtd/sm_ftl.c ++++ b/drivers/mtd/sm_ftl.c +@@ -239,7 +239,7 @@ static int sm_read_sector(struct sm_ftl + uint8_t *buffer, struct sm_oob *oob) + { + struct mtd_info *mtd = ftl->trans->mtd; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct sm_oob tmp_oob; + int ret = -EIO; + int try = 0; +@@ -323,7 +323,7 @@ static int sm_write_sector(struct sm_ftl + int zone, int block, int boffset, + uint8_t *buffer, struct sm_oob *oob) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct mtd_info *mtd = ftl->trans->mtd; + int ret; + +--- a/drivers/mtd/ssfdc.c ++++ b/drivers/mtd/ssfdc.c +@@ -163,7 +163,7 @@ static int read_physical_sector(struct m + /* Read redundancy area (wrapper to MTD_READ_OOB */ + static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + ops.mode = MTD_OPS_RAW; +--- a/drivers/mtd/tests/nandbiterrs.c ++++ b/drivers/mtd/tests/nandbiterrs.c +@@ -99,7 +99,7 @@ static int write_page(int log) + static int rewrite_page(int log) + { + int err = 0; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + if (log) + pr_info("rewrite page\n"); +--- a/drivers/mtd/tests/oobtest.c ++++ b/drivers/mtd/tests/oobtest.c +@@ -56,7 +56,7 @@ static void do_vary_offset(void) + static int write_eraseblock(int ebnum) + { + int i; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + +@@ -165,7 +165,7 @@ static size_t memffshow(loff_t addr, lof + static int verify_eraseblock(int ebnum) + { + int i; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + size_t bitflips; +@@ -260,7 +260,7 @@ static int verify_eraseblock(int ebnum) + + static int verify_eraseblock_in_one_go(int ebnum) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + size_t len = mtd->oobavail * pgcnt; +@@ -338,7 +338,7 @@ static int __init mtd_oobtest_init(void) + int err = 0; + unsigned int i; + uint64_t tmp; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + loff_t addr = 0, addr0; + + printk(KERN_INFO "\n"); +--- a/drivers/mtd/tests/readtest.c ++++ b/drivers/mtd/tests/readtest.c +@@ -47,7 +47,7 @@ static int read_eraseblock_by_page(int e + err = ret; + } + if (mtd->oobsize) { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.len = 0; +--- a/fs/jffs2/wbuf.c ++++ b/fs/jffs2/wbuf.c +@@ -1035,7 +1035,7 @@ int jffs2_check_oob_empty(struct jffs2_s + { + int i, ret; + int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_AUTO_OOB; + ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; +@@ -1076,7 +1076,7 @@ int jffs2_check_oob_empty(struct jffs2_s + int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); + + ops.mode = MTD_OPS_AUTO_OOB; +@@ -1101,7 +1101,7 @@ int jffs2_write_nand_cleanmarker(struct + struct jffs2_eraseblock *jeb) + { + int ret; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); + + ops.mode = MTD_OPS_AUTO_OOB; diff --git a/target/linux/generic/backport-5.15/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch b/target/linux/generic/backport-5.15/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch new file mode 100644 index 0000000000..f2f45eb7bc --- /dev/null +++ b/target/linux/generic/backport-5.15/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch @@ -0,0 +1,172 @@ +From 2ed18d818d1f7492172f8dd5904344c7d367e8ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <kernel@kempniu.pl> +Date: Wed, 29 Jun 2022 14:57:36 +0200 +Subject: [PATCH 3/4] mtd: add ECC error accounting for each read request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend struct mtd_req_stats with two new fields holding the number of +corrected bitflips and uncorrectable errors detected during a read +operation. This is a prerequisite for ultimately passing those counters +to user space, where they can be useful to applications for making +better-informed choices about moving data around. + +Unlike 'max_bitflips' (which is set - in a common code path - to the +return value of a function called while the MTD device's mutex is held), +these counters have to be maintained in each MTD driver which defines +the '_read_oob' callback because the statistics need to be calculated +while the MTD device's mutex is held. + +Suggested-by: Boris Brezillon <boris.brezillon@collabora.com> +Signed-off-by: Michał Kępień <kernel@kempniu.pl> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-4-kernel@kempniu.pl +--- + drivers/mtd/devices/docg3.c | 8 ++++++++ + drivers/mtd/nand/onenand/onenand_base.c | 12 ++++++++++++ + drivers/mtd/nand/raw/nand_base.c | 10 ++++++++++ + drivers/mtd/nand/spi/core.c | 10 ++++++++++ + include/linux/mtd/mtd.h | 2 ++ + 5 files changed, 42 insertions(+) + +--- a/drivers/mtd/devices/docg3.c ++++ b/drivers/mtd/devices/docg3.c +@@ -871,6 +871,7 @@ static int doc_read_oob(struct mtd_info + u8 *buf = ops->datbuf; + size_t len, ooblen, nbdata, nboob; + u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; ++ struct mtd_ecc_stats old_stats; + int max_bitflips = 0; + + if (buf) +@@ -895,6 +896,7 @@ static int doc_read_oob(struct mtd_info + ret = 0; + skip = from % DOC_LAYOUT_PAGE_SIZE; + mutex_lock(&docg3->cascade->lock); ++ old_stats = mtd->ecc_stats; + while (ret >= 0 && (len > 0 || ooblen > 0)) { + calc_block_sector(from - skip, &block0, &block1, &page, &ofs, + docg3->reliable); +@@ -966,6 +968,12 @@ static int doc_read_oob(struct mtd_info + } + + out: ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } + mutex_unlock(&docg3->cascade->lock); + return ret; + err_in_read: +--- a/drivers/mtd/nand/onenand/onenand_base.c ++++ b/drivers/mtd/nand/onenand/onenand_base.c +@@ -1440,6 +1440,7 @@ static int onenand_read_oob(struct mtd_i + struct mtd_oob_ops *ops) + { + struct onenand_chip *this = mtd->priv; ++ struct mtd_ecc_stats old_stats; + int ret; + + switch (ops->mode) { +@@ -1453,12 +1454,23 @@ static int onenand_read_oob(struct mtd_i + } + + onenand_get_device(mtd, FL_READING); ++ ++ old_stats = mtd->ecc_stats; ++ + if (ops->datbuf) + ret = ONENAND_IS_4KB_PAGE(this) ? + onenand_mlc_read_ops_nolock(mtd, from, ops) : + onenand_read_ops_nolock(mtd, from, ops); + else + ret = onenand_read_oob_nolock(mtd, from, ops); ++ ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + onenand_release_device(mtd); + + return ret; +--- a/drivers/mtd/nand/raw/nand_base.c ++++ b/drivers/mtd/nand/raw/nand_base.c +@@ -3815,6 +3815,7 @@ static int nand_read_oob(struct mtd_info + struct mtd_oob_ops *ops) + { + struct nand_chip *chip = mtd_to_nand(mtd); ++ struct mtd_ecc_stats old_stats; + int ret; + + ops->retlen = 0; +@@ -3826,11 +3827,20 @@ static int nand_read_oob(struct mtd_info + + nand_get_device(chip); + ++ old_stats = mtd->ecc_stats; ++ + if (!ops->datbuf) + ret = nand_do_read_oob(chip, from, ops); + else + ret = nand_do_read_ops(chip, from, ops); + ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + nand_release_device(chip); + return ret; + } +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -629,6 +629,7 @@ static int spinand_mtd_read(struct mtd_i + { + struct spinand_device *spinand = mtd_to_spinand(mtd); + struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct mtd_ecc_stats old_stats; + unsigned int max_bitflips = 0; + struct nand_io_iter iter; + bool disable_ecc = false; +@@ -640,6 +641,8 @@ static int spinand_mtd_read(struct mtd_i + + mutex_lock(&spinand->lock); + ++ old_stats = mtd->ecc_stats; ++ + nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) { + if (disable_ecc) + iter.req.mode = MTD_OPS_RAW; +@@ -662,6 +665,13 @@ static int spinand_mtd_read(struct mtd_i + ops->oobretlen += iter.req.ooblen; + } + ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + mutex_unlock(&spinand->lock); + + if (ecc_failed && !ret) +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -41,6 +41,8 @@ struct mtd_erase_region_info { + }; + + struct mtd_req_stats { ++ unsigned int uncorrectable_errors; ++ unsigned int corrected_bitflips; + unsigned int max_bitflips; + }; + diff --git a/target/linux/generic/backport-5.15/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch b/target/linux/generic/backport-5.15/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch new file mode 100644 index 0000000000..182e4f6ab5 --- /dev/null +++ b/target/linux/generic/backport-5.15/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch @@ -0,0 +1,321 @@ +From 2c9745d36e04ac27161acd78514f647b9b587ad4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <kernel@kempniu.pl> +Date: Wed, 29 Jun 2022 14:57:37 +0200 +Subject: [PATCH 4/4] mtdchar: add MEMREAD ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +User-space applications making use of MTD devices via /dev/mtd* +character devices currently have limited capabilities for reading data: + + - only deprecated methods of accessing OOB layout information exist, + + - there is no way to explicitly specify MTD operation mode to use; it + is auto-selected based on the MTD file mode (MTD_FILE_MODE_*) set + for the character device; in particular, this prevents using + MTD_OPS_AUTO_OOB for reads, + + - all existing user-space interfaces which cause mtd_read() or + mtd_read_oob() to be called (via mtdchar_read() and + mtdchar_read_oob(), respectively) return success even when those + functions return -EUCLEAN or -EBADMSG; this renders user-space + applications using these interfaces unaware of any corrected + bitflips or uncorrectable ECC errors detected during reads. + +Note that the existing MEMWRITE ioctl allows the MTD operation mode to +be explicitly set, allowing user-space applications to write page data +and OOB data without requiring them to know anything about the OOB +layout of the MTD device they are writing to (MTD_OPS_AUTO_OOB). Also, +the MEMWRITE ioctl does not mangle the return value of mtd_write_oob(). + +Add a new ioctl, MEMREAD, which addresses the above issues. It is +intended to be a read-side counterpart of the existing MEMWRITE ioctl. +Similarly to the latter, the read operation is performed in a loop which +processes at most mtd->erasesize bytes in each iteration. This is done +to prevent unbounded memory allocations caused by calling kmalloc() with +the 'size' argument taken directly from the struct mtd_read_req provided +by user space. However, the new ioctl is implemented so that the values +it returns match those that would have been returned if just a single +mtd_read_oob() call was issued to handle the entire read operation in +one go. + +Note that while just returning -EUCLEAN or -EBADMSG to user space would +already be a valid and useful indication of the ECC algorithm detecting +errors during a read operation, that signal would not be granular enough +to cover all use cases. For example, knowing the maximum number of +bitflips detected in a single ECC step during a read operation performed +on a given page may be useful when dealing with an MTD partition whose +ECC layout varies across pages (e.g. a partition consisting of a +bootloader area using a "custom" ECC layout followed by data pages using +a "standard" ECC layout). To address that, include ECC statistics in +the structure returned to user space by the new MEMREAD ioctl. + +Link: https://www.infradead.org/pipermail/linux-mtd/2016-April/067085.html + +Suggested-by: Boris Brezillon <boris.brezillon@collabora.com> +Signed-off-by: Michał Kępień <kernel@kempniu.pl> +Acked-by: Richard Weinberger <richard@nod.at> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-5-kernel@kempniu.pl +--- + drivers/mtd/mtdchar.c | 139 +++++++++++++++++++++++++++++++++++++ + include/uapi/mtd/mtd-abi.h | 64 +++++++++++++++-- + 2 files changed, 198 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -621,6 +621,137 @@ static int mtdchar_write_ioctl(struct mt + return ret; + } + ++static int mtdchar_read_ioctl(struct mtd_info *mtd, ++ struct mtd_read_req __user *argp) ++{ ++ struct mtd_info *master = mtd_get_master(mtd); ++ struct mtd_read_req req; ++ void __user *usr_data, *usr_oob; ++ uint8_t *datbuf = NULL, *oobbuf = NULL; ++ size_t datbuf_len, oobbuf_len; ++ size_t orig_len, orig_ooblen; ++ int ret = 0; ++ ++ if (copy_from_user(&req, argp, sizeof(req))) ++ return -EFAULT; ++ ++ orig_len = req.len; ++ orig_ooblen = req.ooblen; ++ ++ usr_data = (void __user *)(uintptr_t)req.usr_data; ++ usr_oob = (void __user *)(uintptr_t)req.usr_oob; ++ ++ if (!master->_read_oob) ++ return -EOPNOTSUPP; ++ ++ if (!usr_data) ++ req.len = 0; ++ ++ if (!usr_oob) ++ req.ooblen = 0; ++ ++ req.ecc_stats.uncorrectable_errors = 0; ++ req.ecc_stats.corrected_bitflips = 0; ++ req.ecc_stats.max_bitflips = 0; ++ ++ req.len &= 0xffffffff; ++ req.ooblen &= 0xffffffff; ++ ++ if (req.start + req.len > mtd->size) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ datbuf_len = min_t(size_t, req.len, mtd->erasesize); ++ if (datbuf_len > 0) { ++ datbuf = kvmalloc(datbuf_len, GFP_KERNEL); ++ if (!datbuf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ oobbuf_len = min_t(size_t, req.ooblen, mtd->erasesize); ++ if (oobbuf_len > 0) { ++ oobbuf = kvmalloc(oobbuf_len, GFP_KERNEL); ++ if (!oobbuf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ while (req.len > 0 || (!usr_data && req.ooblen > 0)) { ++ struct mtd_req_stats stats; ++ struct mtd_oob_ops ops = { ++ .mode = req.mode, ++ .len = min_t(size_t, req.len, datbuf_len), ++ .ooblen = min_t(size_t, req.ooblen, oobbuf_len), ++ .datbuf = datbuf, ++ .oobbuf = oobbuf, ++ .stats = &stats, ++ }; ++ ++ /* ++ * Shorten non-page-aligned, eraseblock-sized reads so that the ++ * read ends on an eraseblock boundary. This is necessary in ++ * order to prevent OOB data for some pages from being ++ * duplicated in the output of non-page-aligned reads requiring ++ * multiple mtd_read_oob() calls to be completed. ++ */ ++ if (ops.len == mtd->erasesize) ++ ops.len -= mtd_mod_by_ws(req.start + ops.len, mtd); ++ ++ ret = mtd_read_oob(mtd, (loff_t)req.start, &ops); ++ ++ req.ecc_stats.uncorrectable_errors += ++ stats.uncorrectable_errors; ++ req.ecc_stats.corrected_bitflips += stats.corrected_bitflips; ++ req.ecc_stats.max_bitflips = ++ max(req.ecc_stats.max_bitflips, stats.max_bitflips); ++ ++ if (ret && !mtd_is_bitflip_or_eccerr(ret)) ++ break; ++ ++ if (copy_to_user(usr_data, ops.datbuf, ops.retlen) || ++ copy_to_user(usr_oob, ops.oobbuf, ops.oobretlen)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ req.start += ops.retlen; ++ req.len -= ops.retlen; ++ usr_data += ops.retlen; ++ ++ req.ooblen -= ops.oobretlen; ++ usr_oob += ops.oobretlen; ++ } ++ ++ /* ++ * As multiple iterations of the above loop (and therefore multiple ++ * mtd_read_oob() calls) may be necessary to complete the read request, ++ * adjust the final return code to ensure it accounts for all detected ++ * ECC errors. ++ */ ++ if (!ret || mtd_is_bitflip(ret)) { ++ if (req.ecc_stats.uncorrectable_errors > 0) ++ ret = -EBADMSG; ++ else if (req.ecc_stats.corrected_bitflips > 0) ++ ret = -EUCLEAN; ++ } ++ ++out: ++ req.len = orig_len - req.len; ++ req.ooblen = orig_ooblen - req.ooblen; ++ ++ if (copy_to_user(argp, &req, sizeof(req))) ++ ret = -EFAULT; ++ ++ kvfree(datbuf); ++ kvfree(oobbuf); ++ ++ return ret; ++} ++ + static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) + { + struct mtd_file_info *mfi = file->private_data; +@@ -643,6 +774,7 @@ static int mtdchar_ioctl(struct file *fi + case MEMGETINFO: + case MEMREADOOB: + case MEMREADOOB64: ++ case MEMREAD: + case MEMISLOCKED: + case MEMGETOOBSEL: + case MEMGETBADBLOCK: +@@ -817,6 +949,13 @@ static int mtdchar_ioctl(struct file *fi + break; + } + ++ case MEMREAD: ++ { ++ ret = mtdchar_read_ioctl(mtd, ++ (struct mtd_read_req __user *)arg); ++ break; ++ } ++ + case MEMLOCK: + { + struct erase_info_user einfo; +--- a/include/uapi/mtd/mtd-abi.h ++++ b/include/uapi/mtd/mtd-abi.h +@@ -55,9 +55,9 @@ struct mtd_oob_buf64 { + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * +- * These modes can be passed to ioctl(MEMWRITE) and are also used internally. +- * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. +- * %MTD_FILE_MODE_RAW. ++ * These modes can be passed to ioctl(MEMWRITE) and ioctl(MEMREAD); they are ++ * also used internally. See notes on "MTD file modes" for discussion on ++ * %MTD_OPS_RAW vs. %MTD_FILE_MODE_RAW. + */ + enum { + MTD_OPS_PLACE_OOB = 0, +@@ -91,6 +91,53 @@ struct mtd_write_req { + __u8 padding[7]; + }; + ++/** ++ * struct mtd_read_req_ecc_stats - ECC statistics for a read operation ++ * ++ * @uncorrectable_errors: the number of uncorrectable errors that happened ++ * during the read operation ++ * @corrected_bitflips: the number of bitflips corrected during the read ++ * operation ++ * @max_bitflips: the maximum number of bitflips detected in any single ECC ++ * step for the data read during the operation; this information ++ * can be used to decide whether the data stored in a specific ++ * region of the MTD device should be moved somewhere else to ++ * avoid data loss. ++ */ ++struct mtd_read_req_ecc_stats { ++ __u32 uncorrectable_errors; ++ __u32 corrected_bitflips; ++ __u32 max_bitflips; ++}; ++ ++/** ++ * struct mtd_read_req - data structure for requesting a read operation ++ * ++ * @start: start address ++ * @len: length of data buffer (only lower 32 bits are used) ++ * @ooblen: length of OOB buffer (only lower 32 bits are used) ++ * @usr_data: user-provided data buffer ++ * @usr_oob: user-provided OOB buffer ++ * @mode: MTD mode (see "MTD operation modes") ++ * @padding: reserved, must be set to 0 ++ * @ecc_stats: ECC statistics for the read operation ++ * ++ * This structure supports ioctl(MEMREAD) operations, allowing data and/or OOB ++ * reads in various modes. To read from OOB-only, set @usr_data == NULL, and to ++ * read data-only, set @usr_oob == NULL. However, setting both @usr_data and ++ * @usr_oob to NULL is not allowed. ++ */ ++struct mtd_read_req { ++ __u64 start; ++ __u64 len; ++ __u64 ooblen; ++ __u64 usr_data; ++ __u64 usr_oob; ++ __u8 mode; ++ __u8 padding[7]; ++ struct mtd_read_req_ecc_stats ecc_stats; ++}; ++ + #define MTD_ABSENT 0 + #define MTD_RAM 1 + #define MTD_ROM 2 +@@ -207,6 +254,12 @@ struct otp_info { + #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) + /* Erase a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ + #define OTPERASE _IOW('M', 25, struct otp_info) ++/* ++ * Most generic read interface; can read in-band and/or out-of-band in various ++ * modes (see "struct mtd_read_req"). This ioctl is not supported for flashes ++ * without OOB, e.g., NOR flash. ++ */ ++#define MEMREAD _IOWR('M', 26, struct mtd_read_req) + + /* + * Obsolete legacy interface. Keep it in order not to break userspace +@@ -270,8 +323,9 @@ struct mtd_ecc_stats { + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode +- * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is +- * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). ++ * (e.g., when using ioctl(MEMWRITE) or ioctl(MEMREAD)), but in some cases, the ++ * MTD_FILE_MODE is used out of necessity (e.g., `write()', ++ * ioctl(MEMWRITEOOB64)). + */ + enum mtd_file_modes { + MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, diff --git a/target/linux/generic/pending-5.15/400-mtd-mtdsplit-support.patch b/target/linux/generic/pending-5.15/400-mtd-mtdsplit-support.patch index bf82bb3950..46ef15d127 100644 --- a/target/linux/generic/pending-5.15/400-mtd-mtdsplit-support.patch +++ b/target/linux/generic/pending-5.15/400-mtd-mtdsplit-support.patch @@ -264,7 +264,7 @@ Subject: [PATCH] mtd: mtdsplit support * one chunk. Do that by default. --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h -@@ -613,6 +613,24 @@ static inline void mtd_align_erase_req(s +@@ -620,6 +620,24 @@ static inline void mtd_align_erase_req(s req->len += mtd->erasesize - mod; } @@ -289,7 +289,7 @@ Subject: [PATCH] mtd: mtdsplit support static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) { if (mtd->writesize_shift) -@@ -686,6 +704,13 @@ extern struct mtd_info *of_get_mtd_devic +@@ -693,6 +711,13 @@ extern struct mtd_info *of_get_mtd_devic extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); diff --git a/target/linux/generic/pending-5.15/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch b/target/linux/generic/pending-5.15/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch index de76d6918b..d12bc9c3d5 100644 --- a/target/linux/generic/pending-5.15/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch +++ b/target/linux/generic/pending-5.15/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch @@ -234,7 +234,7 @@ Reported-by: Dan Carpenter <dan.carpenter@oracle.com> --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h -@@ -243,6 +243,8 @@ struct mtd_info { +@@ -250,6 +250,8 @@ struct mtd_info { * information below if they desire */ uint32_t erasesize; diff --git a/target/linux/generic/pending-5.15/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch b/target/linux/generic/pending-5.15/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch index c170fedc67..d117cfe0a3 100644 --- a/target/linux/generic/pending-5.15/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch +++ b/target/linux/generic/pending-5.15/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch @@ -31,7 +31,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -896,6 +896,7 @@ static const struct nand_ops spinand_ops +@@ -906,6 +906,7 @@ static const struct nand_ops spinand_ops }; static const struct spinand_manufacturer *spinand_manufacturers[] = { diff --git a/target/linux/generic/pending-5.15/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/generic/pending-5.15/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch index 2f604cfa98..7e20e14bb6 100644 --- a/target/linux/generic/pending-5.15/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch +++ b/target/linux/generic/pending-5.15/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch @@ -47,7 +47,7 @@ Submitted-by: Daniel Danzberger <daniel@dd-wrt.com> obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -898,6 +898,7 @@ static const struct nand_ops spinand_ops +@@ -908,6 +908,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { &esmt_c8_spinand_manufacturer, &gigadevice_spinand_manufacturer, diff --git a/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch b/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch index 0f69b30e94..87c7b7cd29 100644 --- a/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch +++ b/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch @@ -18,7 +18,7 @@ Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-8-miquel.raynal@b --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1211,14 +1211,6 @@ static int spinand_init(struct spinand_d +@@ -1221,14 +1221,6 @@ static int spinand_init(struct spinand_d if (ret) goto err_free_bufs; @@ -33,7 +33,7 @@ Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-8-miquel.raynal@b ret = nanddev_init(nand, &spinand_ops, THIS_MODULE); if (ret) goto err_manuf_cleanup; -@@ -1253,6 +1245,14 @@ static int spinand_init(struct spinand_d +@@ -1263,6 +1255,14 @@ static int spinand_init(struct spinand_d mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength; mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size; diff --git a/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch b/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch index 1188872bd7..35912cd2cd 100644 --- a/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch +++ b/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch @@ -53,7 +53,7 @@ Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-9-miquel.raynal@b while (nbytes) { ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf); -@@ -865,6 +871,31 @@ static int spinand_create_dirmap(struct +@@ -875,6 +881,31 @@ static int spinand_create_dirmap(struct spinand->dirmaps[plane].rdesc = desc; diff --git a/target/linux/mediatek/patches-5.15/121-hack-spi-nand-1b-bbm.patch b/target/linux/mediatek/patches-5.15/121-hack-spi-nand-1b-bbm.patch index 770a7ff9bd..ff5521c44e 100644 --- a/target/linux/mediatek/patches-5.15/121-hack-spi-nand-1b-bbm.patch +++ b/target/linux/mediatek/patches-5.15/121-hack-spi-nand-1b-bbm.patch @@ -1,6 +1,6 @@ --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -714,7 +714,7 @@ static int spinand_mtd_write(struct mtd_ +@@ -724,7 +724,7 @@ static int spinand_mtd_write(struct mtd_ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) { struct spinand_device *spinand = nand_to_spinand(nand); @@ -9,7 +9,7 @@ struct nand_page_io_req req = { .pos = *pos, .ooblen = sizeof(marker), -@@ -725,7 +725,7 @@ static bool spinand_isbad(struct nand_de +@@ -735,7 +735,7 @@ static bool spinand_isbad(struct nand_de spinand_select_target(spinand, pos->target); spinand_read_page(spinand, &req); diff --git a/target/linux/mediatek/patches-5.15/330-snand-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.15/330-snand-mtk-bmt-support.patch index cd1745dd7a..6814e5f5e9 100644 --- a/target/linux/mediatek/patches-5.15/330-snand-mtk-bmt-support.patch +++ b/target/linux/mediatek/patches-5.15/330-snand-mtk-bmt-support.patch @@ -8,7 +8,7 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { -@@ -1333,6 +1334,7 @@ static int spinand_probe(struct spi_mem +@@ -1343,6 +1344,7 @@ static int spinand_probe(struct spi_mem if (ret) return ret; @@ -16,7 +16,7 @@ ret = mtd_device_register(mtd, NULL, 0); if (ret) goto err_spinand_cleanup; -@@ -1340,6 +1342,7 @@ static int spinand_probe(struct spi_mem +@@ -1350,6 +1352,7 @@ static int spinand_probe(struct spi_mem return 0; err_spinand_cleanup: @@ -24,7 +24,7 @@ spinand_cleanup(spinand); return ret; -@@ -1358,6 +1361,7 @@ static int spinand_remove(struct spi_mem +@@ -1368,6 +1371,7 @@ static int spinand_remove(struct spi_mem if (ret) return ret; diff --git a/target/linux/mediatek/patches-5.15/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch b/target/linux/mediatek/patches-5.15/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch index 823630b3c4..6baa32879b 100644 --- a/target/linux/mediatek/patches-5.15/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch +++ b/target/linux/mediatek/patches-5.15/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch @@ -23,7 +23,7 @@ Signed-off-by: Davide Fioravanti <pantanastyle@gmail.com> obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -929,6 +929,7 @@ static const struct nand_ops spinand_ops +@@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { &esmt_c8_spinand_manufacturer, diff --git a/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch b/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch index f71a1d2d58..e2684eebb7 100644 --- a/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch +++ b/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch @@ -11,7 +11,7 @@ Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com> --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -967,6 +967,56 @@ static int spinand_manufacturer_match(st +@@ -977,6 +977,56 @@ static int spinand_manufacturer_match(st return -ENOTSUPP; } @@ -68,7 +68,7 @@ Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com> static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; -@@ -1217,6 +1267,10 @@ static int spinand_init(struct spinand_d +@@ -1227,6 +1277,10 @@ static int spinand_init(struct spinand_d if (!spinand->scratchbuf) return -ENOMEM; diff --git a/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch b/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch index a08b19870c..25a7cd3861 100644 --- a/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch +++ b/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch @@ -12,7 +12,7 @@ Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com> --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1008,7 +1008,10 @@ int spinand_cal_read(void *priv, u32 *ad +@@ -1018,7 +1018,10 @@ int spinand_cal_read(void *priv, u32 *ad if (ret) return ret; |