From 778cb8e39f6ec252be50fc3850d66f3dcbd5dd5a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 10 Jun 2021 16:39:45 +0200 Subject: dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation "PAGESIZE / 512" is the number of ECC chunks. "ECC_BYTES" is the number of bytes needed to store a single ECC code. "2" is the space reserved by the bad block marker. "2 + (PAGESIZE / 512) * ECC_BYTES" should of course be lower or equal than the total number of OOB bytes, otherwise it won't fit. Fix the equation by substituting s/>=/<=/. Suggested-by: Ryan J. Barnett Signed-off-by: Miquel Raynal Acked-by: Rob Herring Link: https://lore.kernel.org/linux-mtd/20210610143945.3504781-1-miquel.raynal@bootlin.com --- Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt index 44919d48d241..c459f169a904 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt @@ -122,7 +122,7 @@ on various other factors also like; so the device should have enough free bytes available its OOB/Spare area to accommodate ECC for entire page. In general following expression helps in determining if given device can accommodate ECC syndrome: - "2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE" + "2 + (PAGESIZE / 512) * ECC_BYTES" <= OOBSIZE" where OOBSIZE number of bytes in OOB/spare area PAGESIZE number of bytes in main-area of device page -- cgit v1.2.3 From 1a57b13e6017d2af575f4f42e848aa0b64d4bcf1 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Fri, 25 Jun 2021 14:38:21 +0200 Subject: mtd: rawnand: nand_bbt: Skip bad blocks when searching for the BBT in NAND The blocks containing the bad block table can become bad as well. So make sure to skip any blocks that are marked bad when searching for the bad block table. Otherwise in very rare cases where two BBT blocks wear out it might happen that an obsolete BBT is used instead of a newer available version. This only applies to drivers which make use of a bad block marker in flash. Other drivers won't be able to identify bad BBT blocks and thus can't skip these. Signed-off-by: Stefan Riedmueller Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210625123821.207458-1-s.riedmueller@phytec.de --- drivers/mtd/nand/raw/nand_bbt.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index dced32a126d9..b7ad030225f8 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, return 0; } +/* Check if a potential BBT block is marked as bad */ +static int bbt_block_checkbad(struct nand_chip *this, struct nand_bbt_descr *td, + loff_t offs, uint8_t *buf) +{ + struct nand_bbt_descr *bd = this->badblock_pattern; + + /* + * No need to check for a bad BBT block if the BBM area overlaps with + * the bad block table marker area in OOB since writing a BBM here + * invalidates the bad block table marker anyway. + */ + if (!(td->options & NAND_BBT_NO_OOB) && + td->offs >= bd->offs && td->offs < bd->offs + bd->len) + return 0; + + /* + * There is no point in checking for a bad block marker if writing + * such marker is not supported + */ + if (this->bbt_options & NAND_BBT_NO_OOB_BBM || + this->options & NAND_NO_BBM_QUIRK) + return 0; + + if (scan_block_fast(this, bd, offs, buf) > 0) + return 1; + + return 0; +} + /** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @this: NAND chip object @@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, int actblock = startblock + dir * block; loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + /* Check if block is marked bad */ + if (bbt_block_checkbad(this, td, offs, buf)) + continue; + /* Read first page */ scan_read(this, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { -- cgit v1.2.3 From 8363dfc845d74b980e109111b82f0a72aa92e47a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 29 Jun 2021 21:51:57 +0200 Subject: mtd: spinand: Fix comment This is a copy paste error, checking the ECC status finishes a page read here, not a page write. Fixes: 945845b54c9c ("mtd: spinand: Instantiate a SPI-NAND on-die ECC engine") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210629195157.567828-1-miquel.raynal@bootlin.com --- drivers/mtd/nand/spi/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 446ba8d43fbc..4af32cfcbd96 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -307,7 +307,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, if (req->type == NAND_PAGE_WRITE) return 0; - /* Finish a page write: check the status, report errors/bitflips */ + /* Finish a page read: check the status, report errors/bitflips */ ret = spinand_check_ecc_status(spinand, engine_conf->status); if (ret == -EBADMSG) mtd->ecc_stats.failed++; -- cgit v1.2.3 From c5b9ee9c361f52cd319135b9ec7fe684d5e2e026 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 4 Jul 2021 10:47:05 +0100 Subject: mtd: rawnand: Fix a couple of spelling mistakes in Kconfig There are two spelling mistakes in the Kconfig text. Fix them. Signed-off-by: Colin Ian King Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210704094705.37175-1-colin.king@canonical.com --- drivers/mtd/nand/raw/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 630728de4b7c..67b7cb67c030 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -480,9 +480,9 @@ config MTD_NAND_RICOH select MTD_SM_COMMON help Enable support for Ricoh R5C852 xD card reader - You also need to enable ether + You also need to enable either NAND SSFDC (SmartMedia) read only translation layer' or new - expermental, readwrite + experimental, readwrite 'SmartMedia/xD new translation layer' config MTD_NAND_DISKONCHIP -- cgit v1.2.3 From 5c2f387b48f063dd8a0c119d3659df8f3e2d88bb Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 26 Jul 2021 16:49:49 +0200 Subject: MAINTAINERS: repair Miquel Raynal's email address Commit d70c6b026069 ("MAINTAINERS: Add PL353 NAND controller entry") and commit 813d52799ad2 ("MAINTAINERS: Add PL353 SMC entry") adds Miquel Raynal as maintainer with an obvious invalid email address, which can be easily fixed. Repair this copy-and-paste error in Miquel Raynal's email address. Signed-off-by: Lukas Bulwahn Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210726144949.10439-1-lukas.bulwahn@gmail.com --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a61f4f3b78a9..10d3fafe056c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1475,7 +1475,7 @@ F: drivers/amba/ F: include/linux/amba/bus.h ARM PRIMECELL PL35X NAND CONTROLLER DRIVER -M: Miquel Raynal +M: Miquel Raynal M: Naga Sureshkumar Relli L: linux-mtd@lists.infradead.org S: Maintained @@ -1483,7 +1483,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml F: drivers/mtd/nand/raw/pl35x-nand-controller.c ARM PRIMECELL PL35X SMC DRIVER -M: Miquel Raynal +M: Miquel Raynal M: Naga Sureshkumar Relli L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -- cgit v1.2.3 From df12a75a2be915e7c419707bc71fba0fa7548d81 Mon Sep 17 00:00:00 2001 From: Daniel Palmer Date: Thu, 17 Jun 2021 20:08:42 +0900 Subject: mtd: spinand: core: Properly fill the OOB area. The comment in spinand_write_to_cache_op() says that spinand_ondie_ecc_prepare_io_req() should 0xff fill the OOB area but it doesn't. This causes the OOB area to get filled with zeros and anytime the first page in a block the bad block marker is cleared and it becomes a bad block on the next boot. This was observed on Longsys FORSEE branded parts and might be specific to these parts. Signed-off-by: Daniel Palmer Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210617110842.2358461-1-daniel@0x0f.com --- drivers/mtd/nand/spi/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4af32cfcbd96..2c8685f1f2fa 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, struct spinand_device *spinand = nand_to_spinand(nand); bool enable = (req->mode != MTD_OPS_RAW); + memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand)); + /* Only enable or disable the engine */ return spinand_ecc_enable(spinand, enable); } -- cgit v1.2.3 From 014665ffd7e84bb2f18912f7285190090e218e4c Mon Sep 17 00:00:00 2001 From: Vladimir Molokov Date: Sun, 1 Aug 2021 22:59:09 +0200 Subject: mtd: rawnand: omap: Fix kernel doc warning on 'calcuate' typo Fix a trivial typo which is reported after enabling W=1 level of warnings: drivers/mtd/nand/raw/omap2.c:927: warning: expecting prototype for omap_calcuate_ecc(). Prototype was for omap_calculate_ecc() instead Signed-off-by: Vladimir Molokov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210801205909.7102-1-vladimir@molokov.se --- drivers/mtd/nand/raw/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index b1839eef5b65..b26d4947af02 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -911,7 +911,7 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat, } /** - * omap_calcuate_ecc - Generate non-inverted ECC bytes. + * omap_calculate_ecc - Generate non-inverted ECC bytes. * @chip: NAND chip object * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer -- cgit v1.2.3 From 74a021a632b07dd990e85e815b8757921b23db4b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 3 Aug 2021 19:33:00 +0800 Subject: mtd: rawnand: remove never changed ret variable The ret variable used for returning value in the function `meson_nfc_rw_cmd_prepare_and_execute` is never change after initialising. Therefore, we can remove it safely and return 0 at the end of the function. Signed-off-by: Jason Wang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210803113300.24230-1-wangborong@cdjrlc.com --- drivers/mtd/nand/raw/meson_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 817bddccb775..ac3be92872d0 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, u32 *addrs = nfc->cmdfifo.rw.addrs; u32 cs = nfc->param.chip_select; u32 cmd0, cmd_num, row_start; - int ret = 0, i; + int i; cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int); @@ -620,7 +620,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, meson_nfc_cmd_idle(nfc, nfc->timing.tadl); } - return ret; + return 0; } static int meson_nfc_write_page_sub(struct nand_chip *nand, -- cgit v1.2.3 From 6f802696c2faf0119781fc3b7977a4eedf9ab239 Mon Sep 17 00:00:00 2001 From: Jaime Liao Date: Mon, 9 Aug 2021 09:27:52 +0800 Subject: mtd: spinand: macronix: Add Quad support for serial NAND flash Adding FLAG "SPINAND_HAS_QE_BIT" for Quad mode support on Macronix Serial Flash. Validated via normal(default) and QUAD mode by read, erase, read back, on Xilinx Zynq PicoZed FPGA board which included Macronix SPI Host(drivers/spi/spi-mxic.c). Signed-off-by: Jaime Liao Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1628472472-32008-1-git-send-email-jaimeliao@mxic.com.tw --- drivers/mtd/nand/spi/macronix.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index a9890350db02..3f31f1381a62 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF4GE4AD", @@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF1G24AD", @@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF2G24AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), - NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF4G24AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), @@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX31LF1GE4BC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), @@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0 /*SPINAND_HAS_QE_BIT*/, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX31UF1GE4BC", @@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0 /*SPINAND_HAS_QE_BIT*/, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), -- cgit v1.2.3 From 0792ec82175ec45a0f45af6e0f2d3cb49c527cd4 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 17 Aug 2021 12:29:30 +0300 Subject: mtd: rawnand: intel: Fix error handling in probe ebu_nand_probe() did not invoke ebu_dma_cleanup() and clk_disable_unprepare() on some error handling paths. The patch fixes that. Found by Linux Driver Verification project (linuxtesting.org). Fixes: 0b1039f016e8 ("mtd: rawnand: Add NAND controller support on Intel LGM SoC") Signed-off-by: Evgeny Novikov Co-developed-by: Kirill Shilimanov Signed-off-by: Kirill Shilimanov Co-developed-by: Anton Vasilyev Signed-off-by: Anton Vasilyev Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210817092930.23040-1-novikov@ispras.ru --- drivers/mtd/nand/raw/intel-nand-controller.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index 8b49fd56cf96..29e8a546dcd6 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -631,19 +631,26 @@ static int ebu_nand_probe(struct platform_device *pdev) ebu_host->clk_rate = clk_get_rate(ebu_host->clk); ebu_host->dma_tx = dma_request_chan(dev, "tx"); - if (IS_ERR(ebu_host->dma_tx)) - return dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), - "failed to request DMA tx chan!.\n"); + if (IS_ERR(ebu_host->dma_tx)) { + ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), + "failed to request DMA tx chan!.\n"); + goto err_disable_unprepare_clk; + } ebu_host->dma_rx = dma_request_chan(dev, "rx"); - if (IS_ERR(ebu_host->dma_rx)) - return dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), - "failed to request DMA rx chan!.\n"); + if (IS_ERR(ebu_host->dma_rx)) { + ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), + "failed to request DMA rx chan!.\n"); + ebu_host->dma_rx = NULL; + goto err_cleanup_dma; + } resname = devm_kasprintf(dev, GFP_KERNEL, "addr_sel%d", cs); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname); - if (!res) - return -EINVAL; + if (!res) { + ret = -EINVAL; + goto err_cleanup_dma; + } ebu_host->cs[cs].addr_sel = res->start; writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN, ebu_host->ebu + EBU_ADDR_SEL(cs)); @@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev) mtd = nand_to_mtd(&ebu_host->chip); if (!mtd->name) { dev_err(ebu_host->dev, "NAND label property is mandatory\n"); - return -EINVAL; + ret = -EINVAL; + goto err_cleanup_dma; } mtd->dev.parent = dev; @@ -681,6 +689,7 @@ err_clean_nand: nand_cleanup(&ebu_host->chip); err_cleanup_dma: ebu_dma_cleanup(ebu_host); +err_disable_unprepare_clk: clk_disable_unprepare(ebu_host->clk); return ret; -- cgit v1.2.3 From 6b430c7595e4eb95fae8fb54adc3c3ce002e75ae Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 21 Aug 2021 09:58:45 +0200 Subject: mtd: rawnand: cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A successful 'init_rs_non_canonical()' call should be balanced by a corresponding 'free_rs()' call in the error handling path of the probe, as already done in the remove function. Update the error handling path accordingly. Fixes: 8c61b7a7f4d4 ("[MTD] [NAND] Use rslib for CAFÉ ECC") Signed-off-by: Christophe JAILLET Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/fd313d3fb787458bcc73189e349f481133a2cdc9.1629532640.git.christophe.jaillet@wanadoo.fr --- drivers/mtd/nand/raw/cafe_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index d0e8ffd55c22..9dbf031716a6 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, "CAFE NAND", mtd); if (err) { dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); - goto out_ior; + goto out_free_rs; } /* Disable master reset, enable NAND clock */ @@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, /* Disable NAND IRQ in global IRQ mask register */ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); + out_free_rs: + free_rs(cafe->rs); out_ior: pci_iounmap(pdev, cafe->mmio); out_free_mtd: -- cgit v1.2.3