dm: add tag support
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 8 Mar 2022 11:36:46 +0000 (20:36 +0900)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Sat, 9 Apr 2022 19:06:31 +0000 (21:06 +0200)
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>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/core/Makefile
drivers/core/root.c
drivers/core/tag.c [new file with mode: 0644]
include/asm-generic/global_data.h
include/dm/tag.h [new file with mode: 0644]

index 5edd4e4..3742e75 100644 (file)
@@ -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
index 8efb425..86b3884 100644 (file)
@@ -199,6 +199,8 @@ int dm_init(bool of_live)
                        return ret;
        }
 
+       INIT_LIST_HEAD((struct list_head *)&gd->dmtag_list);
+
        return 0;
 }
 
diff --git a/drivers/core/tag.c b/drivers/core/tag.c
new file mode 100644 (file)
index 0000000..6829bcd
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Linaro Limited
+ *                     Author: AKASHI Takahiro
+ */
+
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/tag.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct udevice;
+
+DECLARE_GLOBAL_DATA_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, &gd->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, (struct list_head *)&gd->dmtag_list);
+
+       return 0;
+}
+
+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, &gd->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, (struct list_head *)&gd->dmtag_list);
+
+       return 0;
+}
+
+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, &gd->dmtag_list, sibling) {
+               if (node->dev == dev && node->tag == tag) {
+                       *ptrp = node->ptr;
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+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, &gd->dmtag_list, sibling) {
+               if (node->dev == dev && node->tag == tag) {
+                       *valp = node->val;
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+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, &gd->dmtag_list, sibling) {
+               if (node->dev == dev && node->tag == tag) {
+                       list_del(&node->sibling);
+                       free(node);
+
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+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, &gd->dmtag_list, sibling) {
+               if (node->dev == dev) {
+                       list_del(&node->sibling);
+                       free(node);
+                       found = true;
+               }
+       }
+
+       if (found)
+               return 0;
+
+       return -ENOENT;
+}
index beb8bb9..805a6fd 100644 (file)
@@ -474,6 +474,10 @@ struct global_data {
         */
        struct event_state event_state;
 #endif
+       /**
+        * @dmtag_list: List of DM tags
+        */
+       struct list_head dmtag_list;
 };
 #ifndef DO_DEPS_ONLY
 static_assert(sizeof(struct global_data) == GD_SIZE);
diff --git a/include/dm/tag.h b/include/dm/tag.h
new file mode 100644 (file)
index 0000000..54fc31e
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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 {
+       /* EFI_LOADER */
+       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() - set a tag's value as a pointer
+ * @dev: Device to operate
+ * @tag: Tag type
+ * @ptr: Pointer to set
+ *
+ * Set the value, @ptr, as of @tag associated with the device, @dev
+ *
+ * Return: 0 on success, -ve on error
+ */
+int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr);
+
+/**
+ * dev_tag_set_val() set a tag's value as an integer
+ * @dev: Device to operate
+ * @tag: Tag type
+ * @val: Value to set
+ *
+ * Set the value, @val, as of @tag associated with the device, @dev
+ *
+ * Return: on success, -ve on error
+ */
+int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val);
+
+/**
+ * dev_tag_get_ptr() - get a tag's value as a pointer
+ * @dev: Device to operate
+ * @tag: Tag type
+ * @ptrp: Pointer to tag's value (pointer)
+ *
+ * Get a tag's value as a pointer
+ *
+ * Return: on success, -ve on error
+ */
+int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp);
+
+/**
+ * dev_tag_get_val() - get a tag's value as an integer
+ * @dev: Device to operate
+ * @tag: Tag type
+ * @valp: Pointer to tag's value (ulong)
+ *
+ * Get a tag's value as an integer
+ *
+ * Return: 0 on success, -ve on error
+ */
+int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp);
+
+/**
+ * dev_tag_del() - delete a tag
+ * @dev: Device to operate
+ * @tag: Tag type
+ *
+ * Delete a tag of @tag associated with the device, @dev
+ *
+ * Return: 0 on success, -ve on error
+ */
+int dev_tag_del(struct udevice *dev, enum dm_tag_t tag);
+
+/**
+ * dev_tag_del_all() - delete all tags
+ * @dev: Device to operate
+ *
+ * Delete all the tags associated with the device, @dev
+ *
+ * Return: 0 on success, -ve on error
+ */
+int dev_tag_del_all(struct udevice *dev);
+
+#endif /* _DM_TAG_H */