Merge branch '2022-04-23-binman-updates'
authorTom Rini <trini@konsulko.com>
Mon, 25 Apr 2022 20:02:03 +0000 (16:02 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 25 Apr 2022 20:02:03 +0000 (16:02 -0400)
- Assorted binman updates, and add Alper as a maintainer, after talking
  with Simon.

27 files changed:
cmd/Kconfig
cmd/bootefi.c
cmd/bootmenu.c
common/board_r.c
common/main.c
configs/cortina_presidio-asic-emmc_defconfig
disk/Kconfig
disk/Makefile
disk/disk-uclass.c [new file with mode: 0644]
doc/board/apple/m1.rst
doc/develop/driver-model/design.rst
doc/kwboot.1
doc/usage/cmd/bootefi.rst
drivers/block/blk-uclass.c
drivers/core/tag.c
include/dm/uclass-id.h
include/efi_loader.h
include/part.h
include/sandboxblockdev.h
lib/efi_driver/efi_block_device.c
lib/efi_loader/Kconfig
lib/efi_loader/Makefile
lib/efi_loader/efi_device_path.c
lib/efi_loader/efi_disk.c
lib/efi_loader/efi_setup.c
test/dm/Makefile
test/dm/tag.c [new file with mode: 0644]

index f580797..65517cb 100644 (file)
@@ -1246,6 +1246,7 @@ config CMD_OSD
 
 config CMD_PART
        bool "part"
+       depends on PARTITIONS
        select HAVE_BLOCK_DEVICE
        select PARTITION_UUIDS
        help
index 53d9f0e..d80353f 100644 (file)
@@ -422,10 +422,11 @@ static int do_efibootmgr(void)
  * Set up memory image for the binary to be loaded, prepare device path, and
  * then call do_bootefi_exec() to execute it.
  *
- * @image_opt: string of image start address
+ * @image_opt: string with image start address
+ * @size_opt:  string with image size or NULL
  * Return:     status code
  */
-static int do_bootefi_image(const char *image_opt)
+static int do_bootefi_image(const char *image_opt, const char *size_opt)
 {
        void *image_buf;
        unsigned long addr, size;
@@ -443,14 +444,21 @@ static int do_bootefi_image(const char *image_opt)
                /* Check that a numeric value was passed */
                if (!addr)
                        return CMD_RET_USAGE;
-
                image_buf = map_sysmem(addr, 0);
 
-               if (image_buf != image_addr) {
-                       log_err("No UEFI binary known at %s\n", image_opt);
-                       return CMD_RET_FAILURE;
+               if (size_opt) {
+                       size = strtoul(size_opt, NULL, 16);
+                       if (!size)
+                               return CMD_RET_USAGE;
+                       efi_clear_bootdev();
+               } else {
+                       if (image_buf != image_addr) {
+                               log_err("No UEFI binary known at %s\n",
+                                       image_opt);
+                               return CMD_RET_FAILURE;
+                       }
+                       size = image_size;
                }
-               size = image_size;
        }
        ret = efi_run_image(image_buf, size);
 
@@ -654,7 +662,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
                return CMD_RET_FAILURE;
        }
 
-       if (argc > 2) {
+       if (argc > 2 && strcmp(argv[2], "-")) {
                uintptr_t fdt_addr;
 
                fdt_addr = hextoul(argv[2], NULL);
@@ -677,15 +685,15 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
                return do_efi_selftest();
 #endif
 
-       return do_bootefi_image(argv[1]);
+       return do_bootefi_image(argv[1], argc > 3 ? argv[3] : NULL);
 }
 
 #ifdef CONFIG_SYS_LONGHELP
 static char bootefi_help_text[] =
-       "<image address> [fdt address]\n"
-       "  - boot EFI payload stored at address <image address>.\n"
-       "    If specified, the device tree located at <fdt address> gets\n"
-       "    exposed as EFI configuration table.\n"
+       "<image address> [fdt address [image size]]\n"
+       "  - boot EFI payload stored at <image address>\n"
+       "    fdt address, address of device-tree or '-'\n"
+       "    image size, required if image not preloaded\n"
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
        "bootefi hello\n"
        "  - boot a sample Hello World application stored within U-Boot\n"
@@ -707,7 +715,7 @@ static char bootefi_help_text[] =
 #endif
 
 U_BOOT_CMD(
-       bootefi, 3, 0, do_bootefi,
+       bootefi, 4, 0, do_bootefi,
        "Boots an EFI payload from memory",
        bootefi_help_text
 );
index 409ef9a..d573487 100644 (file)
@@ -463,7 +463,7 @@ static void bootmenu_show(int delay)
        }
 
        for (iter = bootmenu->first; iter; iter = iter->next) {
-               if (!menu_item_add(menu, iter->key, iter))
+               if (menu_item_add(menu, iter->key, iter) != 1)
                        goto cleanup;
        }
 
@@ -476,7 +476,7 @@ static void bootmenu_show(int delay)
 
        init = 1;
 
-       if (menu_get_choice(menu, &choice)) {
+       if (menu_get_choice(menu, &choice) == 1) {
                iter = choice;
                title = strdup(iter->title);
                command = strdup(iter->command);
index 8dc87ed..7d0281f 100644 (file)
@@ -795,7 +795,7 @@ static init_fnc_t init_sequence_r[] = {
        initr_mem,
 #endif
 #ifdef CONFIG_EFI_SETUP_EARLY
-       (init_fnc_t)efi_init_obj_list,
+       efi_init_early,
 #endif
        run_main_loop,
 };
index 3f5214f..682f335 100644 (file)
@@ -54,8 +54,11 @@ void main_loop(void)
        if (IS_ENABLED(CONFIG_UPDATE_TFTP))
                update_tftp(0UL, NULL, NULL);
 
-       if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
-               efi_launch_capsules();
+       if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) {
+               /* efi_init_early() already called */
+               if (efi_init_obj_list() == EFI_SUCCESS)
+                       efi_launch_capsules();
+       }
 
        s = bootdelay_process();
        if (cli_process_fdt(&s))
index b0bd54f..b8a1c96 100644 (file)
@@ -20,7 +20,6 @@ CONFIG_LAST_STAGE_INIT=y
 CONFIG_SYS_PROMPT="G3#"
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_PART=y
 CONFIG_CMD_WDT=y
 CONFIG_BOOTP_BOOTFILESIZE=y
 CONFIG_CMD_CACHE=y
index 1370032..359af3b 100644 (file)
@@ -2,8 +2,7 @@
 menu "Partition Types"
 
 config PARTITIONS
-       bool "Enable Partition Labels (disklabels) support"
-       default y
+       bool
        help
          Partition Labels (disklabels) Supported:
          Zero or more of the following:
@@ -20,8 +19,7 @@ config PARTITIONS
          as well.
 
 config SPL_PARTITIONS
-       bool "Enable Partition Labels (disklabels) support in SPL"
-       default y if PARTITIONS
+       bool
        select SPL_SPRINTF
        select SPL_STRTO
        help
@@ -30,8 +28,7 @@ config SPL_PARTITIONS
          small amount of size to SPL, typically 500 bytes.
 
 config TPL_PARTITIONS
-       bool "Enable Partition Labels (disklabels) support in TPL"
-       default y if PARTITIONS
+       bool
        select TPL_SPRINTF
        select TPL_STRTO
        help
@@ -41,57 +38,61 @@ config TPL_PARTITIONS
 
 config MAC_PARTITION
        bool "Enable Apple's MacOS partition table"
-       depends on PARTITIONS
+       select PARTITIONS
        help
          Say Y here if you would like to use device under U-Boot which
          were partitioned on a Macintosh.
 
 config SPL_MAC_PARTITION
        bool "Enable Apple's MacOS partition table for SPL"
-       depends on SPL && PARTITIONS
+       depends on SPL
        default y if MAC_PARTITION
+       select SPL_PARTITIONS
 
 config DOS_PARTITION
        bool "Enable MS Dos partition table"
-       depends on PARTITIONS
        default y if DISTRO_DEFAULTS
        default y if x86 || CMD_FAT || USB_STORAGE
+       select PARTITIONS
        help
          traditional on the Intel architecture, USB sticks, etc.
 
 config SPL_DOS_PARTITION
        bool "Enable MS Dos partition table for SPL"
-       depends on SPL && PARTITIONS
+       depends on SPL
        default n if ARCH_SUNXI
        default y if DOS_PARTITION
+       select SPL_PARTITIONS
 
 config ISO_PARTITION
        bool "Enable ISO partition table"
-       depends on PARTITIONS
        default y if DISTRO_DEFAULTS
        default y if MIPS || ARCH_TEGRA
+       select PARTITIONS
 
 config SPL_ISO_PARTITION
        bool "Enable ISO partition table for SPL"
-       depends on SPL && PARTITIONS
+       depends on SPL
+       select SPL_PARTITIONS
 
 config AMIGA_PARTITION
        bool "Enable AMIGA partition table"
-       depends on PARTITIONS
+       select PARTITIONS
        help
          Say Y here if you would like to use device under U-Boot which
          were partitioned under AmigaOS.
 
 config SPL_AMIGA_PARTITION
        bool "Enable AMIGA partition table for SPL"
-       depends on SPL && PARTITIONS
+       depends on SPL
        default y if AMIGA_PARTITION
+       select SPL_PARTITIONS
 
 config EFI_PARTITION
        bool "Enable EFI GPT partition table"
-       depends on PARTITIONS
        default y if DISTRO_DEFAULTS
        default y if ARCH_TEGRA
+       select PARTITIONS
        select LIB_UUID
        help
          Say Y here if you would like to use device under U-Boot which
@@ -128,9 +129,10 @@ config EFI_PARTITION_ENTRIES_OFF
 
 config SPL_EFI_PARTITION
        bool "Enable EFI GPT partition table for SPL"
-       depends on  SPL && PARTITIONS
+       depends on  SPL
        default n if ARCH_SUNXI
        default y if EFI_PARTITION
+       select SPL_PARTITIONS
 
 config PARTITION_UUIDS
        bool "Enable support of UUID for partition"
@@ -143,12 +145,11 @@ config PARTITION_UUIDS
 
 config SPL_PARTITION_UUIDS
        bool "Enable support of UUID for partition in SPL"
-       depends on SPL && PARTITIONS
+       depends on SPL_PARTITIONS
        default y if SPL_EFI_PARTITION
 
 config PARTITION_TYPE_GUID
        bool "Enable support of GUID for partition type"
-       depends on PARTITIONS
        depends on EFI_PARTITION
        help
          Activate the configuration of GUID type
index 5ca10c5..ec14883 100644 (file)
@@ -6,6 +6,9 @@
 #ccflags-y += -DET_DEBUG -DDEBUG
 
 obj-$(CONFIG_$(SPL_TPL_)PARTITIONS)  += part.o
+ifdef CONFIG_$(SPL_TPL_)BLK
+obj-$(CONFIG_$(SPL_TPL_)PARTITIONS)  += disk-uclass.o
+endif
 obj-$(CONFIG_$(SPL_TPL_)MAC_PARTITION)   += part_mac.o
 obj-$(CONFIG_$(SPL_TPL_)DOS_PARTITION)   += part_dos.o
 obj-$(CONFIG_$(SPL_TPL_)ISO_PARTITION)   += part_iso.o
diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c
new file mode 100644 (file)
index 0000000..72ff62e
--- /dev/null
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Software partition device (UCLASS_PARTITION)
+ *
+ *  Copyright (c) 2021 Linaro Limited
+ *                     Author: AKASHI Takahiro
+ */
+
+#define LOG_CATEGORY UCLASS_PARTITION
+
+#include <blk.h>
+#include <dm.h>
+#include <log.h>
+#include <part.h>
+#include <vsprintf.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+int part_create_block_devices(struct udevice *blk_dev)
+{
+       int part, count;
+       struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
+       struct disk_partition info;
+       struct disk_part *part_data;
+       char devname[32];
+       struct udevice *dev;
+       int ret;
+
+       if (!CONFIG_IS_ENABLED(PARTITIONS) ||
+           !CONFIG_IS_ENABLED(HAVE_BLOCK_DEVICE))
+               return 0;
+
+       if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
+               return 0;
+
+       /* Add devices for each partition */
+       for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+               if (part_get_info(desc, part, &info))
+                       continue;
+               snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
+                        part);
+
+               ret = device_bind_driver(blk_dev, "blk_partition",
+                                        strdup(devname), &dev);
+               if (ret)
+                       return ret;
+
+               part_data = dev_get_uclass_plat(dev);
+               part_data->partnum = part;
+               part_data->gpt_part_info = info;
+               count++;
+
+               ret = device_probe(dev);
+               if (ret) {
+                       debug("Can't probe\n");
+                       count--;
+                       device_unbind(dev);
+
+                       continue;
+               }
+       }
+       debug("%s: %d partitions found in %s\n", __func__, count,
+             blk_dev->name);
+
+       return 0;
+}
+
+static ulong blk_part_read(struct udevice *dev, lbaint_t start,
+                          lbaint_t blkcnt, void *buffer)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->read)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->read(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_write(struct udevice *dev, lbaint_t start,
+                           lbaint_t blkcnt, const void *buffer)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->write)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->write(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_erase(struct udevice *dev, lbaint_t start,
+                           lbaint_t blkcnt)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->erase)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->erase(parent, start, blkcnt);
+}
+
+static const struct blk_ops blk_part_ops = {
+       .read   = blk_part_read,
+       .write  = blk_part_write,
+       .erase  = blk_part_erase,
+};
+
+U_BOOT_DRIVER(blk_partition) = {
+       .name           = "blk_partition",
+       .id             = UCLASS_PARTITION,
+       .ops            = &blk_part_ops,
+};
+
+/*
+ * BLOCK IO APIs
+ */
+static struct blk_desc *dev_get_blk(struct udevice *dev)
+{
+       struct blk_desc *block_dev;
+
+       switch (device_get_uclass_id(dev)) {
+       /*
+        * We won't support UCLASS_BLK with dev_* interfaces.
+        */
+       case UCLASS_PARTITION:
+               block_dev = dev_get_uclass_plat(dev_get_parent(dev));
+               break;
+       default:
+               block_dev = NULL;
+               break;
+       }
+
+       return block_dev;
+}
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+                      lbaint_t blkcnt, void *buffer)
+{
+       struct blk_desc *block_dev;
+       const struct blk_ops *ops;
+       struct disk_part *part;
+       lbaint_t start_in_disk;
+       ulong blks_read;
+
+       block_dev = dev_get_blk(dev);
+       if (!block_dev)
+               return -ENOSYS;
+
+       ops = blk_get_ops(dev);
+       if (!ops->read)
+               return -ENOSYS;
+
+       start_in_disk = start;
+       if (device_get_uclass_id(dev) == UCLASS_PARTITION) {
+               part = dev_get_uclass_plat(dev);
+               start_in_disk += part->gpt_part_info.start;
+       }
+
+       if (blkcache_read(block_dev->if_type, block_dev->devnum,
+                         start_in_disk, blkcnt, block_dev->blksz, buffer))
+               return blkcnt;
+       blks_read = ops->read(dev, start, blkcnt, buffer);
+       if (blks_read == blkcnt)
+               blkcache_fill(block_dev->if_type, block_dev->devnum,
+                             start_in_disk, blkcnt, block_dev->blksz, buffer);
+
+       return blks_read;
+}
+
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+                       lbaint_t blkcnt, const void *buffer)
+{
+       struct blk_desc *block_dev;
+       const struct blk_ops *ops;
+
+       block_dev = dev_get_blk(dev);
+       if (!block_dev)
+               return -ENOSYS;
+
+       ops = blk_get_ops(dev);
+       if (!ops->write)
+               return -ENOSYS;
+
+       blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+       return ops->write(dev, start, blkcnt, buffer);
+}
+
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+                       lbaint_t blkcnt)
+{
+       struct blk_desc *block_dev;
+       const struct blk_ops *ops;
+
+       block_dev = dev_get_blk(dev);
+       if (!block_dev)
+               return -ENOSYS;
+
+       ops = blk_get_ops(dev);
+       if (!ops->erase)
+               return -ENOSYS;
+
+       blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+       return ops->erase(dev, start, blkcnt);
+}
+
+UCLASS_DRIVER(partition) = {
+       .id             = UCLASS_PARTITION,
+       .per_device_plat_auto   = sizeof(struct disk_part),
+       .name           = "partition",
+};
index 083bfb0..8fa7637 100644 (file)
@@ -10,6 +10,7 @@ the following SoCs work:
  - Apple M1 SoC (t8103)
  - Apple M1 Pro SoC (t6000)
  - Apple M1 Max SoC (t6001)
