2009-11-24 00:53:09 +03:00
/*
* Functions for working with the Flattened Device Tree data format
*
* Copyright 2009 Benjamin Herrenschmidt , IBM Corp
* benh @ kernel . crashing . org
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*/
2009-11-24 06:07:01 +03:00
# include <linux/kernel.h>
2009-11-24 13:26:58 +03:00
# include <linux/initrd.h>
2009-11-24 00:53:09 +03:00
# include <linux/of.h>
# include <linux/of_fdt.h>
2010-02-14 17:13:47 +03:00
# include <linux/string.h>
# include <linux/errno.h>
2010-02-02 07:34:14 +03:00
2009-12-11 09:42:21 +03:00
# ifdef CONFIG_PPC
# include <asm/machdep.h>
# endif /* CONFIG_PPC */
2010-02-14 17:13:47 +03:00
# include <asm/page.h>
2009-11-24 13:27:10 +03:00
int __initdata dt_root_addr_cells ;
int __initdata dt_root_size_cells ;
2009-11-24 00:53:09 +03:00
struct boot_param_header * initial_boot_params ;
char * find_flat_dt_string ( u32 offset )
{
return ( ( char * ) initial_boot_params ) +
2010-01-30 14:14:19 +03:00
be32_to_cpu ( initial_boot_params - > off_dt_strings ) + offset ;
2009-11-24 00:53:09 +03:00
}
2009-11-24 04:54:23 +03:00
/**
* of_scan_flat_dt - scan flattened tree blob and call callback on each .
* @ it : callback function
* @ data : context data pointer
*
* This function is used to scan the flattened device - tree , it is
* used to extract the memory information at boot before we can
* unflatten the tree
*/
int __init of_scan_flat_dt ( int ( * it ) ( unsigned long node ,
const char * uname , int depth ,
void * data ) ,
void * data )
{
unsigned long p = ( ( unsigned long ) initial_boot_params ) +
2010-01-30 14:14:19 +03:00
be32_to_cpu ( initial_boot_params - > off_dt_struct ) ;
2009-11-24 04:54:23 +03:00
int rc = 0 ;
int depth = - 1 ;
do {
2010-01-30 11:45:26 +03:00
u32 tag = be32_to_cpup ( ( __be32 * ) p ) ;
2009-11-24 04:54:23 +03:00
char * pathp ;
p + = 4 ;
if ( tag = = OF_DT_END_NODE ) {
depth - - ;
continue ;
}
if ( tag = = OF_DT_NOP )
continue ;
if ( tag = = OF_DT_END )
break ;
if ( tag = = OF_DT_PROP ) {
2010-01-30 11:45:26 +03:00
u32 sz = be32_to_cpup ( ( __be32 * ) p ) ;
2009-11-24 04:54:23 +03:00
p + = 8 ;
2010-01-30 14:14:19 +03:00
if ( be32_to_cpu ( initial_boot_params - > version ) < 0x10 )
2010-06-25 22:16:52 +04:00
p = ALIGN ( p , sz > = 8 ? 8 : 4 ) ;
2009-11-24 04:54:23 +03:00
p + = sz ;
2010-06-25 22:16:52 +04:00
p = ALIGN ( p , 4 ) ;
2009-11-24 04:54:23 +03:00
continue ;
}
if ( tag ! = OF_DT_BEGIN_NODE ) {
pr_err ( " Invalid tag %x in flat device tree! \n " , tag ) ;
return - EINVAL ;
}
depth + + ;
pathp = ( char * ) p ;
2010-06-25 22:16:52 +04:00
p = ALIGN ( p + strlen ( pathp ) + 1 , 4 ) ;
2009-11-24 04:54:23 +03:00
if ( ( * pathp ) = = ' / ' ) {
char * lp , * np ;
for ( lp = NULL , np = pathp ; * np ; np + + )
if ( ( * np ) = = ' / ' )
lp = np + 1 ;
if ( lp ! = NULL )
pathp = lp ;
}
rc = it ( p , pathp , depth , data ) ;
if ( rc ! = 0 )
break ;
} while ( 1 ) ;
return rc ;
}
2009-11-24 05:44:23 +03:00
/**
* of_get_flat_dt_root - find the root node in the flat blob
*/
unsigned long __init of_get_flat_dt_root ( void )
{
unsigned long p = ( ( unsigned long ) initial_boot_params ) +
2010-01-30 14:14:19 +03:00
be32_to_cpu ( initial_boot_params - > off_dt_struct ) ;
2009-11-24 05:44:23 +03:00
2010-01-30 11:45:26 +03:00
while ( be32_to_cpup ( ( __be32 * ) p ) = = OF_DT_NOP )
2009-11-24 05:44:23 +03:00
p + = 4 ;
2010-01-30 11:45:26 +03:00
BUG_ON ( be32_to_cpup ( ( __be32 * ) p ) ! = OF_DT_BEGIN_NODE ) ;
2009-11-24 05:44:23 +03:00
p + = 4 ;
2010-06-25 22:16:52 +04:00
return ALIGN ( p + strlen ( ( char * ) p ) + 1 , 4 ) ;
2009-11-24 05:44:23 +03:00
}
2009-11-24 06:06:59 +03:00
/**
* of_get_flat_dt_prop - Given a node in the flat blob , return the property ptr
*
* This function can be used within scan_flattened_dt callback to get
* access to properties
*/
void * __init of_get_flat_dt_prop ( unsigned long node , const char * name ,
unsigned long * size )
{
unsigned long p = node ;
do {
2010-01-30 11:45:26 +03:00
u32 tag = be32_to_cpup ( ( __be32 * ) p ) ;
2009-11-24 06:06:59 +03:00
u32 sz , noff ;
const char * nstr ;
p + = 4 ;
if ( tag = = OF_DT_NOP )
continue ;
if ( tag ! = OF_DT_PROP )
return NULL ;
2010-01-30 11:45:26 +03:00
sz = be32_to_cpup ( ( __be32 * ) p ) ;
noff = be32_to_cpup ( ( __be32 * ) ( p + 4 ) ) ;
2009-11-24 06:06:59 +03:00
p + = 8 ;
2010-01-30 14:14:19 +03:00
if ( be32_to_cpu ( initial_boot_params - > version ) < 0x10 )
2010-06-25 22:16:52 +04:00
p = ALIGN ( p , sz > = 8 ? 8 : 4 ) ;
2009-11-24 06:06:59 +03:00
nstr = find_flat_dt_string ( noff ) ;
if ( nstr = = NULL ) {
pr_warning ( " Can't find property index name ! \n " ) ;
return NULL ;
}
if ( strcmp ( name , nstr ) = = 0 ) {
if ( size )
* size = sz ;
return ( void * ) p ;
}
p + = sz ;
2010-06-25 22:16:52 +04:00
p = ALIGN ( p , 4 ) ;
2009-11-24 06:06:59 +03:00
} while ( 1 ) ;
}
2009-11-24 06:07:00 +03:00
/**
* of_flat_dt_is_compatible - Return true if given node has compat in compatible list
* @ node : node to test
* @ compat : compatible string to compare with compatible list .
*/
int __init of_flat_dt_is_compatible ( unsigned long node , const char * compat )
{
const char * cp ;
unsigned long cplen , l ;
cp = of_get_flat_dt_prop ( node , " compatible " , & cplen ) ;
if ( cp = = NULL )
return 0 ;
while ( cplen > 0 ) {
2010-07-23 22:42:44 +04:00
if ( of_compat_cmp ( cp , compat , strlen ( compat ) ) = = 0 )
2009-11-24 06:07:00 +03:00
return 1 ;
l = strlen ( cp ) + 1 ;
cp + = l ;
cplen - = l ;
}
return 0 ;
}
2009-11-24 06:07:00 +03:00
static void * __init unflatten_dt_alloc ( unsigned long * mem , unsigned long size ,
unsigned long align )
{
void * res ;
2010-06-25 22:16:52 +04:00
* mem = ALIGN ( * mem , align ) ;
2009-11-24 06:07:00 +03:00
res = ( void * ) * mem ;
* mem + = size ;
return res ;
}
/**
* unflatten_dt_node - Alloc and populate a device_node from the flat tree
* @ p : pointer to node in flat tree
* @ dad : Parent struct device_node
* @ allnextpp : pointer to - > allnext from last allocated device_node
* @ fpsize : Size of the node path up at the current depth .
*/
unsigned long __init unflatten_dt_node ( unsigned long mem ,
unsigned long * p ,
struct device_node * dad ,
struct device_node * * * allnextpp ,
unsigned long fpsize )
{
struct device_node * np ;
struct property * pp , * * prev_pp = NULL ;
char * pathp ;
u32 tag ;
unsigned int l , allocl ;
int has_name = 0 ;
int new_format = 0 ;
2010-01-30 11:45:26 +03:00
tag = be32_to_cpup ( ( __be32 * ) ( * p ) ) ;
2009-11-24 06:07:00 +03:00
if ( tag ! = OF_DT_BEGIN_NODE ) {
pr_err ( " Weird tag at start of node: %x \n " , tag ) ;
return mem ;
}
* p + = 4 ;
pathp = ( char * ) * p ;
l = allocl = strlen ( pathp ) + 1 ;
2010-06-25 22:16:52 +04:00
* p = ALIGN ( * p + l , 4 ) ;
2009-11-24 06:07:00 +03:00
/* version 0x10 has a more compact unit name here instead of the full
* path . we accumulate the full path size using " fpsize " , we ' ll rebuild
* it later . We detect this because the first character of the name is
* not ' / ' .
*/
if ( ( * pathp ) ! = ' / ' ) {
new_format = 1 ;
if ( fpsize = = 0 ) {
/* root node: special case. fpsize accounts for path
* plus terminating zero . root node only has ' / ' , so
* fpsize should be 2 , but we want to avoid the first
* level nodes to have two ' / ' so we use fpsize 1 here
*/
fpsize = 1 ;
allocl = 2 ;
} else {
/* account for '/' and path size minus terminal 0
* already in ' l '
*/
fpsize + = l ;
allocl = fpsize ;
}
}
np = unflatten_dt_alloc ( & mem , sizeof ( struct device_node ) + allocl ,
__alignof__ ( struct device_node ) ) ;
if ( allnextpp ) {
memset ( np , 0 , sizeof ( * np ) ) ;
np - > full_name = ( ( char * ) np ) + sizeof ( struct device_node ) ;
if ( new_format ) {
char * fn = np - > full_name ;
/* rebuild full path for new format */
if ( dad & & dad - > parent ) {
strcpy ( fn , dad - > full_name ) ;
# ifdef DEBUG
if ( ( strlen ( fn ) + l + 1 ) ! = allocl ) {
pr_debug ( " %s: p: %d, l: %d, a: %d \n " ,
pathp , ( int ) strlen ( fn ) ,
l , allocl ) ;
}
# endif
fn + = strlen ( fn ) ;
}
* ( fn + + ) = ' / ' ;
memcpy ( fn , pathp , l ) ;
} else
memcpy ( np - > full_name , pathp , l ) ;
prev_pp = & np - > properties ;
* * allnextpp = np ;
* allnextpp = & np - > allnext ;
if ( dad ! = NULL ) {
np - > parent = dad ;
/* we temporarily use the next field as `last_child'*/
if ( dad - > next = = NULL )
dad - > child = np ;
else
dad - > next - > sibling = np ;
dad - > next = np ;
}
kref_init ( & np - > kref ) ;
}
while ( 1 ) {
u32 sz , noff ;
char * pname ;
2010-01-30 11:45:26 +03:00
tag = be32_to_cpup ( ( __be32 * ) ( * p ) ) ;
2009-11-24 06:07:00 +03:00
if ( tag = = OF_DT_NOP ) {
* p + = 4 ;
continue ;
}
if ( tag ! = OF_DT_PROP )
break ;
* p + = 4 ;
2010-01-30 11:45:26 +03:00
sz = be32_to_cpup ( ( __be32 * ) ( * p ) ) ;
noff = be32_to_cpup ( ( __be32 * ) ( ( * p ) + 4 ) ) ;
2009-11-24 06:07:00 +03:00
* p + = 8 ;
2010-01-30 14:14:19 +03:00
if ( be32_to_cpu ( initial_boot_params - > version ) < 0x10 )
2010-06-25 22:16:52 +04:00
* p = ALIGN ( * p , sz > = 8 ? 8 : 4 ) ;
2009-11-24 06:07:00 +03:00
pname = find_flat_dt_string ( noff ) ;
if ( pname = = NULL ) {
pr_info ( " Can't find property name in list ! \n " ) ;
break ;
}
if ( strcmp ( pname , " name " ) = = 0 )
has_name = 1 ;
l = strlen ( pname ) + 1 ;
pp = unflatten_dt_alloc ( & mem , sizeof ( struct property ) ,
__alignof__ ( struct property ) ) ;
if ( allnextpp ) {
2010-02-02 07:34:15 +03:00
/* We accept flattened tree phandles either in
* ePAPR - style " phandle " properties , or the
* legacy " linux,phandle " properties . If both
* appear and have different values , things
* will get weird . Don ' t do that . */
if ( ( strcmp ( pname , " phandle " ) = = 0 ) | |
( strcmp ( pname , " linux,phandle " ) = = 0 ) ) {
2010-01-29 00:06:53 +03:00
if ( np - > phandle = = 0 )
2010-07-23 11:48:25 +04:00
np - > phandle = be32_to_cpup ( ( __be32 * ) * p ) ;
2009-11-24 06:07:00 +03:00
}
2010-02-02 07:34:15 +03:00
/* And we process the "ibm,phandle" property
* used in pSeries dynamic device tree
* stuff */
2009-11-24 06:07:00 +03:00
if ( strcmp ( pname , " ibm,phandle " ) = = 0 )
2010-07-23 11:48:25 +04:00
np - > phandle = be32_to_cpup ( ( __be32 * ) * p ) ;
2009-11-24 06:07:00 +03:00
pp - > name = pname ;
pp - > length = sz ;
pp - > value = ( void * ) * p ;
* prev_pp = pp ;
prev_pp = & pp - > next ;
}
2010-06-25 22:16:52 +04:00
* p = ALIGN ( ( * p ) + sz , 4 ) ;
2009-11-24 06:07:00 +03:00
}
/* with version 0x10 we may not have the name property, recreate
* it here from the unit name if absent
*/
if ( ! has_name ) {
char * p1 = pathp , * ps = pathp , * pa = NULL ;
int sz ;
while ( * p1 ) {
if ( ( * p1 ) = = ' @ ' )
pa = p1 ;
if ( ( * p1 ) = = ' / ' )
ps = p1 + 1 ;
p1 + + ;
}
if ( pa < ps )
pa = p1 ;
sz = ( pa - ps ) + 1 ;
pp = unflatten_dt_alloc ( & mem , sizeof ( struct property ) + sz ,
__alignof__ ( struct property ) ) ;
if ( allnextpp ) {
pp - > name = " name " ;
pp - > length = sz ;
pp - > value = pp + 1 ;
* prev_pp = pp ;
prev_pp = & pp - > next ;
memcpy ( pp - > value , ps , sz - 1 ) ;
( ( char * ) pp - > value ) [ sz - 1 ] = 0 ;
pr_debug ( " fixed up name for %s -> %s \n " , pathp ,
( char * ) pp - > value ) ;
}
}
if ( allnextpp ) {
* prev_pp = NULL ;
np - > name = of_get_property ( np , " name " , NULL ) ;
np - > type = of_get_property ( np , " device_type " , NULL ) ;
if ( ! np - > name )
np - > name = " <NULL> " ;
if ( ! np - > type )
np - > type = " <NULL> " ;
}
2010-03-27 07:09:56 +03:00
while ( tag = = OF_DT_BEGIN_NODE | | tag = = OF_DT_NOP ) {
if ( tag = = OF_DT_NOP )
* p + = 4 ;
else
mem = unflatten_dt_node ( mem , p , np , allnextpp , fpsize ) ;
2010-01-30 11:45:26 +03:00
tag = be32_to_cpup ( ( __be32 * ) ( * p ) ) ;
2009-11-24 06:07:00 +03:00
}
if ( tag ! = OF_DT_END_NODE ) {
pr_err ( " Weird tag at end of node: %x \n " , tag ) ;
return mem ;
}
* p + = 4 ;
return mem ;
}
2009-11-24 06:07:01 +03:00
2009-11-24 13:26:58 +03:00
# ifdef CONFIG_BLK_DEV_INITRD
/**
* early_init_dt_check_for_initrd - Decode initrd location from flat tree
* @ node : reference to node containing initrd location ( ' chosen ' )
*/
void __init early_init_dt_check_for_initrd ( unsigned long node )
{
2010-01-30 11:31:21 +03:00
unsigned long start , end , len ;
2010-01-30 11:45:26 +03:00
__be32 * prop ;
2009-11-24 13:26:58 +03:00
pr_debug ( " Looking for initrd properties... " ) ;
prop = of_get_flat_dt_prop ( node , " linux,initrd-start " , & len ) ;
2010-01-30 11:31:21 +03:00
if ( ! prop )
return ;
start = of_read_ulong ( prop , len / 4 ) ;
prop = of_get_flat_dt_prop ( node , " linux,initrd-end " , & len ) ;
if ( ! prop )
return ;
end = of_read_ulong ( prop , len / 4 ) ;
2009-11-24 13:26:58 +03:00
2010-01-30 11:31:21 +03:00
early_init_dt_setup_initrd_arch ( start , end ) ;
pr_debug ( " initrd_start=0x%lx initrd_end=0x%lx \n " , start , end ) ;
2009-11-24 13:26:58 +03:00
}
# else
inline void early_init_dt_check_for_initrd ( unsigned long node )
{
}
# endif /* CONFIG_BLK_DEV_INITRD */
2009-11-24 13:27:10 +03:00
/**
* early_init_dt_scan_root - fetch the top level address and size cells
*/
int __init early_init_dt_scan_root ( unsigned long node , const char * uname ,
int depth , void * data )
{
2010-01-30 11:45:26 +03:00
__be32 * prop ;
2009-11-24 13:27:10 +03:00
if ( depth ! = 0 )
return 0 ;
2010-01-30 11:45:26 +03:00
dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT ;
dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT ;
2009-11-24 13:27:10 +03:00
prop = of_get_flat_dt_prop ( node , " #size-cells " , NULL ) ;
2010-01-30 11:45:26 +03:00
if ( prop )
dt_root_size_cells = be32_to_cpup ( prop ) ;
2009-11-24 13:27:10 +03:00
pr_debug ( " dt_root_size_cells = %x \n " , dt_root_size_cells ) ;
prop = of_get_flat_dt_prop ( node , " #address-cells " , NULL ) ;
2010-01-30 11:45:26 +03:00
if ( prop )
dt_root_addr_cells = be32_to_cpup ( prop ) ;
2009-11-24 13:27:10 +03:00
pr_debug ( " dt_root_addr_cells = %x \n " , dt_root_addr_cells ) ;
/* break now */
return 1 ;
}
2010-01-30 11:41:49 +03:00
u64 __init dt_mem_next_cell ( int s , __be32 * * cellp )
2009-11-24 13:37:56 +03:00
{
2010-01-30 11:41:49 +03:00
__be32 * p = * cellp ;
2009-11-24 13:37:56 +03:00
* cellp = p + s ;
return of_read_number ( p , s ) ;
}
2010-02-02 07:34:14 +03:00
/**
* early_init_dt_scan_memory - Look for an parse memory nodes
*/
int __init early_init_dt_scan_memory ( unsigned long node , const char * uname ,
int depth , void * data )
{
char * type = of_get_flat_dt_prop ( node , " device_type " , NULL ) ;
__be32 * reg , * endp ;
unsigned long l ;
/* We are scanning "memory" nodes only */
if ( type = = NULL ) {
/*
* The longtrail doesn ' t have a device_type on the
* / memory node , so look for the node called / memory @ 0.
*/
if ( depth ! = 1 | | strcmp ( uname , " memory@0 " ) ! = 0 )
return 0 ;
} else if ( strcmp ( type , " memory " ) ! = 0 )
return 0 ;
reg = of_get_flat_dt_prop ( node , " linux,usable-memory " , & l ) ;
if ( reg = = NULL )
reg = of_get_flat_dt_prop ( node , " reg " , & l ) ;
if ( reg = = NULL )
return 0 ;
endp = reg + ( l / sizeof ( __be32 ) ) ;
pr_debug ( " memory scan node %s, reg size %ld, data: %x %x %x %x, \n " ,
uname , l , reg [ 0 ] , reg [ 1 ] , reg [ 2 ] , reg [ 3 ] ) ;
while ( ( endp - reg ) > = ( dt_root_addr_cells + dt_root_size_cells ) ) {
u64 base , size ;
base = dt_mem_next_cell ( dt_root_addr_cells , & reg ) ;
size = dt_mem_next_cell ( dt_root_size_cells , & reg ) ;
if ( size = = 0 )
continue ;
pr_debug ( " - %llx , %llx \n " , ( unsigned long long ) base ,
( unsigned long long ) size ) ;
early_init_dt_add_memory_arch ( base , size ) ;
}
return 0 ;
}
2009-12-11 09:42:21 +03:00
int __init early_init_dt_scan_chosen ( unsigned long node , const char * uname ,
int depth , void * data )
{
unsigned long l ;
char * p ;
pr_debug ( " search \" chosen \" , depth: %d, uname: %s \n " , depth , uname ) ;
if ( depth ! = 1 | |
( strcmp ( uname , " chosen " ) ! = 0 & & strcmp ( uname , " chosen@0 " ) ! = 0 ) )
return 0 ;
early_init_dt_check_for_initrd ( node ) ;
/* Retreive command line */
p = of_get_flat_dt_prop ( node , " bootargs " , & l ) ;
if ( p ! = NULL & & l > 0 )
strlcpy ( cmd_line , p , min ( ( int ) l , COMMAND_LINE_SIZE ) ) ;
# ifdef CONFIG_CMDLINE
# ifndef CONFIG_CMDLINE_FORCE
if ( p = = NULL | | l = = 0 | | ( l = = 1 & & ( * p ) = = 0 ) )
# endif
strlcpy ( cmd_line , CONFIG_CMDLINE , COMMAND_LINE_SIZE ) ;
# endif /* CONFIG_CMDLINE */
pr_debug ( " Command line is: %s \n " , cmd_line ) ;
/* break now */
return 1 ;
}
2009-11-24 06:07:01 +03:00
/**
* unflatten_device_tree - create tree of device_nodes from flat blob
*
* unflattens the device - tree passed by the firmware , creating the
* tree of struct device_node . It also fills the " name " and " type "
* pointers of the nodes so the normal device - tree walking functions
* can be used .
*/
void __init unflatten_device_tree ( void )
{
unsigned long start , mem , size ;
struct device_node * * allnextp = & allnodes ;
pr_debug ( " -> unflatten_device_tree() \n " ) ;
2010-04-14 03:12:26 +04:00
if ( ! initial_boot_params ) {
pr_debug ( " No device tree pointer \n " ) ;
return ;
}
pr_debug ( " Unflattening device tree: \n " ) ;
pr_debug ( " magic: %08x \n " , be32_to_cpu ( initial_boot_params - > magic ) ) ;
pr_debug ( " size: %08x \n " , be32_to_cpu ( initial_boot_params - > totalsize ) ) ;
pr_debug ( " version: %08x \n " , be32_to_cpu ( initial_boot_params - > version ) ) ;
if ( be32_to_cpu ( initial_boot_params - > magic ) ! = OF_DT_HEADER ) {
pr_err ( " Invalid device tree blob header \n " ) ;
return ;
}
2009-11-24 06:07:01 +03:00
/* First pass, scan for size */
start = ( ( unsigned long ) initial_boot_params ) +
2010-01-30 14:14:19 +03:00
be32_to_cpu ( initial_boot_params - > off_dt_struct ) ;
2009-11-24 06:07:01 +03:00
size = unflatten_dt_node ( 0 , & start , NULL , NULL , 0 ) ;
size = ( size | 3 ) + 1 ;
pr_debug ( " size is %lx, allocating... \n " , size ) ;
/* Allocate memory for the expanded device tree */
2010-02-14 17:13:47 +03:00
mem = early_init_dt_alloc_memory_arch ( size + 4 ,
__alignof__ ( struct device_node ) ) ;
2009-11-24 06:07:01 +03:00
mem = ( unsigned long ) __va ( mem ) ;
2010-01-30 11:45:26 +03:00
( ( __be32 * ) mem ) [ size / 4 ] = cpu_to_be32 ( 0xdeadbeef ) ;
2009-11-24 06:07:01 +03:00
pr_debug ( " unflattening %lx... \n " , mem ) ;
/* Second pass, do actual unflattening */
start = ( ( unsigned long ) initial_boot_params ) +
2010-01-30 14:14:19 +03:00
be32_to_cpu ( initial_boot_params - > off_dt_struct ) ;
2009-11-24 06:07:01 +03:00
unflatten_dt_node ( mem , & start , NULL , & allnextp , 0 ) ;
2010-01-30 11:45:26 +03:00
if ( be32_to_cpup ( ( __be32 * ) start ) ! = OF_DT_END )
2009-11-24 06:07:01 +03:00
pr_warning ( " Weird tag at end of tree: %08x \n " , * ( ( u32 * ) start ) ) ;
2010-01-30 11:45:26 +03:00
if ( be32_to_cpu ( ( ( __be32 * ) mem ) [ size / 4 ] ) ! = 0xdeadbeef )
2009-11-24 06:07:01 +03:00
pr_warning ( " End of tree marker overwritten: %08x \n " ,
2010-01-30 11:45:26 +03:00
be32_to_cpu ( ( ( __be32 * ) mem ) [ size / 4 ] ) ) ;
2009-11-24 06:07:01 +03:00
* allnextp = NULL ;
/* Get pointer to OF "/chosen" node for use everywhere */
of_chosen = of_find_node_by_path ( " /chosen " ) ;
if ( of_chosen = = NULL )
of_chosen = of_find_node_by_path ( " /chosen@0 " ) ;
pr_debug ( " <- unflatten_device_tree() \n " ) ;
}