@@ -2,7 +2,7 @@
#
# Copyright (c) 2013 Google, Inc
-obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o
+obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o tag.o
obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o
obj-$(CONFIG_DEVRES) += devres.o
obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o
new file mode 100644
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <malloc.h>
+#include <dm/tag.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct udevice;
+
+static LIST_HEAD(dmtag_list);
+
+/**
+ * dev_tag_set_ptr()
+ *
+ */
+int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
+{
+ struct dmtag_node *node;
+
+ if (!dev || tag > DM_TAG_COUNT)
+ return -EINVAL;
+
+ list_for_each_entry(node, &dmtag_list, sibling) {
+ if (node->dev == dev && node->tag == tag)
+ return -EEXIST;
+ }
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -ENOSPC;
+
+ node->dev = dev;
+ node->tag = tag;
+ node->ptr = ptr;
+ list_add_tail(&node->sibling, &dmtag_list);
+
+ return 0;
+}
+
+/**
+ * dev_tag_set_val()
+ *
+ */
+int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
+{
+ struct dmtag_node *node;
+
+ if (!dev || tag > DM_TAG_COUNT)
+ return -EINVAL;
+
+ list_for_each_entry(node, &dmtag_list, sibling) {
+ if (node->dev == dev && node->tag == tag)
+ return -EEXIST;
+ }
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -ENOSPC;
+
+ node->dev = dev;
+ node->tag = tag;
+ node->val = val;
+ list_add_tail(&node->sibling, &dmtag_list);
+
+ return 0;
+}
+
+/**
+ * dev_tag_get_ptr()
+ *
+ */
+int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp)
+{
+ struct dmtag_node *node;
+
+ if (!dev || tag > DM_TAG_COUNT)
+ return -EINVAL;
+
+ list_for_each_entry(node, &dmtag_list, sibling) {
+ if (node->dev == dev && node->tag == tag) {
+ *ptrp = node->ptr;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * dev_tag_get_val()
+ *
+ */
+int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp)
+{
+ struct dmtag_node *node;
+
+ if (!dev || tag > DM_TAG_COUNT)
+ return -EINVAL;
+
+ list_for_each_entry(node, &dmtag_list, sibling) {
+ if (node->dev == dev && node->tag == tag) {
+ *valp = node->val;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * dev_tag_del()
+ *
+ */
+int dev_tag_del(struct udevice *dev, enum dm_tag_t tag)
+{
+ struct dmtag_node *node, *tmp;
+
+ if (!dev || tag > DM_TAG_COUNT)
+ return -EINVAL;
+
+ list_for_each_entry_safe(node, tmp, &dmtag_list, sibling) {
+ if (node->dev == dev && node->tag == tag) {
+ list_del(&node->sibling);
+ free(node);
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * dev_tag_del_all()
+ *
+ */
+int dev_tag_del_all(struct udevice *dev)
+{
+ struct dmtag_node *node, *tmp;
+ bool found = false;
+
+ if (!dev)
+ return -EINVAL;
+
+ list_for_each_entry_safe(node, tmp, &dmtag_list, sibling) {
+ if (node->dev == dev) {
+ list_del(&node->sibling);
+ free(node);
+ found = true;
+ }
+ }
+
+ if (found)
+ return 0;
+
+ return -ENOENT;
+}
new file mode 100644
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#ifndef _DM_TAG_H
+#define _DM_TAG_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct udevice;
+
+enum dm_tag_t {
+ DM_TAG_EFI = 0,
+
+ DM_TAG_COUNT,
+};
+
+/**
+ * dmtag_node
+ *
+ * @sibling: List of dm-tag nodes
+ * @dev: Associated udevice
+ * @tag: Tag type
+ * @ptr: Pointer as a value
+ * @val: Value
+ */
+struct dmtag_node {
+ struct list_head sibling;
+ struct udevice *dev;
+ enum dm_tag_t tag;
+ union {
+ void *ptr;
+ ulong val;
+ };
+};
+
+/**
+ * dev_tag_set_ptr()
+ *
+ */
+int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr);
+
+/**
+ * dev_tag_set_val()
+ *
+ */
+int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val);
+
+/**
+ * dev_tag_get_ptr()
+ *
+ */
+int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp);
+
+/**
+ * dev_tag_get_val()
+ *
+ */
+int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp);
+
+/**
+ * dev_tag_del()
+ *
+ */
+int dev_tag_del(struct udevice *dev, enum dm_tag_t tag);
+
+/**
+ * dev_tag_del_all()
+ *
+ */
+int dev_tag_del_all(struct udevice *dev);
+
+#endif /* _DM_TAG_H */
With dm-tag feature, any U-Boot subsystem is allowed to associate arbitrary number of data with a particular udevice. This can been see as expanding "struct udevice" without modifying the definition. As a first user, UEFI subsystem makes use of tags to associate an efi_disk object with a block device. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> --- drivers/core/Makefile | 2 +- drivers/core/tag.c | 162 ++++++++++++++++++++++++++++++++++++++++++ include/dm/tag.h | 76 ++++++++++++++++++++ 3 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 drivers/core/tag.c create mode 100644 include/dm/tag.h