Create some infrastructure to aid trouble shooting device tree related boot issues. Add a %driver_name file to each device tree node sysfs directory which has had a driver bound to it. This allows detecting device tree nodes which failed to be bound to any driver. Examples of using the %driver_name file (note that /proc/device-tree is a link to the base of the device tree sysfs tree): 1) To find list of device tree nodes with no driver: # A few false positives may be reported. For example, # node_full_path of "." is the board. # # output is: node_full_path compatible_string # cd /proc/device-tree for k in `find . -type d`; do if [[ -f ${k}/compatible && ! -f ${k}/%driver_name ]] ; then if [[ "`cat ${k}/compatible`" != "simple-bus" ]] ; then echo `echo ${k} | sed -e 's|./||'` `cat ${k}/compatible` fi fi done | sort 2) To find list of device tree nodes with a bound driver: # output is: node_full_path driver_name # cd /proc/device-tree for k in `find . -name %driver_name` ; do echo `echo ${k} | sed -e 's|./||' -e 's|/%driver_name$||'` `cat ${k}` done | sort 3) To find list of device tree nodes with a bound driver: # output is: driver_name node_full_path # cd /proc/device-tree for k in `find . -name %driver_name` ; do echo `cat ${k}` `echo ${k} | sed -e 's|./||' -e 's|/%driver_name$||'` done | sort Signed-off-by: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx> --- Documentation/ABI/testing/sysfs-firmware-ofw | 17 +++++++- drivers/base/dd.c | 5 ++ drivers/of/base.c | 55 +++++++++++++++++++++++++++ include/linux/of.h | 9 ++++ 4 files changed, 85 insertions(+), 1 deletion(-) Index: b/drivers/base/dd.c =================================================================== --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -25,6 +25,7 @@ #include <linux/kthread.h> #include <linux/wait.h> #include <linux/async.h> +#include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/devinfo.h> @@ -194,6 +195,8 @@ static void driver_bound(struct device * klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); + of_notify_driver_bound(dev); + /* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices @@ -505,6 +508,8 @@ static void __device_release_driver(stru pm_runtime_put_sync(dev); + of_notify_driver_released(dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) Index: b/drivers/of/base.c =================================================================== --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -19,6 +19,7 @@ */ #include <linux/ctype.h> #include <linux/cpu.h> +#include <linux/kallsyms.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> @@ -168,7 +169,61 @@ static void of_node_release(struct kobje } #endif /* CONFIG_OF_DYNAMIC */ +static ssize_t driver_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->name); +} + +static const struct device_attribute of_driver_attr = + __ATTR(%driver_name, S_IRUGO, driver_show, NULL); + +void of_notify_driver_bound(struct device *dev) +{ + int err; + + if (dev->of_node) { + dev->of_node->bound_dev = dev; + err = sysfs_create_file(&dev->of_node->kobj, &of_driver_attr.attr); + } + +} + +void of_notify_driver_released(struct device *dev) +{ + if (dev->of_node) { + sysfs_remove_file(&dev->of_node->kobj, &of_driver_attr.attr); + dev->of_node->bound_dev = NULL; + } +} + +#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) + +static ssize_t of_node_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device_node *np = container_of(kobj, struct device_node, kobj); + struct device *dev = np->bound_dev; + + ssize_t ret = -EIO; + + if (dev_attr->show) + ret = dev_attr->show(dev, dev_attr, buf); + if (ret >= (ssize_t)PAGE_SIZE) { + print_symbol("dev_attr_show: %s returned bad count\n", + (unsigned long)dev_attr->show); + } + return ret; +} + + +static const struct sysfs_ops of_node_sysfs_ops = { + .show = of_node_attr_show, +}; + struct kobj_type of_node_ktype = { + .sysfs_ops = &of_node_sysfs_ops, .release = of_node_release, }; Index: b/include/linux/of.h =================================================================== --- a/include/linux/of.h +++ b/include/linux/of.h @@ -60,6 +60,7 @@ struct device_node { struct kobject kobj; unsigned long _flags; void *data; + struct device *bound_dev; #if defined(CONFIG_SPARC) const char *path_component_name; unsigned int unique_id; @@ -347,6 +348,9 @@ const char *of_prop_next_string(struct p int of_device_is_stdout_path(struct device_node *dn); +void of_notify_driver_bound(struct device *dev); +void of_notify_driver_released(struct device *dev); + #else /* CONFIG_OF */ static inline const char* of_node_full_name(struct device_node *np) @@ -571,6 +575,11 @@ static inline const char *of_prop_next_s #define of_match_ptr(_ptr) NULL #define of_match_node(_matches, _node) NULL + +void of_notify_driver_bound(struct device *dev) { } + +void of_notify_driver_released(struct device *dev) { } + #endif /* CONFIG_OF */ #if defined(CONFIG_OF) && defined(CONFIG_NUMA) Index: b/Documentation/ABI/testing/sysfs-firmware-ofw =================================================================== --- a/Documentation/ABI/testing/sysfs-firmware-ofw +++ b/Documentation/ABI/testing/sysfs-firmware-ofw @@ -25,4 +25,19 @@ Description: directory name is the resolved path component name (node name plus address). Properties are represented as files in the directory. The contents of each file is the exact - binary data from the device tree. + binary data from the device tree. Files that are exceptions + to this description will be described separately in this file. + +What: /sys/firmware/devicetree/.../%driver_name +Date: April 2014 +KernelVersion: 3.15 +Contact: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx> +Description: + This file does not represent a device tree property. The file + will exist only if a driver is bound to the device tree node. + Reading from this file returns the name of the driver. + + The apparently bizarre choice of prefixing the file name with + "%" is to avoid any possible conflict with a valid device tree + property name. ePAPR version 1.1 does not allow a property + name to contain the character "%". -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html