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.aka...@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 diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 5edd4e413576..3742e7574525 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -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 diff --git a/drivers/core/tag.c b/drivers/core/tag.c new file mode 100644 index 000000000000..562df3590c44 --- /dev/null +++ b/drivers/core/tag.c @@ -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; +} diff --git a/include/dm/tag.h b/include/dm/tag.h new file mode 100644 index 000000000000..8f81b4f7ffaa --- /dev/null +++ b/include/dm/tag.h @@ -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 */ -- 2.33.0