There were some conflicts with the rpi and xlnx-soc branches. i kept the DT-overlay versions that were already in those BSPs (git merge -X ours), and only merged the non conflicting delta.
If there's an issue with the results, please send follow up patches. Bruce On Tue, Aug 17, 2021 at 3:02 AM Yanfei Xu <yanfei...@windriver.com> wrote: > > From: Pantelis Antoniou <pantelis.anton...@konsulko.com> > > commit ba900332d141bf2d1d3b6aa7da8f01fe4b9fb256 from > https://github.com/altera-opensource/linux-socfpga.git > > Add a runtime interface to using configfs for generic device tree overlay > usage. With it its possible to use device tree overlays without having > to use a per-platform overlay manager. > > Please see Documentation/devicetree/configfs-overlays.txt for more info. > > Changes since v6: > - Default groups properties API changed. > > Changes since v5: > - New style configfs. > > Changes since v4: > - Loading fix for multiple overlays as found out by > Geert Uytterhoeven <ge...@linux-m68k.org> > > Changes since v3: > - Fixed compilation on SPARC & Xtensa > > Changes since v2: > - Removed ifdef CONFIG_OF_OVERLAY (since for now it's required) > - Created a documentation entry > - Slight rewording in Kconfig > > Changes since v1: > - of_resolve() -> of_resolve_phandles(). > > Signed-off-by: Pantelis Antoniou <pantelis.anton...@konsulko.com> > [geert: Use %zu to format size_t] > [geert: Rebase to v4.15-rc1] > [geert: Make cfs_overlay_item_dtbo_{read,write}() and > of_cfs_overlay_group static] > [geert: Let OF_CONFIGFS select OF_FLATTREE to fix sparc all*config] > [geert: Spelling/grammar s/rationalle of/rationale for/] > [geert: Rebase on top of commit 39a751a4cb7e4798 ("of: change overlay apply > input data from unflattened to FDT") > Signed-off-by: Geert Uytterhoeven <geert+rene...@glider.be> > Signed-off-by: Meng Li <meng...@windriver.com> > Signed-off-by: Yanfei Xu <yanfei...@windriver.com> > --- > .../devicetree/configfs-overlays.txt | 31 ++ > drivers/of/Kconfig | 8 + > drivers/of/Makefile | 1 + > drivers/of/configfs.c | 284 ++++++++++++++++++ > 4 files changed, 324 insertions(+) > create mode 100644 Documentation/devicetree/configfs-overlays.txt > create mode 100644 drivers/of/configfs.c > > diff --git a/Documentation/devicetree/configfs-overlays.txt > b/Documentation/devicetree/configfs-overlays.txt > new file mode 100644 > index 000000000000..185d85ef52e4 > --- /dev/null > +++ b/Documentation/devicetree/configfs-overlays.txt > @@ -0,0 +1,31 @@ > +Howto use the configfs overlay interface. > + > +A device-tree configfs entry is created in /config/device-tree/overlays > +and and it is manipulated using standard file system I/O. > +Note that this is a debug level interface, for use by developers and > +not necessarily something accessed by normal users due to the > +security implications of having direct access to the kernel's device tree. > + > +* To create an overlay you mkdir the directory: > + > + # mkdir /config/device-tree/overlays/foo > + > +* Either you echo the overlay firmware file to the path property file. > + > + # echo foo.dtbo >/config/device-tree/overlays/foo/path > + > +* Or you cat the contents of the overlay to the dtbo file > + > + # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo > + > +The overlay file will be applied, and devices will be created/destroyed > +as required. > + > +To remove it simply rmdir the directory. > + > + # rmdir /config/device-tree/overlays/foo > + > +The rationale for the dual interface (firmware & direct copy) is that each is > +better suited to different use patterns. The firmware interface is what's > +intended to be used by hardware managers in the kernel, while the copy > interface > +make sense for developers (since it avoids problems with namespaces). > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig > index 37c2ccbefecd..0968b8da9f36 100644 > --- a/drivers/of/Kconfig > +++ b/drivers/of/Kconfig > @@ -100,6 +100,14 @@ config OF_OVERLAY > While this option is selected automatically when needed, you can > enable it manually to improve device tree unit test coverage. > > +config OF_CONFIGFS > + bool "Device Tree Overlay ConfigFS interface" > + select CONFIGFS_FS > + select OF_FLATTREE > + depends on OF_OVERLAY > + help > + Enable a simple user-space driven DT overlay interface. > + > config OF_NUMA > bool > > diff --git a/drivers/of/Makefile b/drivers/of/Makefile > index 663a4af0cccd..b00a95adf519 100644 > --- a/drivers/of/Makefile > +++ b/drivers/of/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0 > obj-y = base.o device.o platform.o property.o > obj-$(CONFIG_OF_KOBJ) += kobj.o > +obj-$(CONFIG_OF_CONFIGFS) += configfs.o > obj-$(CONFIG_OF_DYNAMIC) += dynamic.o > obj-$(CONFIG_OF_FLATTREE) += fdt.o > obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o > diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c > new file mode 100644 > index 000000000000..7a6cae074381 > --- /dev/null > +++ b/drivers/of/configfs.c > @@ -0,0 +1,284 @@ > +/* > + * Configfs entries for device-tree > + * > + * Copyright (C) 2013 - Pantelis Antoniou <pa...@antoniou-consulting.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version > + * 2 of the License, or (at your option) any later version. > + */ > +#include <linux/ctype.h> > +#include <linux/cpu.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/of_fdt.h> > +#include <linux/spinlock.h> > +#include <linux/sizes.h> > +#include <linux/slab.h> > +#include <linux/proc_fs.h> > +#include <linux/configfs.h> > +#include <linux/types.h> > +#include <linux/stat.h> > +#include <linux/limits.h> > +#include <linux/file.h> > +#include <linux/vmalloc.h> > +#include <linux/firmware.h> > + > +#include "of_private.h" > + > +struct cfs_overlay_item { > + struct config_item item; > + > + char path[PATH_MAX]; > + > + const struct firmware *fw; > + struct device_node *overlay; > + int ov_id; > + > + void *dtbo; > + int dtbo_size; > +}; > + > +static int create_overlay(struct cfs_overlay_item *overlay, const void *blob, > + size_t size) > +{ > + int err; > + > + err = of_overlay_fdt_apply(blob, size, &overlay->ov_id); > + if (err < 0) > + pr_err("%s: Failed to create overlay (err=%d)\n", __func__, > + err); > + > + return err; > +} > + > +static inline struct cfs_overlay_item *to_cfs_overlay_item( > + struct config_item *item) > +{ > + return item ? container_of(item, struct cfs_overlay_item, item) : > NULL; > +} > + > +static ssize_t cfs_overlay_item_path_show(struct config_item *item, char > *page) > +{ > + return sprintf(page, "%s\n", to_cfs_overlay_item(item)->path); > +} > + > +static ssize_t cfs_overlay_item_path_store(struct config_item *item, > + const char *page, size_t count) > +{ > + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); > + const char *p = page; > + char *s; > + int err; > + > + /* if it's set do not allow changes */ > + if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) > + return -EPERM; > + > + /* copy to path buffer (and make sure it's always zero terminated */ > + count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p); > + overlay->path[sizeof(overlay->path) - 1] = '\0'; > + > + /* strip trailing newlines */ > + s = overlay->path + strlen(overlay->path); > + while (s > overlay->path && *--s == '\n') > + *s = '\0'; > + > + pr_debug("%s: path is '%s'\n", __func__, overlay->path); > + > + err = request_firmware(&overlay->fw, overlay->path, NULL); > + if (err != 0) > + goto out_err; > + > + err = create_overlay(overlay, overlay->fw->data, overlay->fw->size); > + if (err < 0) > + goto out_err; > + > + return count; > + > +out_err: > + > + release_firmware(overlay->fw); > + overlay->fw = NULL; > + > + overlay->path[0] = '\0'; > + return err; > +} > + > +static ssize_t cfs_overlay_item_status_show(struct config_item *item, > + char *page) > +{ > + return sprintf(page, "%s\n", to_cfs_overlay_item(item)->ov_id >= 0 ? > + "applied" : "unapplied"); > +} > + > +CONFIGFS_ATTR(cfs_overlay_item_, path); > +CONFIGFS_ATTR_RO(cfs_overlay_item_, status); > + > +static struct configfs_attribute *cfs_overlay_attrs[] = { > + &cfs_overlay_item_attr_path, > + &cfs_overlay_item_attr_status, > + NULL, > +}; > + > +static ssize_t cfs_overlay_item_dtbo_read(struct config_item *item, void > *buf, > + size_t max_count) > +{ > + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); > + > + pr_debug("%s: buf=%p max_count=%zu\n", __func__, > + buf, max_count); > + > + if (overlay->dtbo == NULL) > + return 0; > + > + /* copy if buffer provided */ > + if (buf != NULL) { > + /* the buffer must be large enough */ > + if (overlay->dtbo_size > max_count) > + return -ENOSPC; > + > + memcpy(buf, overlay->dtbo, overlay->dtbo_size); > + } > + > + return overlay->dtbo_size; > +} > + > +static ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, > + const void *buf, size_t count) > +{ > + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); > + int err; > + > + /* if it's set do not allow changes */ > + if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) > + return -EPERM; > + > + /* copy the contents */ > + overlay->dtbo = kmemdup(buf, count, GFP_KERNEL); > + if (overlay->dtbo == NULL) > + return -ENOMEM; > + > + overlay->dtbo_size = count; > + > + err = create_overlay(overlay, overlay->dtbo, overlay->dtbo_size); > + if (err < 0) > + goto out_err; > + > + return count; > + > +out_err: > + kfree(overlay->dtbo); > + overlay->dtbo = NULL; > + overlay->dtbo_size = 0; > + > + return err; > +} > + > +CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M); > + > +static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = { > + &cfs_overlay_item_attr_dtbo, > + NULL, > +}; > + > +static void cfs_overlay_release(struct config_item *item) > +{ > + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); > + > + if (overlay->ov_id >= 0) > + of_overlay_remove(&overlay->ov_id); > + if (overlay->fw) > + release_firmware(overlay->fw); > + /* kfree with NULL is safe */ > + kfree(overlay->dtbo); > + kfree(overlay); > +} > + > +static struct configfs_item_operations cfs_overlay_item_ops = { > + .release = cfs_overlay_release, > +}; > + > +static struct config_item_type cfs_overlay_type = { > + .ct_item_ops = &cfs_overlay_item_ops, > + .ct_attrs = cfs_overlay_attrs, > + .ct_bin_attrs = cfs_overlay_bin_attrs, > + .ct_owner = THIS_MODULE, > +}; > + > +static struct config_item *cfs_overlay_group_make_item( > + struct config_group *group, const char *name) > +{ > + struct cfs_overlay_item *overlay; > + > + overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); > + if (!overlay) > + return ERR_PTR(-ENOMEM); > + overlay->ov_id = -1; > + > + config_item_init_type_name(&overlay->item, name, &cfs_overlay_type); > + return &overlay->item; > +} > + > +static void cfs_overlay_group_drop_item(struct config_group *group, > + struct config_item *item) > +{ > + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); > + > + config_item_put(&overlay->item); > +} > + > +static struct configfs_group_operations overlays_ops = { > + .make_item = cfs_overlay_group_make_item, > + .drop_item = cfs_overlay_group_drop_item, > +}; > + > +static struct config_item_type overlays_type = { > + .ct_group_ops = &overlays_ops, > + .ct_owner = THIS_MODULE, > +}; > + > +static struct configfs_group_operations of_cfs_ops = { > + /* empty - we don't allow anything to be created */ > +}; > + > +static struct config_item_type of_cfs_type = { > + .ct_group_ops = &of_cfs_ops, > + .ct_owner = THIS_MODULE, > +}; > + > +static struct config_group of_cfs_overlay_group; > + > +static struct configfs_subsystem of_cfs_subsys = { > + .su_group = { > + .cg_item = { > + .ci_namebuf = "device-tree", > + .ci_type = &of_cfs_type, > + }, > + }, > + .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex), > +}; > + > +static int __init of_cfs_init(void) > +{ > + int ret; > + > + pr_info("%s\n", __func__); > + > + config_group_init(&of_cfs_subsys.su_group); > + config_group_init_type_name(&of_cfs_overlay_group, "overlays", > + &overlays_type); > + configfs_add_default_group(&of_cfs_overlay_group, > + &of_cfs_subsys.su_group); > + > + ret = configfs_register_subsystem(&of_cfs_subsys); > + if (ret != 0) { > + pr_err("%s: failed to register subsys\n", __func__); > + goto out; > + } > + pr_info("%s: OK\n", __func__); > +out: > + return ret; > +} > +late_initcall(of_cfs_init); > -- > 2.27.0 > -- - Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end - "Use the force Harry" - Gandalf, Star Trek II
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#10292): https://lists.yoctoproject.org/g/linux-yocto/message/10292 Mute This Topic: https://lists.yoctoproject.org/mt/84942590/21656 Group Owner: linux-yocto+ow...@lists.yoctoproject.org Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-