+ - Apple M1 Ultra SoC (t6002)
 
 On these SoCs the following hardware is supported:
 
@@ -78,5 +79,5 @@ supported SoCs.
      - Base Address
    * - M1 (t8103)
      - 0x235200000
-   * - M1 Pro/Max (t6000/t6001)
+   * - M1 Pro/Max/Ultra (t6000/t6001/t6002)
      - 0x39b200000
index b0e6337..5f33f9f 100644 (file)
@@ -1042,6 +1042,27 @@ data structure might be worthwhile in some rare cases, once we understand
 what the bottlenecks are.
 
 
+Tag Support
+-----------
+
+It is sometimes useful for a subsystem to associate its own private
+data (or object) to a DM device, i.e. struct udevice, to support
+additional features.
+
+Tag support in driver model will give us the ability to do so dynamically
+instead of modifying "udevice" data structure. In the initial release, we
+will support two type of attributes:
+
+- a pointer with dm_tag_set_ptr(), and
+- an unsigned long with dm_tag_set_val()
+
+For example, UEFI subsystem utilizes the feature to maintain efi_disk
+objects depending on linked udevice's lifecycle.
+
+While the current implementation is quite simple, it will get evolved
+as the feature is more extensively used in U-Boot subsystems.
+
+
 Changes since v1
 ----------------
 
