DeviceTree updates for 4.10:

- Add various vendor prefixes.
 
 - Fix NUMA node handling when "numa=off" is passed on kernel command
   line.
 
 - Coding style Clean-up of overlay handling code.
 
 - DocBook fixes in DT platform driver code
 
 - Altera SoCFPGA binding addtions for freeze bridge, arria10 FPGA
   manager and FPGA bridges.
 
 - Couple of printk message fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQItBAABCAAXBQJYUqo6EBxyb2JoQGtlcm5lbC5vcmcACgkQ+vtdtY28YcMHiw//
 WIJH6XF8PkAEkITxChwb3kJ1y7PCtR7YmncMvnMRh9kIcyPwFjiDRqUz/0MiTHgD
 UJsFtX6057GWDd0mlUrQ8iFFlzdGLl2Xw4u6sr4bC7bGVK0Nj9QX+xrFmXCLtGj0
 wYkXIJXDXmLQJPKhG5np5jBYfJIaYr5FcNCwdOEljDDauHAg6f2hvgOby1X8FCOS
 oC3LCqvx4SWp9EcQAvOkKAJazsIlSAynb7EFwTaKo0RHJPzX/Uhp7RmyvAgeVZVE
 a2GS+YwboD3PMa7cjC3R7FwBXhuM/YQLLWfgSGwvr8nADP4a/iZNzJt1H0rU1LKP
 ukgSP5m58bt713H7Gr6OJ1ygAFmvFAzye+mXwHVxwqg3BFp141LCKoD0A2RO+zH8
 5cma2OTl9bQSWxtKJyLm4y9/QegaThyM/eZyk5j6XOjIEtlTS0h8H3ZHbU55k1HC
 7MJrnoAb3z5vGhxPplF1MOeGswz5vLME0e74Po0Nt8X7sdpj7zVWBL8AZh+Xyw2O
 d6oz9xYQVgJ5mqnnXXTWSqNfTM82+aUZV6SREaOJ1GjSy3pfd2s85N1oB8oIOb+o
 gRNYibbv/EvaOBqADwQoRWRTIW+0Vtf/vY1xVFB6Wd8XO2a/dmHZJ95jaPlAfwf3
 l5EqgsHP1kirkNYgCAUSpCkPf61gA+ZAWxjlfrARmCg=
 =1Sex
 -----END PGP SIGNATURE-----

Merge tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux

Pull DeviceTree updates from Rob Herring:

 - add various vendor prefixes.

 - fix NUMA node handling when "numa=off" is passed on kernel command
   line.

 - coding style Clean-up of overlay handling code.

 - DocBook fixes in DT platform driver code

 - Altera SoCFPGA binding addtions for freeze bridge, arria10 FPGA
   manager and FPGA bridges.

 - a couple of printk message fixes.

* tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (33 commits)
  dt: pwm: bcm2835: fix typo in clocks property name
  devicetree: add vendor prefix for National Instruments
  Revert "of: base: add support to get machine model name"
  of: Fix issue where code would fall through to error case.
  drivers/of: fix missing pr_cont()s in of_print_phandle_args
  devicetree: bindings: Add vendor prefix for Oki
  devicetree: bindings: Add vendor prefix for Andes Technology Corporation
  dt-bindings: add MYIR Tech hardware vendor prefix
  add bindings document for altera freeze bridge
  ARM: socfpga: add bindings doc for arria10 fpga manager
  ARM: socfpga: add bindings document for fpga bridge drivers
  of: base: add support to get machine model name
  of/platform: clarify of_find_device_by_node refcounting
  of/platform: fix of_platform_device_destroy comment
  of: Remove unused variable overlay_symbols
  of: Move setting of pointer to beside test for non-null
  of: Add back an error message, restructured
  of: Update comments to reflect changes and increase clarity
  of: Remove redundant size check
  of: Update structure of code to be clearer, also remove BUG_ON()
  ...
This commit is contained in:
Linus Torvalds 2016-12-15 11:49:41 -08:00
commit 6df8b74b17
11 changed files with 278 additions and 215 deletions

View file

