Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.
For some boards vendor specific kernel modules exist for
managing device tree overlays but they have not been
upstreamed or upstreaming stalled.
https://lkml.org/lkml/2015/6/12/624
https://lkml.org/lkml/2013/1/7/366
This patch series provides a sysfs based ABI for creation and
destruction of dt overlays in /sys/firmware/devicetree-overlay.
The following files are provided:
load: This is a write only file.
A string written to it is interpreted as the path to a
flattened device tree overlay file. It is used to create
and apply the contained overlays.
loaded: This is a read only file.
It provides the count of loaded overlays as a decimal
number.
unload: This is a write only file.
If a positive number n is wrtten to this file the n
most recent overlays are destroyed.
If a negative number is written to this file all
overlays are destroyed.
Signed-off-by: Heinrich Schuchardt <[email protected]>
Heinrich Schuchardt (3):
of/overlay: add API function to count and pop last
of/overlay: sysfs based ABI for dt overlays
of/overlay: documentation for sysfs ABI
.../ABI/testing/sysfs-firmware-devicetree-overlays | 24 +++
Documentation/devicetree/overlay-notes.txt | 7 +-
drivers/of/Kconfig | 12 ++
drivers/of/Makefile | 2 +
drivers/of/ov_sysfs.c | 212 +++++++++++++++++++++
drivers/of/overlay.c | 50 +++++
include/linux/of.h | 12 ++
7 files changed, 317 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
create mode 100644 drivers/of/ov_sysfs.c
--
2.11.0
To allow building interfaces which are not id based
two new functions are added to the device tree
overlay API:
of_overlay_count - counts the loaded overlays
of_overlay_destroy_last - removes the last overlay loaded
Signed-off-by: Heinrich Schuchardt <[email protected]>
---
Documentation/devicetree/overlay-notes.txt | 7 +++--
drivers/of/overlay.c | 50 ++++++++++++++++++++++++++++++
include/linux/of.h | 12 +++++++
3 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
index d418a6ce9812..7c8099c81e91 100644
--- a/Documentation/devicetree/overlay-notes.txt
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -89,17 +89,20 @@ Overlay in-kernel API
The API is quite easy to use.
-1. Call of_overlay_create() to create and apply an overlay. The return value
+Call of_overlay_create() to create and apply an overlay. The return value
is a cookie identifying this overlay.
-2. Call of_overlay_destroy() to remove and cleanup the overlay previously
+Call of_overlay_destroy() to remove and cleanup the overlay previously
created via the call to of_overlay_create(). Removal of an overlay that
is stacked by another will not be permitted.
+Or call of_overlay_destroy_last() to remove the most recent overlay.
Finally, if you need to remove all overlays in one-go, just call
of_overlay_destroy_all() which will remove every single one in the correct
order.
+Call of_overlay_count() to determine the number of loaded overlays.
+
Overlay DTS Format
------------------
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 0d4cda7050e0..bd30253b26f9 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -587,3 +587,53 @@ int of_overlay_destroy_all(void)
return 0;
}
EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
+
+/**
+ * of_overlay_destroy_last() - Removes the last overlay from the system
+ *
+ * It is allways possible to delete the last overlay.
+ *
+ * Returns 0 on success, or a negative error number
+ */
+int of_overlay_destroy_last(void)
+{
+ struct of_overlay *ov, *ovn;
+ int id;
+
+ mutex_lock(&of_mutex);
+
+ list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
+ id = ov->id;
+ mutex_unlock(&of_mutex);
+ return of_overlay_destroy(id);
+ }
+
+ mutex_unlock(&of_mutex);
+
+ pr_info("destroy: No overlay to destroy");
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_overlay_destroy_last);
+
+/**
+ * of_overlay_count - Counts number of loaded overlays
+ *
+ * Returns number of loaded overlays
+ */
+int of_overlay_count(void)
+{
+ struct of_overlay *ov, *ovn;
+ int count = 0;
+
+ mutex_lock(&of_mutex);
+
+ list_for_each_entry_safe(ov, ovn, &ov_list, node) {
+ ++count;
+ }
+
+ mutex_unlock(&of_mutex);
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(of_overlay_count);
diff --git a/include/linux/of.h b/include/linux/of.h
index d72f01009297..73c8826c543b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1281,15 +1281,22 @@ struct of_overlay_notify_data {
#ifdef CONFIG_OF_OVERLAY
/* ID based overlays; the API for external users */
+int of_overlay_count(void);
int of_overlay_create(struct device_node *tree);
int of_overlay_destroy(int id);
int of_overlay_destroy_all(void);
+int of_overlay_destroy_last(void);
int of_overlay_notifier_register(struct notifier_block *nb);
int of_overlay_notifier_unregister(struct notifier_block *nb);
#else
+static int of_overlay_count(void)
+{
+ return -ENOTSUPP;
+}
+
static inline int of_overlay_create(struct device_node *tree)
{
return -ENOTSUPP;
@@ -1305,6 +1312,11 @@ static inline int of_overlay_destroy_all(void)
return -ENOTSUPP;
}
+static inline int of_overlay_destroy_last(void)
+{
+ return -ENOTSUPP;
+}
+
static inline int of_overlay_notifier_register(struct notifier_block *nb)
{
return 0;
--
2.11.0
The sysfs filesystem ABI to load and unload devicetree
overlays is decribed.
Signed-off-by: Heinrich Schuchardt <[email protected]>
---
.../ABI/testing/sysfs-firmware-devicetree-overlays | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
diff --git a/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
new file mode 100644
index 000000000000..ce25b637028c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
@@ -0,0 +1,24 @@
+What: /sys/firmware/devicetree-overlays
+Date: Dec 2016
+KernelVersion: 4.11
+Contact: Heinrich Schuchardt <[email protected]>
+Description: Devicetree overlays can be used to update the devicetree
+ while the system is running. For details see
+ Documentation/devicetree/overlay-notes.txt.
+
+ The following attributes are provided:
+
+ load: This is a write only file.
+ A string written to it is interpreted as the path to a
+ flattened device tree overlay file. It is used to create
+ and apply the contained overlays.
+
+ loaded: This is a read only file.
+ It provides the count of loaded overlays as a decimal
+ number.
+
+ unload: This is a write only file.
+ If a positive number n is wrtten to this file the n
+ most recent overlays are destroyed.
+ If a negative number is written to this file all
+ overlays are destroyed.
--
2.11.0
Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.
For some boards vendor specific kernel modules exist for
managing device tree overlays but the have not been
upstreamed.
This patch provides a sysfs based ABI for creation and destruction
of dt overlays in /sys/firmware/devicetree-overlay.
The following files are provided:
load: This is a write only file.
A string written to it is interpreted as the path to a
flattened device tree overlay file. It is used to create
and apply the contained overlays.
loaded: This is a read only file.
It provides the count of loaded overlays as a decimal
number.
unload: This is a write only file.
If a positive number n is wrtten to this file the n
most recent overlays are destroyed.
If a negative number is written to this file all
overlays are destroyed.
Signed-off-by: Heinrich Schuchardt <[email protected]>
---
drivers/of/Kconfig | 14 ++++
drivers/of/Makefile | 2 +
drivers/of/ov_sysfs.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/of/ov_sysfs.c
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index ba7b034b2b91..c981a7e84bcb 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -109,6 +109,20 @@ config OF_OVERLAY
While this option is selected automatically when needed, you can
enable it manually to improve device tree unit test coverage.
+if OF_OVERLAY
+
+config OF_OVERLAY_SYSFS
+
+ tristate "Sysfs support for device tree overlays"
+ default m
+ depends on SYSFS
+ help
+ This module provides a sysfs based ABI to manage device tree
+ overlays. You can use it to create overlays based on flattened
+ device tree overlay files and to destroy them.
+
+endif # OF_OVERLAY
+
config OF_NUMA
bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d7efd9d458aa..7026de457a04 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+
+obj-$(CONFIG_OF_OVERLAY_SYSFS) += ov_sysfs.o
diff --git a/drivers/of/ov_sysfs.c b/drivers/of/ov_sysfs.c
new file mode 100644
index 000000000000..eb1b8fd4bc32
--- /dev/null
+++ b/drivers/of/ov_sysfs.c
@@ -0,0 +1,214 @@
+/*
+ * Sysfs ABI for device tree overlays
+ *
+ * Copyright (C) 2016 Heinrich Schuchardt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+static int of_create_overlay_from_file(const char *path)
+{
+ struct file *filp = NULL;
+ mm_segment_t fs;
+ int ret = 0;
+ loff_t size;
+ char *buffer = NULL;
+ ssize_t bytes_read;
+ loff_t offset = 0;
+ struct device_node *overlay = NULL;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto err_file_open;
+ }
+
+ if (!S_ISREG(filp->f_inode->i_mode)) {
+ ret = -EISDIR;
+ goto err_file_read;
+ }
+ size = i_size_read(filp->f_inode);
+ buffer = vmalloc(size);
+ if (buffer == NULL) {
+ ret = -ENOMEM;
+ goto err_malloc;
+ }
+ for (; size > 0; ) {
+ bytes_read = vfs_read(filp, buffer, size, &offset);
+ if (bytes_read == 0)
+ break;
+ if (bytes_read < 0) {
+ ret = bytes_read;
+ goto err_file_read;
+ }
+ size -= bytes_read;
+ }
+ if (offset < sizeof(struct fdt_header) ||
+ offset < fdt_totalsize(buffer)) {
+ pr_err("OF: Size of %s does not match header information\n",
+ path);
+ ret = -EINVAL;
+ goto err_file_read;
+ }
+ overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
+ if (overlay == NULL) {
+ pr_err("OF: Cannot unflatten %s\n", path);
+ ret = -EINVAL;
+ goto err_file_read;
+ }
+ of_node_set_flag(overlay, OF_DETACHED);
+ ret = of_resolve_phandles(overlay);
+ if (ret < 0) {
+ pr_err("OF: Failed to resolve phandles for %s\n", path);
+ goto err_overlay;
+ }
+ ret = of_overlay_create(overlay);
+ if (ret < 0) {
+ pr_err("OF: Cannot create overlay from %s\n", path);
+ } else {
+ pr_info("OF: Overlay %d created from %s\n", ret, path);
+ ret = 0;
+ }
+err_overlay:
+ of_node_put(overlay);
+err_file_read:
+ vfree(buffer);
+err_malloc:
+ fput(filp);
+err_file_open:
+ set_fs(fs);
+ return ret;
+}
+
+static ssize_t attribute_read(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ if (strcmp(attr->attr.name, "loaded") == 0)
+ ret = sprintf(buf, "%d\n", of_overlay_count());
+ else
+ ret = -ENOENT;
+
+ return ret;
+}
+
+static ssize_t attribute_write(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t size)
+{
+ char *parameter;
+ int ret;
+ long count;
+
+ if (size > PATH_MAX)
+ return -ENAMETOOLONG;
+
+ /* The parameter has to be terminated either by LF or \0. */
+
+ switch (buf[size - 1]) {
+ case 0x00:
+ case 0x0a:
+ break;
+ default:
+ return -ENOENT;
+ }
+ parameter = vmalloc(size);
+ if (!parameter)
+ return -ENOMEM;
+ memcpy(parameter, buf, size);
+ parameter[size - 1] = 0x00;
+
+ if (strcmp(attr->attr.name, "load") == 0) {
+ ret = of_create_overlay_from_file(parameter);
+ if (!ret)
+ ret = size;
+ } else if (strcmp(attr->attr.name, "unload") == 0) {
+ ret = kstrtol(parameter, 0, &count);
+ if (ret)
+ goto out;
+ if (count < 0)
+ ret = of_overlay_destroy_all();
+ else
+ for (; count > 0; --count) {
+ ret = of_overlay_destroy_last();
+ if (ret)
+ goto out;
+ }
+ ret = size;
+ } else
+ ret = -ENOENT;
+out:
+ vfree(parameter);
+
+ return ret;
+}
+
+static struct kobject *kobj;
+
+static struct kobj_attribute load_attribute =
+ __ATTR(load, 0200, NULL, attribute_write);
+static struct kobj_attribute loaded_attribute =
+ __ATTR(loaded, 0444, attribute_read, NULL);
+static struct kobj_attribute unload_attribute =
+ __ATTR(unload, 0200, NULL, attribute_write);
+static struct attribute *attrs[] = {
+ &load_attribute.attr,
+ &loaded_attribute.attr,
+ &unload_attribute.attr,
+ NULL
+};
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+static int __init ov_sysfs_init(void)
+{
+ int ret;
+
+ kobj = kobject_create_and_add("devicetree-overlays", firmware_kobj);
+ if (kobj == 0)
+ return -ENOMEM;
+ ret = sysfs_create_group(kobj, &attr_group);
+ if (ret) {
+ kobject_put(kobj);
+ return ret;
+ }
+
+ /*
+ * It is not possible to ensure that no sysfs io is started while
+ * module_exit is called. So disable unloading.
+ */
+ __module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static void __exit ov_sysfs_exit(void)
+{
+ kobject_put(kobj);
+}
+
+module_init(ov_sysfs_init);
+module_exit(ov_sysfs_exit);
+
+MODULE_AUTHOR("Heinrich Schuchardt <[email protected]>");
+MODULE_DESCRIPTION("Sysfs ABI for device tree overlays");
+MODULE_LICENSE("GPL");
--
2.11.0
Hi Heinrich,
[auto build test ERROR on linus/master]
[also build test ERROR on next-20161216]
[cannot apply to glikely/devicetree/next robh/for-next v4.9]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Heinrich-Schuchardt/of-overlay-sysfs-based-ABI-for-dt-overlays/20161219-093606
config: i386-randconfig-s1-201651 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
In file included from include/linux/irqdomain.h:34:0,
from include/linux/i2c.h:33,
from include/uapi/linux/fb.h:5,
from include/linux/fb.h:5,
from include/linux/vga_switcheroo.h:34,
from drivers/gpu/drm/i915/i915_drv.c:40:
>> include/linux/of.h:1295:12: error: 'of_overlay_count' defined but not used [-Werror=unused-function]
static int of_overlay_count(void)
^~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
vim +/of_overlay_count +1295 include/linux/of.h
1289
1290 int of_overlay_notifier_register(struct notifier_block *nb);
1291 int of_overlay_notifier_unregister(struct notifier_block *nb);
1292
1293 #else
1294
> 1295 static int of_overlay_count(void)
1296 {
1297 return -ENOTSUPP;
1298 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Heinrich,
[auto build test ERROR on linus/master]
[also build test ERROR on next-20161216]
[cannot apply to glikely/devicetree/next robh/for-next v4.9]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Heinrich-Schuchardt/of-overlay-sysfs-based-ABI-for-dt-overlays/20161219-093606
config: i386-randconfig-r0-12190124 (attached as .config)
compiler: gcc-5 (Debian 5.4.1-2) 5.4.1 20160904
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All error/warnings (new ones prefixed by >>):
drivers/of/ov_sysfs.c: In function 'of_create_overlay_from_file':
drivers/of/ov_sysfs.c:69:12: error: implicit declaration of function 'of_fdt_unflatten_tree' [-Werror=implicit-function-declaration]
overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
^
>> drivers/of/ov_sysfs.c:69:10: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
^
cc1: some warnings being treated as errors
vim +/of_fdt_unflatten_tree +69 drivers/of/ov_sysfs.c
63 offset < fdt_totalsize(buffer)) {
64 pr_err("OF: Size of %s does not match header information\n",
65 path);
66 ret = -EINVAL;
67 goto err_file_read;
68 }
> 69 overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
70 if (overlay == NULL) {
71 pr_err("OF: Cannot unflatten %s\n", path);
72 ret = -EINVAL;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
On 12/19/2016 03:34 AM, kbuild test robot wrote:
> Hi Heinrich,
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on next-20161216]
> [cannot apply to glikely/devicetree/next robh/for-next v4.9]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Heinrich-Schuchardt/of-overlay-sysfs-based-ABI-for-dt-overlays/20161219-093606
> config: i386-randconfig-r0-12190124 (attached as .config)
> compiler: gcc-5 (Debian 5.4.1-2) 5.4.1 20160904
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All error/warnings (new ones prefixed by >>):
>
> drivers/of/ov_sysfs.c: In function 'of_create_overlay_from_file':
> drivers/of/ov_sysfs.c:69:12: error: implicit declaration of function 'of_fdt_unflatten_tree' [-Werror=implicit-function-declaration]
select OF_EARLY_FLATTREE
is missing in Kconfig. It is automatically selected on ARM64 but not on
other architectures.
> overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
> ^
>>> drivers/of/ov_sysfs.c:69:10: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
> overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
> ^
> cc1: some warnings being treated as errors
>
> vim +/of_fdt_unflatten_tree +69 drivers/of/ov_sysfs.c
>
> 63 offset < fdt_totalsize(buffer)) {
> 64 pr_err("OF: Size of %s does not match header information\n",
> 65 path);
> 66 ret = -EINVAL;
> 67 goto err_file_read;
> 68 }
> > 69 overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
> 70 if (overlay == NULL) {
> 71 pr_err("OF: Cannot unflatten %s\n", path);
> 72 ret = -EINVAL;
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
>