diff options
author | Matt Weber <matthew.weber@rockwellcollins.com> | 2020-06-02 16:34:03 +0200 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2020-09-02 09:12:52 +0200 |
commit | 3fbe507ebd828bc8ce747181a204ddafbe5cce2f (patch) | |
tree | 11e52c665aad82ed5e1808f6c9997b582e051726 /drivers/mtd/mtdconcat.c | |
parent | mtd: lpddr: fix excessive stack usage with clang (diff) | |
download | linux-3fbe507ebd828bc8ce747181a204ddafbe5cce2f.tar.xz linux-3fbe507ebd828bc8ce747181a204ddafbe5cce2f.zip |
mtd: mtdconcat: map through panic write handler
Allows a mtdconcat's subdevice->_panic_write to be used for
capturing a mtdoops dump.
Note: The ->_panic_write is mapped through from the first chip
that is part of the concat virtual device.
Signed-off-by: Matthew Weber <matthew.weber@rockwellcollins.com>
[miquel.raynal@bootlin.com: return err, not void]
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200602143403.13465-1-matthew.weber@rockwellcollins.com
Diffstat (limited to 'drivers/mtd/mtdconcat.c')
-rw-r--r-- | drivers/mtd/mtdconcat.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 1d6c9e7e7b7d..242c3a660002 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -103,6 +103,48 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, } static int +concat_panic_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) { + size = 0; + to -= subdev->size; + continue; + } + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + err = mtd_panic_write(subdev, to, size, &retsize, buf); + if (err == -EOPNOTSUPP) { + printk(KERN_ERR "mtdconcat: Cannot write from panic without panic_write\n"); + return err; + } + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + return err; +} + + +static int concat_write(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { @@ -648,6 +690,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd._block_isbad = concat_block_isbad; if (subdev[0]->_block_markbad) concat->mtd._block_markbad = concat_block_markbad; + if (subdev[0]->_panic_write) + concat->mtd._panic_write = concat_panic_write; concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; |