* [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
@ 2014-03-18 21:55 Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 1/7] OF: Introduce Device Tree resolve support Pantelis Antoniou
` (7 more replies)
0 siblings, 8 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:55 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
The following patchset introduces Device Tree overlays, a method
of dynamically altering the kernel's live Device Tree, along with
a generic interface to use it in a board agnostic manner.
It is dependent on Grant Likely's DT kobjectification patches located
in his tree as queued for -next.
It relies on the following previously submitted patches/patchsets:
* OF: Add [__]of_find_node_by_full_name
* OF: Utility helper functions for dynamic nodes
* of: Make of_find_node_by_path() handle /aliases
To compile overlays you need the DTC compiler patch
* "dtc: Dynamic symbols & fixup support (v2)"
Changes since V2:
* Use of a configfs board agnostic overlay method
* Use of per bus handlers instead of hardcoded behaviour
* Optional target-path overlay target, which allows one to use standard
DTBs without resolution options.
Changes since V1:
* Removal of any bits related to a specific board (beaglebone).
* Introduced a platform agnostic interface using /proc/device-tree-overlay
* Various bug fixes related to i2c device handling have been squashed in.
Pantelis Antoniou (7):
OF: Introduce Device Tree resolve support.
OF: Introduce DT overlay support.
OF: DT-Overlay configfs interface
OF: platform: Add overlay bus handler
OF: i2c: Add overlay bus handler
OF: spi: Add overlay bus handler
of: i2c: Export single device registration method
.../devicetree/dynamic-resolution-notes.txt | 25 +
Documentation/devicetree/overlay-notes.txt | 187 +++++
drivers/base/platform.c | 99 ++-
drivers/i2c/i2c-core.c | 186 +++--
drivers/of/Kconfig | 24 +
drivers/of/Makefile | 3 +
drivers/of/configfs.c | 272 +++++++
drivers/of/overlay.c | 895 +++++++++++++++++++++
drivers/of/resolver.c | 376 +++++++++
drivers/spi/spi.c | 345 +++++---
include/linux/i2c.h | 10 +
include/linux/of.h | 170 ++++
12 files changed, 2440 insertions(+), 152 deletions(-)
create mode 100644 Documentation/devicetree/dynamic-resolution-notes.txt
create mode 100644 Documentation/devicetree/overlay-notes.txt
create mode 100644 drivers/of/configfs.c
create mode 100644 drivers/of/overlay.c
create mode 100644 drivers/of/resolver.c
--
1.7.12
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 1/7] OF: Introduce Device Tree resolve support.
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
@ 2014-03-18 21:56 ` Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 2/7] OF: Introduce DT overlay support Pantelis Antoniou
` (6 subsequent siblings)
7 siblings, 0 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Introduce support for dynamic device tree resolution.
Using it, it is possible to prepare a device tree that's
been loaded on runtime to be modified and inserted at the kernel
live tree.
Export of of_resolve by Guenter Roeck <groeck@juniper.net>
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
.../devicetree/dynamic-resolution-notes.txt | 25 ++
drivers/of/Kconfig | 9 +
drivers/of/Makefile | 1 +
drivers/of/resolver.c | 376 +++++++++++++++++++++
include/linux/of.h | 17 +
5 files changed, 428 insertions(+)
create mode 100644 Documentation/devicetree/dynamic-resolution-notes.txt
create mode 100644 drivers/of/resolver.c
diff --git a/Documentation/devicetree/dynamic-resolution-notes.txt b/Documentation/devicetree/dynamic-resolution-notes.txt
new file mode 100644
index 0000000..0b396c4
--- /dev/null
+++ b/Documentation/devicetree/dynamic-resolution-notes.txt
@@ -0,0 +1,25 @@
+Device Tree Dynamic Resolver Notes
+----------------------------------
+
+This document describes the implementation of the in-kernel
+Device Tree resolver, residing in drivers/of/resolver.c and is a
+companion document to Documentation/devicetree/dt-object-internal.txt[1]
+
+How the resolver works
+----------------------
+
+The resolver is given as an input an arbitrary tree compiled with the
+proper dtc option and having a /plugin/ tag. This generates the
+appropriate __fixups__ & __local_fixups__ nodes as described in [1].
+
+In sequence the resolver works by the following steps:
+
+1. Get the maximum device tree phandle value from the live tree + 1.
+2. Adjust all the local phandles of the tree to resolve by that amount.
+3. Using the __local__fixups__ node information adjust all local references
+ by the same amount.
+4. For each property in the __fixups__ node locate the node it references
+ in the live tree. This is the label used to tag the node.
+5. Retrieve the phandle of the target of the fixup.
+5. For each fixup in the property locate the node:property:offset location
+ and replace it with the phandle value.
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 889005f..33a8fef 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -77,4 +77,13 @@ config OF_RESERVED_MEM
help
Helpers to allow for reservation of memory regions
+config OF_RESOLVE
+ bool "OF Dynamic resolution support"
+ depends on OF
+ select OF_DYNAMIC
+ select OF_DEVICE
+ help
+ Enable OF dynamic resolution support. This allows you to
+ load Device Tree object fragments are run time.
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 26de2ed..c241e79 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
+obj-$(CONFIG_OF_RESOLVE) += resolver.o
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
new file mode 100644
index 0000000..14fbbd3
--- /dev/null
+++ b/drivers/of/resolver.c
@@ -0,0 +1,376 @@
+/*
+ * Functions for dealing with DT resolution
+ *
+ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
+ * Copyright (C) 2012 Texas Instruments Inc.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/**
+ * Find live tree's maximum phandle value.
+ */
+static phandle of_get_tree_max_phandle(void)
+{
+ struct device_node *node;
+ phandle phandle;
+ unsigned long flags;
+
+ /* now search recursively */
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ phandle = 0;
+ for_each_of_allnodes(node) {
+ if (node->phandle != OF_PHANDLE_ILLEGAL &&
+ node->phandle > phandle)
+ phandle = node->phandle;
+ }
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+ return phandle;
+}
+
+/**
+ * Adjust a subtree's phandle values by a given delta.
+ * Makes sure not to just adjust the device node's phandle value,
+ * but modify the phandle properties values as well.
+ */
+static void __of_adjust_tree_phandles(struct device_node *node,
+ int phandle_delta)
+{
+ struct device_node *child;
+ struct property *prop;
+ phandle phandle;
+
+ /* first adjust the node's phandle direct value */
+ if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
+ node->phandle += phandle_delta;
+
+ /* now adjust phandle & linux,phandle values */
+ for_each_property_of_node(node, prop) {
+
+ /* only look for these two */
+ if (of_prop_cmp(prop->name, "phandle") != 0 &&
+ of_prop_cmp(prop->name, "linux,phandle") != 0)
+ continue;
+
+ /* must be big enough */
+ if (prop->length < 4)
+ continue;
+
+ /* read phandle value */
+ phandle = be32_to_cpu(*(uint32_t *)prop->value);
+ if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */
+ continue;
+
+ /* adjust */
+ *(uint32_t *)prop->value = cpu_to_be32(node->phandle);
+ }
+
+ /* now do the children recursively */
+ __for_each_child_of_node(node, child)
+ __of_adjust_tree_phandles(child, phandle_delta);
+}
+
+/**
+ * Adjust the local phandle references by the given phandle delta.
+ * Assumes the existances of a __local_fixups__ node at the root
+ * of the tree. Does not take any devtree locks so make sure you
+ * call this on a tree which is at the detached state.
+ */
+static int __of_adjust_tree_phandle_references(struct device_node *node,
+ int phandle_delta)
+{
+ phandle phandle;
+ struct device_node *refnode, *child;
+ struct property *rprop, *sprop;
+ char *propval, *propcur, *propend, *nodestr, *propstr, *s;
+ int offset, propcurlen;
+ int err;
+
+ /* locate the symbols & fixups nodes on resolve */
+ __for_each_child_of_node(node, child)
+ if (of_node_cmp(child->name, "__local_fixups__") == 0)
+ break;
+
+ /* no local fixups */
+ if (child == NULL)
+ return 0;
+
+ /* find the local fixups property */
+ for_each_property_of_node(child, rprop) {
+
+ /* skip properties added automatically */
+ if (of_prop_cmp(rprop->name, "name") == 0)
+ continue;
+
+ /* make a copy */
+ propval = kmalloc(rprop->length, GFP_KERNEL);
+ if (propval == NULL) {
+ pr_err("%s: Could not copy value of '%s'\n",
+ __func__, rprop->name);
+ return -ENOMEM;
+ }
+ memcpy(propval, rprop->value, rprop->length);
+
+ propend = propval + rprop->length;
+ for (propcur = propval; propcur < propend;
+ propcur += propcurlen + 1) {
+
+ propcurlen = strlen(propcur);
+
+ nodestr = propcur;
+ s = strchr(propcur, ':');
+ if (s == NULL) {
+ pr_err("%s: Illegal symbol entry '%s' (1)\n",
+ __func__, propcur);
+ err = -EINVAL;
+ goto err_fail;
+ }
+ *s++ = '\0';
+
+ propstr = s;
+ s = strchr(s, ':');
+ if (s == NULL) {
+ pr_err("%s: Illegal symbol entry '%s' (2)\n",
+ __func__, (char *)rprop->value);
+ err = -EINVAL;
+ goto err_fail;
+ }
+
+ *s++ = '\0';
+ offset = simple_strtoul(s, NULL, 10);
+
+ /* look into the resolve node for the full path */
+ refnode = __of_find_node_by_full_name(node, nodestr);
+ if (refnode == NULL) {
+ pr_warn("%s: Could not find refnode '%s'\n",
+ __func__, (char *)rprop->value);
+ continue;
+ }
+
+ /* now find the property */
+ for_each_property_of_node(refnode, sprop) {
+ if (of_prop_cmp(sprop->name, propstr) == 0)
+ break;
+ }
+
+ if (sprop == NULL) {
+ pr_err("%s: Could not find property '%s'\n",
+ __func__, (char *)rprop->value);
+ err = -ENOENT;
+ goto err_fail;
+ }
+
+ phandle = be32_to_cpu(*(uint32_t *)
+ (sprop->value + offset));
+ *(uint32_t *)(sprop->value + offset) =
+ cpu_to_be32(phandle + phandle_delta);
+ }
+
+ kfree(propval);
+ }
+
+ return 0;
+
+err_fail:
+ kfree(propval);
+ return err;
+}
+
+/**
+ * of_resolve - Resolve the given node against the live tree.
+ *
+ * @resolve: Node to resolve
+ *
+ * Perform dynamic Device Tree resolution against the live tree
+ * to the given node to resolve. This depends on the live tree
+ * having a __symbols__ node, and the resolve node the __fixups__ &
+ * __local_fixups__ nodes (if needed).
+ * The result of the operation is a resolve node that it's contents
+ * are fit to be inserted or operate upon the live tree.
+ * Returns 0 on success or a negative error value on error.
+ */
+int of_resolve(struct device_node *resolve)
+{
+ struct device_node *child, *refnode;
+ struct device_node *root_sym, *resolve_sym, *resolve_fix;
+ struct property *rprop, *sprop;
+ const char *refpath;
+ char *propval, *propcur, *propend, *nodestr, *propstr, *s;
+ int offset, propcurlen;
+ phandle phandle, phandle_delta;
+ int err;
+
+ /* the resolve node must exist, and be detached */
+ if (resolve == NULL ||
+ !of_node_check_flag(resolve, OF_DETACHED)) {
+ return -EINVAL;
+ }
+
+ /* first we need to adjust the phandles */
+ phandle_delta = of_get_tree_max_phandle() + 1;
+ __of_adjust_tree_phandles(resolve, phandle_delta);
+ err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
+ if (err != 0)
+ return err;
+
+ root_sym = NULL;
+ resolve_sym = NULL;
+ resolve_fix = NULL;
+
+ /* this may fail (if no fixups are required) */
+ root_sym = of_find_node_by_path("/__symbols__");
+
+ /* locate the symbols & fixups nodes on resolve */
+ __for_each_child_of_node(resolve, child) {
+
+ if (resolve_sym == NULL &&
+ of_node_cmp(child->name, "__symbols__") == 0)
+ resolve_sym = child;
+
+ if (resolve_fix == NULL &&
+ of_node_cmp(child->name, "__fixups__") == 0)
+ resolve_fix = child;
+
+ /* both found, don't bother anymore */
+ if (resolve_sym != NULL && resolve_fix != NULL)
+ break;
+ }
+
+ /* we do allow for the case where no fixups are needed */
+ if (resolve_fix == NULL)
+ goto merge_sym;
+
+ /* we need to fixup, but no root symbols... */
+ if (root_sym == NULL)
+ return -EINVAL;
+
+ for_each_property_of_node(resolve_fix, rprop) {
+
+ /* skip properties added automatically */
+ if (of_prop_cmp(rprop->name, "name") == 0)
+ continue;
+
+ err = of_property_read_string(root_sym,
+ rprop->name, &refpath);
+ if (err != 0) {
+ pr_err("%s: Could not find symbol '%s'\n",
+ __func__, rprop->name);
+ goto err_fail;
+ }
+
+ refnode = of_find_node_by_path(refpath);
+ if (refnode == NULL) {
+ pr_err("%s: Could not find node by path '%s'\n",
+ __func__, refpath);
+ err = -ENOENT;
+ goto err_fail;
+ }
+
+ phandle = refnode->phandle;
+ of_node_put(refnode);
+
+ pr_debug("%s: %s phandle is 0x%08x\n",
+ __func__, rprop->name, phandle);
+
+ /* make a copy */
+ propval = kmalloc(rprop->length, GFP_KERNEL);
+ if (propval == NULL) {
+ pr_err("%s: Could not copy value of '%s'\n",
+ __func__, rprop->name);
+ err = -ENOMEM;
+ goto err_fail;
+ }
+
+ memcpy(propval, rprop->value, rprop->length);
+
+ propend = propval + rprop->length;
+ for (propcur = propval; propcur < propend;
+ propcur += propcurlen + 1) {
+ propcurlen = strlen(propcur);
+
+ nodestr = propcur;
+ s = strchr(propcur, ':');
+ if (s == NULL) {
+ pr_err("%s: Illegal symbol "
+ "entry '%s' (1)\n",
+ __func__, (char *)rprop->value);
+ kfree(propval);
+ err = -EINVAL;
+ goto err_fail;
+ }
+ *s++ = '\0';
+
+ propstr = s;
+ s = strchr(s, ':');
+ if (s == NULL) {
+ pr_err("%s: Illegal symbol "
+ "entry '%s' (2)\n",
+ __func__, (char *)rprop->value);
+ kfree(propval);
+ err = -EINVAL;
+ goto err_fail;
+ }
+
+ *s++ = '\0';
+ offset = simple_strtoul(s, NULL, 10);
+
+ /* look into the resolve node for the full path */
+ refnode = __of_find_node_by_full_name(resolve,
+ nodestr);
+ if (refnode == NULL) {
+ pr_err("%s: Could not find refnode '%s'\n",
+ __func__, (char *)rprop->value);
+ kfree(propval);
+ err = -ENOENT;
+ goto err_fail;
+ }
+
+ /* now find the property */
+ for_each_property_of_node(refnode, sprop) {
+ if (of_prop_cmp(sprop->name, propstr) == 0)
+ break;
+ }
+
+ if (sprop == NULL) {
+ pr_err("%s: Could not find property '%s'\n",
+ __func__, (char *)rprop->value);
+ kfree(propval);
+ err = -ENOENT;
+ goto err_fail;
+ }
+
+ *(uint32_t *)(sprop->value + offset) =
+ cpu_to_be32(phandle);
+ }
+
+ kfree(propval);
+ }
+
+merge_sym:
+
+ of_node_put(root_sym);
+
+ return 0;
+
+err_fail:
+
+ if (root_sym != NULL)
+ of_node_put(root_sym);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(of_resolve);
diff --git a/include/linux/of.h b/include/linux/of.h
index 9a55889..4932a8f 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -735,4 +735,21 @@ static inline struct device_node *__of_create_empty_node( const char *name,
#endif /* !CONFIG_OF */
+
+/* illegal phandle value (set when unresolved) */
+#define OF_PHANDLE_ILLEGAL 0xdeadbeef
+
+#ifdef CONFIG_OF_RESOLVE
+
+int of_resolve(struct device_node *resolve);
+
+#else
+
+static inline int of_resolve(struct device_node *resolve)
+{
+ return -ENOTSUPP;
+}
+
+#endif
+
#endif /* _LINUX_OF_H */
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 2/7] OF: Introduce DT overlay support.
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 1/7] OF: Introduce Device Tree resolve support Pantelis Antoniou
@ 2014-03-18 21:56 ` Pantelis Antoniou
2014-03-28 14:51 ` delicious quinoa
2014-03-28 18:54 ` delicious quinoa
2014-03-18 21:56 ` [PATCH v3 3/7] OF: DT-Overlay configfs interface Pantelis Antoniou
` (5 subsequent siblings)
7 siblings, 2 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Introduce DT overlay support.
Using this functionality it is possible to dynamically overlay a part of
the kernel's tree with another tree that's been dynamically loaded.
It is also possible to remove node and properties.
The creation/destruction of the devices is handled by calling in to
bus specific handlers which can deal with the peculiarities of each
device.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
Documentation/devicetree/overlay-notes.txt | 187 ++++++
drivers/of/Kconfig | 10 +
drivers/of/Makefile | 1 +
drivers/of/overlay.c | 895 +++++++++++++++++++++++++++++
include/linux/of.h | 153 +++++
5 files changed, 1246 insertions(+)
create mode 100644 Documentation/devicetree/overlay-notes.txt
create mode 100644 drivers/of/overlay.c
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
new file mode 100644
index 0000000..882d512
--- /dev/null
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -0,0 +1,187 @@
+Device Tree Overlay Notes
+-------------------------
+
+This document describes the implementation of the in-kernel
+device tree overlay functionality residing in drivers/of/overlay.c and is a
+companion document to Documentation/devicetree/dt-object-internal.txt[1] &
+Documentation/devicetree/dynamic-resolution-notes.txt[2]
+
+How overlays work
+-----------------
+
+A Device Tree's overlay purpose is to modify the kernel's live tree, and
+have the modification affecting the state of the the kernel in a way that
+is reflecting the changes.
+Since the kernel mainly deals with devices, any new device node that result
+in an active device should have it created while if the device node is either
+disabled or removed all together, the affected device should be deregistered.
+
+Lets take an example where we have a foo board with the following base tree
+which is taken from [1].
+
+---- foo.dts -----------------------------------------------------------------
+ /* FOO platform */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+ }
+ };
+---- foo.dts -----------------------------------------------------------------
+
+The overlay bar.dts, when loaded (and resolved as described in [2]) should
+
+---- bar.dts -----------------------------------------------------------------
+/plugin/; /* allow undefined label references and record them */
+/ {
+ .... /* various properties for loader use; i.e. part id etc. */
+ fragment@0 {
+ target = <&ocp>;
+ __overlay__ {
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ };
+ };
+};
+---- bar.dts -----------------------------------------------------------------
+
+result in foo+bar.dts
+
+---- foo+bar.dts -------------------------------------------------------------
+ /* FOO platform + bar peripheral */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ }
+ };
+---- foo+bar.dts -------------------------------------------------------------
+
+As a result of the the overlay, a new device node (bar) has been created
+so a bar platform device will be registered and if a matching device driver
+is loaded the device will be created as expected.
+
+Overlay in-kernel API
+---------------------
+
+The steps typically required to get an overlay to work are as follows:
+
+1. Use of_build_overlay_info() to create an array of initialized and
+ready to use of_overlay_info structures.
+2. Call of_overlay() to apply the overlays declared in the array.
+3. If the overlay needs to be removed, call of_overlay_revert().
+4. Finally release the memory taken by the overlay info array by
+of_free_overlay_info().
+
+/**
+ * of_build_overlay_info - Build an overlay info array
+ * @tree: Device node containing all the overlays
+ * @cntp: Pointer to where the overlay info count will be help
+ * @ovinfop: Pointer to the pointer of an overlay info structure.
+ *
+ * Helper function that given a tree containing overlay information,
+ * allocates and builds an overlay info array containing it, ready
+ * for use using of_overlay.
+ *
+ * Returns 0 on success with the @cntp @ovinfop pointers valid,
+ * while on error a negative error value is returned.
+ */
+int of_build_overlay_info(struct device_node *tree,
+ int *cntp, struct of_overlay_info **ovinfop);
+
+/**
+ * of_free_overlay_info - Free an overlay info array
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to free
+ *
+ * Releases the memory of a previously allocate ovinfo array
+ * by of_build_overlay_info.
+ * Returns 0, or an error if the arguments are bogus.
+ */
+int of_free_overlay_info(int count, struct of_overlay_info *ovinfo_tab);
+
+/**
+ * of_overlay - Apply @count overlays pointed at by @ovinfo_tab
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to apply
+ *
+ * Applies the overlays given, while handling all error conditions
+ * appropriately. Either the operation succeeds, or if it fails the
+ * live tree is reverted to the state before the attempt.
+ * Returns 0, or an error if the overlay attempt failed.
+ */
+int of_overlay(int count, struct of_overlay_info *ovinfo_tab);
+
+/**
+ * of_overlay_revert - Revert a previously applied overlay
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to apply
+ *
+ * Revert a previous overlay. The state of the live tree
+ * is reverted to the one before the overlay.
+ * Returns 0, or an error if the overlay table is not given.
+ */
+int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab);
+
+Overlay DTS Format
+------------------
+
+The DTS of an overlay should have the following format:
+
+{
+ /* ignored properties by the overlay */
+
+ fragment@0 { /* first child node */
+
+ target=<phandle>; /* phandle target of the overlay */
+ or
+ target-path="/path"; /* target path of the overlay */
+ or
+ target-alias="alias"; /* target alias of the overlay */
+ __overlay__ {
+ property-a; /* add property-a to the target */
+ -property-b; /* remove property-b from target */
+ node-a { /* add to an existing, or create a node-a */
+ ...
+ };
+ -node-b { /* remove an existing node-b */
+ ...
+ };
+ };
+ }
+ fragment@1 { /* second child node */
+ ...
+ };
+ /* more fragments follow */
+}
+
+It should be noted that the DT overlay format described is the one expected
+by the of_build_overlay_info() function, which is a helper function. There
+is nothing stopping someone coming up with his own DTS format and that will
+end up filling in the fields of the of_overlay_info array.
+
+Using the non-phandle based target method allows one to use a base DT which does
+not contain a __symbols__ now, i.e. it was not compiled with the -@ option.
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 33a8fef..7517be2 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -86,4 +86,14 @@ config OF_RESOLVE
Enable OF dynamic resolution support. This allows you to
load Device Tree object fragments are run time.
+config OF_OVERLAY
+ bool "OF overlay support"
+ depends on OF
+ select OF_DYNAMIC
+ select OF_DEVICE
+ select OF_RESOLVE
+ help
+ OpenFirmware overlay support. Allows you to modify on runtime the
+ live tree using overlays.
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c241e79..d2a6e0d 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
+obj-$(CONFIG_OF_OVERLAY) += overlay.o
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
new file mode 100644
index 0000000..2179b9f
--- /dev/null
+++ b/drivers/of/overlay.c
@@ -0,0 +1,895 @@
+/*
+ * Functions for working with device tree overlays
+ *
+ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
+ * Copyright (C) 2012 Texas Instruments Inc.
+ *
+ * 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.
+ */
+#undef DEBUG
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+/* protect the handlers list */
+static DEFINE_MUTEX(of_handler_mutex);
+static struct list_head of_handler_list = LIST_HEAD_INIT(of_handler_list);
+
+int of_overlay_handler_register(struct of_overlay_handler *handler)
+{
+ /* guard against bad data */
+ if (!handler || !handler->name || !handler->ops ||
+ !handler->ops->create || !handler->ops->remove)
+ return -EINVAL;
+
+ mutex_lock(&of_handler_mutex);
+ list_add_tail(&handler->list, &of_handler_list);
+ mutex_unlock(&of_handler_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_overlay_handler_register);
+
+void of_overlay_handler_unregister(struct of_overlay_handler *handler)
+{
+ struct of_overlay_handler *curr;
+
+ mutex_lock(&of_handler_mutex);
+ list_for_each_entry(curr, &of_handler_list, list) {
+ if (handler == curr) {
+ list_del(&handler->list);
+ break;
+ }
+ }
+ mutex_unlock(&of_handler_mutex);
+}
+EXPORT_SYMBOL_GPL(of_overlay_handler_unregister);
+
+static int handler_create(struct of_overlay_device_entry *entry, int revert)
+{
+ struct of_overlay_handler *handler;
+ int ret;
+
+ mutex_lock(&of_handler_mutex);
+ list_for_each_entry(handler, &of_handler_list, list) {
+ ret = (*handler->ops->create)(entry, revert);
+ /* ENOTSUPP means try next */
+ if (ret == -ENOTSUPP)
+ continue;
+ /* anything else means something happened */
+ break;
+ }
+ mutex_unlock(&of_handler_mutex);
+
+ return ret;
+}
+
+static int handler_remove(struct of_overlay_device_entry *entry, int revert)
+{
+ struct of_overlay_handler *handler;
+ int ret;
+
+ mutex_lock(&of_handler_mutex);
+ list_for_each_entry(handler, &of_handler_list, list) {
+ ret = (*handler->ops->remove)(entry, revert);
+ /* ENOTSUPP means try next */
+ if (ret == -ENOTSUPP)
+ continue;
+ /* anything else means something happened */
+ break;
+ }
+ mutex_unlock(&of_handler_mutex);
+
+ return ret;
+}
+
+/**
+ * Apply a single overlay node recursively.
+ *
+ * Property or node names that start with '-' signal that
+ * the property/node is to be removed.
+ *
+ * All the property notifiers are appropriately called.
+ * Note that the in case of an error the target node is left
+ * in a inconsistent state. Error recovery should be performed
+ * by recording the modification using the of notifiers.
+ */
+static int of_overlay_apply_one(struct device_node *target,
+ const struct device_node *overlay)
+{
+ const char *pname, *cname;
+ struct device_node *child, *tchild;
+ struct property *prop, *propn, *tprop;
+ int remove;
+ char *full_name;
+ const char *suffix;
+ int ret;
+
+ /* sanity checks */
+ if (target == NULL || overlay == NULL)
+ return -EINVAL;
+
+ for_each_property_of_node(overlay, prop) {
+
+ /* don't touch, 'name' */
+ if (of_prop_cmp(prop->name, "name") == 0)
+ continue;
+
+ /* default is add */
+ remove = 0;
+ pname = prop->name;
+ if (*pname == '-') { /* skip, - notes removal */
+ pname++;
+ remove = 1;
+ propn = NULL;
+ } else {
+ propn = __of_copy_property(prop, GFP_KERNEL,
+ OF_PROP_ALLOCALL);
+ if (propn == NULL)
+ return -ENOMEM;
+ }
+
+ tprop = of_find_property(target, pname, NULL);
+
+ /* found? */
+ if (tprop != NULL) {
+ if (propn != NULL)
+ ret = of_update_property(target, propn);
+ else
+ ret = of_remove_property(target, tprop);
+ } else {
+ if (propn != NULL)
+ ret = of_add_property(target, propn);
+ else
+ ret = 0;
+ }
+ if (ret != 0)
+ return ret;
+ }
+
+ __for_each_child_of_node(overlay, child) {
+
+ /* default is add */
+ remove = 0;
+ cname = child->name;
+ if (*cname == '-') { /* skip, - notes removal */
+ cname++;
+ remove = 1;
+ }
+
+ /* special case for nodes with a suffix */
+ suffix = strrchr(child->full_name, '@');
+ if (suffix != NULL) {
+ cname = kbasename(child->full_name);
+ WARN_ON(cname == NULL); /* sanity check */
+ if (cname == NULL)
+ continue;
+ if (*cname == '-')
+ cname++;
+ }
+
+ tchild = of_get_child_by_name(target, cname);
+ if (tchild != NULL) {
+
+ if (!remove) {
+
+ /* apply overlay recursively */
+ ret = of_overlay_apply_one(tchild, child);
+ of_node_put(tchild);
+
+ if (ret != 0)
+ return ret;
+
+ } else {
+
+ ret = of_detach_node(tchild);
+ of_node_put(tchild);
+ }
+
+ } else {
+
+ if (!remove) {
+ full_name = kasprintf(GFP_KERNEL, "%s/%s",
+ target->full_name, cname);
+ if (full_name == NULL)
+ return -ENOMEM;
+
+ /* create empty tree as a target */
+ tchild = __of_create_empty_node(cname,
+ child->type, full_name,
+ child->phandle, GFP_KERNEL,
+ OF_NODE_ALLOCALL);
+
+ /* free either way */
+ kfree(full_name);
+
+ if (tchild == NULL)
+ return -ENOMEM;
+
+ /* point to parent */
+ tchild->parent = target;
+
+ ret = of_attach_node(tchild);
+ if (ret != 0)
+ return ret;
+
+ /* apply the overlay */
+ ret = of_overlay_apply_one(tchild, child);
+ if (ret != 0) {
+ __of_free_tree(tchild);
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Lookup an overlay device entry
+ */
+struct of_overlay_device_entry *of_overlay_device_entry_lookup(
+ struct of_overlay_info *ovinfo, struct device_node *node)
+{
+ struct of_overlay_device_entry *de;
+
+ /* no need for locks, we'de under the ovinfo->lock */
+ list_for_each_entry(de, &ovinfo->de_list, node) {
+ if (de->np == node)
+ return de;
+ }
+ return NULL;
+}
+
+/**
+ * Add an overlay log entry
+ */
+static int of_overlay_log_entry_entry_add(struct of_overlay_info *ovinfo,
+ unsigned long action, struct device_node *dn,
+ struct property *prop)
+{
+ struct of_overlay_log_entry *le;
+
+ /* check */
+ if (ovinfo == NULL || dn == NULL)
+ return -EINVAL;
+
+ le = kzalloc(sizeof(*le), GFP_KERNEL);
+ if (le == NULL) {
+ pr_err("%s: Failed to allocate\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* get a reference to the node */
+ le->action = action;
+ le->np = of_node_get(dn);
+ le->prop = prop;
+
+ if (action == OF_RECONFIG_UPDATE_PROPERTY && prop)
+ le->old_prop = of_find_property(dn, prop->name, NULL);
+
+ list_add_tail(&le->node, &ovinfo->le_list);
+
+ return 0;
+}
+
+/**
+ * Add an overlay device entry
+ */
+static void of_overlay_device_entry_entry_add(struct of_overlay_info *ovinfo,
+ struct device_node *node,
+ int prevstate, int state)
+{
+ struct of_overlay_device_entry *de;
+ int fresh;
+
+ /* check */
+ if (ovinfo == NULL)
+ return;
+
+ fresh = 0;
+ de = of_overlay_device_entry_lookup(ovinfo, node);
+ if (de == NULL) {
+ de = kzalloc(sizeof(*de), GFP_KERNEL);
+ if (de == NULL) {
+ pr_err("%s: Failed to allocate\n", __func__);
+ return;
+ }
+ fresh = 1;
+ de->prevstate = -1;
+ }
+
+ if (de->np == NULL)
+ de->np = of_node_get(node);
+ if (fresh)
+ de->prevstate = prevstate;
+ de->state = state;
+
+ if (fresh)
+ list_add_tail(&de->node, &ovinfo->de_list);
+}
+
+/**
+ * Overlay OF notifier
+ *
+ * Called every time there's a property/node modification
+ * Every modification causes a log entry addition, while
+ * any modification that causes a node's state to change
+ * from/to disabled to/from enabled causes a device entry
+ * addition.
+ */
+static int of_overlay_notify(struct notifier_block *nb,
+ unsigned long action, void *arg)
+{
+ struct of_overlay_info *ovinfo;
+ struct device_node *node;
+ struct property *prop, *sprop, *cprop;
+ struct of_prop_reconfig *pr;
+ struct device_node *tnode;
+ int depth;
+ int prevstate, state;
+ int err = 0;
+
+ ovinfo = container_of(nb, struct of_overlay_info, notifier);
+
+ /* prep vars */
+ switch (action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ case OF_RECONFIG_DETACH_NODE:
+ node = arg;
+ if (node == NULL)
+ return notifier_from_errno(-EINVAL);
+ prop = NULL;
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ pr = arg;
+ if (pr == NULL)
+ return notifier_from_errno(-EINVAL);
+ node = pr->dn;
+ if (node == NULL)
+ return notifier_from_errno(-EINVAL);
+ prop = pr->prop;
+ if (prop == NULL)
+ return notifier_from_errno(-EINVAL);
+ break;
+ default:
+ return notifier_from_errno(0);
+ }
+
+ /* add to the log */
+ err = of_overlay_log_entry_entry_add(ovinfo, action, node, prop);
+ if (err != 0)
+ return notifier_from_errno(err);
+
+ /* come up with the device entry (if any) */
+ state = 0;
+ prevstate = 0;
+
+ /* determine the state the node will end up */
+ switch (action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ /* we demand that a compatible node is present */
+ state = of_find_property(node, "compatible", NULL) &&
+ of_device_is_available(node);
+ break;
+ case OF_RECONFIG_DETACH_NODE:
+ prevstate = of_find_property(node, "compatible", NULL) &&
+ of_device_is_available(node);
+ state = 0;
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ /* either one cause a change in state */
+ if (strcmp(prop->name, "status") != 0 &&
+ strcmp(prop->name, "compatible") != 0)
+ return notifier_from_errno(0);
+
+ if (strcmp(prop->name, "status") == 0) {
+ /* status */
+ cprop = of_find_property(node, "compatible", NULL);
+ sprop = action != OF_RECONFIG_REMOVE_PROPERTY ?
+ prop : NULL;
+ } else {
+ /* compatible */
+ sprop = of_find_property(node, "status", NULL);
+ cprop = action != OF_RECONFIG_REMOVE_PROPERTY ?
+ prop : NULL;
+ }
+
+ prevstate = of_find_property(node, "compatible", NULL) &&
+ of_device_is_available(node);
+ state = cprop && cprop->length > 0 &&
+ (!sprop || (sprop->length > 0 &&
+ (strcmp(sprop->value, "okay") == 0 ||
+ strcmp(sprop->value, "ok") == 0)));
+ break;
+
+ default:
+ return notifier_from_errno(0);
+ }
+
+ /* find depth */
+ depth = 1;
+ tnode = node;
+ while (tnode != NULL && tnode != ovinfo->target) {
+ tnode = tnode->parent;
+ depth++;
+ }
+
+ /* respect overlay's maximum depth */
+ if (ovinfo->device_depth != 0 && depth > ovinfo->device_depth) {
+ pr_debug("OF: skipping device creation for node=%s depth=%d\n",
+ node->name, depth);
+ goto out;
+ }
+
+ of_overlay_device_entry_entry_add(ovinfo, node, prevstate, state);
+out:
+
+ return notifier_from_errno(err);
+}
+
+/**
+ * Prepare for the overlay, for now it just registers the
+ * notifier.
+ */
+static int of_overlay_prep_one(struct of_overlay_info *ovinfo)
+{
+ int err;
+
+ err = of_reconfig_notifier_register(&ovinfo->notifier);
+ if (err != 0) {
+ pr_err("%s: failed to register notifier for '%s'\n",
+ __func__, ovinfo->target->full_name);
+ return err;
+ }
+ return 0;
+}
+
+static int of_overlay_device_entry_change(struct of_overlay_info *ovinfo,
+ struct of_overlay_device_entry *de, int revert)
+{
+ int state;
+ int ret;
+
+ state = !!de->state ^ !!revert;
+
+ if (state)
+ ret = handler_create(de, revert);
+ else
+ ret = handler_remove(de, revert);
+
+ if (ret != 0 && ret != -ENOTSUPP)
+ pr_warn("%s: Failed to %s device "
+ "for node '%s'\n", __func__,
+ state ? "create" : "remove",
+ de->np->full_name);
+ return 0;
+}
+
+/**
+ * Revert one overlay
+ * Either due to an error, or due to normal overlay removal.
+ * Using the log entries, we revert any change to the live tree.
+ * In the same manner, using the device entries we enable/disable
+ * the devices appropriately.
+ */
+static void of_overlay_revert_one(struct of_overlay_info *ovinfo)
+{
+ struct of_overlay_device_entry *de, *den;
+ struct of_overlay_log_entry *le, *len;
+ struct property *prop, **propp;
+ struct device_node *np;
+ int ret;
+ unsigned long flags;
+
+ if (!ovinfo || !ovinfo->target || !ovinfo->overlay)
+ return;
+
+ pr_debug("%s: Reverting overlay on '%s'\n", __func__,
+ ovinfo->target->full_name);
+
+ /* overlay applied correctly, now create/destroy pdevs */
+ list_for_each_entry_safe_reverse(de, den, &ovinfo->de_list, node) {
+ of_overlay_device_entry_change(ovinfo, de, 1);
+ of_node_put(de->np);
+ list_del(&de->node);
+ kfree(de);
+ }
+
+ list_for_each_entry_safe_reverse(le, len, &ovinfo->le_list, node) {
+
+ /* get node and immediately put */
+ np = le->np;
+ of_node_put(le->np);
+ le->np = NULL;
+
+ ret = 0;
+ switch (le->action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ pr_debug("Reverting ATTACH_NODE %s\n",
+ np->full_name);
+ ret = of_detach_node(np);
+ break;
+
+ case OF_RECONFIG_DETACH_NODE:
+ pr_debug("Reverting DETACH_NODE %s\n",
+ np->full_name);
+ ret = of_attach_node(np);
+ break;
+
+ case OF_RECONFIG_ADD_PROPERTY:
+ pr_debug("Reverting ADD_PROPERTY %s %s\n",
+ np->full_name, le->prop->name);
+ ret = of_remove_property(np, le->prop);
+ break;
+
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ case OF_RECONFIG_UPDATE_PROPERTY:
+
+ pr_debug("Reverting %s_PROPERTY %s %s\n",
+ le->action == OF_RECONFIG_REMOVE_PROPERTY ?
+ "REMOVE" : "UPDATE",
+ np->full_name, le->prop->name);
+
+ /* property is possibly on deadprops (avoid alloc) */
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ prop = le->action == OF_RECONFIG_REMOVE_PROPERTY ?
+ le->prop : le->old_prop;
+ propp = &np->deadprops;
+ while (*propp != NULL) {
+ if (*propp == prop)
+ break;
+ propp = &(*propp)->next;
+ }
+ if (*propp != NULL) {
+ /* remove it from deadprops */
+ (*propp)->next = prop->next;
+ raw_spin_unlock_irqrestore(&devtree_lock,
+ flags);
+ } else {
+ raw_spin_unlock_irqrestore(&devtree_lock,
+ flags);
+ /* not found, just make a copy */
+ prop = __of_copy_property(prop, GFP_KERNEL,
+ OF_PROP_ALLOCALL);
+ if (prop == NULL) {
+ pr_err("%s: Failed to copy property\n",
+ __func__);
+ break;
+ }
+ }
+
+ if (le->action == OF_RECONFIG_REMOVE_PROPERTY)
+ ret = of_add_property(np, prop);
+ else
+ ret = of_update_property(np, prop);
+ break;
+
+ default:
+ /* nothing */
+ break;
+ }
+
+ if (ret != 0)
+ pr_err("%s: revert on node %s Failed!\n",
+ __func__, np->full_name);
+
+ list_del(&le->node);
+
+ kfree(le);
+ }
+}
+
+/**
+ * Perform the post overlay work.
+ *
+ * We unregister the notifier, and in the case on an error we
+ * revert the overlay.
+ * If the overlay applied correctly, we iterare over the device entries
+ * and create/destroy the devices appropriately.
+ */
+static int of_overlay_post_one(struct of_overlay_info *ovinfo, int err)
+{
+ struct of_overlay_device_entry *de, *den;
+
+ of_reconfig_notifier_unregister(&ovinfo->notifier);
+
+ if (err != 0) {
+ /* revert this (possible partially applied) overlay */
+ of_overlay_revert_one(ovinfo);
+ return 0;
+ }
+
+ /* overlay applied correctly, now create/destroy pdevs */
+ list_for_each_entry_safe(de, den, &ovinfo->de_list, node) {
+
+ /* no state change? just remove this entry */
+ if (de->prevstate == de->state) {
+ of_node_put(de->np);
+ list_del(&de->node);
+ kfree(de);
+ continue;
+ }
+
+ of_overlay_device_entry_change(ovinfo, de, 0);
+ }
+
+ return 0;
+}
+
+/**
+ * of_overlay - Apply @count overlays pointed at by @ovinfo_tab
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to apply
+ *
+ * Applies the overlays given, while handling all error conditions
+ * appropriately. Either the operation succeeds, or if it fails the
+ * live tree is reverted to the state before the attempt.
+ * Returns 0, or an error if the overlay attempt failed.
+ */
+int of_overlay(int count, struct of_overlay_info *ovinfo_tab)
+{
+ struct of_overlay_info *ovinfo;
+ int i, err;
+
+ if (!ovinfo_tab)
+ return -EINVAL;
+
+ /* first we apply the overlays atomically */
+ for (i = 0; i < count; i++) {
+
+ ovinfo = &ovinfo_tab[i];
+
+ mutex_lock(&ovinfo->lock);
+
+ err = of_overlay_prep_one(ovinfo);
+ if (err == 0)
+ err = of_overlay_apply_one(ovinfo->target,
+ ovinfo->overlay);
+ of_overlay_post_one(ovinfo, err);
+
+ mutex_unlock(&ovinfo->lock);
+
+ if (err != 0) {
+ pr_err("%s: overlay failed '%s'\n",
+ __func__, ovinfo->target->full_name);
+ goto err_fail;
+ }
+ }
+
+ return 0;
+
+err_fail:
+ while (--i >= 0) {
+ ovinfo = &ovinfo_tab[i];
+
+ mutex_lock(&ovinfo->lock);
+ of_overlay_revert_one(ovinfo);
+ mutex_unlock(&ovinfo->lock);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(of_overlay);
+
+/**
+ * of_overlay_revert - Revert a previously applied overlay
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to apply
+ *
+ * Revert a previous overlay. The state of the live tree
+ * is reverted to the one before the overlay.
+ * Returns 0, or an error if the overlay table is not given.
+ */
+int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab)
+{
+ struct of_overlay_info *ovinfo;
+ int i;
+
+ if (!ovinfo_tab)
+ return -EINVAL;
+
+ /* revert the overlays in reverse */
+ for (i = count - 1; i >= 0; i--) {
+
+ ovinfo = &ovinfo_tab[i];
+
+ mutex_lock(&ovinfo->lock);
+ of_overlay_revert_one(ovinfo);
+ mutex_unlock(&ovinfo->lock);
+
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_overlay_revert);
+
+/**
+ * of_init_overlay_info - Initialize a single of_overlay_info structure
+ * @ovinfo: Pointer to the overlay info structure to initialize
+ *
+ * Initialize a single overlay info structure.
+ */
+void of_init_overlay_info(struct of_overlay_info *ovinfo)
+{
+ memset(ovinfo, 0, sizeof(ovinfo));
+ mutex_init(&ovinfo->lock);
+ INIT_LIST_HEAD(&ovinfo->de_list);
+ INIT_LIST_HEAD(&ovinfo->le_list);
+
+ ovinfo->notifier.notifier_call = of_overlay_notify;
+}
+
+/*
+ * Find the target node using a number of different strategies
+ * in order of preference
+ *
+ * "target" property containing the phandle of the target
+ * "target-path" property containing the path of the target
+ *
+ */
+struct device_node *find_target_node(struct device_node *info_node)
+{
+ const char *path;
+ u32 val;
+ int ret;
+
+ /* first try to go by using the target as a phandle */
+ ret = of_property_read_u32(info_node, "target", &val);
+ if (ret == 0)
+ return of_find_node_by_phandle(val);
+
+ /* now try to locate by path */
+ ret = of_property_read_string(info_node, "target-path", &path);
+ if (ret == 0)
+ return of_find_node_by_path(path);
+
+ pr_err("%s: Failed to find target for node %p (%s)\n", __func__,
+ info_node, info_node->name);
+
+ return NULL;
+}
+
+/**
+ * of_fill_overlay_info - Fill an overlay info structure
+ * @info_node: Device node containing the overlay
+ * @ovinfo: Pointer to the overlay info structure to fill
+ *
+ * Fills an overlay info structure with the overlay information
+ * from a device node. This device node must have a target property
+ * which contains a phandle of the overlay target node, and an
+ * __overlay__ child node which has the overlay contents.
+ * Both ovinfo->target & ovinfo->overlay have their references taken.
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+int of_fill_overlay_info(struct device_node *info_node,
+ struct of_overlay_info *ovinfo)
+{
+ u32 val;
+ int ret;
+
+ if (!info_node || !ovinfo)
+ return -EINVAL;
+
+ ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__");
+ if (ovinfo->overlay == NULL)
+ goto err_fail;
+
+ ovinfo->target = find_target_node(info_node);
+ if (ovinfo->target == NULL)
+ goto err_fail;
+
+ ret = of_property_read_u32(info_node, "depth", &val);
+ if (ret == 0)
+ ovinfo->device_depth = val;
+ else
+ ovinfo->device_depth = 0;
+
+ return 0;
+
+err_fail:
+ of_node_put(ovinfo->target);
+ of_node_put(ovinfo->overlay);
+
+ memset(ovinfo, 0, sizeof(*ovinfo));
+ return -EINVAL;
+}
+
+/**
+ * of_build_overlay_info - Build an overlay info array
+ * @tree: Device node containing all the overlays
+ * @cntp: Pointer to where the overlay info count will be help
+ * @ovinfop: Pointer to the pointer of an overlay info structure.
+ *
+ * Helper function that given a tree containing overlay information,
+ * allocates and builds an overlay info array containing it, ready
+ * for use using of_overlay.
+ *
+ * Returns 0 on success with the @cntp @ovinfop pointers valid,
+ * while on error a negative error value is returned.
+ */
+int of_build_overlay_info(struct device_node *tree,
+ int *cntp, struct of_overlay_info **ovinfop)
+{
+ struct device_node *node;
+ struct of_overlay_info *ovinfo;
+ int cnt, err;
+
+ if (tree == NULL || cntp == NULL || ovinfop == NULL)
+ return -EINVAL;
+
+ /* worst case; every child is a node */
+ cnt = 0;
+ for_each_child_of_node(tree, node)
+ cnt++;
+
+ ovinfo = kzalloc(cnt * sizeof(*ovinfo), GFP_KERNEL);
+ if (ovinfo == NULL)
+ return -ENOMEM;
+
+ cnt = 0;
+ for_each_child_of_node(tree, node) {
+
+ of_init_overlay_info(&ovinfo[cnt]);
+ err = of_fill_overlay_info(node, &ovinfo[cnt]);
+ if (err == 0)
+ cnt++;
+ }
+
+ /* if nothing filled, return error */
+ if (cnt == 0) {
+ kfree(ovinfo);
+ return -ENODEV;
+ }
+
+ *cntp = cnt;
+ *ovinfop = ovinfo;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_build_overlay_info);
+
+/**
+ * of_free_overlay_info - Free an overlay info array
+ * @count: Number of of_overlay_info's
+ * @ovinfo_tab: Array of overlay_info's to free
+ *
+ * Releases the memory of a previously allocate ovinfo array
+ * by of_build_overlay_info.
+ * Returns 0, or an error if the arguments are bogus.
+ */
+int of_free_overlay_info(int count, struct of_overlay_info *ovinfo_tab)
+{
+ struct of_overlay_info *ovinfo;
+ int i;
+
+ if (!ovinfo_tab || count < 0)
+ return -EINVAL;
+
+ /* do it in reverse */
+ for (i = count - 1; i >= 0; i--) {
+ ovinfo = &ovinfo_tab[i];
+
+ of_node_put(ovinfo->target);
+ of_node_put(ovinfo->overlay);
+ }
+ kfree(ovinfo_tab);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_free_overlay_info);
diff --git a/include/linux/of.h b/include/linux/of.h
index 4932a8f..7c1a6f6 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/list.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
@@ -752,4 +753,156 @@ static inline int of_resolve(struct device_node *resolve)
#endif
+/**
+ * Overlay support
+ */
+
+/**
+ * struct of_overlay_log_entry - Holds a DT log entry
+ * @node: list_head for the log list
+ * @action: notifier action
+ * @np: pointer to the device node affected
+ * @prop: pointer to the property affected
+ * @old_prop: hold a pointer to the original property
+ *
+ * Every modification of the device tree during application of the
+ * overlay is held in a list of of_overlay_log_entry structures.
+ * That way we can recover from a partial application, or we can
+ * revert the overlay properly.
+ */
+struct of_overlay_log_entry {
+ struct list_head node;
+ unsigned long action;
+ struct device_node *np;
+ struct property *prop;
+ struct property *old_prop;
+};
+
+struct of_overlay_device_entry;
+
+/**
+ * struct of_overlay_handler_ops - Overlay device handler ops
+ * @create: method to be called to create a device
+ * @remove: method to be called to destroy a device
+ *
+ * Both these functions return 0 on success, ENOTSUPP if the
+ * device entry does not match, and an error code otherwise.
+ */
+struct of_overlay_handler_ops {
+ int (*create)(struct of_overlay_device_entry *entry, int revert);
+ int (*remove)(struct of_overlay_device_entry *entry, int revert);
+};
+
+/**
+ * struct of_overlay_handler - Overlay device handler
+ * @list: list links for all handlers
+ * @name: name of this handler
+ * @ops: ops member functions
+ *
+ * The handler is registered by each bus that supports
+ * dynamic creation/removal of devices
+ */
+struct of_overlay_handler {
+ struct list_head list;
+ const char *name;
+ const struct of_overlay_handler_ops *ops;
+};
+
+/**
+ * struct of_overlay_device_entry - Holds an overlay device entry
+ * @node: list_head for the device list
+ * @np: device node pointer to the device node affected
+ * @state: new device state
+ * @prevstate: previous device state
+ * @priv: private pointer for use by bus handlers
+ *
+ * When the overlay results in a device node's state to change this
+ * fact is recorded in a list of device entries. After the overlay
+ * is applied we can create/destroy the devices according
+ * to the new state of the live tree.
+ */
+struct of_overlay_device_entry {
+ struct list_head node;
+ struct device_node *np;
+ int prevstate;
+ int state;
+ void *priv;
+};
+
+/**
+ * struct of_overlay_info - Holds a single overlay info
+ * @target: target of the overlay operation
+ * @overlay: pointer to the overlay contents node
+ * @lock: Lock to hold when accessing the lists
+ * @le_list: List of the overlay logs
+ * @de_list: List of the overlay records
+ * @notifier: of reconfiguration notifier
+ *
+ * Holds a single overlay state, including all the overlay logs &
+ * records.
+ */
+struct of_overlay_info {
+ struct device_node *target;
+ struct device_node *overlay;
+ struct mutex lock;
+ struct list_head le_list;
+ struct list_head de_list;
+ struct notifier_block notifier;
+ int device_depth;
+};
+
+#ifdef CONFIG_OF_OVERLAY
+
+int of_overlay(int count, struct of_overlay_info *ovinfo_tab);
+int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab);
+
+int of_fill_overlay_info(struct device_node *info_node,
+ struct of_overlay_info *ovinfo);
+int of_build_overlay_info(struct device_node *tree,
+ int *cntp, struct of_overlay_info **ovinfop);
+int of_free_overlay_info(int cnt, struct of_overlay_info *ovinfo);
+
+int of_overlay_handler_register(struct of_overlay_handler *handler);
+void of_overlay_handler_unregister(struct of_overlay_handler *handler);
+
+#else
+
+static inline int of_overlay(int count, struct of_overlay_info *ovinfo_tab)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_fill_overlay_info(struct device_node *info_node,
+ struct of_overlay_info *ovinfo)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_build_overlay_info(struct device_node *tree,
+ int *cntp, struct of_overlay_info **ovinfop)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_free_overlay_info(int cnt, struct of_overlay_info *ovinfo)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_overlay_handler_register(struct of_overlay_handler *handler)
+{
+ return 0;
+}
+
+static inline void of_overlay_handler_unregister(struct of_overlay_handler *handler)
+{
+}
+
+#endif
+
#endif /* _LINUX_OF_H */
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 3/7] OF: DT-Overlay configfs interface
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 1/7] OF: Introduce Device Tree resolve support Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 2/7] OF: Introduce DT overlay support Pantelis Antoniou
@ 2014-03-18 21:56 ` Pantelis Antoniou
[not found] ` <1395179766-31575-4-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-03-18 21:56 ` [PATCH v3 4/7] OF: platform: Add overlay bus handler Pantelis Antoniou
` (4 subsequent siblings)
7 siblings, 1 reply; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Add a runtime interface to using configfs for generic device tree overlay
usage.
A device-tree configfs entry is created in /config/device-tree/overlays
To create an overlay you mkdir the directory and then echo the overlay
firmware file to the path property file.
# mkdir /config/device-tree/overlays/foo
# echo foo.dtbo >/config/device-tree/overlays/foo/path
The overlay file will be loaded using the standard firmware loader
and will be applied.
To remove it simply rmdir the directory.
# rmdir /config/device-tree/overlays/foo
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
drivers/of/Kconfig | 5 +
drivers/of/Makefile | 1 +
drivers/of/configfs.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 278 insertions(+)
create mode 100644 drivers/of/configfs.c
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 7517be2..fc0e3ec 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -77,6 +77,10 @@ config OF_RESERVED_MEM
help
Helpers to allow for reservation of memory regions
+config OF_CONFIGFS
+ select CONFIGFS_FS
+ def_bool n
+
config OF_RESOLVE
bool "OF Dynamic resolution support"
depends on OF
@@ -92,6 +96,7 @@ config OF_OVERLAY
select OF_DYNAMIC
select OF_DEVICE
select OF_RESOLVE
+ select OF_CONFIGFS
help
OpenFirmware overlay support. Allows you to modify on runtime the
live tree using overlays.
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d2a6e0d..4efa17b 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c
new file mode 100644
index 0000000..a494643
--- /dev/null
+++ b/drivers/of/configfs.c
@@ -0,0 +1,272 @@
+/*
+ * 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/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"
+
+#ifdef CONFIG_OF_OVERLAY
+
+struct cfs_overlay_item {
+ struct config_item item;
+
+ char path[PATH_MAX];
+
+ const struct firmware *fw;
+ struct device_node *overlay;
+ int ovinfo_cnt;
+ struct of_overlay_info *ovinfo;
+ unsigned int applied : 1;
+};
+
+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;
+}
+
+CONFIGFS_ATTR_STRUCT(cfs_overlay_item);
+#define CFS_OVERLAY_ITEM_ATTR(_name, _mode, _show, _store) \
+struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
+ __CONFIGFS_ATTR(_name, _mode, _show, _store)
+#define CFS_OVERLAY_ITEM_ATTR_RO(_name, _show) \
+struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
+ __CONFIGFS_ATTR_RO(_name, _show)
+
+static ssize_t cfs_overlay_item_path_show(struct cfs_overlay_item *overlay,
+ char *page)
+{
+ return sprintf(page, "%s\n", overlay->path);
+}
+
+static ssize_t cfs_overlay_item_path_store(struct cfs_overlay_item *overlay,
+ const char *page, size_t count)
+{
+ const char *p = page;
+ char *s;
+ int err;
+
+ /* if it's set do not allow changes */
+ if (overlay->path[0] != '\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;
+
+ /* unflatten the tree */
+ of_fdt_unflatten_tree((void *)overlay->fw->data, &overlay->overlay);
+ if (overlay->overlay == NULL) {
+ pr_err("%s: failed to unflatten tree\n", __func__);
+ err = -EINVAL;
+ goto out_err;
+ }
+ pr_debug("%s: unflattened OK\n", __func__);
+
+ /* mark it as detached */
+ of_node_set_flag(overlay->overlay, OF_DETACHED);
+
+ /* perform resolution */
+ err = of_resolve(overlay->overlay);
+ if (err != 0) {
+ pr_err("%s: Failed to resolve tree\n", __func__);
+ goto out_err;
+ }
+ pr_debug("%s: resolved OK\n", __func__);
+
+ /* now build an overlay info array */
+ err = of_build_overlay_info(overlay->overlay,
+ &overlay->ovinfo_cnt, &overlay->ovinfo);
+ if (err != 0) {
+ pr_err("%s: Failed to build overlay info\n", __func__);
+ goto out_err;
+ }
+
+ pr_debug("%s: built %d overlay segments\n", __func__,
+ overlay->ovinfo_cnt);
+
+ err = of_overlay(overlay->ovinfo_cnt, overlay->ovinfo);
+ if (err != 0) {
+ pr_err("%s: Failed to apply overlay\n", __func__);
+ goto out_err;
+ }
+
+ overlay->applied = 1;
+
+ pr_debug("%s: Applied #%d overlay segments\n", __func__,
+ overlay->ovinfo_cnt);
+
+ return count;
+
+out_err:
+ if (overlay->applied)
+ of_overlay_revert(overlay->ovinfo_cnt, overlay->ovinfo);
+ overlay->applied = 0;
+
+ if (overlay->ovinfo)
+ of_free_overlay_info(overlay->ovinfo_cnt, overlay->ovinfo);
+ overlay->ovinfo = NULL;
+ overlay->ovinfo_cnt = 0;
+
+ release_firmware(overlay->fw);
+ overlay->fw = NULL;
+
+ overlay->path[0] = '\0';
+ return err;
+}
+
+static ssize_t cfs_overlay_item_status_show(struct cfs_overlay_item *overlay,
+ char *page)
+{
+ return sprintf(page, "%s\n",
+ overlay->applied ? "applied" : "unapplied");
+}
+
+CFS_OVERLAY_ITEM_ATTR(path, S_IRUGO | S_IWUSR, \
+ cfs_overlay_item_path_show, cfs_overlay_item_path_store);
+CFS_OVERLAY_ITEM_ATTR_RO(status, cfs_overlay_item_status_show);
+
+static struct configfs_attribute *cfs_overlay_attrs[] = {
+ &cfs_overlay_item_attr_path.attr,
+ &cfs_overlay_item_attr_status.attr,
+ NULL,
+};
+
+static void cfs_overlay_release(struct config_item *item)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+ if (overlay->applied)
+ of_overlay_revert(overlay->ovinfo_cnt, overlay->ovinfo);
+ if (overlay->ovinfo)
+ of_free_overlay_info(overlay->ovinfo_cnt, overlay->ovinfo);
+ if (overlay->fw)
+ release_firmware(overlay->fw);
+ kfree(overlay);
+}
+
+CONFIGFS_ATTR_OPS(cfs_overlay_item);
+static struct configfs_item_operations cfs_overlay_item_ops = {
+ .release = cfs_overlay_release,
+ .show_attribute = cfs_overlay_item_attr_show,
+ .store_attribute = cfs_overlay_item_attr_store,
+};
+
+static struct config_item_type cfs_overlay_type = {
+ .ct_item_ops = &cfs_overlay_item_ops,
+ .ct_attrs = cfs_overlay_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);
+
+ 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,
+};
+
+#endif /* CONFIG_OF_OVERLAY */
+
+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,
+};
+
+struct config_group of_cfs_overlay_group;
+
+struct config_group *of_cfs_def_groups[] = {
+#ifdef CONFIG_OF_OVERLAY
+ &of_cfs_overlay_group,
+#endif
+ NULL
+};
+
+static struct configfs_subsystem of_cfs_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "device-tree",
+ .ci_type = &of_cfs_type,
+ },
+ .default_groups = of_cfs_def_groups,
+ },
+ .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);
+#ifdef CONFIG_OF_OVERLAY
+ config_group_init_type_name(&of_cfs_overlay_group, "overlays", &overlays_type);
+#endif
+
+ 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);
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 4/7] OF: platform: Add overlay bus handler
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
` (2 preceding siblings ...)
2014-03-18 21:56 ` [PATCH v3 3/7] OF: DT-Overlay configfs interface Pantelis Antoniou
@ 2014-03-18 21:56 ` Pantelis Antoniou
[not found] ` <1395179766-31575-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
` (3 subsequent siblings)
7 siblings, 0 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Add the bus handler registration needed for performing overlays
containing platform devices.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
drivers/base/platform.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 96 insertions(+), 3 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index bc78848..e113733 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -925,6 +925,87 @@ struct bus_type platform_bus_type = {
};
EXPORT_SYMBOL_GPL(platform_bus_type);
+#ifdef CONFIG_OF_OVERLAY
+
+static int platform_handler_create(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct platform_device *pdev_parent, *pdev;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ /* verify that the parent is a bus */
+ if (!of_match_node(of_default_bus_match_table, dn->parent))
+ return -ENOTSUPP;
+
+ pdev_parent = of_find_device_by_node(dn->parent);
+ if (pdev_parent == NULL)
+ return -ENOTSUPP;
+
+ pdev = of_platform_device_create(dn, NULL, &pdev_parent->dev);
+ of_dev_put(pdev_parent);
+
+ if (pdev == NULL) {
+ pr_err("%s: failed to create platform device "
+ "for '%s'\n",
+ __func__, dn->full_name);
+ /* of_platform_device_create tosses the real error code */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int platform_handler_remove(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct platform_device *pdev;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ pdev = of_find_device_by_node(dn);
+ if (pdev == NULL)
+ return -ENOTSUPP;
+
+ /* unregister takes one ref away */
+ platform_device_unregister(pdev);
+
+ /* and put the reference of the find */
+ of_dev_put(pdev);
+
+ return 0;
+}
+
+static const struct of_overlay_handler_ops platform_handler_ops = {
+ .create = platform_handler_create,
+ .remove = platform_handler_remove,
+};
+
+static struct of_overlay_handler platform_handler = {
+ .name = "platform",
+ .ops = &platform_handler_ops,
+};
+
+static int __init platform_bus_handler_register(void)
+{
+ return of_overlay_handler_register(&platform_handler);
+}
+
+#else
+static inline int platform_bus_handler_register(void)
+{
+ return 0;
+}
+#endif
+
int __init platform_bus_init(void)
{
int error;
@@ -933,10 +1014,22 @@ int __init platform_bus_init(void)
error = device_register(&platform_bus);
if (error)
- return error;
- error = bus_register(&platform_bus_type);
+ goto err_out;
+
+ error = bus_register(&platform_bus_type);
if (error)
- device_unregister(&platform_bus);
+ goto err_unreg_dev;
+
+ error = platform_bus_handler_register();
+ if (error)
+ goto err_unreg_bus;
+
+ return 0;
+err_unreg_bus:
+ bus_unregister(&platform_bus_type);
+err_unreg_dev:
+ device_unregister(&platform_bus);
+err_out:
return error;
}
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 5/7] OF: i2c: Add overlay bus handler
[not found] ` <1395179766-31575-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
@ 2014-03-18 21:56 ` Pantelis Antoniou
0 siblings, 0 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Add the bus handler registration needed for performing overlays
containing i2c devices.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
drivers/i2c/i2c-core.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 5fb80b8..5120d28 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1073,10 +1073,89 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
return i2c_verify_adapter(dev);
}
EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
+
+#ifdef CONFIG_OF_OVERLAY
+static int i2c_handler_create(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct i2c_adapter *adap;
+ struct i2c_client *client;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ adap = of_find_i2c_adapter_by_node(dn->parent);
+ if (adap == NULL)
+ return -ENOTSUPP;
+
+ client = of_i2c_register_device(adap, dn);
+ put_device(&adap->dev);
+
+ if (client == NULL) {
+ pr_err("%s: failed to create i2c client device "
+ "for '%s'\n",
+ __func__, dn->full_name);
+ /* of_i2c_device_create tosses the real error code */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int i2c_handler_remove(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct i2c_client *client;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ client = of_find_i2c_device_by_node(dn);
+ if (client == NULL)
+ return -ENOTSUPP;
+
+ /* unregister takes one ref away */
+ i2c_unregister_device(client);
+
+ /* and put the reference of the find */
+ put_device(&client->dev);
+
+ return 0;
+}
+
+static const struct of_overlay_handler_ops i2c_handler_ops = {
+ .create = i2c_handler_create,
+ .remove = i2c_handler_remove,
+};
+
+static struct of_overlay_handler i2c_handler = {
+ .name = "i2c",
+ .ops = &i2c_handler_ops,
+};
+
+static int __init i2c_bus_handler_register(void)
+{
+ return of_overlay_handler_register(&i2c_handler);
+}
+#endif
+
#else
static void of_i2c_register_devices(struct i2c_adapter *adap) { }
#endif /* CONFIG_OF */
+#if !defined(CONFIG_OF) || !defined(CONFIG_OF_OVERLAY)
+static inline int i2c_bus_handler_register(void)
+{
+ return 0;
+}
+#endif
+
/* ACPI support code */
#if IS_ENABLED(CONFIG_ACPI)
@@ -1668,8 +1747,14 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
- return 0;
+ retval = i2c_bus_handler_register();
+ if (retval)
+ goto bus_handler_err;
+
+ return 0;
+bus_handler_err:
+ i2c_del_driver(&dummy_driver);
class_err:
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
--
1.7.12
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 6/7] OF: spi: Add overlay bus handler
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
` (4 preceding siblings ...)
[not found] ` <1395179766-31575-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
@ 2014-03-18 21:56 ` Pantelis Antoniou
[not found] ` <1395179766-31575-7-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-03-18 21:56 ` [PATCH v3 7/7] of: i2c: Export single device registration method Pantelis Antoniou
2014-03-28 18:27 ` [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays delicious quinoa
7 siblings, 1 reply; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
Add the bus handler registration needed for performing overlays
containing spi devices.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
drivers/spi/spi.c | 345 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 242 insertions(+), 103 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d0b28bb..2d7037b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -993,6 +993,123 @@ err_init_queue:
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OF)
+
+static struct spi_device *
+of_register_spi_device(struct spi_master *master, struct device_node *node)
+{
+ struct spi_device *spi;
+ struct device_node *nc;
+ int err;
+ u32 value;
+
+ /* Alloc an spi_device */
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "spi_device alloc error for %s\n",
+ nc->full_name);
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ /* Select device driver */
+ err = of_modalias_node(nc, spi->modalias,
+ sizeof(spi->modalias));
+ if (err) {
+ dev_err(&master->dev, "cannot find modalias for %s\n",
+ nc->full_name);
+ goto err_out;
+ }
+
+ /* Device address */
+ err = of_property_read_u32(nc, "reg", &value);
+ if (err) {
+ dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
+ nc->full_name, err);
+ goto err_out;
+ }
+ spi->chip_select = value;
+
+ /* Mode (clock phase/polarity/etc.) */
+ if (of_find_property(nc, "spi-cpha", NULL))
+ spi->mode |= SPI_CPHA;
+ if (of_find_property(nc, "spi-cpol", NULL))
+ spi->mode |= SPI_CPOL;
+ if (of_find_property(nc, "spi-cs-high", NULL))
+ spi->mode |= SPI_CS_HIGH;
+ if (of_find_property(nc, "spi-3wire", NULL))
+ spi->mode |= SPI_3WIRE;
+
+ /* Device DUAL/QUAD mode */
+ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
+ switch (value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_TX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_TX_QUAD;
+ break;
+ default:
+ dev_err(&master->dev,
+ "spi-tx-bus-width %d not supported\n",
+ value);
+ err = -EINVAL;
+ goto err_out;
+ }
+ }
+
+ if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
+ switch (value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_RX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_RX_QUAD;
+ break;
+ default:
+ dev_err(&master->dev,
+ "spi-rx-bus-width %d not supported\n",
+ value);
+ err = -EINVAL;
+ goto err_out;
+ }
+ }
+
+ /* Device speed */
+ err = of_property_read_u32(nc, "spi-max-frequency", &value);
+ if (err) {
+ dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
+ nc->full_name, err);
+ goto err_out;
+ }
+ spi->max_speed_hz = value;
+
+ /* IRQ */
+ spi->irq = irq_of_parse_and_map(nc, 0);
+
+ /* Store a pointer to the node in the device structure */
+ of_node_get(nc);
+ spi->dev.of_node = nc;
+
+ /* Register the new device */
+ request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias);
+ err = spi_add_device(spi);
+ if (err) {
+ dev_err(&master->dev, "spi_device register error %s\n",
+ nc->full_name);
+ goto err_out;
+ }
+
+ return spi;
+
+err_out:
+ spi_dev_put(spi);
+ return ERR_PTR(err);
+}
+
/**
* of_register_spi_devices() - Register child devices onto the SPI bus
* @master: Pointer to spi_master device
@@ -1002,124 +1119,140 @@ err_init_queue:
*/
static void of_register_spi_devices(struct spi_master *master)
{
- struct spi_device *spi;
struct device_node *nc;
- int rc;
- u32 value;
if (!master->dev.of_node)
return;
- for_each_available_child_of_node(master->dev.of_node, nc) {
- /* Alloc an spi_device */
- spi = spi_alloc_device(master);
- if (!spi) {
- dev_err(&master->dev, "spi_device alloc error for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
+ for_each_available_child_of_node(master->dev.of_node, nc)
+ of_register_spi_device(master, nc);
+}
- /* Select device driver */
- if (of_modalias_node(nc, spi->modalias,
- sizeof(spi->modalias)) < 0) {
- dev_err(&master->dev, "cannot find modalias for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
- /* Device address */
- rc = of_property_read_u32(nc, "reg", &value);
- if (rc) {
- dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
- nc->full_name, rc);
- spi_dev_put(spi);
- continue;
- }
- spi->chip_select = value;
-
- /* Mode (clock phase/polarity/etc.) */
- if (of_find_property(nc, "spi-cpha", NULL))
- spi->mode |= SPI_CPHA;
- if (of_find_property(nc, "spi-cpol", NULL))
- spi->mode |= SPI_CPOL;
- if (of_find_property(nc, "spi-cs-high", NULL))
- spi->mode |= SPI_CS_HIGH;
- if (of_find_property(nc, "spi-3wire", NULL))
- spi->mode |= SPI_3WIRE;
-
- /* Device DUAL/QUAD mode */
- if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
- switch (value) {
- case 1:
- break;
- case 2:
- spi->mode |= SPI_TX_DUAL;
- break;
- case 4:
- spi->mode |= SPI_TX_QUAD;
- break;
- default:
- dev_err(&master->dev,
- "spi-tx-bus-width %d not supported\n",
- value);
- spi_dev_put(spi);
- continue;
- }
- }
+/* bah; the match functions differ just by const-ness */
+static int of_dev_node_match_const(struct device *dev, const void *data)
+{
+ return dev->of_node == data;
+}
- if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
- switch (value) {
- case 1:
- break;
- case 2:
- spi->mode |= SPI_RX_DUAL;
- break;
- case 4:
- spi->mode |= SPI_RX_QUAD;
- break;
- default:
- dev_err(&master->dev,
- "spi-rx-bus-width %d not supported\n",
- value);
- spi_dev_put(spi);
- continue;
- }
- }
+/* must call put_device() when done with returned spi_device device */
+struct spi_device *of_find_spi_device_by_node(struct device_node *node)
+{
+ struct device *dev;
- /* Device speed */
- rc = of_property_read_u32(nc, "spi-max-frequency", &value);
- if (rc) {
- dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
- nc->full_name, rc);
- spi_dev_put(spi);
- continue;
- }
- spi->max_speed_hz = value;
-
- /* IRQ */
- spi->irq = irq_of_parse_and_map(nc, 0);
-
- /* Store a pointer to the node in the device structure */
- of_node_get(nc);
- spi->dev.of_node = nc;
-
- /* Register the new device */
- request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias);
- rc = spi_add_device(spi);
- if (rc) {
- dev_err(&master->dev, "spi_device register error %s\n",
- nc->full_name);
- spi_dev_put(spi);
- }
+ dev = bus_find_device(&spi_bus_type, NULL, node,
+ of_dev_node_match);
+ if (!dev)
+ return NULL;
+
+ return to_spi_device(dev);
+}
+EXPORT_SYMBOL(of_find_spi_device_by_node);
+/* forward decl */
+static struct class spi_master_class;
+
+/* the spi masters are not using spi_bus, so we have to find it some other way */
+struct spi_master *of_find_spi_master_by_node(struct device_node *node)
+{
+ struct device *dev;
+
+ dev = class_find_device(&spi_master_class, NULL, node,
+ of_dev_node_match_const);
+ if (!dev)
+ return NULL;
+
+ /* reference got in class_find_device */
+ return container_of(dev, struct spi_master, dev);
+}
+EXPORT_SYMBOL(of_find_spi_master_by_node);
+
+#ifdef CONFIG_OF_OVERLAY
+static int spi_handler_create(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct spi_master *master;
+ struct spi_device *spi;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ master = of_find_spi_master_by_node(dn->parent);
+ if (master == NULL)
+ return -ENOTSUPP;
+
+ spi = of_register_spi_device(master, dn);
+ put_device(&master->dev);
+
+ if (spi == NULL) {
+ pr_err("%s: failed to create spi device "
+ "for '%s'\n",
+ __func__, dn->full_name);
+ /* of_register_spi_device tosses the real error code */
+ return -EINVAL;
}
+
+ return 0;
}
+
+static int spi_handler_remove(struct of_overlay_device_entry *de,
+ int revert)
+{
+ struct device_node *dn;
+ struct spi_device *spi;
+
+ if (!de || !de->np)
+ return -ENOTSUPP;
+
+ dn = de->np;
+
+ spi = of_find_spi_device_by_node(dn);
+ if (spi == NULL)
+ return -ENOTSUPP;
+
+ /* unregister takes one ref away */
+ spi_unregister_device(spi);
+
+ /* and put the reference of the find */
+ put_device(&spi->dev);
+
+ return 0;
+}
+
+static const struct of_overlay_handler_ops spi_handler_ops = {
+ .create = spi_handler_create,
+ .remove = spi_handler_remove,
+};
+
+static struct of_overlay_handler spi_handler = {
+ .name = "spi",
+ .ops = &spi_handler_ops,
+};
+
+static int __init spi_bus_handler_register(void)
+{
+ return of_overlay_handler_register(&spi_handler);
+}
+#endif
+
#else
static void of_register_spi_devices(struct spi_master *master) { }
#endif
+#if !defined(CONFIG_OF) || !defined(CONFIG_OF_OVERLAY)
+static inline int spi_bus_handler_register(void)
+{
+ return 0;
+}
+#endif
+
#ifdef CONFIG_ACPI
static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
{
@@ -2067,8 +2200,14 @@ static int __init spi_init(void)
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
- return 0;
+ status = spi_bus_handler_register();
+ if (status < 0)
+ goto err3;
+
+ return 0;
+err3:
+ class_unregister(&spi_master_class);
err2:
bus_unregister(&spi_bus_type);
err1:
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 7/7] of: i2c: Export single device registration method
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
` (5 preceding siblings ...)
2014-03-18 21:56 ` [PATCH v3 6/7] OF: spi: " Pantelis Antoniou
@ 2014-03-18 21:56 ` Pantelis Antoniou
2014-03-28 18:27 ` [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays delicious quinoa
7 siblings, 0 replies; 20+ messages in thread
From: Pantelis Antoniou @ 2014-03-18 21:56 UTC (permalink / raw)
To: Grant Likely
Cc: Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev, Pantelis Antoniou
From: Pantelis Antoniou <panto@antoniou-consulting.com>
Dynamically inserting i2c client device nodes requires the use
of a single device registration method. Rework and export it.
Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
---
drivers/i2c/i2c-core.c | 99 +++++++++++++++++++++++++++-----------------------
include/linux/i2c.h | 10 +++++
2 files changed, 64 insertions(+), 45 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 5120d28..017fb03 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -49,6 +49,7 @@
#include <linux/pm_runtime.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
+#include <linux/err.h>
#include "i2c-core.h"
@@ -982,63 +983,71 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
/* OF support code */
#if IS_ENABLED(CONFIG_OF)
-static void of_i2c_register_devices(struct i2c_adapter *adap)
+struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap,
+ struct device_node *node)
{
- void *result;
- struct device_node *node;
+ struct i2c_client *result;
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *addr;
+ int len;
- /* Only register child devices if the adapter has a node pointer set */
- if (!adap->dev.of_node)
- return;
+ dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
- dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+ dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- for_each_available_child_of_node(adap->dev.of_node, node) {
- struct i2c_board_info info = {};
- struct dev_archdata dev_ad = {};
- const __be32 *addr;
- int len;
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || (len < sizeof(int))) {
+ dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+ info.addr = be32_to_cpup(addr);
+ if (info.addr > (1 << 10) - 1) {
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+ info.addr, node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
- dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
- node->full_name);
- continue;
- }
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
- addr = of_get_property(node, "reg", &len);
- if (!addr || (len < sizeof(int))) {
- dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
- node->full_name);
- continue;
- }
+ if (of_get_property(node, "wakeup-source", NULL))
+ info.flags |= I2C_CLIENT_WAKE;
- info.addr = be32_to_cpup(addr);
- if (info.addr > (1 << 10) - 1) {
- dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, node->full_name);
- continue;
- }
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
- info.irq = irq_of_parse_and_map(node, 0);
- info.of_node = of_node_get(node);
- info.archdata = &dev_ad;
+ result = i2c_new_device(adap, &info);
+ if (result == NULL) {
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
+ irq_dispose_mapping(info.irq);
+ return ERR_PTR(-EINVAL);
+ }
+ return result;
+}
+EXPORT_SYMBOL(of_i2c_register_device);
- if (of_get_property(node, "wakeup-source", NULL))
- info.flags |= I2C_CLIENT_WAKE;
+static void of_i2c_register_devices(struct i2c_adapter *adap)
+{
+ struct device_node *node;
- request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+ /* Only register child devices if the adapter has a node pointer set */
+ if (!adap->dev.of_node)
+ return;
- result = i2c_new_device(adap, &info);
- if (result == NULL) {
- dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
- node->full_name);
- of_node_put(node);
- irq_dispose_mapping(info.irq);
- continue;
- }
- }
+ dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+
+ for_each_available_child_of_node(adap->dev.of_node, node)
+ of_i2c_register_device(adap, node);
}
static int of_dev_node_match(struct device *dev, void *data)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index deddeb8..a5802be 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -557,6 +557,9 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
#endif /* I2C */
#if IS_ENABLED(CONFIG_OF)
+struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node);
+
/* must call put_device() when done with returned i2c_client device */
extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
@@ -565,6 +568,13 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
#else
+static inline struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap,
+ struct device_node *node)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
return NULL;
--
1.7.12
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v3 6/7] OF: spi: Add overlay bus handler
[not found] ` <1395179766-31575-7-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
@ 2014-03-20 10:51 ` Michael Stickel
0 siblings, 0 replies; 20+ messages in thread
From: Michael Stickel @ 2014-03-20 10:51 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Guenter Roeck, Dirk Behme, Alan Tull, Sascha Hauer, Michael Bohan,
Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Pete Popov, Dan Malek,
Georgi Vlaev
Am 18.03.2014 22:56, schrieb Pantelis Antoniou:
> Add the bus handler registration needed for performing overlays
> containing spi devices.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
> ---
> drivers/spi/spi.c | 345 ++++++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 242 insertions(+), 103 deletions(-)
>
nc is not set in of_register_spi_device and causes an Oops.
Using nc = node works.
What is the purpose of nc?
> +of_register_spi_device(struct spi_master *master, struct device_node *node)
> +{
> + struct spi_device *spi;
> + struct device_node *nc;
> + int err;
> + u32 value;
> +
> + /* Alloc an spi_device */
> + spi = spi_alloc_device(master);
> + if (!spi) {
> + dev_err(&master->dev, "spi_device alloc error for %s\n",
> + nc->full_name);
> + err = -ENOMEM;
> + goto err_out;
> + }
> +
> + /* Select device driver */
> + err = of_modalias_node(nc, spi->modalias,
> + sizeof(spi->modalias));
> + if (err) {
> + dev_err(&master->dev, "cannot find modalias for %s\n",
> + nc->full_name);
> + goto err_out;
> + }
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 3/7] OF: DT-Overlay configfs interface
[not found] ` <1395179766-31575-4-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
@ 2014-03-21 13:39 ` Rob Herring
[not found] ` <CAL_JsqKJqakXGWDEKPAoJ9P5myYXnodcYCdvowV6MPuZXgwVmw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 20+ messages in thread
From: Rob Herring @ 2014-03-21 13:39 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Pete Popov,
Dan Malek, Georgi Vlaev
On Tue, Mar 18, 2014 at 4:56 PM, Pantelis Antoniou
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
> Add a runtime interface to using configfs for generic device tree overlay
> usage.
>
> A device-tree configfs entry is created in /config/device-tree/overlays
>
> To create an overlay you mkdir the directory and then echo the overlay
> firmware file to the path property file.
>
> # mkdir /config/device-tree/overlays/foo
> # echo foo.dtbo >/config/device-tree/overlays/foo/path
The purpose of 'path' and what determines its name is not really
clear. The documentation should be clear enough that a user knowing no
details of overlays can be handed a dtbo file and pointer to the
documentation and they can apply it without further information.
> The overlay file will be loaded using the standard firmware loader
> and will be applied.
>
> To remove it simply rmdir the directory.
>
> # rmdir /config/device-tree/overlays/foo
This description should be put into a file in Documentation/. Probably
Documentation/devicetree/ since it is a kernel interface and not a
bindings.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
> ---
> drivers/of/Kconfig | 5 +
> drivers/of/Makefile | 1 +
> drivers/of/configfs.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 278 insertions(+)
> create mode 100644 drivers/of/configfs.c
>
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 7517be2..fc0e3ec 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -77,6 +77,10 @@ config OF_RESERVED_MEM
> help
> Helpers to allow for reservation of memory regions
>
> +config OF_CONFIGFS
> + select CONFIGFS_FS
> + def_bool n
Is it feasible to make this a module (perhaps all of the overlay support)?
> +
> config OF_RESOLVE
> bool "OF Dynamic resolution support"
> depends on OF
> @@ -92,6 +96,7 @@ config OF_OVERLAY
> select OF_DYNAMIC
> select OF_DEVICE
> select OF_RESOLVE
> + select OF_CONFIGFS
> help
> OpenFirmware overlay support. Allows you to modify on runtime the
> live tree using overlays.
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index d2a6e0d..4efa17b 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -12,3 +12,4 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
> obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> obj-$(CONFIG_OF_RESOLVE) += resolver.o
> obj-$(CONFIG_OF_OVERLAY) += overlay.o
> +obj-$(CONFIG_OF_CONFIGFS) += configfs.o
> diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c
> new file mode 100644
> index 0000000..a494643
> --- /dev/null
> +++ b/drivers/of/configfs.c
> @@ -0,0 +1,272 @@
> +/*
> + * Configfs entries for device-tree
> + *
> + * Copyright (C) 2013 - Pantelis Antoniou <panto-wVdstyuyKrO8r51toPun2/C9HSW9iNxf@public.gmane.org>
It's 2014 now. I assume you have made some changes in 2014.
> + *
> + * 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/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"
> +
> +#ifdef CONFIG_OF_OVERLAY
This file is only compiled with this defined, so it isn't needed.
> +
> +struct cfs_overlay_item {
> + struct config_item item;
> +
> + char path[PATH_MAX];
> +
Remove the blank lines.
> + const struct firmware *fw;
> + struct device_node *overlay;
> + int ovinfo_cnt;
> + struct of_overlay_info *ovinfo;
> + unsigned int applied : 1;
Do you plan to expand this? If not, just use bool.
> +};
> +
> +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;
> +}
> +
> +CONFIGFS_ATTR_STRUCT(cfs_overlay_item);
> +#define CFS_OVERLAY_ITEM_ATTR(_name, _mode, _show, _store) \
> +struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
> + __CONFIGFS_ATTR(_name, _mode, _show, _store)
> +#define CFS_OVERLAY_ITEM_ATTR_RO(_name, _show) \
> +struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
> + __CONFIGFS_ATTR_RO(_name, _show)
> +
> +static ssize_t cfs_overlay_item_path_show(struct cfs_overlay_item *overlay,
> + char *page)
> +{
> + return sprintf(page, "%s\n", overlay->path);
> +}
> +
> +static ssize_t cfs_overlay_item_path_store(struct cfs_overlay_item *overlay,
> + const char *page, size_t count)
> +{
> + const char *p = page;
> + char *s;
> + int err;
> +
> + /* if it's set do not allow changes */
> + if (overlay->path[0] != '\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';
Seems like this would be common pattern. There are no helpers to do this?
> +
> + pr_debug("%s: path is '%s'\n", __func__, overlay->path);
> +
> + err = request_firmware(&overlay->fw, overlay->path, NULL);
> + if (err != 0)
> + goto out_err;
> +
> + /* unflatten the tree */
> + of_fdt_unflatten_tree((void *)overlay->fw->data, &overlay->overlay);
> + if (overlay->overlay == NULL) {
"if (!overlay->overlay)" is preferred.
overlay->node would be better naming.
> + pr_err("%s: failed to unflatten tree\n", __func__);
> + err = -EINVAL;
> + goto out_err;
> + }
> + pr_debug("%s: unflattened OK\n", __func__);
> +
> + /* mark it as detached */
> + of_node_set_flag(overlay->overlay, OF_DETACHED);
> +
> + /* perform resolution */
> + err = of_resolve(overlay->overlay);
> + if (err != 0) {
> + pr_err("%s: Failed to resolve tree\n", __func__);
> + goto out_err;
> + }
> + pr_debug("%s: resolved OK\n", __func__);
> +
> + /* now build an overlay info array */
> + err = of_build_overlay_info(overlay->overlay,
> + &overlay->ovinfo_cnt, &overlay->ovinfo);
> + if (err != 0) {
> + pr_err("%s: Failed to build overlay info\n", __func__);
> + goto out_err;
> + }
> +
> + pr_debug("%s: built %d overlay segments\n", __func__,
> + overlay->ovinfo_cnt);
> +
> + err = of_overlay(overlay->ovinfo_cnt, overlay->ovinfo);
This really applies to the previous patches, but there's not much
consistency in the function naming. It is not clear what of_overlay
does.
I would prefix all funcitons of_overlay_* and call this one
of_overlay_apply (or finalize?).
> + if (err != 0) {
> + pr_err("%s: Failed to apply overlay\n", __func__);
> + goto out_err;
> + }
> +
> + overlay->applied = 1;
> +
> + pr_debug("%s: Applied #%d overlay segments\n", __func__,
> + overlay->ovinfo_cnt);
> +
> + return count;
> +
> +out_err:
> + if (overlay->applied)
> + of_overlay_revert(overlay->ovinfo_cnt, overlay->ovinfo);
> + overlay->applied = 0;
> +
> + if (overlay->ovinfo)
> + of_free_overlay_info(overlay->ovinfo_cnt, overlay->ovinfo);
> + overlay->ovinfo = NULL;
> + overlay->ovinfo_cnt = 0;
> +
> + release_firmware(overlay->fw);
This needs some clean-up with multiple jump labels. You shouldn't need
the if statements and you cal release_firmware on request_firmware
error.
> + overlay->fw = NULL;
> +
> + overlay->path[0] = '\0';
> + return err;
> +}
> +
> +static ssize_t cfs_overlay_item_status_show(struct cfs_overlay_item *overlay,
> + char *page)
> +{
> + return sprintf(page, "%s\n",
> + overlay->applied ? "applied" : "unapplied");
> +}
This needs to be added to the above mentioned documentation along with
any other files.
> +
> +CFS_OVERLAY_ITEM_ATTR(path, S_IRUGO | S_IWUSR, \
> + cfs_overlay_item_path_show, cfs_overlay_item_path_store);
> +CFS_OVERLAY_ITEM_ATTR_RO(status, cfs_overlay_item_status_show);
> +
> +static struct configfs_attribute *cfs_overlay_attrs[] = {
> + &cfs_overlay_item_attr_path.attr,
> + &cfs_overlay_item_attr_status.attr,
> + NULL,
> +};
> +
> +static void cfs_overlay_release(struct config_item *item)
> +{
> + struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
> +
> + if (overlay->applied)
> + of_overlay_revert(overlay->ovinfo_cnt, overlay->ovinfo);
> + if (overlay->ovinfo)
> + of_free_overlay_info(overlay->ovinfo_cnt, overlay->ovinfo);
> + if (overlay->fw)
> + release_firmware(overlay->fw);
> + kfree(overlay);
> +}
> +
> +CONFIGFS_ATTR_OPS(cfs_overlay_item);
> +static struct configfs_item_operations cfs_overlay_item_ops = {
> + .release = cfs_overlay_release,
> + .show_attribute = cfs_overlay_item_attr_show,
> + .store_attribute = cfs_overlay_item_attr_store,
> +};
> +
> +static struct config_item_type cfs_overlay_type = {
> + .ct_item_ops = &cfs_overlay_item_ops,
> + .ct_attrs = cfs_overlay_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);
> +
> + 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,
> +};
> +
> +#endif /* CONFIG_OF_OVERLAY */
> +
> +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,
> +};
> +
> +struct config_group of_cfs_overlay_group;
> +
> +struct config_group *of_cfs_def_groups[] = {
> +#ifdef CONFIG_OF_OVERLAY
> + &of_cfs_overlay_group,
> +#endif
> + NULL
> +};
> +
> +static struct configfs_subsystem of_cfs_subsys = {
> + .su_group = {
> + .cg_item = {
> + .ci_namebuf = "device-tree",
> + .ci_type = &of_cfs_type,
> + },
> + .default_groups = of_cfs_def_groups,
> + },
> + .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);
> +#ifdef CONFIG_OF_OVERLAY
> + config_group_init_type_name(&of_cfs_overlay_group, "overlays", &overlays_type);
> +#endif
> +
> + 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__);
These pr_info prints are not necessary you can use initcall_debug.
> +out:
> + return ret;
> +}
> +late_initcall(of_cfs_init);
Does this really need to be late_initcall?
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 3/7] OF: DT-Overlay configfs interface
[not found] ` <CAL_JsqKJqakXGWDEKPAoJ9P5myYXnodcYCdvowV6MPuZXgwVmw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-03-21 13:56 ` Sebastian Hesselbarth
0 siblings, 0 replies; 20+ messages in thread
From: Sebastian Hesselbarth @ 2014-03-21 13:56 UTC (permalink / raw)
To: Rob Herring, Pantelis Antoniou
Cc: Grant Likely, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Alan Tull,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Pete Popov,
Dan Malek, Georgi Vlaev
On 03/21/2014 02:39 PM, Rob Herring wrote:
> On Tue, Mar 18, 2014 at 4:56 PM, Pantelis Antoniou
> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>> Add a runtime interface to using configfs for generic device tree overlay
>> usage.
>>
>> A device-tree configfs entry is created in /config/device-tree/overlays
>>
>> To create an overlay you mkdir the directory and then echo the overlay
>> firmware file to the path property file.
>>
>> # mkdir /config/device-tree/overlays/foo
>> # echo foo.dtbo >/config/device-tree/overlays/foo/path
[...]
>> +static ssize_t cfs_overlay_item_status_show(struct cfs_overlay_item *overlay,
>> + char *page)
>> +{
>> + return sprintf(page, "%s\n",
>> + overlay->applied ? "applied" : "unapplied");
>> +}
>
> This needs to be added to the above mentioned documentation along with
> any other files.
It is also terrible to grep for. Maybe just have the file named
"applied" and use a bool instead?
Sebastian
>> +
>> +CFS_OVERLAY_ITEM_ATTR(path, S_IRUGO | S_IWUSR, \
>> + cfs_overlay_item_path_show, cfs_overlay_item_path_store);
>> +CFS_OVERLAY_ITEM_ATTR_RO(status, cfs_overlay_item_status_show);
>> +
>> +static struct configfs_attribute *cfs_overlay_attrs[] = {
>> + &cfs_overlay_item_attr_path.attr,
>> + &cfs_overlay_item_attr_status.attr,
>> + NULL,
>> +};
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 2/7] OF: Introduce DT overlay support.
2014-03-18 21:56 ` [PATCH v3 2/7] OF: Introduce DT overlay support Pantelis Antoniou
@ 2014-03-28 14:51 ` delicious quinoa
2014-03-28 18:54 ` delicious quinoa
1 sibling, 0 replies; 20+ messages in thread
From: delicious quinoa @ 2014-03-28 14:51 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree@vger.kernel.org, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev
On Tue, Mar 18, 2014 at 4:56 PM, Pantelis Antoniou
<pantelis.antoniou@konsulko.com> wrote:
> Introduce DT overlay support.
> Using this functionality it is possible to dynamically overlay a part of
> the kernel's tree with another tree that's been dynamically loaded.
> It is also possible to remove node and properties.
>
> The creation/destruction of the devices is handled by calling in to
> bus specific handlers which can deal with the peculiarities of each
> device.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
> ---
> Documentation/devicetree/overlay-notes.txt | 187 ++++++
> drivers/of/Kconfig | 10 +
> drivers/of/Makefile | 1 +
> drivers/of/overlay.c | 895 +++++++++++++++++++++++++++++
> include/linux/of.h | 153 +++++
> 5 files changed, 1246 insertions(+)
> create mode 100644 Documentation/devicetree/overlay-notes.txt
> create mode 100644 drivers/of/overlay.c
>
> diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
> new file mode 100644
> index 0000000..882d512
> --- /dev/null
> +++ b/Documentation/devicetree/overlay-notes.txt
> @@ -0,0 +1,187 @@
> +Device Tree Overlay Notes
> +-------------------------
> +
> +This document describes the implementation of the in-kernel
> +device tree overlay functionality residing in drivers/of/overlay.c and is a
> +companion document to Documentation/devicetree/dt-object-internal.txt[1] &
> +Documentation/devicetree/dynamic-resolution-notes.txt[2]
> +
> +How overlays work
> +-----------------
> +
> +A Device Tree's overlay purpose is to modify the kernel's live tree, and
> +have the modification affecting the state of the the kernel in a way that
> +is reflecting the changes.
> +Since the kernel mainly deals with devices, any new device node that result
> +in an active device should have it created while if the device node is either
> +disabled or removed all together, the affected device should be deregistered.
> +
> +Lets take an example where we have a foo board with the following base tree
> +which is taken from [1].
> +
> +---- foo.dts -----------------------------------------------------------------
> + /* FOO platform */
> + / {
> + compatible = "corp,foo";
> +
> + /* shared resources */
> + res: res {
> + };
> +
> + /* On chip peripherals */
> + ocp: ocp {
> + /* peripherals that are always instantiated */
> + peripheral1 { ... };
> + }
> + };
> +---- foo.dts -----------------------------------------------------------------
> +
> +The overlay bar.dts, when loaded (and resolved as described in [2]) should
> +
> +---- bar.dts -----------------------------------------------------------------
> +/plugin/; /* allow undefined label references and record them */
> +/ {
> + .... /* various properties for loader use; i.e. part id etc. */
> + fragment@0 {
> + target = <&ocp>;
> + __overlay__ {
> + /* bar peripheral */
> + bar {
> + compatible = "corp,bar";
> + ... /* various properties and child nodes */
> + }
> + };
> + };
> +};
> +---- bar.dts -----------------------------------------------------------------
> +
> +result in foo+bar.dts
> +
> +---- foo+bar.dts -------------------------------------------------------------
> + /* FOO platform + bar peripheral */
> + / {
> + compatible = "corp,foo";
> +
> + /* shared resources */
> + res: res {
> + };
> +
> + /* On chip peripherals */
> + ocp: ocp {
> + /* peripherals that are always instantiated */
> + peripheral1 { ... };
> +
> + /* bar peripheral */
> + bar {
> + compatible = "corp,bar";
> + ... /* various properties and child nodes */
> + }
> + }
> + };
> +---- foo+bar.dts -------------------------------------------------------------
> +
> +As a result of the the overlay, a new device node (bar) has been created
> +so a bar platform device will be registered and if a matching device driver
> +is loaded the device will be created as expected.
> +
> +Overlay in-kernel API
> +---------------------
> +
> +The steps typically required to get an overlay to work are as follows:
> +
> +1. Use of_build_overlay_info() to create an array of initialized and
> +ready to use of_overlay_info structures.
> +2. Call of_overlay() to apply the overlays declared in the array.
> +3. If the overlay needs to be removed, call of_overlay_revert().
> +4. Finally release the memory taken by the overlay info array by
> +of_free_overlay_info().
> +
> +/**
> + * of_build_overlay_info - Build an overlay info array
> + * @tree: Device node containing all the overlays
> + * @cntp: Pointer to where the overlay info count will be help
> + * @ovinfop: Pointer to the pointer of an overlay info structure.
> + *
> + * Helper function that given a tree containing overlay information,
> + * allocates and builds an overlay info array containing it, ready
> + * for use using of_overlay.
> + *
> + * Returns 0 on success with the @cntp @ovinfop pointers valid,
> + * while on error a negative error value is returned.
> + */
> +int of_build_overlay_info(struct device_node *tree,
> + int *cntp, struct of_overlay_info **ovinfop);
> +
> +/**
> + * of_free_overlay_info - Free an overlay info array
> + * @count: Number of of_overlay_info's
> + * @ovinfo_tab: Array of overlay_info's to free
> + *
> + * Releases the memory of a previously allocate ovinfo array
> + * by of_build_overlay_info.
> + * Returns 0, or an error if the arguments are bogus.
> + */
> +int of_free_overlay_info(int count, struct of_overlay_info *ovinfo_tab);
> +
> +/**
> + * of_overlay - Apply @count overlays pointed at by @ovinfo_tab
> + * @count: Number of of_overlay_info's
> + * @ovinfo_tab: Array of overlay_info's to apply
> + *
> + * Applies the overlays given, while handling all error conditions
> + * appropriately. Either the operation succeeds, or if it fails the
> + * live tree is reverted to the state before the attempt.
> + * Returns 0, or an error if the overlay attempt failed.
> + */
> +int of_overlay(int count, struct of_overlay_info *ovinfo_tab);
> +
> +/**
> + * of_overlay_revert - Revert a previously applied overlay
> + * @count: Number of of_overlay_info's
> + * @ovinfo_tab: Array of overlay_info's to apply
> + *
> + * Revert a previous overlay. The state of the live tree
> + * is reverted to the one before the overlay.
> + * Returns 0, or an error if the overlay table is not given.
> + */
> +int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab);
> +
> +Overlay DTS Format
> +------------------
> +
> +The DTS of an overlay should have the following format:
> +
> +{
> + /* ignored properties by the overlay */
> +
> + fragment@0 { /* first child node */
> +
> + target=<phandle>; /* phandle target of the overlay */
> + or
> + target-path="/path"; /* target path of the overlay */
> + or
> + target-alias="alias"; /* target alias of the overlay */
> + __overlay__ {
> + property-a; /* add property-a to the target */
> + -property-b; /* remove property-b from target */
> + node-a { /* add to an existing, or create a node-a */
> + ...
> + };
> + -node-b { /* remove an existing node-b */
> + ...
> + };
> + };
> + }
> + fragment@1 { /* second child node */
> + ...
> + };
> + /* more fragments follow */
> +}
> +
> +It should be noted that the DT overlay format described is the one expected
> +by the of_build_overlay_info() function, which is a helper function. There
> +is nothing stopping someone coming up with his own DTS format and that will
> +end up filling in the fields of the of_overlay_info array.
> +
> +Using the non-phandle based target method allows one to use a base DT which does
> +not contain a __symbols__ now, i.e. it was not compiled with the -@ option.
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 33a8fef..7517be2 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -86,4 +86,14 @@ config OF_RESOLVE
> Enable OF dynamic resolution support. This allows you to
> load Device Tree object fragments are run time.
>
> +config OF_OVERLAY
> + bool "OF overlay support"
> + depends on OF
> + select OF_DYNAMIC
> + select OF_DEVICE
> + select OF_RESOLVE
> + help
> + OpenFirmware overlay support. Allows you to modify on runtime the
> + live tree using overlays.
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index c241e79..d2a6e0d 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> obj-$(CONFIG_OF_RESOLVE) += resolver.o
> +obj-$(CONFIG_OF_OVERLAY) += overlay.o
> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
> new file mode 100644
> index 0000000..2179b9f
> --- /dev/null
> +++ b/drivers/of/overlay.c
> @@ -0,0 +1,895 @@
> +/*
> + * Functions for working with device tree overlays
> + *
> + * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
> + * Copyright (C) 2012 Texas Instruments Inc.
> + *
> + * 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.
> + */
> +#undef DEBUG
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/string.h>
> +#include <linux/ctype.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +
> +/* protect the handlers list */
> +static DEFINE_MUTEX(of_handler_mutex);
> +static struct list_head of_handler_list = LIST_HEAD_INIT(of_handler_list);
> +
> +int of_overlay_handler_register(struct of_overlay_handler *handler)
> +{
> + /* guard against bad data */
> + if (!handler || !handler->name || !handler->ops ||
> + !handler->ops->create || !handler->ops->remove)
> + return -EINVAL;
> +
> + mutex_lock(&of_handler_mutex);
> + list_add_tail(&handler->list, &of_handler_list);
> + mutex_unlock(&of_handler_mutex);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_overlay_handler_register);
> +
> +void of_overlay_handler_unregister(struct of_overlay_handler *handler)
> +{
> + struct of_overlay_handler *curr;
> +
> + mutex_lock(&of_handler_mutex);
> + list_for_each_entry(curr, &of_handler_list, list) {
> + if (handler == curr) {
> + list_del(&handler->list);
> + break;
> + }
> + }
> + mutex_unlock(&of_handler_mutex);
> +}
> +EXPORT_SYMBOL_GPL(of_overlay_handler_unregister);
> +
> +static int handler_create(struct of_overlay_device_entry *entry, int revert)
> +{
> + struct of_overlay_handler *handler;
> + int ret;
> +
> + mutex_lock(&of_handler_mutex);
> + list_for_each_entry(handler, &of_handler_list, list) {
> + ret = (*handler->ops->create)(entry, revert);
> + /* ENOTSUPP means try next */
> + if (ret == -ENOTSUPP)
> + continue;
> + /* anything else means something happened */
> + break;
> + }
> + mutex_unlock(&of_handler_mutex);
> +
> + return ret;
> +}
> +
> +static int handler_remove(struct of_overlay_device_entry *entry, int revert)
> +{
> + struct of_overlay_handler *handler;
> + int ret;
> +
> + mutex_lock(&of_handler_mutex);
> + list_for_each_entry(handler, &of_handler_list, list) {
> + ret = (*handler->ops->remove)(entry, revert);
> + /* ENOTSUPP means try next */
> + if (ret == -ENOTSUPP)
> + continue;
> + /* anything else means something happened */
> + break;
> + }
> + mutex_unlock(&of_handler_mutex);
> +
> + return ret;
> +}
> +
> +/**
> + * Apply a single overlay node recursively.
> + *
> + * Property or node names that start with '-' signal that
> + * the property/node is to be removed.
> + *
> + * All the property notifiers are appropriately called.
> + * Note that the in case of an error the target node is left
> + * in a inconsistent state. Error recovery should be performed
> + * by recording the modification using the of notifiers.
> + */
> +static int of_overlay_apply_one(struct device_node *target,
> + const struct device_node *overlay)
> +{
> + const char *pname, *cname;
> + struct device_node *child, *tchild;
> + struct property *prop, *propn, *tprop;
> + int remove;
> + char *full_name;
> + const char *suffix;
> + int ret;
> +
> + /* sanity checks */
> + if (target == NULL || overlay == NULL)
> + return -EINVAL;
> +
> + for_each_property_of_node(overlay, prop) {
> +
> + /* don't touch, 'name' */
> + if (of_prop_cmp(prop->name, "name") == 0)
> + continue;
> +
> + /* default is add */
> + remove = 0;
> + pname = prop->name;
> + if (*pname == '-') { /* skip, - notes removal */
> + pname++;
> + remove = 1;
> + propn = NULL;
> + } else {
> + propn = __of_copy_property(prop, GFP_KERNEL,
> + OF_PROP_ALLOCALL);
> + if (propn == NULL)
> + return -ENOMEM;
> + }
> +
> + tprop = of_find_property(target, pname, NULL);
> +
> + /* found? */
> + if (tprop != NULL) {
> + if (propn != NULL)
> + ret = of_update_property(target, propn);
> + else
> + ret = of_remove_property(target, tprop);
> + } else {
> + if (propn != NULL)
> + ret = of_add_property(target, propn);
> + else
> + ret = 0;
> + }
> + if (ret != 0)
> + return ret;
> + }
> +
> + __for_each_child_of_node(overlay, child) {
> +
> + /* default is add */
> + remove = 0;
> + cname = child->name;
> + if (*cname == '-') { /* skip, - notes removal */
> + cname++;
> + remove = 1;
> + }
> +
> + /* special case for nodes with a suffix */
> + suffix = strrchr(child->full_name, '@');
> + if (suffix != NULL) {
> + cname = kbasename(child->full_name);
> + WARN_ON(cname == NULL); /* sanity check */
> + if (cname == NULL)
> + continue;
> + if (*cname == '-')
> + cname++;
> + }
> +
> + tchild = of_get_child_by_name(target, cname);
> + if (tchild != NULL) {
> +
> + if (!remove) {
> +
> + /* apply overlay recursively */
> + ret = of_overlay_apply_one(tchild, child);
> + of_node_put(tchild);
> +
> + if (ret != 0)
> + return ret;
> +
> + } else {
> +
> + ret = of_detach_node(tchild);
> + of_node_put(tchild);
> + }
> +
> + } else {
> +
> + if (!remove) {
> + full_name = kasprintf(GFP_KERNEL, "%s/%s",
> + target->full_name, cname);
> + if (full_name == NULL)
> + return -ENOMEM;
> +
> + /* create empty tree as a target */
> + tchild = __of_create_empty_node(cname,
> + child->type, full_name,
> + child->phandle, GFP_KERNEL,
> + OF_NODE_ALLOCALL);
> +
> + /* free either way */
> + kfree(full_name);
> +
> + if (tchild == NULL)
> + return -ENOMEM;
> +
> + /* point to parent */
> + tchild->parent = target;
> +
> + ret = of_attach_node(tchild);
> + if (ret != 0)
> + return ret;
> +
> + /* apply the overlay */
> + ret = of_overlay_apply_one(tchild, child);
> + if (ret != 0) {
> + __of_free_tree(tchild);
> + return ret;
> + }
> + }
> + }
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * Lookup an overlay device entry
> + */
> +struct of_overlay_device_entry *of_overlay_device_entry_lookup(
> + struct of_overlay_info *ovinfo, struct device_node *node)
> +{
> + struct of_overlay_device_entry *de;
> +
> + /* no need for locks, we'de under the ovinfo->lock */
> + list_for_each_entry(de, &ovinfo->de_list, node) {
> + if (de->np == node)
> + return de;
> + }
> + return NULL;
> +}
> +
> +/**
> + * Add an overlay log entry
> + */
> +static int of_overlay_log_entry_entry_add(struct of_overlay_info *ovinfo,
> + unsigned long action, struct device_node *dn,
> + struct property *prop)
> +{
> + struct of_overlay_log_entry *le;
> +
> + /* check */
> + if (ovinfo == NULL || dn == NULL)
> + return -EINVAL;
> +
> + le = kzalloc(sizeof(*le), GFP_KERNEL);
> + if (le == NULL) {
> + pr_err("%s: Failed to allocate\n", __func__);
> + return -ENOMEM;
> + }
> +
> + /* get a reference to the node */
> + le->action = action;
> + le->np = of_node_get(dn);
> + le->prop = prop;
> +
> + if (action == OF_RECONFIG_UPDATE_PROPERTY && prop)
> + le->old_prop = of_find_property(dn, prop->name, NULL);
> +
> + list_add_tail(&le->node, &ovinfo->le_list);
> +
> + return 0;
> +}
> +
> +/**
> + * Add an overlay device entry
> + */
> +static void of_overlay_device_entry_entry_add(struct of_overlay_info *ovinfo,
> + struct device_node *node,
> + int prevstate, int state)
> +{
> + struct of_overlay_device_entry *de;
> + int fresh;
> +
> + /* check */
> + if (ovinfo == NULL)
> + return;
> +
> + fresh = 0;
> + de = of_overlay_device_entry_lookup(ovinfo, node);
> + if (de == NULL) {
> + de = kzalloc(sizeof(*de), GFP_KERNEL);
> + if (de == NULL) {
> + pr_err("%s: Failed to allocate\n", __func__);
> + return;
> + }
> + fresh = 1;
> + de->prevstate = -1;
> + }
> +
> + if (de->np == NULL)
> + de->np = of_node_get(node);
> + if (fresh)
> + de->prevstate = prevstate;
> + de->state = state;
> +
> + if (fresh)
> + list_add_tail(&de->node, &ovinfo->de_list);
> +}
> +
> +/**
> + * Overlay OF notifier
> + *
> + * Called every time there's a property/node modification
> + * Every modification causes a log entry addition, while
> + * any modification that causes a node's state to change
> + * from/to disabled to/from enabled causes a device entry
> + * addition.
> + */
> +static int of_overlay_notify(struct notifier_block *nb,
> + unsigned long action, void *arg)
> +{
> + struct of_overlay_info *ovinfo;
> + struct device_node *node;
> + struct property *prop, *sprop, *cprop;
> + struct of_prop_reconfig *pr;
> + struct device_node *tnode;
> + int depth;
> + int prevstate, state;
> + int err = 0;
> +
> + ovinfo = container_of(nb, struct of_overlay_info, notifier);
> +
> + /* prep vars */
> + switch (action) {
> + case OF_RECONFIG_ATTACH_NODE:
> + case OF_RECONFIG_DETACH_NODE:
> + node = arg;
> + if (node == NULL)
> + return notifier_from_errno(-EINVAL);
> + prop = NULL;
> + break;
> + case OF_RECONFIG_ADD_PROPERTY:
> + case OF_RECONFIG_REMOVE_PROPERTY:
> + case OF_RECONFIG_UPDATE_PROPERTY:
> + pr = arg;
> + if (pr == NULL)
> + return notifier_from_errno(-EINVAL);
> + node = pr->dn;
> + if (node == NULL)
> + return notifier_from_errno(-EINVAL);
> + prop = pr->prop;
> + if (prop == NULL)
> + return notifier_from_errno(-EINVAL);
> + break;
> + default:
> + return notifier_from_errno(0);
> + }
> +
> + /* add to the log */
> + err = of_overlay_log_entry_entry_add(ovinfo, action, node, prop);
> + if (err != 0)
> + return notifier_from_errno(err);
> +
> + /* come up with the device entry (if any) */
> + state = 0;
> + prevstate = 0;
> +
> + /* determine the state the node will end up */
> + switch (action) {
> + case OF_RECONFIG_ATTACH_NODE:
> + /* we demand that a compatible node is present */
> + state = of_find_property(node, "compatible", NULL) &&
> + of_device_is_available(node);
> + break;
> + case OF_RECONFIG_DETACH_NODE:
> + prevstate = of_find_property(node, "compatible", NULL) &&
> + of_device_is_available(node);
> + state = 0;
> + break;
> + case OF_RECONFIG_ADD_PROPERTY:
> + case OF_RECONFIG_REMOVE_PROPERTY:
> + case OF_RECONFIG_UPDATE_PROPERTY:
> + /* either one cause a change in state */
> + if (strcmp(prop->name, "status") != 0 &&
> + strcmp(prop->name, "compatible") != 0)
> + return notifier_from_errno(0);
> +
> + if (strcmp(prop->name, "status") == 0) {
> + /* status */
> + cprop = of_find_property(node, "compatible", NULL);
> + sprop = action != OF_RECONFIG_REMOVE_PROPERTY ?
> + prop : NULL;
> + } else {
> + /* compatible */
> + sprop = of_find_property(node, "status", NULL);
> + cprop = action != OF_RECONFIG_REMOVE_PROPERTY ?
> + prop : NULL;
> + }
> +
> + prevstate = of_find_property(node, "compatible", NULL) &&
> + of_device_is_available(node);
> + state = cprop && cprop->length > 0 &&
> + (!sprop || (sprop->length > 0 &&
> + (strcmp(sprop->value, "okay") == 0 ||
> + strcmp(sprop->value, "ok") == 0)));
> + break;
> +
> + default:
> + return notifier_from_errno(0);
> + }
> +
> + /* find depth */
> + depth = 1;
> + tnode = node;
> + while (tnode != NULL && tnode != ovinfo->target) {
> + tnode = tnode->parent;
> + depth++;
> + }
> +
> + /* respect overlay's maximum depth */
> + if (ovinfo->device_depth != 0 && depth > ovinfo->device_depth) {
> + pr_debug("OF: skipping device creation for node=%s depth=%d\n",
> + node->name, depth);
> + goto out;
> + }
> +
> + of_overlay_device_entry_entry_add(ovinfo, node, prevstate, state);
> +out:
> +
> + return notifier_from_errno(err);
> +}
> +
> +/**
> + * Prepare for the overlay, for now it just registers the
> + * notifier.
> + */
> +static int of_overlay_prep_one(struct of_overlay_info *ovinfo)
> +{
> + int err;
> +
> + err = of_reconfig_notifier_register(&ovinfo->notifier);
> + if (err != 0) {
> + pr_err("%s: failed to register notifier for '%s'\n",
> + __func__, ovinfo->target->full_name);
> + return err;
> + }
> + return 0;
> +}
> +
> +static int of_overlay_device_entry_change(struct of_overlay_info *ovinfo,
> + struct of_overlay_device_entry *de, int revert)
> +{
> + int state;
> + int ret;
> +
> + state = !!de->state ^ !!revert;
> +
> + if (state)
> + ret = handler_create(de, revert);
> + else
> + ret = handler_remove(de, revert);
> +
> + if (ret != 0 && ret != -ENOTSUPP)
Build warning about ret might not be initialized.
Alan Tull
> + pr_warn("%s: Failed to %s device "
> + "for node '%s'\n", __func__,
> + state ? "create" : "remove",
> + de->np->full_name);
> + return 0;
> +}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
` (6 preceding siblings ...)
2014-03-18 21:56 ` [PATCH v3 7/7] of: i2c: Export single device registration method Pantelis Antoniou
@ 2014-03-28 18:27 ` delicious quinoa
[not found] ` <CANk1AXTb=ob52AfK2z--HvFkxJnjnfYWuTCch_Gw99OCoS1ABg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
7 siblings, 1 reply; 20+ messages in thread
From: delicious quinoa @ 2014-03-28 18:27 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree@vger.kernel.org, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev
On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
<pantelis.antoniou@konsulko.com> wrote:
> The following patchset introduces Device Tree overlays, a method
> of dynamically altering the kernel's live Device Tree, along with
> a generic interface to use it in a board agnostic manner.
>
> It is dependent on Grant Likely's DT kobjectification patches located
> in his tree as queued for -next.
>
> It relies on the following previously submitted patches/patchsets:
>
> * OF: Add [__]of_find_node_by_full_name
> * OF: Utility helper functions for dynamic nodes
> * of: Make of_find_node_by_path() handle /aliases
>
> To compile overlays you need the DTC compiler patch
>
> * "dtc: Dynamic symbols & fixup support (v2)"
>
> Changes since V2:
> * Use of a configfs board agnostic overlay method
> * Use of per bus handlers instead of hardcoded behaviour
> * Optional target-path overlay target, which allows one to use standard
> DTBs without resolution options.
>
> Changes since V1:
>
> * Removal of any bits related to a specific board (beaglebone).
> * Introduced a platform agnostic interface using /proc/device-tree-overlay
> * Various bug fixes related to i2c device handling have been squashed in.
>
>
> Pantelis Antoniou (7):
> OF: Introduce Device Tree resolve support.
> OF: Introduce DT overlay support.
> OF: DT-Overlay configfs interface
> OF: platform: Add overlay bus handler
> OF: i2c: Add overlay bus handler
> OF: spi: Add overlay bus handler
> of: i2c: Export single device registration method
>
> .../devicetree/dynamic-resolution-notes.txt | 25 +
> Documentation/devicetree/overlay-notes.txt | 187 +++++
> drivers/base/platform.c | 99 ++-
> drivers/i2c/i2c-core.c | 186 +++--
> drivers/of/Kconfig | 24 +
> drivers/of/Makefile | 3 +
> drivers/of/configfs.c | 272 +++++++
> drivers/of/overlay.c | 895 +++++++++++++++++++++
> drivers/of/resolver.c | 376 +++++++++
> drivers/spi/spi.c | 345 +++++---
> include/linux/i2c.h | 10 +
> include/linux/of.h | 170 ++++
> 12 files changed, 2440 insertions(+), 152 deletions(-)
> create mode 100644 Documentation/devicetree/dynamic-resolution-notes.txt
> create mode 100644 Documentation/devicetree/overlay-notes.txt
> create mode 100644 drivers/of/configfs.c
> create mode 100644 drivers/of/overlay.c
> create mode 100644 drivers/of/resolver.c
I can get a NULL pointer when I apply and remove an overlay and the
conditions are right. The overlay applies correctly. The crash is
when I do the rmdir. My overlay is:
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target-path="/soc";
__overlay__ {
#address-cells = <1>;
#size-cells = <1>;
agpio0: agpio0 {
compatible = "altr,pio-1.0";
reg = <0xff210040 0x10>;
interrupts = <0 45 4>;
altr,gpio-bank-width = <32>;
altr,interrupt_type = <1>;
#gpio-cells = <2>;
gpio-controller;
#interrupt-cells = <1>;
interrupt-controller;
};
};
};
};
The log info I have is:
root@socfpga_cyclone5:~# ./do-overlay-only
+ mkdir /config/device-tree/overlays/foo
+ echo socfpga_overlay.dtbo
+ rmdir /config/device-tree/overlays/foo
Unable to handle kernel NULL pointer dereference at virtual address 00000018
pgd = bf164000
[00000018] *pgd=3fb9c831, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] SMP ARM
Modules linked in:
CPU: 1 PID: 175 Comm: rmdir Not tainted 3.13.0-00299-g2e61581 #7
task: bf00f400 ti: bfba4000 task.ti: bfba4000
PC is at release_resource+0x24/0x98
LR is at release_resource+0x20/0x98
pc : [<800286e0>] lr : [<800286dc>] psr: 60000013
sp : bfba5da0 ip : bfba5da0 fp : bfba5db4
r10: 00100100 r9 : 00000000 r8 : 00200200
r7 : 80732ff8 r6 : 00000001 r5 : bfbb8400 r4 : bfbd1100
r3 : 00000000 r2 : 00000000 r1 : 00000002 r0 : 8074e580
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 3f16404a DAC: 00000015
Process rmdir (pid: 175, stack limit = 0xbfba4248)
Stack: (0xbfba5da0 to 0xbfba6000)
5da0: 00000000 00000001 bfba5dcc bfba5db8 802f2e40 800286c8 bfbb8400 bfb930c0
5dc0: bfba5de4 bfba5dd0 802f31e0 802f2dd0 bfbb8434 bfbb8400 bfba5dfc bfba5de8
5de0: 802f3224 802f31d0 802f31ec 807410ac bfba5e24 bfba5e00 803b4f20 802f31f8
5e00: bfb930c0 bfbe61a8 bfbe61a8 bfbe6180 00200200 00100100 bfba5e4c bfba5e28
5e20: 803b4fec 803b4e68 bfbe6140 ffffffff bfbe6188 00000000 80782dd4 80741108
5e40: bfba5e6c bfba5e50 803b51ec 803b4f94 00001040 bf82e000 807410b4 00000000
5e60: bfba5e84 bfba5e70 803b57f0 803b51b4 803b5778 bf82e018 bfba5ea4 bfba5e88
5e80: 80161df8 803b5784 00000000 00000000 bf82e000 bfb26070 bfba5eb4 bfba5ea8
5ea0: 80161e64 80161d9c bfba5eec bfba5eb8 8016071c 80161e28 80110da0 8010efbc
5ec0: bf59a198 bf59a198 00000000 bf5543f0 7e96ef14 ffffff9c bfba4000 bf59a198
5ee0: bfba5f0c bfba5ef0 801086e4 8016054c bf5533b8 bf128000 00000000 00000000
5f00: bfba5f94 bfba5f10 80108870 80108650 bf8e3010 bf5533b8 006f6f66 00000003
5f20: bf12802d 80107348 00000000 bf576660 bf5543f0 00000000 00000004 00000060
5f40: 00000000 00000000 bfba5f64 bfba5f58 800fcb1c 8003f114 bfba5f84 bfba5f68
5f60: 8003f114 804d1630 bfba4000 bfba4000 7e96ef14 00000000 7e96ee28 00000028
5f80: 8000ece4 00000000 bfba5fa4 bfba5f98 8010a800 8010875c 00000000 bfba5fa8
5fa0: 8000eac0 8010a7ec 7e96ef14 00000000 7e96ef14 00000000 00000002 7e96ee28
5fc0: 7e96ef14 00000000 7e96ee28 00000028 00000002 7e96ee24 0006a754 00000000
5fe0: 76f3d450 7e96ec74 0003c2e5 76f3d45c 80000010 7e96ef14 00000000 00000000
[<800286e0>] (release_resource+0x24/0x98) from [<802f2e40>]
(platform_device_del+0x7c/0xac)
[<802f2e40>] (platform_device_del+0x7c/0xac) from [<802f31e0>]
(platform_device_unregister+0x1c/0x28)
[<802f31e0>] (platform_device_unregister+0x1c/0x28) from [<802f3224>]
(platform_handler_remove+0x38/0x54)
[<802f3224>] (platform_handler_remove+0x38/0x54) from [<803b4f20>]
(of_overlay_device_entry_change.isra.0+0xc4/0x12c)
[<803b4f20>] (of_overlay_device_entry_change.isra.0+0xc4/0x12c) from
[<803b4fec>] (of_overlay_revert_one+0x64/0x220)
[<803b4fec>] (of_overlay_revert_one+0x64/0x220) from [<803b51ec>]
(of_overlay_revert+0x44/0x64)
[<803b51ec>] (of_overlay_revert+0x44/0x64) from [<803b57f0>]
(cfs_overlay_release+0x78/0x7c)
[<803b57f0>] (cfs_overlay_release+0x78/0x7c) from [<80161df8>]
(config_item_release+0x68/0x8c)
[<80161df8>] (config_item_release+0x68/0x8c) from [<80161e64>]
(config_item_put+0x48/0x4c)
[<80161e64>] (config_item_put+0x48/0x4c) from [<8016071c>]
(configfs_rmdir+0x1dc/0x264)
[<8016071c>] (configfs_rmdir+0x1dc/0x264) from [<801086e4>]
(vfs_rmdir+0xa0/0x10c)
[<801086e4>] (vfs_rmdir+0xa0/0x10c) from [<80108870>] (do_rmdir+0x120/0x150)
[<80108870>] (do_rmdir+0x120/0x150) from [<8010a800>] (SyS_rmdir+0x20/0x24)
[<8010a800>] (SyS_rmdir+0x20/0x24) from [<8000eac0>] (ret_fast_syscall+0x0/0x30)
Code: e1a04000 e59f0074 eb12b02b e5943010 (e5932018)
---[ end trace 1b8539e83d8e0ecc ]---
./do-overlay-only: line 7: 175 Segmentation fault rmdir
/config/device-tree/overlays/foo
root@socfpga_cyclone5:~#
I did some debug, haven't figured anything out yet.
I have been able to successfully add/remove an overlay if it was to a
fpga node that was at /fpga and used 'target = <&fpga>;' Also
'target-path="/fpga";' works fine.
Alan Tull
aka
delicious quinoa
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 2/7] OF: Introduce DT overlay support.
2014-03-18 21:56 ` [PATCH v3 2/7] OF: Introduce DT overlay support Pantelis Antoniou
2014-03-28 14:51 ` delicious quinoa
@ 2014-03-28 18:54 ` delicious quinoa
1 sibling, 0 replies; 20+ messages in thread
From: delicious quinoa @ 2014-03-28 18:54 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree@vger.kernel.org, linux-kernel, Pete Popov, Dan Malek,
Georgi Vlaev
On Tue, Mar 18, 2014 at 4:56 PM, Pantelis Antoniou
<pantelis.antoniou@konsulko.com> wrote:
> Introduce DT overlay support.
> Using this functionality it is possible to dynamically overlay a part of
> the kernel's tree with another tree that's been dynamically loaded.
> It is also possible to remove node and properties.
>
> The creation/destruction of the devices is handled by calling in to
> bus specific handlers which can deal with the peculiarities of each
> device.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
> ---
> Documentation/devicetree/overlay-notes.txt | 187 ++++++
> drivers/of/Kconfig | 10 +
> drivers/of/Makefile | 1 +
> drivers/of/overlay.c | 895 +++++++++++++++++++++++++++++
> include/linux/of.h | 153 +++++
> 5 files changed, 1246 insertions(+)
> create mode 100644 Documentation/devicetree/overlay-notes.txt
> create mode 100644 drivers/of/overlay.c
>
> diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
> new file mode 100644
> index 0000000..882d512
> --- /dev/null
> +++ b/Documentation/devicetree/overlay-notes.txt
> @@ -0,0 +1,187 @@
> +Device Tree Overlay Notes
> +-------------------------
> +
> +This document describes the implementation of the in-kernel
> +device tree overlay functionality residing in drivers/of/overlay.c and is a
> +companion document to Documentation/devicetree/dt-object-internal.txt[1] &
> +Documentation/devicetree/dynamic-resolution-notes.txt[2]
> +
> +How overlays work
> +-----------------
> +
> +A Device Tree's overlay purpose is to modify the kernel's live tree, and
> +have the modification affecting the state of the the kernel in a way that
> +is reflecting the changes.
> +Since the kernel mainly deals with devices, any new device node that result
> +in an active device should have it created while if the device node is either
> +disabled or removed all together, the affected device should be deregistered.
Suggestion for readability:
Since the kernel mainly deals with devices, any new device node that results
in an active device should have that device created. If the device node is
either disabled or removed altogether, the affected device should be
deregistered.
> +/**
> + * of_overlay - Apply @count overlays pointed at by @ovinfo_tab
> + * @count: Number of of_overlay_info's
> + * @ovinfo_tab: Array of overlay_info's to apply
> + *
> + * Applies the overlays given, while handling all error conditions
> + * appropriately. Either the operation succeeds, or if it fails the
> + * live tree is reverted to the state before the attempt.
> + * Returns 0, or an error if the overlay attempt failed.
> + */
> +int of_overlay(int count, struct of_overlay_info *ovinfo_tab);
Suggest renaming this function of_overlay_apply() for grep-ability
Alan Tull
aka
delicious quinoa
> +
> +/**
> + * of_overlay_revert - Revert a previously applied overlay
> + * @count: Number of of_overlay_info's
> + * @ovinfo_tab: Array of overlay_info's to apply
> + *
> + * Revert a previous overlay. The state of the live tree
> + * is reverted to the one before the overlay.
> + * Returns 0, or an error if the overlay table is not given.
> + */
> +int of_overlay_revert(int count, struct of_overlay_info *ovinfo_tab);
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
[not found] ` <CANk1AXTb=ob52AfK2z--HvFkxJnjnfYWuTCch_Gw99OCoS1ABg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-04-03 20:40 ` delicious quinoa
2014-04-16 21:23 ` delicious quinoa
2014-04-17 16:12 ` Pantelis Antoniou
1 sibling, 1 reply; 20+ messages in thread
From: delicious quinoa @ 2014-04-03 20:40 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
Pete Popov, Dan Malek, Georgi Vlaev
On Fri, Mar 28, 2014 at 1:27 PM, delicious quinoa
<delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>> The following patchset introduces Device Tree overlays, a method
>> of dynamically altering the kernel's live Device Tree, along with
>> a generic interface to use it in a board agnostic manner.
>>
>> It is dependent on Grant Likely's DT kobjectification patches located
>> in his tree as queued for -next.
>>
>> It relies on the following previously submitted patches/patchsets:
>>
>> * OF: Add [__]of_find_node_by_full_name
>> * OF: Utility helper functions for dynamic nodes
>> * of: Make of_find_node_by_path() handle /aliases
>>
>> To compile overlays you need the DTC compiler patch
>>
>> * "dtc: Dynamic symbols & fixup support (v2)"
>>
>> Changes since V2:
>> * Use of a configfs board agnostic overlay method
>> * Use of per bus handlers instead of hardcoded behaviour
>> * Optional target-path overlay target, which allows one to use standard
>> DTBs without resolution options.
>>
>> Changes since V1:
>>
>> * Removal of any bits related to a specific board (beaglebone).
>> * Introduced a platform agnostic interface using /proc/device-tree-overlay
>> * Various bug fixes related to i2c device handling have been squashed in.
>>
>>
>> Pantelis Antoniou (7):
>> OF: Introduce Device Tree resolve support.
>> OF: Introduce DT overlay support.
>> OF: DT-Overlay configfs interface
>> OF: platform: Add overlay bus handler
>> OF: i2c: Add overlay bus handler
>> OF: spi: Add overlay bus handler
>> of: i2c: Export single device registration method
>>
>> .../devicetree/dynamic-resolution-notes.txt | 25 +
>> Documentation/devicetree/overlay-notes.txt | 187 +++++
>> drivers/base/platform.c | 99 ++-
>> drivers/i2c/i2c-core.c | 186 +++--
>> drivers/of/Kconfig | 24 +
>> drivers/of/Makefile | 3 +
>> drivers/of/configfs.c | 272 +++++++
>> drivers/of/overlay.c | 895 +++++++++++++++++++++
>> drivers/of/resolver.c | 376 +++++++++
>> drivers/spi/spi.c | 345 +++++---
>> include/linux/i2c.h | 10 +
>> include/linux/of.h | 170 ++++
>> 12 files changed, 2440 insertions(+), 152 deletions(-)
>> create mode 100644 Documentation/devicetree/dynamic-resolution-notes.txt
>> create mode 100644 Documentation/devicetree/overlay-notes.txt
>> create mode 100644 drivers/of/configfs.c
>> create mode 100644 drivers/of/overlay.c
>> create mode 100644 drivers/of/resolver.c
>
> I can get a NULL pointer when I apply and remove an overlay and the
> conditions are right. The overlay applies correctly. The crash is
> when I do the rmdir. My overlay is:
>
> /dts-v1/;
> /plugin/;
> / {
> fragment@0 {
> target-path="/soc";
> __overlay__ {
> #address-cells = <1>;
> #size-cells = <1>;
> agpio0: agpio0 {
> compatible = "altr,pio-1.0";
> reg = <0xff210040 0x10>;
Added some printks and got a bit further with debug. If I leave this
as-is, the platform device has 2 resources. We get the NULL pointer in
__release_resource() when releasing the first one (reg). If I remove
this one line ('reg =') the crash goes away. So in this case, we are
ok when releasing an irq resource but get a NULL pointer when removing
a reg resource. Don't know why at this point.
> interrupts = <0 45 4>;
> altr,gpio-bank-width = <32>;
> altr,interrupt_type = <1>;
> #gpio-cells = <2>;
> gpio-controller;
> #interrupt-cells = <1>;
> interrupt-controller;
> };
> };
> };
> };
>
> The log info I have is:
>
> root@socfpga_cyclone5:~# ./do-overlay-only
> + mkdir /config/device-tree/overlays/foo
> + echo socfpga_overlay.dtbo
> + rmdir /config/device-tree/overlays/foo
> Unable to handle kernel NULL pointer dereference at virtual address 00000018
> pgd = bf164000
> [00000018] *pgd=3fb9c831, *pte=00000000, *ppte=00000000
> Internal error: Oops: 17 [#1] SMP ARM
> Modules linked in:
> CPU: 1 PID: 175 Comm: rmdir Not tainted 3.13.0-00299-g2e61581 #7
> task: bf00f400 ti: bfba4000 task.ti: bfba4000
> PC is at release_resource+0x24/0x98
> LR is at release_resource+0x20/0x98
> pc : [<800286e0>] lr : [<800286dc>] psr: 60000013
> sp : bfba5da0 ip : bfba5da0 fp : bfba5db4
> r10: 00100100 r9 : 00000000 r8 : 00200200
> r7 : 80732ff8 r6 : 00000001 r5 : bfbb8400 r4 : bfbd1100
> r3 : 00000000 r2 : 00000000 r1 : 00000002 r0 : 8074e580
> Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 3f16404a DAC: 00000015
> Process rmdir (pid: 175, stack limit = 0xbfba4248)
> Stack: (0xbfba5da0 to 0xbfba6000)
> 5da0: 00000000 00000001 bfba5dcc bfba5db8 802f2e40 800286c8 bfbb8400 bfb930c0
> 5dc0: bfba5de4 bfba5dd0 802f31e0 802f2dd0 bfbb8434 bfbb8400 bfba5dfc bfba5de8
> 5de0: 802f3224 802f31d0 802f31ec 807410ac bfba5e24 bfba5e00 803b4f20 802f31f8
> 5e00: bfb930c0 bfbe61a8 bfbe61a8 bfbe6180 00200200 00100100 bfba5e4c bfba5e28
> 5e20: 803b4fec 803b4e68 bfbe6140 ffffffff bfbe6188 00000000 80782dd4 80741108
> 5e40: bfba5e6c bfba5e50 803b51ec 803b4f94 00001040 bf82e000 807410b4 00000000
> 5e60: bfba5e84 bfba5e70 803b57f0 803b51b4 803b5778 bf82e018 bfba5ea4 bfba5e88
> 5e80: 80161df8 803b5784 00000000 00000000 bf82e000 bfb26070 bfba5eb4 bfba5ea8
> 5ea0: 80161e64 80161d9c bfba5eec bfba5eb8 8016071c 80161e28 80110da0 8010efbc
> 5ec0: bf59a198 bf59a198 00000000 bf5543f0 7e96ef14 ffffff9c bfba4000 bf59a198
> 5ee0: bfba5f0c bfba5ef0 801086e4 8016054c bf5533b8 bf128000 00000000 00000000
> 5f00: bfba5f94 bfba5f10 80108870 80108650 bf8e3010 bf5533b8 006f6f66 00000003
> 5f20: bf12802d 80107348 00000000 bf576660 bf5543f0 00000000 00000004 00000060
> 5f40: 00000000 00000000 bfba5f64 bfba5f58 800fcb1c 8003f114 bfba5f84 bfba5f68
> 5f60: 8003f114 804d1630 bfba4000 bfba4000 7e96ef14 00000000 7e96ee28 00000028
> 5f80: 8000ece4 00000000 bfba5fa4 bfba5f98 8010a800 8010875c 00000000 bfba5fa8
> 5fa0: 8000eac0 8010a7ec 7e96ef14 00000000 7e96ef14 00000000 00000002 7e96ee28
> 5fc0: 7e96ef14 00000000 7e96ee28 00000028 00000002 7e96ee24 0006a754 00000000
> 5fe0: 76f3d450 7e96ec74 0003c2e5 76f3d45c 80000010 7e96ef14 00000000 00000000
> [<800286e0>] (release_resource+0x24/0x98) from [<802f2e40>]
> (platform_device_del+0x7c/0xac)
> [<802f2e40>] (platform_device_del+0x7c/0xac) from [<802f31e0>]
> (platform_device_unregister+0x1c/0x28)
> [<802f31e0>] (platform_device_unregister+0x1c/0x28) from [<802f3224>]
> (platform_handler_remove+0x38/0x54)
> [<802f3224>] (platform_handler_remove+0x38/0x54) from [<803b4f20>]
> (of_overlay_device_entry_change.isra.0+0xc4/0x12c)
> [<803b4f20>] (of_overlay_device_entry_change.isra.0+0xc4/0x12c) from
> [<803b4fec>] (of_overlay_revert_one+0x64/0x220)
> [<803b4fec>] (of_overlay_revert_one+0x64/0x220) from [<803b51ec>]
> (of_overlay_revert+0x44/0x64)
> [<803b51ec>] (of_overlay_revert+0x44/0x64) from [<803b57f0>]
> (cfs_overlay_release+0x78/0x7c)
> [<803b57f0>] (cfs_overlay_release+0x78/0x7c) from [<80161df8>]
> (config_item_release+0x68/0x8c)
> [<80161df8>] (config_item_release+0x68/0x8c) from [<80161e64>]
> (config_item_put+0x48/0x4c)
> [<80161e64>] (config_item_put+0x48/0x4c) from [<8016071c>]
> (configfs_rmdir+0x1dc/0x264)
> [<8016071c>] (configfs_rmdir+0x1dc/0x264) from [<801086e4>]
> (vfs_rmdir+0xa0/0x10c)
> [<801086e4>] (vfs_rmdir+0xa0/0x10c) from [<80108870>] (do_rmdir+0x120/0x150)
> [<80108870>] (do_rmdir+0x120/0x150) from [<8010a800>] (SyS_rmdir+0x20/0x24)
> [<8010a800>] (SyS_rmdir+0x20/0x24) from [<8000eac0>] (ret_fast_syscall+0x0/0x30)
> Code: e1a04000 e59f0074 eb12b02b e5943010 (e5932018)
> ---[ end trace 1b8539e83d8e0ecc ]---
> ./do-overlay-only: line 7: 175 Segmentation fault rmdir
> /config/device-tree/overlays/foo
> root@socfpga_cyclone5:~#
>
> I did some debug, haven't figured anything out yet.
>
> I have been able to successfully add/remove an overlay if it was to a
> fpga node that was at /fpga and used 'target = <&fpga>;' Also
> 'target-path="/fpga";' works fine.
>
> Alan Tull
> aka
> delicious quinoa
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
2014-04-03 20:40 ` delicious quinoa
@ 2014-04-16 21:23 ` delicious quinoa
[not found] ` <CANk1AXT7bPeus3WFPJ3mVHZ+HSuJ5DabxKQ7df1TV2A8-82-OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 20+ messages in thread
From: delicious quinoa @ 2014-04-16 21:23 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
Pete Popov, Dan Malek, Georgi Vlaev
On Thu, Apr 3, 2014 at 3:40 PM, delicious quinoa
<delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Fri, Mar 28, 2014 at 1:27 PM, delicious quinoa
> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
>> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>>> The following patchset introduces Device Tree overlays, a method
>>> of dynamically altering the kernel's live Device Tree, along with
>>> a generic interface to use it in a board agnostic manner.
>>>
>>> It is dependent on Grant Likely's DT kobjectification patches located
>>> in his tree as queued for -next.
>>>
>>> It relies on the following previously submitted patches/patchsets:
>>>
>>> * OF: Add [__]of_find_node_by_full_name
>>> * OF: Utility helper functions for dynamic nodes
>>> * of: Make of_find_node_by_path() handle /aliases
>>>
>>> To compile overlays you need the DTC compiler patch
>>>
>>> * "dtc: Dynamic symbols & fixup support (v2)"
>>>
>>> Changes since V2:
>>> * Use of a configfs board agnostic overlay method
>>> * Use of per bus handlers instead of hardcoded behaviour
>>> * Optional target-path overlay target, which allows one to use standard
>>> DTBs without resolution options.
>>>
>>> Changes since V1:
>>>
>>> * Removal of any bits related to a specific board (beaglebone).
>>> * Introduced a platform agnostic interface using /proc/device-tree-overlay
>>> * Various bug fixes related to i2c device handling have been squashed in.
>>>
>>>
>>> Pantelis Antoniou (7):
>>> OF: Introduce Device Tree resolve support.
>>> OF: Introduce DT overlay support.
>>> OF: DT-Overlay configfs interface
>>> OF: platform: Add overlay bus handler
>>> OF: i2c: Add overlay bus handler
>>> OF: spi: Add overlay bus handler
>>> of: i2c: Export single device registration method
>>>
>>> .../devicetree/dynamic-resolution-notes.txt | 25 +
>>> Documentation/devicetree/overlay-notes.txt | 187 +++++
>>> drivers/base/platform.c | 99 ++-
>>> drivers/i2c/i2c-core.c | 186 +++--
>>> drivers/of/Kconfig | 24 +
>>> drivers/of/Makefile | 3 +
>>> drivers/of/configfs.c | 272 +++++++
>>> drivers/of/overlay.c | 895 +++++++++++++++++++++
>>> drivers/of/resolver.c | 376 +++++++++
>>> drivers/spi/spi.c | 345 +++++---
>>> include/linux/i2c.h | 10 +
>>> include/linux/of.h | 170 ++++
>>> 12 files changed, 2440 insertions(+), 152 deletions(-)
>>> create mode 100644 Documentation/devicetree/dynamic-resolution-notes.txt
>>> create mode 100644 Documentation/devicetree/overlay-notes.txt
>>> create mode 100644 drivers/of/configfs.c
>>> create mode 100644 drivers/of/overlay.c
>>> create mode 100644 drivers/of/resolver.c
>>
>> I can get a NULL pointer when I apply and remove an overlay and the
>> conditions are right. The overlay applies correctly. The crash is
>> when I do the rmdir. My overlay is:
>>
>> /dts-v1/;
>> /plugin/;
>> / {
>> fragment@0 {
>> target-path="/soc";
>> __overlay__ {
>> #address-cells = <1>;
>> #size-cells = <1>;
>> agpio0: agpio0 {
>> compatible = "altr,pio-1.0";
>> reg = <0xff210040 0x10>;
>
> Added some printks and got a bit further with debug. If I leave this
> as-is, the platform device has 2 resources. We get the NULL pointer in
> __release_resource() when releasing the first one (reg). If I remove
> this one line ('reg =') the crash goes away. So in this case, we are
> ok when releasing an irq resource but get a NULL pointer when removing
> a reg resource. Don't know why at this point.
The crash is confirmed on v4 patches as well. The immediate cause of the crash:
static int __release_resource(struct resource *old)
{
struct resource *tmp, **p;
p = &old->parent->child;
for (;;) {
tmp = *p; <===kablooey
...
when __release_resource() is called for the reg resource, it does 'p =
&olde->parent->child' and then crashes when it does 'tmp = *p'.
Root cause: It appears that there isn't any code in drivers/of/ that
eventually calls __request_resource() or __insert_resource() so the
resource's parents/sibling pointers are never initialized. Maybe I'm
missing some patches or something.
Alan Tull
aka
delicious quinoa
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
[not found] ` <CANk1AXT7bPeus3WFPJ3mVHZ+HSuJ5DabxKQ7df1TV2A8-82-OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-04-16 21:33 ` Rob Herring
[not found] ` <CAL_JsqKHY_osEhE6HefV_PT+bXmv1vBWvCOY_93Sju0pbULoqQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 20+ messages in thread
From: Rob Herring @ 2014-04-16 21:33 UTC (permalink / raw)
To: delicious quinoa
Cc: Pantelis Antoniou, Grant Likely, Stephen Warren, Matt Porter,
Koen Kooi, Alison Chaiken, Dinh Nguyen, Jan Lubbe,
Alexander Sverdlin, Michael Stickel, Guenter Roeck, Dirk Behme,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel, Pete Popov, Dan Malek, Georgi Vlaev
On Wed, Apr 16, 2014 at 4:23 PM, delicious quinoa
<delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Thu, Apr 3, 2014 at 3:40 PM, delicious quinoa
> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On Fri, Mar 28, 2014 at 1:27 PM, delicious quinoa
>> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
>>> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>>>> The following patchset introduces Device Tree overlays, a method
>>>> of dynamically altering the kernel's live Device Tree, along with
>>>> a generic interface to use it in a board agnostic manner.
[snip]
>>> I can get a NULL pointer when I apply and remove an overlay and the
>>> conditions are right. The overlay applies correctly. The crash is
>>> when I do the rmdir. My overlay is:
>>>
>>> /dts-v1/;
>>> /plugin/;
>>> / {
>>> fragment@0 {
>>> target-path="/soc";
>>> __overlay__ {
>>> #address-cells = <1>;
>>> #size-cells = <1>;
>>> agpio0: agpio0 {
>>> compatible = "altr,pio-1.0";
>>> reg = <0xff210040 0x10>;
>>
>> Added some printks and got a bit further with debug. If I leave this
>> as-is, the platform device has 2 resources. We get the NULL pointer in
>> __release_resource() when releasing the first one (reg). If I remove
>> this one line ('reg =') the crash goes away. So in this case, we are
>> ok when releasing an irq resource but get a NULL pointer when removing
>> a reg resource. Don't know why at this point.
>
> The crash is confirmed on v4 patches as well. The immediate cause of the crash:
>
> static int __release_resource(struct resource *old)
> {
> struct resource *tmp, **p;
>
> p = &old->parent->child;
> for (;;) {
> tmp = *p; <===kablooey
> ...
>
> when __release_resource() is called for the reg resource, it does 'p =
> &olde->parent->child' and then crashes when it does 'tmp = *p'.
>
> Root cause: It appears that there isn't any code in drivers/of/ that
> eventually calls __request_resource() or __insert_resource() so the
> resource's parents/sibling pointers are never initialized. Maybe I'm
> missing some patches or something.
It's probably related to this issue:
https://groups.google.com/forum/#!topic/fa.linux.kernel/CTx1ReiOjnQ
http://www.mail-archive.com/linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org/msg63678.html
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
[not found] ` <CAL_JsqKHY_osEhE6HefV_PT+bXmv1vBWvCOY_93Sju0pbULoqQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-04-17 15:46 ` delicious quinoa
0 siblings, 0 replies; 20+ messages in thread
From: delicious quinoa @ 2014-04-17 15:46 UTC (permalink / raw)
To: Rob Herring
Cc: Pantelis Antoniou, Grant Likely, Stephen Warren, Matt Porter,
Koen Kooi, Alison Chaiken, Dinh Nguyen, Jan Lubbe,
Alexander Sverdlin, Michael Stickel, Guenter Roeck, Dirk Behme,
Sascha Hauer, Michael Bohan, Ionut Nicu, Michal Simek,
Matt Ranostay, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel, Pete Popov, Dan Malek, Georgi Vlaev
On Wed, Apr 16, 2014 at 4:33 PM, Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Wed, Apr 16, 2014 at 4:23 PM, delicious quinoa
> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On Thu, Apr 3, 2014 at 3:40 PM, delicious quinoa
>> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>> On Fri, Mar 28, 2014 at 1:27 PM, delicious quinoa
>>> <delicious.quinoa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>>> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
>>>> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>>>>> The following patchset introduces Device Tree overlays, a method
>>>>> of dynamically altering the kernel's live Device Tree, along with
>>>>> a generic interface to use it in a board agnostic manner.
>
> [snip]
>
>>>> I can get a NULL pointer when I apply and remove an overlay and the
>>>> conditions are right. The overlay applies correctly. The crash is
>>>> when I do the rmdir. My overlay is:
>>>>
>>>> /dts-v1/;
>>>> /plugin/;
>>>> / {
>>>> fragment@0 {
>>>> target-path="/soc";
>>>> __overlay__ {
>>>> #address-cells = <1>;
>>>> #size-cells = <1>;
>>>> agpio0: agpio0 {
>>>> compatible = "altr,pio-1.0";
>>>> reg = <0xff210040 0x10>;
>>>
>>> Added some printks and got a bit further with debug. If I leave this
>>> as-is, the platform device has 2 resources. We get the NULL pointer in
>>> __release_resource() when releasing the first one (reg). If I remove
>>> this one line ('reg =') the crash goes away. So in this case, we are
>>> ok when releasing an irq resource but get a NULL pointer when removing
>>> a reg resource. Don't know why at this point.
>>
>> The crash is confirmed on v4 patches as well. The immediate cause of the crash:
>>
>> static int __release_resource(struct resource *old)
>> {
>> struct resource *tmp, **p;
>>
>> p = &old->parent->child;
>> for (;;) {
>> tmp = *p; <===kablooey
>> ...
>>
>> when __release_resource() is called for the reg resource, it does 'p =
>> &olde->parent->child' and then crashes when it does 'tmp = *p'.
>>
>> Root cause: It appears that there isn't any code in drivers/of/ that
>> eventually calls __request_resource() or __insert_resource() so the
>> resource's parents/sibling pointers are never initialized. Maybe I'm
>> missing some patches or something.
>
> It's probably related to this issue:
>
> https://groups.google.com/forum/#!topic/fa.linux.kernel/CTx1ReiOjnQ
> http://www.mail-archive.com/linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org/msg63678.html
>
> Rob
Yes, that's the same root problem (devices are released by 'of' code
that were never added using resource.c code). Adding a
"of_device_unpopulate()" function to a bunch of drivers won't work
because the crash happens without loading any driver.
Alan
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
[not found] ` <CANk1AXTb=ob52AfK2z--HvFkxJnjnfYWuTCch_Gw99OCoS1ABg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-03 20:40 ` delicious quinoa
@ 2014-04-17 16:12 ` Pantelis Antoniou
[not found] ` <7706B5FF-45EB-4860-BD12-204B341A510D-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
1 sibling, 1 reply; 20+ messages in thread
From: Pantelis Antoniou @ 2014-04-17 16:12 UTC (permalink / raw)
To: delicious quinoa
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
Pete Popov, Dan Malek, Georgi Vlaev
Hi Alan,
Ugh, very sorry for the late reply; my mailer filed this somewhere I don't look at very frequently.
On Mar 28, 2014, at 8:27 PM, delicious quinoa wrote:
> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>> The following patchset introduces Device Tree overlays, a method
>> of dynamically altering the kernel's live Device Tree, along with
>> a generic interface to use it in a board agnostic manner.
>>
[snip]
> \
> I did some debug, haven't figured anything out yet.
>
> I have been able to successfully add/remove an overlay if it was to a
> fpga node that was at /fpga and used 'target = <&fpga>;' Also
> 'target-path="/fpga";' works fine.
>
Yes, platform devices are broken; I carry a patch that fixes all of that mess, and I intend to follow up with it.
> Alan Tull
> aka
> delicious quinoa
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Regards
-- Pantelis
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays
[not found] ` <7706B5FF-45EB-4860-BD12-204B341A510D-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
@ 2014-04-18 16:54 ` delicious quinoa
0 siblings, 0 replies; 20+ messages in thread
From: delicious quinoa @ 2014-04-18 16:54 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Grant Likely, Rob Herring, Stephen Warren, Matt Porter, Koen Kooi,
Alison Chaiken, Dinh Nguyen, Jan Lubbe, Alexander Sverdlin,
Michael Stickel, Guenter Roeck, Dirk Behme, Sascha Hauer,
Michael Bohan, Ionut Nicu, Michal Simek, Matt Ranostay,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
Pete Popov, Dan Malek, Georgi Vlaev
On Thu, Apr 17, 2014 at 11:12 AM, Pantelis Antoniou
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
> Hi Alan,
>
> Ugh, very sorry for the late reply; my mailer filed this somewhere I don't look at very frequently.
>
> On Mar 28, 2014, at 8:27 PM, delicious quinoa wrote:
>
>> On Tue, Mar 18, 2014 at 4:55 PM, Pantelis Antoniou
>> <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
>>> The following patchset introduces Device Tree overlays, a method
>>> of dynamically altering the kernel's live Device Tree, along with
>>> a generic interface to use it in a board agnostic manner.
>>>
>
> [snip]
>
>> \
>> I did some debug, haven't figured anything out yet.
>>
>> I have been able to successfully add/remove an overlay if it was to a
>> fpga node that was at /fpga and used 'target = <&fpga>;' Also
>> 'target-path="/fpga";' works fine.
>>
>
> Yes, platform devices are broken; I carry a patch that fixes all of that mess, and I intend to follow up with it.
That's great. I like this patchset and what it can do.
Regards,
Alan
>
>> Alan Tull
>> aka
>> delicious quinoa
>> --
>> To unsubscribe from this list: send the line "unsubscribe devicetree" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> Regards
>
> -- Pantelis
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2014-04-18 16:54 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-18 21:55 [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 1/7] OF: Introduce Device Tree resolve support Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 2/7] OF: Introduce DT overlay support Pantelis Antoniou
2014-03-28 14:51 ` delicious quinoa
2014-03-28 18:54 ` delicious quinoa
2014-03-18 21:56 ` [PATCH v3 3/7] OF: DT-Overlay configfs interface Pantelis Antoniou
[not found] ` <1395179766-31575-4-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-03-21 13:39 ` Rob Herring
[not found] ` <CAL_JsqKJqakXGWDEKPAoJ9P5myYXnodcYCdvowV6MPuZXgwVmw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-03-21 13:56 ` Sebastian Hesselbarth
2014-03-18 21:56 ` [PATCH v3 4/7] OF: platform: Add overlay bus handler Pantelis Antoniou
[not found] ` <1395179766-31575-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-03-18 21:56 ` [PATCH v3 5/7] OF: i2c: " Pantelis Antoniou
2014-03-18 21:56 ` [PATCH v3 6/7] OF: spi: " Pantelis Antoniou
[not found] ` <1395179766-31575-7-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-03-20 10:51 ` Michael Stickel
2014-03-18 21:56 ` [PATCH v3 7/7] of: i2c: Export single device registration method Pantelis Antoniou
2014-03-28 18:27 ` [PATCH v3 0/7] Introducing (yet again) Device Tree Overlays delicious quinoa
[not found] ` <CANk1AXTb=ob52AfK2z--HvFkxJnjnfYWuTCch_Gw99OCoS1ABg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-03 20:40 ` delicious quinoa
2014-04-16 21:23 ` delicious quinoa
[not found] ` <CANk1AXT7bPeus3WFPJ3mVHZ+HSuJ5DabxKQ7df1TV2A8-82-OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-16 21:33 ` Rob Herring
[not found] ` <CAL_JsqKHY_osEhE6HefV_PT+bXmv1vBWvCOY_93Sju0pbULoqQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-17 15:46 ` delicious quinoa
2014-04-17 16:12 ` Pantelis Antoniou
[not found] ` <7706B5FF-45EB-4860-BD12-204B341A510D-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2014-04-18 16:54 ` delicious quinoa
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).