index f555ff2..d663bf1 100644 (file)
@@ -74,7 +74,7 @@ BootROM's standard input and BootROM's terminal echo are active and working
 fine. To workaround this BootROM bug with standard output, it is possible
 to manually overwrite BootROM variables stored in SRAM which BootROM use
 for checking if standard output is enabled or not. To enable BootROM
-standard output on UART, type this command folled by ENTER key:
+standard output on UART, type this command followed by ENTER key:
 
 .RS 1.2i
 .TP
index 31279fc..4cc8c07 100644 (file)
@@ -9,7 +9,7 @@ Synopsis
 
 ::
 
-    bootefi [image_addr] [fdt_addr]
+    bootefi [image_addr] [fdt_addr [image_size]]
     bootefi bootmgr [fdt_addr]
     bootefi hello [fdt_addr]
     bootefi selftest [fdt_addr]
@@ -41,13 +41,28 @@ command sequence to run a UEFI application might look like
     load mmc 0:1 $kernel_addr_r /EFI/grub/grubaa64.efi
     bootefi $kernel_addr_r $fdt_addr_r
 
-The last file loaded defines the image file path in the loaded image protocol.
-Hence the executable should always be loaded last.
+The last UEFI binary loaded defines the image file path in the loaded image
+protocol.
 
 The value of the environment variable *bootargs* is converted from UTF-8 to
 UTF-16 and passed as load options in the loaded image protocol to the UEFI
 binary.
 
