diff options
Diffstat (limited to 'recipes-kernel/linux/linux-at91-5.4.195/linux-5.4-OF-DT-Overlay-configfs-interface.patch')
-rw-r--r-- | recipes-kernel/linux/linux-at91-5.4.195/linux-5.4-OF-DT-Overlay-configfs-interface.patch | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-at91-5.4.195/linux-5.4-OF-DT-Overlay-configfs-interface.patch b/recipes-kernel/linux/linux-at91-5.4.195/linux-5.4-OF-DT-Overlay-configfs-interface.patch new file mode 100644 index 0000000..b818a7c --- /dev/null +++ b/recipes-kernel/linux/linux-at91-5.4.195/linux-5.4-OF-DT-Overlay-configfs-interface.patch @@ -0,0 +1,411 @@ +From 746f647c66dc4501b6a2954ffd22a8a0555d10a2 Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou <pantelis.antoniou@konsulko.com> +Date: Wed, 4 Dec 2013 19:32:00 +0200 +Subject: OF: DT-Overlay configfs interface (v7) + +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 <geert@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.antoniou@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+renesas@glider.be> +--- + Documentation/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 0000000000000..185d85ef52e49 +--- /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 18450437d5d5a..303737ebce435 100644 +--- a/drivers/of/Kconfig ++++ b/drivers/of/Kconfig +@@ -93,6 +93,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 6e1e5212f0589..3222259b03932 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 0000000000000..7a6cae074381c +--- /dev/null ++++ b/drivers/of/configfs.c +@@ -0,0 +1,284 @@ ++/* ++ * Configfs entries for device-tree ++ * ++ * Copyright (C) 2013 - Pantelis Antoniou <panto@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); +-- +cgit 1.2.3-1.el7 + |