summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/address.c24
-rw-r--r--drivers/of/base.c46
-rw-r--r--drivers/of/device.c75
-rw-r--r--drivers/of/dynamic.c33
-rw-r--r--drivers/of/irq.c77
-rw-r--r--drivers/of/of_mdio.c4
-rw-r--r--drivers/of/of_pci.c72
-rw-r--r--drivers/of/overlay.c142
-rw-r--r--drivers/of/platform.c34
-rw-r--r--drivers/of/property.c23
-rw-r--r--drivers/of/unittest-data/Makefile19
-rw-r--r--drivers/of/unittest-data/overlay.dts31
-rw-r--r--drivers/of/unittest-data/overlay_bad_symbol.dts22
-rw-r--r--drivers/of/unittest-data/overlay_base.dts11
-rw-r--r--drivers/of/unittest.c77
15 files changed, 418 insertions, 272 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 580bbf6ca2b1..792722e7d458 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -274,10 +274,9 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
/* Now consume following elements while they are contiguous */
while (parser->range + parser->np <= parser->end) {
- u32 flags, pci_space;
+ u32 flags;
u64 pci_addr, cpu_addr, size;
- pci_space = be32_to_cpup(parser->range);
flags = of_bus_pci_get_flags(parser->range);
pci_addr = of_read_number(parser->range + 1, ns);
cpu_addr = of_translate_address(parser->node,
@@ -559,7 +558,7 @@ static u64 __of_translate_address(struct device_node *dev,
int na, ns, pna, pns;
u64 result = OF_BAD_ADDR;
- pr_debug("** translation for device %s **\n", of_node_full_name(dev));
+ pr_debug("** translation for device %pOF **\n", dev);
/* Increase refcount at current level */
of_node_get(dev);
@@ -573,13 +572,13 @@ static u64 __of_translate_address(struct device_node *dev,
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
- pr_debug("Bad cell count for %s\n", of_node_full_name(dev));
+ pr_debug("Bad cell count for %pOF\n", dev);
goto bail;
}
memcpy(addr, in_addr, na * 4);
- pr_debug("bus is %s (na=%d, ns=%d) on %s\n",
- bus->name, na, ns, of_node_full_name(parent));
+ pr_debug("bus is %s (na=%d, ns=%d) on %pOF\n",
+ bus->name, na, ns, parent);
of_dump_addr("translating address:", addr, na);
/* Translate */
@@ -600,13 +599,12 @@ static u64 __of_translate_address(struct device_node *dev,
pbus = of_match_bus(parent);
pbus->count_cells(dev, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
- pr_err("Bad cell count for %s\n",
- of_node_full_name(dev));
+ pr_err("Bad cell count for %pOF\n", dev);
break;
}
- pr_debug("parent bus is %s (na=%d, ns=%d) on %s\n",
- pbus->name, pna, pns, of_node_full_name(parent));
+ pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
+ pbus->name, pna, pns, parent);
/* Apply bus translation */
if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
@@ -855,7 +853,7 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
}
if (!ranges) {
- pr_debug("no dma-ranges found for node(%s)\n", np->full_name);
+ pr_debug("no dma-ranges found for node(%pOF)\n", np);
ret = -ENODEV;
goto out;
}
@@ -872,8 +870,8 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
dmaaddr = of_read_number(ranges, naddr);
*paddr = of_translate_dma_address(np, ranges);
if (*paddr == OF_BAD_ADDR) {
- pr_err("translation of DMA address(%pad) to CPU address failed node(%s)\n",
- dma_addr, np->full_name);
+ pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
+ dma_addr, np);
ret = -EINVAL;
goto out;
}
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 686628d1dfa6..260d33c0f26c 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -60,14 +60,13 @@ DEFINE_RAW_SPINLOCK(devtree_lock);
int of_n_addr_cells(struct device_node *np)
{
- const __be32 *ip;
+ u32 cells;
do {
if (np->parent)
np = np->parent;
- ip = of_get_property(np, "#address-cells", NULL);
- if (ip)
- return be32_to_cpup(ip);
+ if (!of_property_read_u32(np, "#address-cells", &cells))
+ return cells;
} while (np->parent);
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
@@ -76,14 +75,13 @@ EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
- const __be32 *ip;
+ u32 cells;
do {
if (np->parent)
np = np->parent;
- ip = of_get_property(np, "#size-cells", NULL);
- if (ip)
- return be32_to_cpup(ip);
+ if (!of_property_read_u32(np, "#size-cells", &cells))
+ return cells;
} while (np->parent);
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
@@ -160,7 +158,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
pp->attr.read = of_node_property_read;
rc = sysfs_create_bin_file(&np->kobj, &pp->attr);
- WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name);
+ WARN(rc, "error adding attribute %s to node %pOF\n", pp->name, np);
return rc;
}
@@ -1122,7 +1120,7 @@ EXPORT_SYMBOL(of_find_node_by_phandle);
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
- printk("%s %s", msg, of_node_full_name(args->np));
+ printk("%s %pOF", msg, args->np);
for (i = 0; i < args->args_count; i++) {
const char delim = i ? ',' : ':';
@@ -1184,17 +1182,17 @@ int of_phandle_iterator_next(struct of_phandle_iterator *it)
if (it->cells_name) {
if (!it->node) {
- pr_err("%s: could not find phandle\n",
- it->parent->full_name);
+ pr_err("%pOF: could not find phandle\n",
+ it->parent);
goto err;
}
if (of_property_read_u32(it->node, it->cells_name,
&count)) {
- pr_err("%s: could not get %s for %s\n",
- it->parent->full_name,
+ pr_err("%pOF: could not get %s for %pOF\n",
+ it->parent,
it->cells_name,
- it->node->full_name);
+ it->node);
goto err;
}
} else {
@@ -1206,8 +1204,8 @@ int of_phandle_iterator_next(struct of_phandle_iterator *it)
* property data length
*/
if (it->cur + count > it->list_end) {
- pr_err("%s: arguments longer than property\n",
- it->parent->full_name);
+ pr_err("%pOF: arguments longer than property\n",
+ it->parent);
goto err;
}
}
@@ -1639,8 +1637,8 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
strncpy(ap->stem, stem, stem_len);
ap->stem[stem_len] = 0;
list_add_tail(&ap->link, &aliases_lookup);
- pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
- ap->alias, ap->stem, ap->id, of_node_full_name(np));
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n",
+ ap->alias, ap->stem, ap->id, np);
}
/**
@@ -1664,11 +1662,13 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
if (of_chosen) {
/* linux,stdout-path and /aliases/stdout are for legacy compatibility */
- const char *name = of_get_property(of_chosen, "stdout-path", NULL);
- if (!name)
- name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ const char *name = NULL;
+
+ if (of_property_read_string(of_chosen, "stdout-path", &name))
+ of_property_read_string(of_chosen, "linux,stdout-path",
+ &name);
if (IS_ENABLED(CONFIG_PPC) && !name)
- name = of_get_property(of_aliases, "stdout", NULL);
+ of_property_read_string(of_aliases, "stdout", &name);
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
}
diff --git a/drivers/of/device.c b/drivers/of/device.c
index e0a28ea341fe..17b66e9715d2 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -58,7 +58,7 @@ int of_device_add(struct platform_device *ofdev)
/* name and id have to be set so that the platform bus doesn't get
* confused on matching */
ofdev->name = dev_name(&ofdev->dev);
- ofdev->id = -1;
+ ofdev->id = PLATFORM_DEVID_NONE;
/*
* If this device has not binding numa node in devicetree, that is
@@ -196,8 +196,10 @@ EXPORT_SYMBOL(of_device_get_match_data);
static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
{
const char *compat;
- int cplen, i;
- ssize_t tsize, csize, repend;
+ char *c;
+ struct property *p;
+ ssize_t csize;
+ ssize_t tsize;
if ((!dev) || (!dev->of_node))
return -ENODEV;
@@ -205,42 +207,28 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len
/* Name & Type */
csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name,
dev->of_node->type);
-
- /* Get compatible property if any */
- compat = of_get_property(dev->of_node, "compatible", &cplen);
- if (!compat)
- return csize;
-
- /* Find true end (we tolerate multiple \0 at the end */
- for (i = (cplen - 1); i >= 0 && !compat[i]; i--)
- cplen--;
- if (!cplen)
- return csize;
- cplen++;
-
- /* Check space (need cplen+1 chars including final \0) */
- tsize = csize + cplen;
- repend = tsize;
-
- if (csize >= len) /* @ the limit, all is already filled */
- return tsize;
-
- if (tsize >= len) { /* limit compat list */
- cplen = len - csize - 1;
- repend = len;
- }
-
- /* Copy and do char replacement */
- memcpy(&str[csize + 1], compat, cplen);
- for (i = csize; i < repend; i++) {
- char c = str[i];
- if (c == '\0')
- str[i] = 'C';
- else if (c == ' ')
- str[i] = '_';
+ tsize = csize;
+ len -= csize;
+ if (str)
+ str += csize;
+
+ of_property_for_each_string(dev->of_node, "compatible", p, compat) {
+ csize = strlen(compat) + 1;
+ tsize += csize;
+ if (csize > len)
+ continue;
+
+ csize = snprintf(str, len, "C%s", compat);
+ for (c = str; c; ) {
+ c = strchr(c, ' ');
+ if (c)
+ *c++ = '_';
+ }
+ len -= csize;
+ str += csize;
}
- return repend;
+ return tsize;
}
int of_device_request_module(struct device *dev)
@@ -274,6 +262,8 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
ssize_t sl = of_device_get_modalias(dev, str, len - 2);
if (sl < 0)
return sl;
+ if (sl > len - 2)
+ return -ENOMEM;
str[sl++] = '\n';
str[sl] = 0;
@@ -288,25 +278,22 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const char *compat;
struct alias_prop *app;
- int seen = 0, cplen, sl;
+ struct property *p;
+ int seen = 0;
if ((!dev) || (!dev->of_node))
return;
add_uevent_var(env, "OF_NAME=%s", dev->of_node->name);
- add_uevent_var(env, "OF_FULLNAME=%s", dev->of_node->full_name);
+ add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node);
if (dev->of_node->type && strcmp("<NULL>", dev->of_node->type) != 0)
add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type);
/* Since the compatible field can contain pretty much anything
* it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */
- compat = of_get_property(dev->of_node, "compatible", &cplen);
- while (compat && *compat && cplen > 0) {
+ of_property_for_each_string(dev->of_node, "compatible", p, compat) {
add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
- sl = strlen(compat) + 1;
- compat += sl;
- cplen -= sl;
seen++;
}
add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 0542cf8b6e3d..301b6db2b48d 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -98,14 +98,14 @@ int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
case OF_RECONFIG_DETACH_NODE:
- pr_debug("notify %-15s %s\n", action_names[action],
- pr->dn->full_name);
+ pr_debug("notify %-15s %pOF\n", action_names[action],
+ pr->dn);
break;
case OF_RECONFIG_ADD_PROPERTY:
case OF_RECONFIG_REMOVE_PROPERTY:
case OF_RECONFIG_UPDATE_PROPERTY:
- pr_debug("notify %-15s %s:%s\n", action_names[action],
- pr->dn->full_name, pr->prop->name);
+ pr_debug("notify %-15s %pOF:%s\n", action_names[action],
+ pr->dn, pr->prop->name);
break;
}
@@ -328,11 +328,10 @@ void of_node_release(struct kobject *kobj)
/* We should never be releasing nodes that haven't been detached. */
if (!of_node_check_flag(node, OF_DETACHED)) {
- pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
+ pr_err("ERROR: Bad of_node_put() on %pOF\n", node);
dump_stack();
return;
}
-
if (!of_node_check_flag(node, OF_DYNAMIC))
return;
@@ -462,13 +461,13 @@ static void __of_changeset_entry_dump(struct of_changeset_entry *ce)
case OF_RECONFIG_ADD_PROPERTY:
case OF_RECONFIG_REMOVE_PROPERTY:
case OF_RECONFIG_UPDATE_PROPERTY:
- pr_debug("cset<%p> %-15s %s/%s\n", ce, action_names[ce->action],
- ce->np->full_name, ce->prop->name);
+ pr_debug("cset<%p> %-15s %pOF/%s\n", ce, action_names[ce->action],
+ ce->np, ce->prop->name);
break;
case OF_RECONFIG_ATTACH_NODE:
case OF_RECONFIG_DETACH_NODE:
- pr_debug("cset<%p> %-15s %s\n", ce, action_names[ce->action],
- ce->np->full_name);
+ pr_debug("cset<%p> %-15s %pOF\n", ce, action_names[ce->action],
+ ce->np);
break;
}
}
@@ -539,7 +538,7 @@ static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool reve
}
if (ret)
- pr_err("changeset notifier error @%s\n", ce->np->full_name);
+ pr_err("changeset notifier error @%pOF\n", ce->np);
}
static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
@@ -570,8 +569,8 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
ret = __of_add_property(ce->np, ce->prop);
if (ret) {
- pr_err("changeset: add_property failed @%s/%s\n",
- ce->np->full_name,
+ pr_err("changeset: add_property failed @%pOF/%s\n",
+ ce->np,
ce->prop->name);
break;
}
@@ -579,8 +578,8 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
case OF_RECONFIG_REMOVE_PROPERTY:
ret = __of_remove_property(ce->np, ce->prop);
if (ret) {
- pr_err("changeset: remove_property failed @%s/%s\n",
- ce->np->full_name,
+ pr_err("changeset: remove_property failed @%pOF/%s\n",
+ ce->np,
ce->prop->name);
break;
}
@@ -598,8 +597,8 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
ret = __of_update_property(ce->np, ce->prop, &old_prop);
if (ret) {
- pr_err("changeset: update_property failed @%s/%s\n",
- ce->np->full_name,
+ pr_err("changeset: update_property failed @%pOF/%s\n",
+ ce->np,
ce->prop->name);
break;
}
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index ab21c846eb27..ec00ae7384c2 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -59,20 +59,19 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
struct device_node *of_irq_find_parent(struct device_node *child)
{
struct device_node *p;
- const __be32 *parp;
+ phandle parent;
if (!of_node_get(child))
return NULL;
do {
- parp = of_get_property(child, "interrupt-parent", NULL);
- if (parp == NULL)
+ if (of_property_read_u32(child, "interrupt-parent", &parent)) {
p = of_get_parent(child);
- else {
+ } else {
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
p = of_node_get(of_irq_dflt_pic);
else
- p = of_find_node_by_phandle(be32_to_cpup(parp));
+ p = of_find_node_by_phandle(parent);
}
of_node_put(child);
child = p;
@@ -117,11 +116,8 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
* is none, we are nice and just walk up the tree
*/
do {
- tmp = of_get_property(ipar, "#interrupt-cells", NULL);
- if (tmp != NULL) {
- intsize = be32_to_cpu(*tmp);
+ if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
break;
- }
tnode = ipar;
ipar = of_irq_find_parent(ipar);
of_node_put(tnode);
@@ -131,7 +127,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
goto fail;
}
- pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
+ pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
if (out_irq->args_count != intsize)
goto fail;
@@ -169,8 +165,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
/* Now check if cursor is an interrupt-controller and if it is
* then we are done
*/
- if (of_get_property(ipar, "interrupt-controller", NULL) !=
- NULL) {
+ if (of_property_read_bool(ipar, "interrupt-controller")) {
pr_debug(" -> got it !\n");
return 0;
}
@@ -229,14 +224,14 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
/* Get #interrupt-cells and #address-cells of new
* parent
*/
- tmp = of_get_property(newpar, "#interrupt-cells", NULL);
- if (tmp == NULL) {
+ if (of_property_read_u32(newpar, "#interrupt-cells",
+ &newintsize)) {
pr_debug(" -> parent lacks #interrupt-cells!\n");
goto fail;
}
- newintsize = be32_to_cpu(*tmp);
- tmp = of_get_property(newpar, "#address-cells", NULL);
- newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
+ if (of_property_read_u32(newpar, "#address-cells",
+ &newaddrsize))
+ newaddrsize = 0;
pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
newintsize, newaddrsize);
@@ -269,7 +264,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
skiplevel:
/* Iterate again with new parent */
out_irq->np = newpar;
- pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
+ pr_debug(" -> new parent: %pOF\n", newpar);
of_node_put(ipar);
ipar = newpar;
newpar = NULL;
@@ -297,11 +292,11 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
struct device_node *p;
- const __be32 *intspec, *tmp, *addr;
- u32 intsize, intlen;
+ const __be32 *addr;
+ u32 intsize;
int i, res;
- pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
+ pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
/* OldWorld mac stuff is "special", handle out of line */
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
@@ -316,42 +311,32 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
if (!res)
return of_irq_parse_raw(addr, out_irq);
- /* Get the interrupts property */
- intspec = of_get_property(device, "interrupts", &intlen);
- if (intspec == NULL)
- return -EINVAL;
-
- intlen /= sizeof(*intspec);
-
- pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
-
/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
if (p == NULL)
return -EINVAL;
/* Get size of interrupt specifier */
- tmp = of_get_property(p, "#interrupt-cells", NULL);
- if (tmp == NULL) {
+ if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
res = -EINVAL;
goto out;
}
- intsize = be32_to_cpu(*tmp);
- pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
-
- /* Check index */
- if ((index + 1) * intsize > intlen) {
- res = -EINVAL;
- goto out;
- }
+ pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
/* Copy intspec into irq structure */
- intspec += index * intsize;
out_irq->np = p;
out_irq->args_count = intsize;
- for (i = 0; i < intsize; i++)
- out_irq->args[i] = be32_to_cpup(intspec++);
+ for (i = 0; i < intsize; i++) {
+ res = of_property_read_u32_index(device, "interrupts",
+ (index * intsize) + i,
+ out_irq->args + i);
+ if (res)
+ goto out;
+ }
+
+ pr_debug(" intspec=%d\n", *out_irq->args);
+
/* Check if there are any interrupt-map translations to process */
res = of_irq_parse_raw(addr, out_irq);
@@ -508,7 +493,7 @@ void __init of_irq_init(const struct of_device_id *matches)
INIT_LIST_HEAD(&intc_parent_list);
for_each_matching_node_and_match(np, matches, &match) {
- if (!of_find_property(np, "interrupt-controller", NULL) ||
+ if (!of_property_read_bool(np, "interrupt-controller") ||
!of_device_is_available(np))
continue;
@@ -555,8 +540,8 @@ void __init of_irq_init(const struct of_device_id *matches)
of_node_set_flag(desc->dev, OF_POPULATED);
- pr_debug("of_irq_init: init %s (%p), parent %p\n",
- desc->dev->full_name,
+ pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
+ desc->dev,
desc->dev, desc->interrupt_parent);
ret = desc->irq_init_cb(desc->dev,
desc->interrupt_parent);
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index b14a00034fb1..d94dd8b77abd 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -166,8 +166,8 @@ static bool of_mdiobus_child_is_phy(struct device_node *child)
if (of_match_node(whitelist_phys, child)) {
pr_warn(FW_WARN
- "%s: Whitelisted compatible string. Please remove\n",
- child->full_name);
+ "%pOF: Whitelisted compatible string. Please remove\n",
+ child);
return true;
}
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index c9d4d3a7b0fe..e9ec931f5b9a 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -57,15 +57,14 @@ EXPORT_SYMBOL_GPL(of_pci_find_child_device);
*/
int of_pci_get_devfn(struct device_node *np)
{
- unsigned int size;
- const __be32 *reg;
+ u32 reg[5];
+ int error;
- reg = of_get_property(np, "reg", &size);
+ error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
+ if (error)
+ return error;
- if (!reg || size < 5 * sizeof(__be32))
- return -EINVAL;
-
- return (be32_to_cpup(reg) >> 8) & 0xff;
+ return (reg[0] >> 8) & 0xff;
}
EXPORT_SYMBOL_GPL(of_pci_get_devfn);
@@ -78,16 +77,17 @@ EXPORT_SYMBOL_GPL(of_pci_get_devfn);
*/
int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
{
- const __be32 *values;
- int len;
+ u32 bus_range[2];
+ int error;
- values = of_get_property(node, "bus-range", &len);
- if (!values || len < sizeof(*values) * 2)
- return -EINVAL;
+ error = of_property_read_u32_array(node, "bus-range", bus_range,
+ ARRAY_SIZE(bus_range));
+ if (error)
+ return error;
res->name = node->name;
- res->start = be32_to_cpup(values++);
- res->end = be32_to_cpup(values);
+ res->start = bus_range[0];
+ res->end = bus_range[1];
res->flags = IORESOURCE_BUS;
return 0;
@@ -105,17 +105,14 @@ EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
*/
int of_get_pci_domain_nr(struct device_node *node)
{
- const __be32 *value;
- int len;
- u16 domain;
-
- value = of_get_property(node, "linux,pci-domain", &len);
- if (!value || len < sizeof(*value))
- return -EINVAL;
+ u32 domain;
+ int error;
- domain = (u16)be32_to_cpup(value);
+ error = of_property_read_u32(node, "linux,pci-domain", &domain);
+ if (error)
+ return error;
- return domain;
+ return (u16)domain;
}
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
@@ -204,15 +201,15 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
if (!bus_range)
return -ENOMEM;
- pr_info("host bridge %s ranges:\n", dev->full_name);
+ pr_info("host bridge %pOF ranges:\n", dev);
err = of_pci_parse_bus_range(dev, bus_range);
if (err) {
bus_range->start = busno;
bus_range->end = bus_max;
bus_range->flags = IORESOURCE_BUS;
- pr_info(" No bus range found for %s, using %pR\n",
- dev->full_name, bus_range);
+ pr_info(" No bus range found for %pOF, using %pR\n",
+ dev, bus_range);
} else {
if (bus_range->end > bus_range->start + bus_max)
bus_range->end = bus_range->start + bus_max;
@@ -258,14 +255,14 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
if (resource_type(res) == IORESOURCE_IO) {
if (!io_base) {
- pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n",
- dev->full_name);
+ pr_err("I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n",
+ dev);
err = -EINVAL;
goto conversion_failed;
}
if (*io_base != (resource_size_t)OF_BAD_ADDR)
- pr_warn("More than one I/O resource converted for %s. CPU base address for old range lost!\n",
- dev->full_name);
+ pr_warn("More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
+ dev);
*io_base = range.cpu_addr;
}
@@ -325,7 +322,7 @@ int of_pci_map_rid(struct device_node *np, u32 rid,
}
if (!map_len || map_len % (4 * sizeof(*map))) {
- pr_err("%s: Error: Bad %s length: %d\n", np->full_name,
+ pr_err("%pOF: Error: Bad %s length: %d\n", np,
map_name, map_len);
return -EINVAL;
}
@@ -349,8 +346,8 @@ int of_pci_map_rid(struct device_node *np, u32 rid,
u32 rid_len = be32_to_cpup(map + 3);
if (rid_base & ~map_mask) {
- pr_err("%s: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
- np->full_name, map_name, map_name,
+ pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
+ np, map_name, map_name,
map_mask, rid_base);
return -EFAULT;
}
@@ -375,14 +372,13 @@ int of_pci_map_rid(struct device_node *np, u32 rid,
if (id_out)
*id_out = masked_rid - rid_base + out_base;
- pr_debug("%s: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
- np->full_name, map_name, map_mask, rid_base, out_base,
+ pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
+ np, map_name, map_mask, rid_base, out_base,
rid_len, rid, *id_out);
return 0;
}
- pr_err("%s: Invalid %s translation - no match for rid 0x%x on %s\n",
- np->full_name, map_name, rid,
- target && *target ? (*target)->full_name : "any target");
+ pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
+ np, map_name, rid, target && *target ? *target : NULL);
return -EFAULT;
}
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index c0e4ee1cd1ba..8ecfee31ab6d 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -35,6 +35,7 @@
struct of_overlay_info {
struct device_node *target;
struct device_node *overlay;
+ bool is_symbols_node;
};
/**
@@ -55,7 +56,8 @@ struct of_overlay {
};
static int of_overlay_apply_one(struct of_overlay *ov,
- struct device_node *target, const struct device_node *overlay);
+ struct device_node *target, const struct device_node *overlay,
+ bool is_symbols_node);
static BLOCKING_NOTIFIER_HEAD(of_overlay_chain);
@@ -92,10 +94,74 @@ static int of_overlay_notify(struct of_overlay *ov,
return 0;
}
+static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
+ const struct property *prop)
+{
+ struct of_overlay_info *ovinfo;
+ struct property *new;
+ const char *overlay_name;
+ char *label_path;
+ char *symbol_path;
+ const char *target_path;
+ int k;
+ int label_path_len;
+ int overlay_name_len;
+ int target_path_len;
+
+ if (!prop->value)
+ return NULL;
+ symbol_path = prop->value;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ for (k = 0; k < ov->count; k++) {
+ ovinfo = &ov->ovinfo_tab[k];
+ overlay_name = ovinfo->overlay->full_name;
+ overlay_name_len = strlen(overlay_name);
+ if (!strncasecmp(symbol_path, overlay_name, overlay_name_len))
+ break;
+ }
+
+ if (k >= ov->count)
+ goto err_free;
+
+ target_path = ovinfo->target->full_name;
+ target_path_len = strlen(target_path);
+
+ label_path = symbol_path + overlay_name_len;
+ label_path_len = strlen(label_path);
+
+ new->name = kstrdup(prop->name, GFP_KERNEL);
+ new->length = target_path_len + label_path_len + 1;
+ new->value = kzalloc(new->length, GFP_KERNEL);
+
+ if (!new->name || !new->value)
+ goto err_free;
+
+ strcpy(new->value, target_path);
+ strcpy(new->value + target_path_len, label_path);
+
+ /* mark the property as dynamic */
+ of_property_set_flag(new, OF_DYNAMIC);
+
+ return new;
+
+ err_free:
+ kfree(new->name);
+ kfree(new->value);
+ kfree(new);
+ return NULL;
+
+
+}
+
static int of_overlay_apply_single_property(struct of_overlay *ov,
- struct device_node *target, struct property *prop)
+ struct device_node *target, struct property *prop,
+ bool is_symbols_node)
{
- struct property *propn, *tprop;
+ struct property *propn = NULL, *tprop;
/* NOTE: Multiple changes of single properties not supported */
tprop = of_find_property(target, prop->name, NULL);
@@ -106,7 +172,15 @@ static int of_overlay_apply_single_property(struct of_overlay *ov,
of_prop_cmp(prop->name, "linux,phandle") == 0)
return 0;
- propn = __of_prop_dup(prop, GFP_KERNEL);
+ if (is_symbols_node) {
+ /* changing a property in __symbols__ node not allowed */
+ if (tprop)
+ return -EINVAL;
+ propn = dup_and_fixup_symbol_prop(ov, prop);
+ } else {
+ propn = __of_prop_dup(prop, GFP_KERNEL);
+ }
+
if (propn == NULL)
return -ENOMEM;
@@ -130,18 +204,21 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
return -ENOMEM;
/* NOTE: Multiple mods of created nodes not supported */
- tchild = of_get_child_by_name(target, cname);
+ for_each_child_of_node(target, tchild)
+ if (!of_node_cmp(cname, kbasename(tchild->full_name)))
+ break;
+
if (tchild != NULL) {
/* new overlay phandle value conflicts with existing value */
if (child->phandle)
return -EINVAL;
/* apply overlay recursively */
- ret = of_overlay_apply_one(ov, tchild, child);
+ ret = of_overlay_apply_one(ov, tchild, child, 0);
of_node_put(tchild);
} else {
/* create empty tree as a target */
- tchild = __of_node_dup(child, "%s/%s", target->full_name, cname);
+ tchild = __of_node_dup(child, "%pOF/%s", target, cname);
if (!tchild)
return -ENOMEM;
@@ -152,7 +229,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
if (ret)
return ret;
- ret = of_overlay_apply_one(ov, tchild, child);
+ ret = of_overlay_apply_one(ov, tchild, child, 0);
if (ret)
return ret;
}
@@ -168,26 +245,32 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
* by using the changeset.
*/
static int of_overlay_apply_one(struct of_overlay *ov,
- struct device_node *target, const struct device_node *overlay)
+ struct device_node *target, const struct device_node *overlay,
+ bool is_symbols_node)
{
struct device_node *child;
struct property *prop;
int ret;
for_each_property_of_node(overlay, prop) {
- ret = of_overlay_apply_single_property(ov, target, prop);
+ ret = of_overlay_apply_single_property(ov, target, prop,
+ is_symbols_node);
if (ret) {
- pr_err("Failed to apply prop @%s/%s\n",
- target->full_name, prop->name);
+ pr_err("Failed to apply prop @%pOF/%s\n",
+ target, prop->name);
return ret;
}
}
+ /* do not allow symbols node to have any children */
+ if (is_symbols_node)
+ return 0;
+
for_each_child_of_node(overlay, child) {
ret = of_overlay_apply_single_device_node(ov, target, child);
if (ret != 0) {
- pr_err("Failed to apply single node @%s/%s\n",
- target->full_name, child->name);
+ pr_err("Failed to apply single node @%pOF/%s\n",
+ target, child->name);
of_node_put(child);
return ret;
}
@@ -213,9 +296,10 @@ static int of_overlay_apply(struct of_overlay *ov)
for (i = 0; i < ov->count; i++) {
struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
- err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay);
+ err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay,
+ ovinfo->is_symbols_node);
if (err != 0) {
- pr_err("apply failed '%s'\n", ovinfo->target->full_name);
+ pr_err("apply failed '%pOF'\n", ovinfo->target);
return err;
}
}
@@ -311,6 +395,9 @@ static int of_build_overlay_info(struct of_overlay *ov,
for_each_child_of_node(tree, node)
cnt++;
+ if (of_get_child_by_name(tree, "__symbols__"))
+ cnt++;
+
ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
if (ovinfo == NULL)
return -ENOMEM;