2017-12-27 12:55:14 -06:00
// SPDX-License-Identifier: GPL-2.0
2014-07-04 19:59:20 +03:00
/*
* Functions for dealing with DT resolution
*
* Copyright ( C ) 2012 Pantelis Antoniou < panto @ antoniou - consulting . com >
* Copyright ( C ) 2012 Texas Instruments Inc .
*/
2016-06-15 08:32:18 -05:00
# define pr_fmt(fmt) "OF: resolver: " fmt
2014-07-04 19:59:20 +03:00
# 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/slab.h>
2017-06-02 12:43:18 -05:00
# include "of_private.h"
2016-10-28 23:26:24 -07:00
static phandle live_tree_max_phandle ( void )
2014-07-04 19:59:20 +03:00
{
struct device_node * node ;
phandle phandle ;
unsigned long flags ;
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 ;
}
2016-10-28 23:26:26 -07:00
static void adjust_overlay_phandles ( struct device_node * overlay ,
2014-07-04 19:59:20 +03:00
int phandle_delta )
{
struct device_node * child ;
struct property * prop ;
phandle phandle ;
2016-10-28 23:26:29 -07:00
/* adjust node's phandle in node */
2016-10-28 23:26:26 -07:00
if ( overlay - > phandle ! = 0 & & overlay - > phandle ! = OF_PHANDLE_ILLEGAL )
overlay - > phandle + = phandle_delta ;
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:29 -07:00
/* copy adjusted phandle into *phandle properties */
2016-10-28 23:26:26 -07:00
for_each_property_of_node ( overlay , prop ) {
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:23 -07:00
if ( of_prop_cmp ( prop - > name , " phandle " ) & &
of_prop_cmp ( prop - > name , " linux,phandle " ) )
2014-07-04 19:59:20 +03:00
continue ;
if ( prop - > length < 4 )
continue ;
phandle = be32_to_cpup ( prop - > value ) ;
2016-10-28 23:26:21 -07:00
if ( phandle = = OF_PHANDLE_ILLEGAL )
2014-07-04 19:59:20 +03:00
continue ;
2017-05-04 12:56:12 -05:00
* ( __be32 * ) prop - > value = cpu_to_be32 ( overlay - > phandle ) ;
2014-07-04 19:59:20 +03:00
}
2016-10-28 23:26:26 -07:00
for_each_child_of_node ( overlay , child )
2016-10-28 23:26:24 -07:00
adjust_overlay_phandles ( child , phandle_delta ) ;
2014-07-04 19:59:20 +03:00
}
2016-10-28 23:26:26 -07:00
static int update_usages_of_a_phandle_reference ( struct device_node * overlay ,
struct property * prop_fixup , phandle phandle )
2014-07-04 19:59:20 +03:00
{
struct device_node * refnode ;
2016-10-28 23:26:26 -07:00
struct property * prop ;
char * value , * cur , * end , * node_path , * prop_name , * s ;
int offset , len ;
2014-07-04 19:59:20 +03:00
int err = 0 ;
2017-10-13 00:35:58 -07:00
value = kmemdup ( prop_fixup - > value , prop_fixup - > length , GFP_KERNEL ) ;
2016-10-28 23:26:26 -07:00
if ( ! value )
2014-07-04 19:59:20 +03:00
return - ENOMEM ;
2016-10-28 23:26:29 -07:00
/* prop_fixup contains a list of tuples of path:property_name:offset */
2016-10-28 23:26:26 -07:00
end = value + prop_fixup - > length ;
for ( cur = value ; cur < end ; cur + = len + 1 ) {
len = strlen ( cur ) ;
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:26 -07:00
node_path = cur ;
s = strchr ( cur , ' : ' ) ;
2014-07-04 19:59:20 +03:00
if ( ! s ) {
err = - EINVAL ;
goto err_fail ;
}
* s + + = ' \0 ' ;
2016-10-28 23:26:26 -07:00
prop_name = s ;
2014-07-04 19:59:20 +03:00
s = strchr ( s , ' : ' ) ;
if ( ! s ) {
err = - EINVAL ;
goto err_fail ;
}
* s + + = ' \0 ' ;
2016-10-28 23:26:27 -07:00
2014-07-04 19:59:20 +03:00
err = kstrtoint ( s , 10 , & offset ) ;
2016-10-28 23:26:23 -07:00
if ( err )
2014-07-04 19:59:20 +03:00
goto err_fail ;
2017-06-02 12:43:18 -05:00
refnode = __of_find_node_by_full_path ( of_node_get ( overlay ) , node_path ) ;
2016-10-28 23:26:22 -07:00
if ( ! refnode )
2014-07-04 19:59:20 +03:00
continue ;
2016-10-28 23:26:26 -07:00
for_each_property_of_node ( refnode , prop ) {
if ( ! of_prop_cmp ( prop - > name , prop_name ) )
2014-07-04 19:59:20 +03:00
break ;
}
2016-02-03 23:39:01 +05:30
of_node_put ( refnode ) ;
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:26 -07:00
if ( ! prop ) {
2014-07-04 19:59:20 +03:00
err = - ENOENT ;
goto err_fail ;
}
2018-05-16 21:19:51 -07:00
if ( offset < 0 | | offset + sizeof ( __be32 ) > prop - > length ) {
err = - EINVAL ;
goto err_fail ;
}
2016-10-28 23:26:26 -07:00
* ( __be32 * ) ( prop - > value + offset ) = cpu_to_be32 ( phandle ) ;
2014-07-04 19:59:20 +03:00
}
err_fail :
2016-10-28 23:26:26 -07:00
kfree ( value ) ;
2014-07-04 19:59:20 +03:00
return err ;
}
2014-10-28 22:33:49 +02:00
/* compare nodes taking into account that 'name' strips out the @ part */
2016-10-28 23:26:25 -07:00
static int node_name_cmp ( const struct device_node * dn1 ,
2014-10-28 22:33:49 +02:00
const struct device_node * dn2 )
{
2017-06-01 18:00:00 -05:00
const char * n1 = kbasename ( dn1 - > full_name ) ;
const char * n2 = kbasename ( dn2 - > full_name ) ;
2014-10-28 22:33:49 +02:00
return of_node_cmp ( n1 , n2 ) ;
}
2014-07-04 19:59:20 +03:00
/*
* Adjust the local phandle references by the given phandle delta .
2016-10-28 23:26:29 -07:00
*
* 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 .
2014-07-04 19:59:20 +03:00
*/
2016-10-28 23:26:26 -07:00
static int adjust_local_phandle_references ( struct device_node * local_fixups ,
struct device_node * overlay , int phandle_delta )
2014-07-04 19:59:20 +03:00
{
2016-10-28 23:26:26 -07:00
struct device_node * child , * overlay_child ;
struct property * prop_fix , * prop ;
2014-10-28 22:33:49 +02:00
int err , i , count ;
unsigned int off ;
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:26 -07:00
if ( ! local_fixups )
2014-07-04 19:59:20 +03:00
return 0 ;
2016-10-28 23:26:26 -07:00
for_each_property_of_node ( local_fixups , prop_fix ) {
2014-10-28 22:33:49 +02:00
2014-07-04 19:59:20 +03:00
/* skip properties added automatically */
2016-10-28 23:26:26 -07:00
if ( ! of_prop_cmp ( prop_fix - > name , " name " ) | |
! of_prop_cmp ( prop_fix - > name , " phandle " ) | |
! of_prop_cmp ( prop_fix - > name , " linux,phandle " ) )
2014-07-04 19:59:20 +03:00
continue ;
2016-10-28 23:26:26 -07:00
if ( ( prop_fix - > length % 4 ) ! = 0 | | prop_fix - > length = = 0 )
2014-10-28 22:33:49 +02:00
return - EINVAL ;
2016-10-28 23:26:26 -07:00
count = prop_fix - > length / sizeof ( __be32 ) ;
2014-10-28 22:33:49 +02:00
2016-10-28 23:26:26 -07:00
for_each_property_of_node ( overlay , prop ) {
if ( ! of_prop_cmp ( prop - > name , prop_fix - > name ) )
2014-10-28 22:33:49 +02:00
break ;
}
2016-10-28 23:26:26 -07:00
if ( ! prop )
2014-10-28 22:33:49 +02:00
return - EINVAL ;
for ( i = 0 ; i < count ; i + + ) {
2016-10-28 23:26:26 -07:00
off = be32_to_cpu ( ( ( __be32 * ) prop_fix - > value ) [ i ] ) ;
2016-10-28 23:26:28 -07:00
if ( ( off + 4 ) > prop - > length )
2014-10-28 22:33:49 +02:00
return - EINVAL ;
2017-10-13 00:35:57 -07:00
be32_add_cpu ( prop - > value + off , phandle_delta ) ;
2014-10-28 22:33:49 +02:00
}
}
2016-10-28 23:26:29 -07:00
/*
* 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 .
*/
2016-10-28 23:26:26 -07:00
for_each_child_of_node ( local_fixups , child ) {
2014-10-28 22:33:49 +02:00
2016-10-28 23:26:26 -07:00
for_each_child_of_node ( overlay , overlay_child )
if ( ! node_name_cmp ( child , overlay_child ) )
2014-10-28 22:33:49 +02:00
break ;
2016-10-28 23:26:26 -07:00
if ( ! overlay_child )
2014-10-28 22:33:49 +02:00
return - EINVAL ;
2016-10-28 23:26:26 -07:00
err = adjust_local_phandle_references ( child , overlay_child ,
2014-10-28 22:33:49 +02:00
phandle_delta ) ;
2016-10-28 23:26:23 -07:00
if ( err )
2014-07-04 19:59:20 +03:00
return err ;
}
return 0 ;
}
/**
2016-10-28 23:26:29 -07:00
* of_resolve_phandles - Relocate and resolve overlay against live tree
*
* @ overlay : Pointer to devicetree overlay to relocate and resolve
*
* 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 .
2014-07-04 19:59:20 +03:00
*
2016-10-28 23:26:29 -07:00
* 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 .
2014-07-04 19:59:20 +03:00
*
2016-10-28 23:26:29 -07:00
* Return : % 0 on success or a negative error value on error .
2014-07-04 19:59:20 +03:00
*/
2016-10-28 23:26:26 -07:00
int of_resolve_phandles ( struct device_node * overlay )
2014-07-04 19:59:20 +03:00
{
2016-10-28 23:26:26 -07:00
struct device_node * child , * local_fixups , * refnode ;
2016-10-28 23:26:32 -07:00
struct device_node * tree_symbols , * overlay_fixups ;
2016-10-28 23:26:26 -07:00
struct property * prop ;
2014-07-04 19:59:20 +03:00
const char * refpath ;
phandle phandle , phandle_delta ;
int err ;
2016-10-28 23:26:30 -07:00
tree_symbols = NULL ;
2016-10-28 23:26:27 -07:00
if ( ! overlay ) {
pr_err ( " null overlay \n " ) ;
2016-10-28 23:26:30 -07:00
err = - EINVAL ;
2016-12-01 22:10:25 -08:00
goto out ;
2016-10-28 23:26:27 -07:00
}
2017-10-17 16:36:29 -07:00
2016-10-28 23:26:27 -07:00
if ( ! of_node_check_flag ( overlay , OF_DETACHED ) ) {
pr_err ( " overlay not detached \n " ) ;
2016-10-28 23:26:30 -07:00
err = - EINVAL ;
2016-12-01 22:10:25 -08:00
goto out ;
2016-10-28 23:26:27 -07:00
}
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:24 -07:00
phandle_delta = live_tree_max_phandle ( ) + 1 ;
2016-10-28 23:26:26 -07:00
adjust_overlay_phandles ( overlay , phandle_delta ) ;
2014-10-28 22:33:49 +02:00
2016-10-28 23:26:26 -07:00
for_each_child_of_node ( overlay , local_fixups )
if ( ! of_node_cmp ( local_fixups - > name , " __local_fixups__ " ) )
2014-10-28 22:33:49 +02:00
break ;
2016-10-28 23:26:27 -07:00
err = adjust_local_phandle_references ( local_fixups , overlay , phandle_delta ) ;
if ( err )
2016-12-01 22:10:25 -08:00
goto out ;
2014-10-28 22:33:49 +02:00
2016-10-28 23:26:26 -07:00
overlay_fixups = NULL ;
2014-07-04 19:59:20 +03:00
2016-10-28 23:26:26 -07:00
for_each_child_of_node ( overlay , child ) {
2016-10-28 23:26:27 -07:00
if ( ! of_node_cmp ( child - > name , " __fixups__ " ) )
2016-10-28 23:26:26 -07:00
overlay_fixups = child ;
2014-07-04 19:59:20 +03:00
}
2016-10-28 23:26:26 -07:00
if ( ! overlay_fixups ) {
2016-10-28 23:26:21 -07:00
err = 0 ;
2014-07-04 19:59:20 +03:00
goto out ;
}
2016-10-28 23:26:31 -07:00
tree_symbols = of_find_node_by_path ( " /__symbols__ " ) ;
2016-10-28 23:26:26 -07:00
if ( ! tree_symbols ) {
2016-10-28 23:26:27 -07:00
pr_err ( " no symbols in root of device tree. \n " ) ;
2014-07-04 19:59:20 +03:00
err = - EINVAL ;
2016-12-01 22:10:25 -08:00
goto out ;
2014-07-04 19:59:20 +03:00
}
2016-10-28 23:26:26 -07:00
for_each_property_of_node ( overlay_fixups , prop ) {
2014-07-04 19:59:20 +03:00
/* skip properties added automatically */
2016-10-28 23:26:26 -07:00
if ( ! of_prop_cmp ( prop - > name , " name " ) )
2014-07-04 19:59:20 +03:00
continue ;
2016-10-28 23:26:26 -07:00
err = of_property_read_string ( tree_symbols ,
prop - > name , & refpath ) ;
2016-10-28 23:26:23 -07:00
if ( err )
2016-12-01 22:10:25 -08:00
goto out ;
2014-07-04 19:59:20 +03:00
refnode = of_find_node_by_path ( refpath ) ;
if ( ! refnode ) {
err = - ENOENT ;
2016-12-01 22:10:25 -08:00
goto out ;
2014-07-04 19:59:20 +03:00
}
phandle = refnode - > phandle ;
of_node_put ( refnode ) ;
2016-10-28 23:26:26 -07:00
err = update_usages_of_a_phandle_reference ( overlay , prop , phandle ) ;
2014-07-04 19:59:20 +03:00
if ( err )
break ;
}
out :
2016-12-01 22:10:25 -08:00
if ( err )
pr_err ( " overlay phandle fixup failed: %d \n " , err ) ;
2016-10-28 23:26:26 -07:00
of_node_put ( tree_symbols ) ;
2014-07-04 19:59:20 +03:00
return err ;
}
EXPORT_SYMBOL_GPL ( of_resolve_phandles ) ;