linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
To: Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Frank Rowand <frowand.list@gmail.com>
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Heinrich Schuchardt <xypron.glpk@gmx.de>
Subject: [PATCH 2/3] of/overlay: sysfs based ABI for dt overlays
Date: Mon, 19 Dec 2016 02:10:34 +0100	[thread overview]
Message-ID: <1482109835-9000-3-git-send-email-xypron.glpk@gmx.de> (raw)
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>

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 <xypron.glpk@gmx.de>
---
 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 <xypron.glpk@gmx.de>
+ *
+ * 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 <xypron.glpk@gmx.de>");
+MODULE_DESCRIPTION("Sysfs ABI for device tree overlays");
+MODULE_LICENSE("GPL");
-- 
2.11.0

  parent reply	other threads:[~2016-12-19  1:13 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-19  1:10 [PATCH 0/3] of/overlay: sysfs based ABI for dt overlays Heinrich Schuchardt
2016-12-19  1:10 ` [PATCH 1/3] of/overlay: add API function to count and pop last Heinrich Schuchardt
2016-12-19  2:15   ` kbuild test robot
2016-12-19  1:10 ` Heinrich Schuchardt [this message]
2016-12-19  2:34   ` [PATCH 2/3] of/overlay: sysfs based ABI for dt overlays kbuild test robot
2016-12-19  8:03     ` Heinrich Schuchardt
2016-12-19  1:10 ` [PATCH 3/3] of/overlay: documentation for sysfs ABI Heinrich Schuchardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1482109835-9000-3-git-send-email-xypron.glpk@gmx.de \
    --to=xypron.glpk@gmx.de \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).