+image_addr
+    Address of the UEFI binary.
+
+fdt_addr
+    Address of the device-tree or '-'. If no address is specifiy, the
+    environment variable $fdt_addr is used as first fallback, the address of
+    U-Boot's internal device-tree $fdtcontroladdr as second fallback.
+    When using ACPI no device-tree shall be specified.
+
+image_size
+    Size of the UEFI binary file. This argument is only needed if *image_addr*
+    does not match the address of the last loaded UEFI binary. In this case
+    a memory device path will be used as image file path in the loaded image
+    protocol.
+
 Note
     UEFI binaries that are contained in FIT images are launched via the
     *bootm* command.
index f1e4a85..791e26c 100644 (file)
@@ -741,6 +741,10 @@ static int blk_post_probe(struct udevice *dev)
                struct blk_desc *desc = dev_get_uclass_plat(dev);
 
                part_init(desc);
+
+               if (desc->part_type != PART_TYPE_UNKNOWN &&
+                   part_create_block_devices(dev))
+                       debug("*** creating partitions failed\n");
        }
 
        return 0;
index 6829bcd..2299919 100644 (file)
@@ -29,7 +29,7 @@ int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
 
        node = calloc(sizeof(*node), 1);
        if (!node)
-               return -ENOSPC;
+               return -ENOMEM;
 
        node->dev = dev;
        node->tag = tag;
@@ -53,7 +53,7 @@ int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
 
        node = calloc(sizeof(*node), 1);
        if (!node)
-               return -ENOSPC;
+               return -ENOMEM;
 
        node->dev = dev;
        node->tag = tag;