@ -1534,9 +1534,12 @@ 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));
for (i = 0; i < args->args_count; i++)
printk(i ? ",%08x" : ":%08x", args->args[i]);
printk("\n");
for (i = 0; i < args->args_count; i++) {
const char delim = i ? ',' : ':';
pr_cont("%c%08x", delim, args->args[i]);
}
pr_cont("\n");
}
int of_phandle_iterator_init(struct of_phandle_iterator *it,

View file

@ -176,7 +176,12 @@ int of_node_to_nid(struct device_node *device)
np->name);
of_node_put(np);
if (!r)
/*
* If numa=off passed on command line, or with a defective
* device tree, the nid may not be in the set of possible
* nodes. Check for this case and return NUMA_NO_NODE.
*/
if (!r && nid < MAX_NUMNODES && node_possible(nid))
return nid;
return NUMA_NO_NODE;

View file

@ -45,6 +45,9 @@ static int of_dev_node_match(struct device *dev, void *data)
* of_find_device_by_node - Find the platform_device associated with a node
* @np: Pointer to device tree node
*
* Takes a reference to the embedded struct device which needs to be dropped
* after use.
*
* Returns platform_device pointer, or NULL if not found
*/
struct platform_device *of_find_device_by_node(struct device_node *np)
@ -558,9 +561,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
* of the given device (and, recurrently, their children) that have been
* created from their respective device tree nodes (and only those,
* leaving others - eg. manually created - unharmed).
*
* Returns 0 when all children devices have been removed or
* -EBUSY when some children remained.
*/
void of_platform_depopulate(struct device *parent)
{

View file

@ -28,20 +28,19 @@
* Find a node with the give full name by recursively following any of
* the child node links.
*/
static struct device_node *__of_find_node_by_full_name(struct device_node *node,
static struct device_node *find_node_by_full_name(struct device_node *node,
const char *full_name)
{
struct device_node *child, *found;
if (node == NULL)
if (!node)
return NULL;
/* check */
if (of_node_cmp(node->full_name, full_name) == 0)
if (!of_node_cmp(node->full_name, full_name))
return of_node_get(node);
for_each_child_of_node(node, child) {
found = __of_find_node_by_full_name(child, full_name);
found = find_node_by_full_name(child, full_name);
if (found != NULL) {
of_node_put(child);
return found;
@ -51,16 +50,12 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node,
return NULL;
}
/*
* Find live tree's maximum phandle value.
*/
static phandle of_get_tree_max_phandle(void)
static phandle live_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) {
@ -73,131 +68,102 @@ static phandle of_get_tree_max_phandle(void)
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,
static void adjust_overlay_phandles(struct device_node *overlay,
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;
/* adjust node's phandle in node */
if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL)
overlay->phandle += phandle_delta;
/* now adjust phandle & linux,phandle values */
for_each_property_of_node(node, prop) {
/* copy adjusted phandle into *phandle properties */
for_each_property_of_node(overlay, prop) {
/* only look for these two */
if (of_prop_cmp(prop->name, "phandle") != 0 &&
of_prop_cmp(prop->name, "linux,phandle") != 0)
if (of_prop_cmp(prop->name, "phandle") &&
of_prop_cmp(prop->name, "linux,phandle"))
continue;
/* must be big enough */
if (prop->length < 4)
continue;
/* read phandle value */
phandle = be32_to_cpup(prop->value);
if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */
if (phandle == OF_PHANDLE_ILLEGAL)
continue;
/* adjust */
*(uint32_t *)prop->value = cpu_to_be32(node->phandle);
*(uint32_t *)prop->value = cpu_to_be32(overlay->phandle);
}
/* now do the children recursively */
for_each_child_of_node(node, child)
__of_adjust_tree_phandles(child, phandle_delta);
for_each_child_of_node(overlay, child)
adjust_overlay_phandles(child, phandle_delta);
}
static int __of_adjust_phandle_ref(struct device_node *node,
struct property *rprop, int value)
static int update_usages_of_a_phandle_reference(struct device_node *overlay,
struct property *prop_fixup, phandle phandle)
{
phandle phandle;
struct device_node *refnode;
struct property *sprop;
char *propval, *propcur, *propend, *nodestr, *propstr, *s;
int offset, propcurlen;
struct property *prop;
char *value, *cur, *end, *node_path, *prop_name, *s;
int offset, len;
int err = 0;
/* make a copy */
propval = kmalloc(rprop->length, GFP_KERNEL);
if (!propval) {
pr_err("%s: Could not copy value of '%s'\n",
__func__, rprop->name);
value = kmalloc(prop_fixup->length, GFP_KERNEL);
if (!value)
return -ENOMEM;
}
memcpy(propval, rprop->value, rprop->length);
memcpy(value, prop_fixup->value, prop_fixup->length);
propend = propval + rprop->length;
for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
propcurlen = strlen(propcur);
/* prop_fixup contains a list of tuples of path:property_name:offset */
end = value + prop_fixup->length;
for (cur = value; cur < end; cur += len + 1) {
len = strlen(cur);
nodestr = propcur;
s = strchr(propcur, ':');
node_path = cur;
s = strchr(cur, ':');
if (!s) {
pr_err("%s: Illegal symbol entry '%s' (1)\n",
__func__, propcur);
err = -EINVAL;
goto err_fail;
}
*s++ = '\0';
propstr = s;
prop_name = s;
s = strchr(s, ':');
if (!s) {
pr_err("%s: Illegal symbol entry '%s' (2)\n",
__func__, (char *)rprop->value);
err = -EINVAL;
goto err_fail;
}
*s++ = '\0';
err = kstrtoint(s, 10, &offset);
if (err != 0) {
pr_err("%s: Could get offset '%s'\n",
__func__, (char *)rprop->value);
if (err)
goto err_fail;
}
/* look into the resolve node for the full path */
refnode = __of_find_node_by_full_name(node, nodestr);
if (!refnode) {
pr_warn("%s: Could not find refnode '%s'\n",
__func__, (char *)rprop->value);
refnode = find_node_by_full_name(overlay, node_path);
if (!refnode)
continue;
}
/* now find the property */
for_each_property_of_node(refnode, sprop) {
if (of_prop_cmp(sprop->name, propstr) == 0)
for_each_property_of_node(refnode, prop) {
if (!of_prop_cmp(prop->name, prop_name))
break;
}
of_node_put(refnode);
if (!sprop) {
pr_err("%s: Could not find property '%s'\n",
__func__, (char *)rprop->value);
if (!prop) {
err = -ENOENT;
goto err_fail;
}
phandle = value;
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
*(__be32 *)(prop->value + offset) = cpu_to_be32(phandle);
}
err_fail:
kfree(propval);
kfree(value);
return err;
}
/* compare nodes taking into account that 'name' strips out the @ part */
static int __of_node_name_cmp(const struct device_node *dn1,
static int node_name_cmp(const struct device_node *dn1,
const struct device_node *dn2)
{
const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
@ -208,85 +174,77 @@ static int __of_node_name_cmp(const struct device_node *dn1,
/*
* Adjust the local phandle references by the given phandle delta.
* Assumes the existances of a __local_fixups__ node at the root.
* Assumes that __of_verify_tree_phandle_references has been called.
* Does not take any devtree locks so make sure you call this on a tree
* which is at the detached state.
*
* Subtree @local_fixups, which is overlay node __local_fixups__,
* mirrors the fragment node structure at the root of the overlay.
*
* For each property in the fragments that contains a phandle reference,
* @local_fixups has a property of the same name that contains a list
* of offsets of the phandle reference(s) within the respective property
* value(s). The values at these offsets will be fixed up.
*/
static int __of_adjust_tree_phandle_references(struct device_node *node,
struct device_node *target, int phandle_delta)
static int adjust_local_phandle_references(struct device_node *local_fixups,
struct device_node *overlay, int phandle_delta)
{
struct device_node *child, *childtarget;
struct property *rprop, *sprop;
struct device_node *child, *overlay_child;
struct property *prop_fix, *prop;
int err, i, count;
unsigned int off;
phandle phandle;
if (node == NULL)
if (!local_fixups)
return 0;
for_each_property_of_node(node, rprop) {
for_each_property_of_node(local_fixups, prop_fix) {
/* skip properties added automatically */
if (of_prop_cmp(rprop->name, "name") == 0 ||
of_prop_cmp(rprop->name, "phandle") == 0 ||
of_prop_cmp(rprop->name, "linux,phandle") == 0)
if (!of_prop_cmp(prop_fix->name, "name") ||
!of_prop_cmp(prop_fix->name, "phandle") ||
!of_prop_cmp(prop_fix->name, "linux,phandle"))
continue;
if ((rprop->length % 4) != 0 || rprop->length == 0) {
pr_err("%s: Illegal property (size) '%s' @%s\n",
__func__, rprop->name, node->full_name);
if ((prop_fix->length % 4) != 0 || prop_fix->length == 0)
return -EINVAL;
}
count = rprop->length / sizeof(__be32);
count = prop_fix->length / sizeof(__be32);
/* now find the target property */
for_each_property_of_node(target, sprop) {
if (of_prop_cmp(sprop->name, rprop->name) == 0)
for_each_property_of_node(overlay, prop) {
if (!of_prop_cmp(prop->name, prop_fix->name))
break;
}
if (sprop == NULL) {
pr_err("%s: Could not find target property '%s' @%s\n",
__func__, rprop->name, node->full_name);
if (!prop)
return -EINVAL;
}
for (i = 0; i < count; i++) {
off = be32_to_cpu(((__be32 *)rprop->value)[i]);
/* make sure the offset doesn't overstep (even wrap) */
if (off >= sprop->length ||
(off + 4) > sprop->length) {
pr_err("%s: Illegal property '%s' @%s\n",
__func__, rprop->name,
node->full_name);
off = be32_to_cpu(((__be32 *)prop_fix->value)[i]);
if ((off + 4) > prop->length)
return -EINVAL;
}
if (phandle_delta) {
/* adjust */
phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
phandle += phandle_delta;
*(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
}
phandle = be32_to_cpu(*(__be32 *)(prop->value + off));
phandle += phandle_delta;
*(__be32 *)(prop->value + off) = cpu_to_be32(phandle);
}
}
for_each_child_of_node(node, child) {
/*
* These nested loops recurse down two subtrees in parallel, where the
* node names in the two subtrees match.
*
* The roots of the subtrees are the overlay's __local_fixups__ node
* and the overlay's root node.
*/
for_each_child_of_node(local_fixups, child) {
for_each_child_of_node(target, childtarget)
if (__of_node_name_cmp(child, childtarget) == 0)
for_each_child_of_node(overlay, overlay_child)
if (!node_name_cmp(child, overlay_child))
break;
if (!childtarget) {
pr_err("%s: Could not find target child '%s' @%s\n",
__func__, child->name, node->full_name);
if (!overlay_child)
return -EINVAL;
}
err = __of_adjust_tree_phandle_references(child, childtarget,
err = adjust_local_phandle_references(child, overlay_child,
phandle_delta);
if (err != 0)
if (err)
return err;
}
@ -294,111 +252,103 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
}
/**
* of_resolve - Resolve the given node against the live tree.
* of_resolve_phandles - Relocate and resolve overlay against live tree
*
* @resolve: Node to resolve
* @overlay: Pointer to devicetree overlay to relocate and 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.
* Modify (relocate) values of local phandles in @overlay to a range that
* does not conflict with the live expanded devicetree. Update references
* to the local phandles in @overlay. Update (resolve) phandle references
* in @overlay that refer to the live expanded devicetree.
*
* Phandle values in the live tree are in the range of
* 1 .. live_tree_max_phandle(). The range of phandle values in the overlay
* also begin with at 1. Adjust the phandle values in the overlay to begin
* at live_tree_max_phandle() + 1. Update references to the phandles to
* the adjusted phandle values.
*
* The name of each property in the "__fixups__" node in the overlay matches
* the name of a symbol (a label) in the live tree. The values of each
* property in the "__fixups__" node is a list of the property values in the
* overlay that need to be updated to contain the phandle reference
* corresponding to that symbol in the live tree. Update the references in
* the overlay with the phandle values in the live tree.
*
* @overlay must be detached.
*
* Resolving and applying @overlay to the live expanded devicetree must be
* protected by a mechanism to ensure that multiple overlays are processed
* in a single threaded manner so that multiple overlays will not relocate
* phandles to overlapping ranges. The mechanism to enforce this is not
* yet implemented.
*
* Return: %0 on success or a negative error value on error.
*/
int of_resolve_phandles(struct device_node *resolve)
int of_resolve_phandles(struct device_node *overlay)
{
struct device_node *child, *childroot, *refnode;
struct device_node *root_sym, *resolve_sym, *resolve_fix;
struct property *rprop;
struct device_node *child, *local_fixups, *refnode;
struct device_node *tree_symbols, *overlay_fixups;
struct property *prop;
const char *refpath;
phandle phandle, phandle_delta;
int err;
if (!resolve)
pr_err("%s: null node\n", __func__);
if (resolve && !of_node_check_flag(resolve, OF_DETACHED))
pr_err("%s: node %s not detached\n", __func__,
resolve->full_name);
/* the resolve node must exist, and be detached */
if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
return -EINVAL;
tree_symbols = NULL;
/* first we need to adjust the phandles */
phandle_delta = of_get_tree_max_phandle() + 1;
__of_adjust_tree_phandles(resolve, phandle_delta);
/* locate the local fixups */
childroot = NULL;
for_each_child_of_node(resolve, childroot)
if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
break;
if (childroot != NULL) {
/* resolve root is guaranteed to be the '/' */
err = __of_adjust_tree_phandle_references(childroot,
resolve, 0);
if (err != 0)
return err;
BUG_ON(__of_adjust_tree_phandle_references(childroot,
resolve, phandle_delta));
}
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 &&
of_node_cmp(child->name, "__symbols__") == 0)
resolve_sym = child;
if (!resolve_fix &&
of_node_cmp(child->name, "__fixups__") == 0)
resolve_fix = child;
/* both found, don't bother anymore */
if (resolve_sym && resolve_fix)
break;
}
/* we do allow for the case where no fixups are needed */
if (!resolve_fix) {
err = 0; /* no error */
if (!overlay) {
pr_err("null overlay\n");
err = -EINVAL;
goto out;
}
/* we need to fixup, but no root symbols... */
if (!root_sym) {
pr_err("%s: no symbols in root of device tree.\n", __func__);
if (!of_node_check_flag(overlay, OF_DETACHED)) {
pr_err("overlay not detached\n");
err = -EINVAL;
goto out;
}
for_each_property_of_node(resolve_fix, rprop) {
phandle_delta = live_tree_max_phandle() + 1;
adjust_overlay_phandles(overlay, phandle_delta);
for_each_child_of_node(overlay, local_fixups)
if (!of_node_cmp(local_fixups->name, "__local_fixups__"))
break;
err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta);
if (err)
goto out;
overlay_fixups = NULL;
for_each_child_of_node(overlay, child) {
if (!of_node_cmp(child->name, "__fixups__"))
overlay_fixups = child;
}
if (!overlay_fixups) {
err = 0;
goto out;
}
tree_symbols = of_find_node_by_path("/__symbols__");
if (!tree_symbols) {
pr_err("no symbols in root of device tree.\n");
err = -EINVAL;
goto out;
}
for_each_property_of_node(overlay_fixups, prop) {
/* skip properties added automatically */
if (of_prop_cmp(rprop->name, "name") == 0)
if (!of_prop_cmp(prop->name, "name"))
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);
err = of_property_read_string(tree_symbols,
prop->name, &refpath);
if (err)
goto out;
}
refnode = of_find_node_by_path(refpath);
if (!refnode) {
pr_err("%s: Could not find node by path '%s'\n",
__func__, refpath);
err = -ENOENT;
goto out;
}
@ -406,17 +356,15 @@ int of_resolve_phandles(struct device_node *resolve)
phandle = refnode->phandle;
of_node_put(refnode);
pr_debug("%s: %s phandle is 0x%08x\n",
__func__, rprop->name, phandle);
err = __of_adjust_phandle_ref(resolve, rprop, phandle);
err = update_usages_of_a_phandle_reference(overlay, prop, phandle);
if (err)
break;
}
out:
/* NULL is handled by of_node_put as NOP */
of_node_put(root_sym);
if (err)
pr_err("overlay phandle fixup failed: %d\n", err);
of_node_put(tree_symbols);
return err;
}