All of lore.kernel.org
 help / color / mirror / Atom feed
From: Adam Ford <aford173@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v13 5/7] cmd: mtd: add 'mtd' command
Date: Wed, 3 Oct 2018 07:35:15 -0500	[thread overview]
Message-ID: <CAHCN7xKX3cVvZJAwwG+2wg6X8wGe4paU8J_ofMCikjbuJOB_oA@mail.gmail.com> (raw)
In-Reply-To: <20181001134331.9756-6-miquel.raynal@bootlin.com>

On Mon, Oct 1, 2018 at 8:48 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> There should not be a 'nand' command, a 'sf' command and certainly not
> a new 'spi-nand' command. Write a 'mtd' command instead to manage all
> MTD devices/partitions at once. This should be the preferred way to
> access any MTD device.

What is the expected behavior when I type 'mtd list' on my omap37
board, it just hangs.

I can use the nand read/write functions and mtdparts lists the
partitions, so I know nand works.  My defconfig
lists the partitions, so if we're not supposed to use mtdparts, where
I do store the partition information?

I intentionally removed it from the device tree a while ago, because
U-Boot was passing the partition info to Linux.

adam

>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> Acked-by: Jagan Teki <jagan@openedev.com>
> Reviewed-by: Stefan Roese <sr@denx.de>
> Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  cmd/Kconfig             |  10 +-
>  cmd/Makefile            |   1 +
>  cmd/mtd.c               | 473 ++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/Makefile    |   2 +-
>  drivers/mtd/mtd_uboot.c | 161 +++++++++++++-
>  include/mtd.h           |  16 ++
>  6 files changed, 659 insertions(+), 4 deletions(-)
>  create mode 100644 cmd/mtd.c
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 13d4c991bf..c9be85989c 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -864,6 +864,12 @@ config CMD_MMC_SWRITE
>           Enable support for the "mmc swrite" command to write Android sparse
>           images to eMMC.
>
> +config CMD_MTD
> +       bool "mtd"
> +       select MTD_PARTITIONS
> +       help
> +         MTD commands support.
> +
>  config CMD_NAND
>         bool "nand"
>         default y if NAND_SUNXI
> @@ -1697,14 +1703,14 @@ config CMD_MTDPARTS
>
>  config MTDIDS_DEFAULT
>         string "Default MTD IDs"
> -       depends on CMD_MTDPARTS || CMD_NAND || CMD_FLASH
> +       depends on CMD_MTD || CMD_MTDPARTS || CMD_NAND || CMD_FLASH
>         help
>           Defines a default MTD IDs list for use with MTD partitions in the
>           Linux MTD command line partitions format.
>
>  config MTDPARTS_DEFAULT
>         string "Default MTD partition scheme"
> -       depends on CMD_MTDPARTS || CMD_NAND || CMD_FLASH
> +       depends on CMD_MTD || CMD_MTDPARTS || CMD_NAND || CMD_FLASH
>         help
>           Defines a default MTD partitioning scheme in the Linux MTD command
>           line partitions format
> diff --git a/cmd/Makefile b/cmd/Makefile
> index a61fab6583..3ba65d4d93 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -92,6 +92,7 @@ obj-$(CONFIG_CMD_MISC) += misc.o
>  obj-$(CONFIG_CMD_MMC) += mmc.o
>  obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o
>  obj-$(CONFIG_MP) += mp.o
> +obj-$(CONFIG_CMD_MTD) += mtd.o
>  obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
>  obj-$(CONFIG_CMD_NAND) += nand.o
>  obj-$(CONFIG_CMD_NET) += net.o
> diff --git a/cmd/mtd.c b/cmd/mtd.c
> new file mode 100644
> index 0000000000..6142223984
> --- /dev/null
> +++ b/cmd/mtd.c
> @@ -0,0 +1,473 @@
> +// SPDX-License-Identifier:  GPL-2.0+
> +/*
> + * mtd.c
> + *
> + * Generic command to handle basic operations on any memory device.
> + *
> + * Copyright: Bootlin, 2018
> + * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
> + */
> +
> +#include <command.h>
> +#include <common.h>
> +#include <console.h>
> +#include <malloc.h>
> +#include <mapmem.h>
> +#include <mtd.h>
> +
> +static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
> +{
> +       do_div(len, mtd->writesize);
> +
> +       return len;
> +}
> +
> +static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
> +{
> +       return !do_div(size, mtd->writesize);
> +}
> +
> +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
> +{
> +       return !do_div(size, mtd->erasesize);
> +}
> +
> +static void mtd_dump_buf(const u8 *buf, uint len, uint offset)
> +{
> +       int i, j;
> +
> +       for (i = 0; i < len; ) {
> +               printf("0x%08x:\t", offset + i);
> +               for (j = 0; j < 8; j++)
> +                       printf("%02x ", buf[i + j]);
> +               printf(" ");
> +               i += 8;
> +               for (j = 0; j < 8; j++)
> +                       printf("%02x ", buf[i + j]);
> +               printf("\n");
> +               i += 8;
> +       }
> +}
> +
> +static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off,
> +                               const u8 *buf, u64 len, bool woob)
> +{
> +       bool has_pages = mtd->type == MTD_NANDFLASH ||
> +               mtd->type == MTD_MLCNANDFLASH;
> +       int npages = mtd_len_to_pages(mtd, len);
> +       uint page;
> +
> +       if (has_pages) {
> +               for (page = 0; page < npages; page++) {
> +                       u64 data_off = page * mtd->writesize;
> +
> +                       printf("\nDump %d data bytes from 0x%08llx:\n",
> +                              mtd->writesize, start_off + data_off);
> +                       mtd_dump_buf(&buf[data_off],
> +                                    mtd->writesize, start_off + data_off);
> +
> +                       if (woob) {
> +                               u64 oob_off = page * mtd->oobsize;
> +
> +                               printf("Dump %d OOB bytes from page at 0x%08llx:\n",
> +                                      mtd->oobsize, start_off + data_off);
> +                               mtd_dump_buf(&buf[len + oob_off],
> +                                            mtd->oobsize, 0);
> +                       }
> +               }
> +       } else {
> +               printf("\nDump %lld data bytes from 0x%llx:\n",
> +                      len, start_off);
> +               mtd_dump_buf(buf, len, start_off);
> +       }
> +}
> +
> +static void mtd_show_parts(struct mtd_info *mtd, int level)
> +{
> +       struct mtd_info *part;
> +       int i;
> +
> +       list_for_each_entry(part, &mtd->partitions, node) {
> +               for (i = 0; i < level; i++)
> +                       printf("\t");
> +               printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
> +                      part->offset, part->offset + part->size, part->name);
> +
> +               mtd_show_parts(part, level + 1);
> +       }
> +}
> +
> +static void mtd_show_device(struct mtd_info *mtd)
> +{
> +       /* Device */
> +       printf("* %s\n", mtd->name);
> +#if defined(CONFIG_DM)
> +       if (mtd->dev) {
> +               printf("  - device: %s\n", mtd->dev->name);
> +               printf("  - parent: %s\n", mtd->dev->parent->name);
> +               printf("  - driver: %s\n", mtd->dev->driver->name);
> +       }
> +#endif
> +
> +       /* MTD device information */
> +       printf("  - type: ");
> +       switch (mtd->type) {
> +       case MTD_RAM:
> +               printf("RAM\n");
> +               break;
> +       case MTD_ROM:
> +               printf("ROM\n");
> +               break;
> +       case MTD_NORFLASH:
> +               printf("NOR flash\n");
> +               break;
> +       case MTD_NANDFLASH:
> +               printf("NAND flash\n");
> +               break;
> +       case MTD_DATAFLASH:
> +               printf("Data flash\n");
> +               break;
> +       case MTD_UBIVOLUME:
> +               printf("UBI volume\n");
> +               break;
> +       case MTD_MLCNANDFLASH:
> +               printf("MLC NAND flash\n");
> +               break;
> +       case MTD_ABSENT:
> +       default:
> +               printf("Unknown\n");
> +               break;
> +       }
> +
> +       printf("  - block size: 0x%x bytes\n", mtd->erasesize);
> +       printf("  - min I/O: 0x%x bytes\n", mtd->writesize);
> +
> +       if (mtd->oobsize) {
> +               printf("  - OOB size: %u bytes\n", mtd->oobsize);
> +               printf("  - OOB available: %u bytes\n", mtd->oobavail);
> +       }
> +
> +       if (mtd->ecc_strength) {
> +               printf("  - ECC strength: %u bits\n", mtd->ecc_strength);
> +               printf("  - ECC step size: %u bytes\n", mtd->ecc_step_size);
> +               printf("  - bitflip threshold: %u bits\n",
> +                      mtd->bitflip_threshold);
> +       }
> +
> +       printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
> +              mtd->offset, mtd->offset + mtd->size, mtd->name);
> +
> +       /* MTD partitions, if any */
> +       mtd_show_parts(mtd, 1);
> +}
> +
> +/* Logic taken from fs/ubifs/recovery.c:is_empty() */
> +static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
> +{
> +       int i;
> +
> +       for (i = 0; i < op->len; i++)
> +               if (op->datbuf[i] != 0xff)
> +                       return false;
> +
> +       for (i = 0; i < op->ooblen; i++)
> +               if (op->oobbuf[i] != 0xff)
> +                       return false;
> +
> +       return true;
> +}
> +
> +static int do_mtd_list(void)
> +{
> +       struct mtd_info *mtd;
> +       int dev_nb = 0;
> +
> +       /* Ensure all devices (and their partitions) are probed */
> +       mtd_probe_devices();
> +
> +       printf("List of MTD devices:\n");
> +       mtd_for_each_device(mtd) {
> +               if (!mtd_is_partition(mtd))
> +                       mtd_show_device(mtd);
> +
> +               dev_nb++;
> +       }
> +
> +       if (!dev_nb) {
> +               printf("No MTD device found\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       return CMD_RET_SUCCESS;
> +}
> +
> +static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
> +                                struct mtd_oob_ops *io_op,
> +                                bool write_empty_pages, bool woob)
> +{
> +       int ret = 0;
> +
> +       /*
> +        * By default, do not write an empty page.
> +        * Skip it by simulating a successful write.
> +        */
> +       if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
> +               io_op->retlen = mtd->writesize;
> +               io_op->oobretlen = woob ? mtd->oobsize : 0;
> +       } else {
> +               ret = mtd_write_oob(mtd, off, io_op);
> +       }
> +
> +       return ret;
> +}
> +
> +static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       struct mtd_info *mtd;
> +       const char *cmd;
> +       char *mtd_name;
> +
> +       /* All MTD commands need at least two arguments */
> +       if (argc < 2)
> +               return CMD_RET_USAGE;
> +
> +       /* Parse the command name and its optional suffixes */
> +       cmd = argv[1];
> +
> +       /* List the MTD devices if that is what the user wants */
> +       if (strcmp(cmd, "list") == 0)
> +               return do_mtd_list();
> +
> +       /*
> +        * The remaining commands require also at least a device ID.
> +        * Check the selected device is valid. Ensure it is probed.
> +        */
> +       if (argc < 3)
> +               return CMD_RET_USAGE;
> +
> +       mtd_name = argv[2];
> +       mtd_probe_devices();
> +       mtd = get_mtd_device_nm(mtd_name);
> +       if (IS_ERR_OR_NULL(mtd)) {
> +               printf("MTD device %s not found, ret %ld\n",
> +                      mtd_name, PTR_ERR(mtd));
> +               return CMD_RET_FAILURE;
> +       }
> +       put_mtd_device(mtd);
> +
> +       argc -= 3;
> +       argv += 3;
> +
> +       /* Do the parsing */
> +       if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "dump", 4) ||
> +           !strncmp(cmd, "write", 5)) {
> +               bool has_pages = mtd->type == MTD_NANDFLASH ||
> +                                mtd->type == MTD_MLCNANDFLASH;
> +               bool dump, read, raw, woob, write_empty_pages;
> +               struct mtd_oob_ops io_op = {};
> +               uint user_addr = 0, npages;
> +               u64 start_off, off, len, remaining, default_len;
> +               u32 oob_len;
> +               u8 *buf;
> +               int ret;
> +
> +               dump = !strncmp(cmd, "dump", 4);
> +               read = dump || !strncmp(cmd, "read", 4);
> +               raw = strstr(cmd, ".raw");
> +               woob = strstr(cmd, ".oob");
> +               write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
> +
> +               if (!dump) {
> +                       if (!argc)
> +                               return CMD_RET_USAGE;
> +
> +                       user_addr = simple_strtoul(argv[0], NULL, 16);
> +                       argc--;
> +                       argv++;
> +               }
> +
> +               start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
> +               if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
> +                       printf("Offset not aligned with a page (0x%x)\n",
> +                              mtd->writesize);
> +                       return CMD_RET_FAILURE;
> +               }
> +
> +               default_len = dump ? mtd->writesize : mtd->size;
> +               len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) :
> +                                default_len;
> +               if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
> +                       len = round_up(len, mtd->writesize);
> +                       printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
> +                              mtd->writesize, len);
> +               }
> +
> +               remaining = len;
> +               npages = mtd_len_to_pages(mtd, len);
> +               oob_len = woob ? npages * mtd->oobsize : 0;
> +
> +               if (dump)
> +                       buf = kmalloc(len + oob_len, GFP_KERNEL);
> +               else
> +                       buf = map_sysmem(user_addr, 0);
> +
> +               if (!buf) {
> +                       printf("Could not map/allocate the user buffer\n");
> +                       return CMD_RET_FAILURE;
> +               }
> +
> +               if (has_pages)
> +                       printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
> +                              read ? "Reading" : "Writing", len, npages, start_off,
> +                              raw ? " [raw]" : "", woob ? " [oob]" : "",
> +                              !read && write_empty_pages ? " [dontskipff]" : "");
> +               else
> +                       printf("%s %lld byte(s) at offset 0x%08llx\n",
> +                              read ? "Reading" : "Writing", len, start_off);
> +
> +               io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
> +               io_op.len = has_pages ? mtd->writesize : len;
> +               io_op.ooblen = woob ? mtd->oobsize : 0;
> +               io_op.datbuf = buf;
> +               io_op.oobbuf = woob ? &buf[len] : NULL;
> +
> +               /* Search for the first good block after the given offset */
> +               off = start_off;
> +               while (mtd_block_isbad(mtd, off))
> +                       off += mtd->erasesize;
> +
> +               /* Loop over the pages to do the actual read/write */
> +               while (remaining) {
> +                       /* Skip the block if it is bad */
> +                       if (mtd_is_aligned_with_block_size(mtd, off) &&
> +                           mtd_block_isbad(mtd, off)) {
> +                               off += mtd->erasesize;
> +                               continue;
> +                       }
> +
> +                       if (read)
> +                               ret = mtd_read_oob(mtd, off, &io_op);
> +                       else
> +                               ret = mtd_special_write_oob(mtd, off, &io_op,
> +                                                           write_empty_pages,
> +                                                           woob);
> +
> +                       if (ret) {
> +                               printf("Failure while %s at offset 0x%llx\n",
> +                                      read ? "reading" : "writing", off);
> +                               return CMD_RET_FAILURE;
> +                       }
> +
> +                       off += io_op.retlen;
> +                       remaining -= io_op.retlen;
> +                       io_op.datbuf += io_op.retlen;
> +                       io_op.oobbuf += io_op.oobretlen;
> +               }
> +
> +               if (!ret && dump)
> +                       mtd_dump_device_buf(mtd, start_off, buf, len, woob);
> +
> +               if (dump)
> +                       kfree(buf);
> +               else
> +                       unmap_sysmem(buf);
> +
> +               if (ret) {
> +                       printf("%s on %s failed with error %d\n",
> +                              read ? "Read" : "Write", mtd->name, ret);
> +                       return CMD_RET_FAILURE;
> +               }
> +
> +       } else if (!strcmp(cmd, "erase")) {
> +               bool scrub = strstr(cmd, ".dontskipbad");
> +               struct erase_info erase_op = {};
> +               u64 off, len;
> +               int ret;
> +
> +               off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
> +               len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
> +
> +               if (!mtd_is_aligned_with_block_size(mtd, off)) {
> +                       printf("Offset not aligned with a block (0x%x)\n",
> +                              mtd->erasesize);
> +                       return CMD_RET_FAILURE;
> +               }
> +
> +               if (!mtd_is_aligned_with_block_size(mtd, len)) {
> +                       printf("Size not a multiple of a block (0x%x)\n",
> +                              mtd->erasesize);
> +                       return CMD_RET_FAILURE;
> +               }
> +
> +               printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
> +                      off, off + len - 1, mtd_div_by_eb(len, mtd));
> +
> +               erase_op.mtd = mtd;
> +               erase_op.addr = off;
> +               erase_op.len = len;
> +               erase_op.scrub = scrub;
> +
> +               while (erase_op.len) {
> +                       ret = mtd_erase(mtd, &erase_op);
> +
> +                       /* Abort if its not a bad block error */
> +                       if (ret != -EIO)
> +                               break;
> +
> +                       printf("Skipping bad block at 0x%08llx\n",
> +                              erase_op.fail_addr);
> +
> +                       /* Skip bad block and continue behind it */
> +                       erase_op.len -= erase_op.fail_addr - erase_op.addr;
> +                       erase_op.len -= mtd->erasesize;
> +                       erase_op.addr = erase_op.fail_addr + mtd->erasesize;
> +               }
> +
> +               if (ret && ret != -EIO)
> +                       return CMD_RET_FAILURE;
> +       } else if (!strcmp(cmd, "bad")) {
> +               loff_t off;
> +
> +               if (!mtd_can_have_bb(mtd)) {
> +                       printf("Only NAND-based devices can have bad blocks\n");
> +                       return CMD_RET_SUCCESS;
> +               }
> +
> +               printf("MTD device %s bad blocks list:\n", mtd->name);
> +               for (off = 0; off < mtd->size; off += mtd->erasesize)
> +                       if (mtd_block_isbad(mtd, off))
> +                               printf("\t0x%08llx\n", off);
> +       } else {
> +               return CMD_RET_USAGE;
> +       }
> +
> +       return CMD_RET_SUCCESS;
> +}
> +
> +static char mtd_help_text[] =
> +#ifdef CONFIG_SYS_LONGHELP
> +       "- generic operations on memory technology devices\n\n"
> +       "mtd list\n"
> +       "mtd read[.raw][.oob]                  <name> <addr> [<off> [<size>]]\n"
> +       "mtd dump[.raw][.oob]                  <name>        [<off> [<size>]]\n"
> +       "mtd write[.raw][.oob][.dontskipff]    <name> <addr> [<off> [<size>]]\n"
> +       "mtd erase[.dontskipbad]               <name>        [<off> [<size>]]\n"
> +       "\n"
> +       "Specific functions:\n"
> +       "mtd bad                               <name>\n"
> +       "\n"
> +       "With:\n"
> +       "\t<name>: NAND partition/chip name\n"
> +       "\t<addr>: user address from/to which data will be retrieved/stored\n"
> +       "\t<off>: offset in <name> in bytes (default: start of the part)\n"
> +       "\t\t* must be block-aligned for erase\n"
> +       "\t\t* must be page-aligned otherwise\n"
> +       "\t<size>: length of the operation in bytes (default: the entire device)\n"
> +       "\t\t* must be a multiple of a block for erase\n"
> +       "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
> +       "\n"
> +       "The .dontskipff option forces writing empty pages, don't use it if unsure.\n"
> +#endif
> +       "";
> +
> +U_BOOT_CMD(mtd, 10, 1, do_mtd, "MTD utils", mtd_help_text);
> diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
> index cdf515256a..22ceda93c0 100644
> --- a/drivers/mtd/Makefile
> +++ b/drivers/mtd/Makefile
> @@ -3,7 +3,7 @@
>  # (C) Copyright 2000-2007
>  # Wolfgang Denk, DENX Software Engineering, wd at denx.de.
>
> -ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
> +ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)$(CONFIG_CMD_MTD)))
>  obj-y += mtdcore.o mtd_uboot.o
>  endif
>  obj-$(CONFIG_MTD) += mtd-uclass.o
> diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c
> index 8d7e7890b7..6a211d52ff 100644
> --- a/drivers/mtd/mtd_uboot.c
> +++ b/drivers/mtd/mtd_uboot.c
> @@ -4,8 +4,15 @@
>   * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>   */
>  #include <common.h>
> +#include <dm/device.h>
> +#include <dm/uclass-internal.h>
> +#include <jffs2/jffs2.h> /* LEGACY */
>  #include <linux/mtd/mtd.h>
> -#include <jffs2/jffs2.h> /* Legacy */
> +#include <linux/mtd/partitions.h>
> +#include <mtd.h>
> +
> +#define MTD_NAME_MAX_LEN 20
> +
>
>  /**
>   * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
> @@ -68,6 +75,158 @@ int mtd_search_alternate_name(const char *mtdname, char *altname,
>         return -EINVAL;
>  }
>
> +#if IS_ENABLED(CONFIG_MTD)
> +static void mtd_probe_uclass_mtd_devs(void)
> +{
> +       struct udevice *dev;
> +       int idx = 0;
> +
> +       /* Probe devices with DM compliant drivers */
> +       while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) {
> +               mtd_probe(dev);
> +               idx++;
> +       }
> +}
> +#else
> +static void mtd_probe_uclass_mtd_devs(void) { }
> +#endif
> +
> +#if defined(CONFIG_MTD_PARTITIONS)
> +int mtd_probe_devices(void)
> +{
> +       static char *old_mtdparts;
> +       static char *old_mtdids;
> +       const char *mtdparts = env_get("mtdparts");
> +       const char *mtdids = env_get("mtdids");
> +       bool remaining_partitions = true;
> +       struct mtd_info *mtd;
> +
> +       mtd_probe_uclass_mtd_devs();
> +
> +       /* Check if mtdparts/mtdids changed since last call, otherwise: exit */
> +       if (!strcmp(mtdparts, old_mtdparts) && !strcmp(mtdids, old_mtdids))
> +               return 0;
> +
> +       /* Update the local copy of mtdparts */
> +       free(old_mtdparts);
> +       free(old_mtdids);
> +       old_mtdparts = strdup(mtdparts);
> +       old_mtdids = strdup(mtdids);
> +
> +       /* If at least one partition is still in use, do not delete anything */
> +       mtd_for_each_device(mtd) {
> +               if (mtd->usecount) {
> +                       printf("Partition \"%s\" already in use, aborting\n",
> +                              mtd->name);
> +                       return -EACCES;
> +               }
> +       }
> +
> +       /*
> +        * Everything looks clear, remove all partitions. It is not safe to
> +        * remove entries from the mtd_for_each_device loop as it uses idr
> +        * indexes and the partitions removal is done in bulk (all partitions of
> +        * one device at the same time), so break and iterate from start each
> +        * time a new partition is found and deleted.
> +        */
> +       while (remaining_partitions) {
> +               remaining_partitions = false;
> +               mtd_for_each_device(mtd) {
> +                       if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) {
> +                               del_mtd_partitions(mtd);
> +                               remaining_partitions = true;
> +                               break;
> +                       }
> +               }
> +       }
> +
> +       /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
> +       if (strstr(mtdparts, "mtdparts="))
> +               mtdparts += 9;
> +
> +       /* For each MTD device in mtdparts */
> +       while (mtdparts[0] != '\0') {
> +               char mtd_name[MTD_NAME_MAX_LEN], *colon;
> +               struct mtd_partition *parts;
> +               int mtd_name_len, nparts;
> +               int ret;
> +
> +               colon = strchr(mtdparts, ':');
> +               if (!colon) {
> +                       printf("Wrong mtdparts: %s\n", mtdparts);
> +                       return -EINVAL;
> +               }
> +
> +               mtd_name_len = colon - mtdparts;
> +               strncpy(mtd_name, mtdparts, mtd_name_len);
> +               mtd_name[mtd_name_len] = '\0';
> +               /* Move the pointer forward (including the ':') */
> +               mtdparts += mtd_name_len + 1;
> +               mtd = get_mtd_device_nm(mtd_name);
> +               if (IS_ERR_OR_NULL(mtd)) {
> +                       char linux_name[MTD_NAME_MAX_LEN];
> +
> +                       /*
> +                        * The MTD device named "mtd_name" does not exist. Try
> +                        * to find a correspondance with an MTD device having
> +                        * the same type and number as defined in the mtdids.
> +                        */
> +                       debug("No device named %s\n", mtd_name);
> +                       ret = mtd_search_alternate_name(mtd_name, linux_name,
> +                                                       MTD_NAME_MAX_LEN);
> +                       if (!ret)
> +                               mtd = get_mtd_device_nm(linux_name);
> +
> +                       /*
> +                        * If no device could be found, move the mtdparts
> +                        * pointer forward until the next set of partitions.
> +                        */
> +                       if (ret || IS_ERR_OR_NULL(mtd)) {
> +                               printf("Could not find a valid device for %s\n",
> +                                      mtd_name);
> +                               mtdparts = strchr(mtdparts, ';');
> +                               if (mtdparts)
> +                                       mtdparts++;
> +
> +                               continue;
> +                       }
> +               }
> +
> +               /*
> +                * Parse the MTD device partitions. It will update the mtdparts
> +                * pointer, create an array of parts (that must be freed), and
> +                * return the number of partition structures in the array.
> +                */
> +               ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts);
> +               if (ret) {
> +                       printf("Could not parse device %s\n", mtd->name);
> +                       put_mtd_device(mtd);
> +                       return -EINVAL;
> +               }
> +
> +               if (!nparts)
> +                       continue;
> +
> +               /* Create the new MTD partitions */
> +               add_mtd_partitions(mtd, parts, nparts);
> +
> +               /* Free the structures allocated during the parsing */
> +               mtd_free_parsed_partitions(parts, nparts);
> +
> +               put_mtd_device(mtd);
> +       }
> +
> +       return 0;
> +}
> +#else
> +int mtd_probe_devices(void)
> +{
> +       mtd_probe_uclass_mtd_devs();
> +
> +       return 0;
> +}
> +#endif /* defined(CONFIG_MTD_PARTITIONS) */
> +
>  /* Legacy */
>
>  static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
> diff --git a/include/mtd.h b/include/mtd.h
> index 6e6da3002f..011f26b3e1 100644
> --- a/include/mtd.h
> +++ b/include/mtd.h
> @@ -8,6 +8,9 @@
>
>  #include <linux/mtd/mtd.h>
>
> +struct udevice;
> +
> +#if defined(CONFIG_DM)
>  /*
>   * Get mtd_info structure of the dev, which is stored as uclass private.
>   *
> @@ -20,5 +23,18 @@ static inline struct mtd_info *mtd_get_info(struct udevice *dev)
>  }
>
>  int mtd_probe(struct udevice *dev);
> +#else
> +static inline struct mtd_info *mtd_get_info(struct udevice *dev)
> +{
> +       return NULL;
> +}
> +
> +static inline int mtd_probe(struct udevice *dev)
> +{
> +       return 0;
> +}
> +#endif
> +
> +int mtd_probe_devices(void);
>
>  #endif /* _MTD_H_ */
> --
> 2.17.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

  parent reply	other threads:[~2018-10-03 12:35 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-01 13:43 [U-Boot] [PATCH v13 0/7] SPI-NAND support (third batch) Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 1/7] mtd: uclass: add probe function Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 2/7] mtd: mtdpart: add a generic mtdparts-like parser Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 3/7] mtd: uboot: search for an equivalent MTD name with the mtdids Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 4/7] mtd: mtdpart: implement proper partition handling Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 5/7] cmd: mtd: add 'mtd' command Miquel Raynal