index 0e26e1d..230b1ea 100644 (file)
@@ -83,6 +83,7 @@ enum uclass_id {
        UCLASS_P2SB,            /* (x86) Primary-to-Sideband Bus */
        UCLASS_PANEL,           /* Display panel, such as an LCD */
        UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */
+       UCLASS_PARTITION,       /* Logical disk partition device */
        UCLASS_PCH,             /* x86 platform controller hub */
        UCLASS_PCI,             /* PCI bus */
        UCLASS_PCI_EP,          /* PCI endpoint device */
index c52ea59..ba79a9a 100644 (file)
@@ -493,6 +493,8 @@ struct efi_register_notify_event {
 /* List of all events registered by RegisterProtocolNotify() */
 extern struct list_head efi_register_notify_events;
 
+/* called at pre-initialization */
+int efi_init_early(void);
 /* Initialize efi execution environment */
 efi_status_t efi_init_obj_list(void);
 /* Install device tree */
@@ -523,8 +525,8 @@ void efi_carve_out_dt_rsv(void *fdt);
 void efi_try_purge_kaslr_seed(void *fdt);
 /* Called by bootefi to make console interface available */
 efi_status_t efi_console_register(void);
-/* Called by bootefi to make all disk storage accessible as EFI objects */
-efi_status_t efi_disk_register(void);
+/* Called by efi_init_obj_list() to initialize efi_disks */
+efi_status_t efi_disk_init(void);
 /* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
 efi_status_t efi_rng_register(void);
 /* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
index 53cfbdd..3a6958d 100644 (file)
@@ -10,6 +10,7 @@
 #include <ide.h>
 #include <uuid.h>
 #include <linker_lists.h>
+#include <linux/errno.h>
 #include <linux/list.h>
 
 struct block_drvr {
@@ -86,7 +87,7 @@ struct disk_part {
 };
 
 /* Misc _get_dev functions */
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
 /**
  * blk_get_dev() - get a pointer to a block device given its type and number
  *
@@ -103,7 +104,6 @@ struct disk_part {
 struct blk_desc *blk_get_dev(const char *ifname, int dev);
 
 struct blk_desc *mg_disk_get_dev(int dev);
-int host_get_dev_err(int dev, struct blk_desc **blk_devp);
 
 /* disk/part.c */
 int part_get_info(struct blk_desc *dev_desc, int part,
@@ -275,6 +275,22 @@ static inline int blk_get_device_part_str(const char *ifname,
                                          struct disk_partition *info,
                                          int allow_whole_dev)
 { *dev_desc = NULL; return -1; }
+
+static inline int part_get_info_by_name_type(struct blk_desc *dev_desc,
+                                            const char *name,
+                                            struct disk_partition *info,
+                                            int part_type)
+{
+       return -ENOENT;
+}
+
+static inline int part_get_info_by_name(struct blk_desc *dev_desc,
+                                       const char *name,
+                                       struct disk_partition *info)
+{
+       return -ENOENT;
+}
+
 static inline int
 part_get_info_by_dev_and_name_or_num(const char *dev_iface,
                                     const char *dev_part_str,
@@ -287,6 +303,23 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
 }
 #endif
 
+struct udevice;
+/**
+ * part_create_block_devices - Create block devices for disk partitions
+ *
+ * Create UCLASS_PARTITION udevices for each of disk partitions in @parent
+ *
+ * @blk_dev:   Whole disk device
+ */
+int part_create_block_devices(struct udevice *blk_dev);
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+                      lbaint_t blkcnt, void *buffer);
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+                       lbaint_t blkcnt, const void *buffer);
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+                       lbaint_t blkcnt);
+
 /*
  * We don't support printing partition information in SPL and only support
  * getting partition information in a few cases.
@@ -496,7 +529,7 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
 
 #endif
 
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
 /**
  * part_driver_get_count() - get partition driver count
  *
index 4ca9554..dc983f0 100644 (file)
@@ -26,4 +26,6 @@ struct host_block_dev {
  */
 int host_dev_bind(int dev, char *filename, bool removable);
 
+int host_get_dev_err(int dev, struct blk_desc **blk_devp);
+
 #endif
index 04cb3ef..5baa6f8 100644 (file)
@@ -35,6 +35,7 @@
 #include <malloc.h>
 #include <dm/device-internal.h>
 #include <dm/root.h>
+#include <dm/tag.h>
 
 /*
  * EFI attributes of the udevice handled by this driver.
@@ -107,25 +108,6 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 }
 
 /**
- * Create partions for the block device.
- *
- * @handle:    EFI handle of the block device
- * @dev:       udevice of the block device
- * Return:     number of partitions created
- */
-static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
-{
-       struct blk_desc *desc;
-       const char *if_typename;
-
-       desc = dev_get_uclass_plat(dev);
-       if_typename = blk_get_if_type_name(desc->if_type);
-
-       return efi_disk_create_partitions(handle, desc, if_typename,
-                                         desc->devnum, dev->name);
-}
-
-/**
  * Create a block device for a handle
  *
  * @handle:    handle
@@ -139,7 +121,6 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
        char *name;
        struct efi_object *obj = efi_search_obj(handle);
        struct efi_block_io *io = interface;
-       int disks;
        struct efi_blk_plat *plat;
 
        EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
@@ -173,15 +154,20 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
        plat->handle = handle;
        plat->io = interface;
 
+       /*
+        * FIXME: necessary because we won't do almost nothing in
+        * efi_disk_create() when called from device_probe().
+        */
+       ret = dev_tag_set_ptr(bdev, DM_TAG_EFI, handle);
+       if (ret)
+               /* FIXME: cleanup for bdev */
+               return ret;
+
        ret = device_probe(bdev);
        if (ret)
                return ret;
        EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
 
-       /* Create handles for the partions of the block device */
-       disks = efi_bl_bind_partitions(handle, bdev);
-       EFI_PRINT("Found %d partitions\n", disks);
-
        return 0;
 }
 
index d50cd25..6b245f5 100644 (file)
@@ -14,8 +14,10 @@ config EFI_LOADER
        depends on DM_ETH || !NET
        depends on !EFI_APP
        default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
+       select DM_EVENT
+       select EVENT_DYNAMIC
        select LIB_UUID
-       select PARTITION_UUIDS
+       imply PARTITION_UUIDS
        select HAVE_BLOCK_DEVICE
        select REGEX
        imply FAT
@@ -40,6 +42,7 @@ config CMD_BOOTEFI_BOOTMGR
 
 config EFI_SETUP_EARLY
        bool
+       default y
 
 choice
        prompt "Store for non-volatile UEFI variables"
index 034d26c..aaaa25c 100644 (file)
@@ -68,7 +68,7 @@ obj-y += efi_watchdog.o
 obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
-obj-$(CONFIG_PARTITIONS) += efi_disk.o
+obj-$(CONFIG_BLK) += efi_disk.o
 obj-$(CONFIG_NET) += efi_net.o
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
 obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
index 0542aaa..50a988c 100644 (file)
@@ -864,11 +864,16 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
                        break;
                case SIG_TYPE_GUID:
                        hddp->signature_type = 2;
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+                       /* info.uuid exists only with PARTITION_UUIDS */
                        if (uuid_str_to_bin(info.uuid,
-                                           hddp->partition_signature, 1))
+                                           hddp->partition_signature,
+                                           UUID_STR_FORMAT_GUID)) {
                                log_warning(
-                                       "Partition no. %d: invalid guid: %s\n",
+                                       "Partition %d: invalid GUID %s\n",
                                        part, info.uuid);
+                       }
+#endif
                        break;
                }
 
