[PATCH 3/3] of: add node status update via name format with cmdline

From: Dong Aisheng
Date: Thu Aug 15 2013 - 06:58:33 EST


The node full patch is a bit long to use in the command line to
update the device node status, so we add a more convenient way to
simply use device node name in device tree.

e.g:
formerly:
fdt.enable=/soc/aips-bus@02100000/i2c@021a8000,/soc/aips-bus@02100000/weim@021b8000
fdt.disable=/soc/aips-bus@02100000/weim@021b8000
now:
fdt.enable=i2c@021a8000,weim@021b8000
fdt.disable=weim@021b8000

Signed-off-by: Dong Aisheng <b29396@xxxxxxxxxxxxx>
---
Documentation/kernel-parameters.txt | 3 +-
drivers/of/base.c | 33 +++++++++++++++++
drivers/of/fdt.c | 66 ++++++++++++++++++++++++++++------
include/linux/of.h | 8 ++++
4 files changed, 97 insertions(+), 13 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 65f3be2..7fbdb86 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -900,10 +900,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
fdt.disable=
[KNL,FDT]
update device tree node status before populating devices
- Format: fdt.<enable|disable>=<path>[,<path>]
+ Format: fdt.<enable|disable>=<path|node>[,<path|node>]
enable := update the device node to a enabled state
disable := update the device node to a disabled state
<path> := node path or node full name in device tree
+ <node> := node name in device tree

floppy= [HW]
See Documentation/blockdev/floppy.txt.
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f944a54..b072722 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -20,6 +20,7 @@
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
@@ -514,6 +515,38 @@ struct device_node *of_find_node_by_name(struct device_node *from,
EXPORT_SYMBOL(of_find_node_by_name);

/**
+ * of_find_node_by_name_and_reg - Find a node by its "name" and "reg" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @name: The name string to match against
+ * @reg: The reg address to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name_and_reg(struct device_node *from,
+ const char *name, resource_size_t reg)
+{
+ struct device_node *np;
+ struct resource res;
+
+ while ((np = of_find_node_by_name(from, name)) != NULL) {
+ if (!of_address_to_resource(np, 0, &res))
+ if ((res.start == reg) && of_node_get(np)) {
+ pr_debug("find node %s 0x%x: %s\n", name,
+ reg, np->full_name);
+ break;
+ }
+ from = np;
+ }
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name_and_reg);
+
+/**
* of_find_node_by_type - Find a node by its "device_type" property
* @from: The node to start searching from, or NULL to start searching
* the entire device tree. The node you pass will not be
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 423624b..27ad6ae 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -718,21 +718,52 @@ void __init unflatten_device_tree(void)
of_alias_scan(early_init_dt_alloc_memory_arch);
}

+static int of_flat_update_node_by_name(const char *s, bool enable)
+{
+ char node[256];
+ char *r, *p;
+ struct device_node *np;
+ unsigned long reg;
+
+ if (!s)
+ return -EINVAL;
+
+ p = strchr(s, '@');
+ strncpy(node, s, p - s);
+ node[p - s] = '\0';
+ r = p + 1;
+ if (kstrtoul(r, 16, &reg))
+ return -EINVAL;
+
+ np = of_find_node_by_name_and_reg(NULL, node, reg);
+ if (!np) {
+ pr_debug("%s: unable to find node %s\n", __func__, s);
+ return -ENODEV;
+ }
+
+ return enable ? of_node_status_enable(np) :
+ of_node_status_disable(np);
+}
+
/*
* The format for the command line is as follows:
*
- * fdt.<enable|disable>=<path>[,<path>]
+ * fdt.<enable|disable>=<path|node>[,<path|node>]
* enable := update the device node to a enabled state
* disable := update the device node to a disabled state
* <path> := node path or node full name in device tree
+ * <node> := node name in device tree
*
* e.g:
* fdt.enable=/soc/aips-bus@02100000/i2c@021a8000,/soc/aips-bus@02100000/weim@021b8000
* fdt.disable=/soc/aips-bus@02100000/weim@021b8000
+ * or
+ * fdt.enable=i2c@021a8000,weim@021b8000
+ * fdt.disable=weim@021b8000
*/
static int __init __of_flat_parse_param(char *s, bool enable)
{
- char path[256], *p;
+ char node[256], *p;

if (!s)
return 0;
@@ -742,20 +773,31 @@ static int __init __of_flat_parse_param(char *s, bool enable)
p = strchr(s, ',');
if (p != NULL) {
BUG_ON((p - s) >= 256);
- strncpy(path, s, p - s);
- path[p - s] = '\0';
- if (enable)
- of_node_status_enable_by_path(path);
- else
- of_node_status_disable_by_path(path);
+ strncpy(node, s, p - s);
+ node[p - s] = '\0';
+ if (*s != '/') {
+ /* device tree node name */
+ of_flat_update_node_by_name(node, enable);
+ } else {
+ /* device tree node full path*/
+ if (enable)
+ of_node_status_enable_by_path(node);
+ else
+ of_node_status_disable_by_path(node);
+ }
+
/* search for next node */
s = p + 1;
} else {
/* last node */
- if (enable)
- of_node_status_enable_by_path(s);
- else
- of_node_status_disable_by_path(s);
+ if (*s != '/') {
+ of_flat_update_node_by_name(s, enable);
+ } else {
+ if (enable)
+ of_node_status_enable_by_path(s);
+ else
+ of_node_status_disable_by_path(s);
+ }
break;
}
}
diff --git a/include/linux/of.h b/include/linux/of.h
index 61b35fe..7dd3da0 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -170,6 +170,8 @@ extern struct device_node *of_find_node_by_name(struct device_node *from,
#define for_each_node_by_name(dn, name) \
for (dn = of_find_node_by_name(NULL, name); dn; \
dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_name_and_reg(struct device_node *from,
+ const char *name, resource_size_t reg);
extern struct device_node *of_find_node_by_type(struct device_node *from,
const char *type);
#define for_each_node_by_type(dn, type) \
@@ -361,6 +363,12 @@ static inline struct device_node *of_find_node_by_name(struct device_node *from,
return NULL;
}

+static inline struct device_node *of_find_node_by_name_and_reg(
+ struct device_node *from, const char *name, resource_size_t reg)
+{
+ return NULL;
+}
+
static inline struct device_node *of_get_parent(const struct device_node *node)
{
return NULL;
--
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/