2018-10-01 16:19   ` Jagan Teki
2018-10-01 20:39     ` Miquel Raynal
2018-10-03 12:35   ` Adam Ford [this message]
2018-10-03 12:42     ` Miquel Raynal
2018-10-03 12:47       ` Adam Ford
2018-10-03 12:57         ` Miquel Raynal
2018-10-03 13:35           ` Miquel Raynal
2018-10-03 13:41             ` Adam Ford
2018-10-08 16:13               ` Adam Ford
2018-10-08 16:28                 ` Boris Brezillon
2018-10-08 16:52                   ` Adam Ford
2018-10-08 16:58                     ` Adam Ford
2018-10-08 17:27                       ` Boris Brezillon
2018-10-08 17:46   ` Boris Brezillon
2018-10-08 18:26     ` Adam Ford
2018-10-08 19:07     ` Thomas Petazzoni
2018-10-08 19:14       ` Adam Ford
2018-10-01 13:43 ` [U-Boot] [PATCH v13 6/7] cmd: ubi: clean the partition handling Miquel Raynal
2018-10-01 13:43 ` [U-Boot] [PATCH v13 7/7] cmd: mtdparts: describe as legacy Miquel Raynal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAHCN7xKX3cVvZJAwwG+2wg6X8wGe4paU8J_ofMCikjbuJOB_oA@mail.gmail.com \
    --to=aford173@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.