index c905c12..8fb5b23 100644 (file)
@@ -10,6 +10,9 @@
 #include <common.h>
 #include <blk.h>
 #include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/tag.h>
+#include <event.h>
 #include <efi_loader.h>
 #include <fs.h>
 #include <log.h>
@@ -33,7 +36,7 @@ const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
  * @part:      partition
  * @volume:    simple file system protocol of the partition
  * @offset:    offset into disk for simple partition
- * @desc:      internal block device descriptor
+ * @dev:       associated DM device
  */
 struct efi_disk_obj {
        struct efi_object header;
@@ -45,7 +48,7 @@ struct efi_disk_obj {
        unsigned int part;
        struct efi_simple_file_system_protocol *volume;
        lbaint_t offset;
-       struct blk_desc *desc;
+       struct udevice *dev; /* TODO: move it to efi_object */
 };
 
 /**
@@ -80,14 +83,12 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
                        void *buffer, enum efi_disk_direction direction)
 {
        struct efi_disk_obj *diskobj;
-       struct blk_desc *desc;
        int blksz;
        int blocks;
        unsigned long n;
 
        diskobj = container_of(this, struct efi_disk_obj, ops);
-       desc = (struct blk_desc *) diskobj->desc;
-       blksz = desc->blksz;
+       blksz = diskobj->media.block_size;
        blocks = buffer_size / blksz;
        lba += diskobj->offset;
 
@@ -98,10 +99,21 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
        if (buffer_size & (blksz - 1))
                return EFI_BAD_BUFFER_SIZE;
 
+#if CONFIG_IS_ENABLED(PARTITIONS)
+       if (direction == EFI_DISK_READ)
+               n = dev_read(diskobj->dev, lba, blocks, buffer);
+       else
+               n = dev_write(diskobj->dev, lba, blocks, buffer);
+#else
+       /* dev is always a block device (UCLASS_BLK) */
+       struct blk_desc *desc;
+
+       desc = dev_get_uclass_plat(diskobj->dev);
        if (direction == EFI_DISK_READ)
                n = blk_dread(desc, lba, blocks, buffer);
        else
                n = blk_dwrite(desc, lba, blocks, buffer);
+#endif
 
        /* We don't do interrupts, so check for timers cooperatively */
        efi_timer_check();
@@ -443,7 +455,6 @@ static efi_status_t efi_disk_add_dev(
        diskobj->ops = block_io_disk_template;
        diskobj->ifname = if_typename;
        diskobj->dev_index = dev_index;
-       diskobj->desc = desc;
 
        /* Fill in EFI IO Media info (for read/write callbacks) */
        diskobj->media.removable_media = desc->removable;
@@ -487,103 +498,255 @@ error:
        return ret;
 }
 
-/**
- * efi_disk_create_partitions() - create handles and protocols for partitions
+/*
+ * Create a handle for a whole raw disk
+ *
+ * @dev                uclass device (UCLASS_BLK)
  *
- * Create handles and protocols for the partitions of a block device.
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
  *
- * @parent:            handle of the parent disk
- * @desc:              block device
- * @if_typename:       interface type
- * @diskid:            device number
- * @pdevname:          device name
- * Return:             number of partitions created
+ * @return     0 on success, -1 otherwise
  */
-int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
-                              const char *if_typename, int diskid,
-                              const char *pdevname)
+static int efi_disk_create_raw(struct udevice *dev)
 {
-       int disks = 0;
-       char devname[32] = { 0 }; /* dp->str is u16[32] long */
-       int part;
-       struct efi_device_path *dp = NULL;
+       struct efi_disk_obj *disk;
+       struct blk_desc *desc;
+       const char *if_typename;
+       int diskid;
        efi_status_t ret;
+
+       desc = dev_get_uclass_plat(dev);
+       if_typename = blk_get_if_type_name(desc->if_type);
+       diskid = desc->devnum;
+
+       ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
+                              diskid, NULL, 0, &disk);
+       if (ret != EFI_SUCCESS) {
+               if (ret == EFI_NOT_READY)
+                       log_notice("Disk %s not ready\n", dev->name);
+               else
+                       log_err("Adding disk for %s failed\n", dev->name);
+
+               return -1;
+       }
+       disk->dev = dev;
+       if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+               efi_free_pool(disk->dp);
+               efi_delete_handle(&disk->header);
+
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Create a handle for a disk partition
+ *
+ * @dev                uclass device (UCLASS_PARTITION)
+ *
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return     0 on success, -1 otherwise
+ */
+static int efi_disk_create_part(struct udevice *dev)
+{
+       efi_handle_t parent;
+       struct blk_desc *desc;
+       const char *if_typename;
+       struct disk_part *part_data;
+       struct disk_partition *info;
+       unsigned int part;
+       int diskid;
        struct efi_handler *handler;
+       struct efi_device_path *dp_parent;
+       struct efi_disk_obj *disk;
+       efi_status_t ret;
+
+       if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
+               return -1;
+
+       desc = dev_get_uclass_plat(dev_get_parent(dev));
+       if_typename = blk_get_if_type_name(desc->if_type);
+       diskid = desc->devnum;
+
+       part_data = dev_get_uclass_plat(dev);
+       part = part_data->partnum;
+       info = &part_data->gpt_part_info;
 
-       /* Get the device path of the parent */
        ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
-       if (ret == EFI_SUCCESS)
-               dp = handler->protocol_interface;
-
-       /* Add devices for each partition */
-       for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
-               struct disk_partition info;
-
-               if (part_get_info(desc, part, &info))
-                       continue;
-               snprintf(devname, sizeof(devname), "%s:%x", pdevname,
-                        part);
-               ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
-                                      &info, part, NULL);
-               if (ret != EFI_SUCCESS) {
-                       log_err("Adding partition %s failed\n", pdevname);
-                       continue;
-               }
-               disks++;
+       if (ret != EFI_SUCCESS)
+               return -1;
+       dp_parent = (struct efi_device_path *)handler->protocol_interface;
+
+       ret = efi_disk_add_dev(parent, dp_parent, if_typename, desc, diskid,
+                              info, part, &disk);
+       if (ret != EFI_SUCCESS) {
+               log_err("Adding partition for %s failed\n", dev->name);
+               return -1;
+       }
+       disk->dev = dev;
+       if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+               efi_free_pool(disk->dp);
+               efi_delete_handle(&disk->header);
+
+               return -1;
        }
 
-       return disks;
+       return 0;
 }
 
-/**
- * efi_disk_register() - register block devices
+/*
+ * Create efi_disk objects for a block device
  *
- * U-Boot doesn't have a list of all online disk devices. So when running our
- * EFI payload, we scan through all of the potentially available ones and
- * store them in our object pool.
+ * @dev                uclass device (UCLASS_BLK)
  *
- * This function is called in efi_init_obj_list().
+ * Create efi_disk objects for partitions as well as a raw disk
+ * which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ * This function is expected to be called at EV_PM_POST_PROBE.
  *
- * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this.
- * Consider converting the code to look up devices as needed. The EFI device
- * could be a child of the UCLASS_BLK block device, perhaps.
+ * @return     0 on success, -1 otherwise
+ */
+static int efi_disk_probe(void *ctx, struct event *event)
+{
+       struct udevice *dev;
+       enum uclass_id id;
+       struct blk_desc *desc;
+       struct udevice *child;
+       int ret;
+
+       dev = event->data.dm.dev;
+       id = device_get_uclass_id(dev);
+
+       /* TODO: We won't support partitions in a partition */
+       if (id != UCLASS_BLK)
+               return 0;
+
+       /*
+        * avoid creating duplicated objects now that efi_driver
+        * has already created an efi_disk at this moment.
+        */
+       desc = dev_get_uclass_plat(dev);
+       if (desc->if_type != IF_TYPE_EFI_LOADER) {
+               ret = efi_disk_create_raw(dev);
+               if (ret)
+                       return -1;
+       }
+
+       device_foreach_child(child, dev) {
+               ret = efi_disk_create_part(child);
+               if (ret)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Delete an efi_disk object for a whole raw disk
  *
- * Return:     status code
+ * @dev                uclass device (UCLASS_BLK)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ *
+ * @return     0 on success, -1 otherwise
  */
-efi_status_t efi_disk_register(void)
+static int efi_disk_delete_raw(struct udevice *dev)
 {
-       struct efi_disk_obj *disk;
-       int disks = 0;
-       efi_status_t ret;
+       efi_handle_t handle;
+       struct blk_desc *desc;
+       struct efi_disk_obj *diskobj;
+
+       if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+               return -1;
+
+       desc = dev_get_uclass_plat(dev);
+       if (desc->if_type != IF_TYPE_EFI_LOADER) {
+               diskobj = container_of(handle, struct efi_disk_obj, header);
+               efi_free_pool(diskobj->dp);
+       }
+
+       efi_delete_handle(handle);
+       dev_tag_del(dev, DM_TAG_EFI);
+
+       return 0;
+}
+
+/*
+ * Delete an efi_disk object for a disk partition
+ *
+ * @dev                uclass device (UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return     0 on success, -1 otherwise
+ */
+static int efi_disk_delete_part(struct udevice *dev)
+{
+       efi_handle_t handle;
+       struct efi_disk_obj *diskobj;
+
+       if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+               return -1;
+
+       diskobj = container_of(handle, struct efi_disk_obj, header);
+
+       efi_free_pool(diskobj->dp);
+       efi_delete_handle(handle);
+       dev_tag_del(dev, DM_TAG_EFI);
+
+       return 0;
+}
+
+/*
+ * Delete an efi_disk object for a block device
+ *
+ * @dev                uclass device (UCLASS_BLK or UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be either UCLASS_BLK or UCLASS_PARTITION.
+ * This function is expected to be called at EV_PM_PRE_REMOVE.
+ *
+ * @return     0 on success, -1 otherwise
+ */
+static int efi_disk_remove(void *ctx, struct event *event)
+{
+       enum uclass_id id;
        struct udevice *dev;
 
-       for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
-            uclass_next_device_check(&dev)) {
-               struct blk_desc *desc = dev_get_uclass_plat(dev);
-               const char *if_typename = blk_get_if_type_name(desc->if_type);
+       dev = event->data.dm.dev;
+       id = device_get_uclass_id(dev);
 
-               /* Add block device for the full device */
-               log_info("Scanning disk %s...\n", dev->name);
-               ret = efi_disk_add_dev(NULL, NULL, if_typename,
-                                       desc, desc->devnum, NULL, 0, &disk);
-               if (ret == EFI_NOT_READY) {
-                       log_notice("Disk %s not ready\n", dev->name);
-                       continue;
-               }
-               if (ret) {
-                       log_err("ERROR: failure to add disk device %s, r = %lu\n",
-                               dev->name, ret & ~EFI_ERROR_MASK);
-                       continue;
-               }
-               disks++;
+       if (id == UCLASS_BLK)
+               return efi_disk_delete_raw(dev);
+       else if (id == UCLASS_PARTITION)
+               return efi_disk_delete_part(dev);
+       else
+               return 0;
+}
+
+efi_status_t efi_disk_init(void)
+{
+       int ret;
 
-               /* Partitions show up as block devices in EFI */
-               disks += efi_disk_create_partitions(
-                                       &disk->header, desc, if_typename,
-                                       desc->devnum, dev->name);
+       ret = event_register("efi_disk add", EVT_DM_POST_PROBE,
+                            efi_disk_probe, NULL);
+       if (ret) {
+               log_err("Event registration for efi_disk add failed\n");
+               return EFI_OUT_OF_RESOURCES;
        }
 
-       log_info("Found %d disks\n", disks);
+       ret = event_register("efi_disk del", EVT_DM_PRE_REMOVE,
+                            efi_disk_remove, NULL);
+       if (ret) {
+               log_err("Event registration for efi_disk del failed\n");
+               return EFI_OUT_OF_RESOURCES;
+       }
 
        return EFI_SUCCESS;
 }
index eee54e4..250eeb2 100644 (file)
@@ -174,20 +174,18 @@ static efi_status_t efi_init_os_indications(void)
                                    &os_indications_supported, false);
 }
 
-
 /**
- * efi_init_obj_list() - Initialize and populate EFI object list
+ * __efi_init_early() - handle initialization at early stage
+ *
+ * This function is called in efi_init_obj_list() only if
+ * !CONFIG_EFI_SETUP_EARLY.
  *
  * Return:     status code
  */
-efi_status_t efi_init_obj_list(void)
+static efi_status_t __efi_init_early(void)
 {
        efi_status_t ret = EFI_SUCCESS;
 
-       /* Initialize once only */
-       if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
-               return efi_obj_list_initialized;
-
        /* Allow unaligned memory access */
        allow_unaligned();
 
@@ -200,11 +198,51 @@ efi_status_t efi_init_obj_list(void)
        if (ret != EFI_SUCCESS)
                goto out;
 
-#ifdef CONFIG_PARTITIONS
-       ret = efi_disk_register();
-       if (ret != EFI_SUCCESS)
-               goto out;
-#endif
+       ret = efi_disk_init();
+out:
+       return ret;
+}
+
+/**
+ * efi_init_early() - handle initialization at early stage
+ *
+ * external version of __efi_init_early(); expected to be called in
+ * board_init_r().
+ *
+ * Return:     status code
+ */
+int efi_init_early(void)
+{
+       efi_status_t ret;
+
+       ret = __efi_init_early();
+       if (ret != EFI_SUCCESS) {
+               /* never re-init UEFI subsystem */
+               efi_obj_list_initialized = ret;
+               return -1;
+       }
+       return 0;
+}
+
+/**
+ * efi_init_obj_list() - Initialize and populate EFI object list
+ *
+ * Return:     status code
+ */
+efi_status_t efi_init_obj_list(void)
+{
+       efi_status_t ret = EFI_SUCCESS;
+
+       /* Initialize once only */
+       if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
+               return efi_obj_list_initialized;
+
+       if (!IS_ENABLED(CONFIG_EFI_SETUP_EARLY)) {
+               ret = __efi_init_early();
+               if (ret != EFI_SUCCESS)
+                       goto out;
+       }
+
        if (IS_ENABLED(CONFIG_EFI_RNG_PROTOCOL)) {
                ret = efi_rng_register();
                if (ret != EFI_SUCCESS)
index 9a1a904..f0a7c97 100644 (file)
@@ -102,6 +102,7 @@ obj-y += syscon.o
 obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
 obj-$(CONFIG_SYSINFO) += sysinfo.o
 obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
+obj-$(CONFIG_UT_DM) += tag.o
 obj-$(CONFIG_TEE) += tee.o
 obj-$(CONFIG_TIMER) += timer.o
 obj-$(CONFIG_DM_USB) += usb.o
diff --git a/test/dm/tag.c b/test/dm/tag.c
new file mode 100644 (file)
index 0000000..8ae8a1f
--- /dev/null
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  DM tag test
+ *
+ *  Copyright (c) 2021 Linaro Limited
+ *  Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <dm/tag.h>
+#include <dm/test.h> /* DM_TEST() */
+#include <test/test.h> /* struct unit_test_state */
+#include <test/ut.h> /* assertions */
+
+/*
+ * Test dm_tag_ptr() API
+ */
+static int dm_test_tag_ptr(struct unit_test_state *uts)
+{
+       ulong val;
+       void *ptr = NULL;
+
+       ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+       ut_assertok(dev_tag_get_ptr(uts->root, DM_TAG_EFI, &ptr));
+
+       ut_asserteq_ptr(&val, ptr);
+
+       ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+       return 0;
+}
+
+DM_TEST(dm_test_tag_ptr, 0);
+
+/*
+ * Test dm_tag_val() API
+ */
+static int dm_test_tag_val(struct unit_test_state *uts)
+{
+       ulong val1 = 0x12345678, val2 = 0;
+
+       ut_assertok(dev_tag_set_val(uts->root, DM_TAG_EFI, val1));
+
+       ut_assertok(dev_tag_get_val(uts->root, DM_TAG_EFI, &val2));
+
+       ut_asserteq_64(val1, val2);
+
+       ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+       return 0;
+}
+
+DM_TEST(dm_test_tag_val, 0);
+
+/*
+ * Test against an invalid tag
+ */
+static int dm_test_tag_inval(struct unit_test_state *uts)
+{
+       ulong val;
+
+       ut_asserteq(-EINVAL, dev_tag_set_ptr(uts->root, DM_TAG_COUNT, &val));
+
+       return 0;
+}
+
+DM_TEST(dm_test_tag_inval, 0);
+
+/*
+ * Test dm_tag_del_all() AP:
+ */
+static int dm_test_tag_del_all(struct unit_test_state *uts)
+{
+       ulong val;
+
+       ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+       ut_assertok(dev_tag_del_all(uts->root));
+
+       return 0;
+}
+
+DM_TEST(dm_test_tag_del_all, 0);