Commit 34153fa3 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[PATCH] flattened device tree changes

This patch updates the format of the flattened device-tree passed
between the boot trampoline and the kernel to support a more compact
representation, for use by embedded systems mostly.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent e28f7faf
...@@ -625,8 +625,8 @@ void __init finish_device_tree(void) ...@@ -625,8 +625,8 @@ void __init finish_device_tree(void)
static inline char *find_flat_dt_string(u32 offset) static inline char *find_flat_dt_string(u32 offset)
{ {
return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings return ((char *)initial_boot_params) +
+ offset; initial_boot_params->off_dt_strings + offset;
} }
/** /**
...@@ -635,25 +635,32 @@ static inline char *find_flat_dt_string(u32 offset) ...@@ -635,25 +635,32 @@ static inline char *find_flat_dt_string(u32 offset)
* unflatten the tree * unflatten the tree
*/ */
static int __init scan_flat_dt(int (*it)(unsigned long node, static int __init scan_flat_dt(int (*it)(unsigned long node,
const char *full_path, void *data), const char *uname, int depth,
void *data),
void *data) void *data)
{ {
unsigned long p = ((unsigned long)initial_boot_params) + unsigned long p = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct; initial_boot_params->off_dt_struct;
int rc = 0; int rc = 0;
int depth = -1;
do { do {
u32 tag = *((u32 *)p); u32 tag = *((u32 *)p);
char *pathp; char *pathp;
p += 4; p += 4;
if (tag == OF_DT_END_NODE) if (tag == OF_DT_END_NODE) {
depth --;
continue;
}
if (tag == OF_DT_NOP)
continue; continue;
if (tag == OF_DT_END) if (tag == OF_DT_END)
break; break;
if (tag == OF_DT_PROP) { if (tag == OF_DT_PROP) {
u32 sz = *((u32 *)p); u32 sz = *((u32 *)p);
p += 8; p += 8;
if (initial_boot_params->version < 0x10)
p = _ALIGN(p, sz >= 8 ? 8 : 4); p = _ALIGN(p, sz >= 8 ? 8 : 4);
p += sz; p += sz;
p = _ALIGN(p, 4); p = _ALIGN(p, 4);
...@@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node, ...@@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node,
" device tree !\n", tag); " device tree !\n", tag);
return -EINVAL; return -EINVAL;
} }
depth++;
pathp = (char *)p; pathp = (char *)p;
p = _ALIGN(p + strlen(pathp) + 1, 4); p = _ALIGN(p + strlen(pathp) + 1, 4);
rc = it(p, pathp, data); 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) if (rc != 0)
break; break;
} while(1); } while(1);
...@@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name, ...@@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
const char *nstr; const char *nstr;
p += 4; p += 4;
if (tag == OF_DT_NOP)
continue;
if (tag != OF_DT_PROP) if (tag != OF_DT_PROP)
return NULL; return NULL;
sz = *((u32 *)p); sz = *((u32 *)p);
noff = *((u32 *)(p + 4)); noff = *((u32 *)(p + 4));
p += 8; p += 8;
if (initial_boot_params->version < 0x10)
p = _ALIGN(p, sz >= 8 ? 8 : 4); p = _ALIGN(p, sz >= 8 ? 8 : 4);
nstr = find_flat_dt_string(noff); nstr = find_flat_dt_string(noff);
if (nstr == NULL) { if (nstr == NULL) {
printk(KERN_WARNING "Can't find property index name !\n"); printk(KERN_WARNING "Can't find property index"
" name !\n");
return NULL; return NULL;
} }
if (strcmp(name, nstr) == 0) { if (strcmp(name, nstr) == 0) {
...@@ -727,13 +747,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, ...@@ -727,13 +747,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
static unsigned long __init unflatten_dt_node(unsigned long mem, static unsigned long __init unflatten_dt_node(unsigned long mem,
unsigned long *p, unsigned long *p,
struct device_node *dad, struct device_node *dad,
struct device_node ***allnextpp) struct device_node ***allnextpp,
unsigned long fpsize)
{ {
struct device_node *np; struct device_node *np;
struct property *pp, **prev_pp = NULL; struct property *pp, **prev_pp = NULL;
char *pathp; char *pathp;
u32 tag; u32 tag;
unsigned int l; unsigned int l, allocl;
int has_name = 0;
int new_format = 0;
tag = *((u32 *)(*p)); tag = *((u32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) { if (tag != OF_DT_BEGIN_NODE) {
...@@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, ...@@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
} }
*p += 4; *p += 4;
pathp = (char *)*p; pathp = (char *)*p;
l = strlen(pathp) + 1; l = allocl = strlen(pathp) + 1;
*p = _ALIGN(*p + l, 4); *p = _ALIGN(*p + l, 4);
np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, /* 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)); __alignof__(struct device_node));
if (allnextpp) { if (allnextpp) {
memset(np, 0, sizeof(*np)); memset(np, 0, sizeof(*np));
np->full_name = ((char*)np) + sizeof(struct device_node); np->full_name = ((char*)np) + sizeof(struct device_node);
if (new_format) {
char *p = np->full_name;
/* rebuild full path for new format */
if (dad && dad->parent) {
strcpy(p, dad->full_name);
#ifdef DEBUG
if ((strlen(p) + l + 1) != allocl) {
DBG("%s: p: %d, l: %d, a: %d\n",
pathp, strlen(p), l, allocl);
}
#endif
p += strlen(p);
}
*(p++) = '/';
memcpy(p, pathp, l);
} else
memcpy(np->full_name, pathp, l); memcpy(np->full_name, pathp, l);
prev_pp = &np->properties; prev_pp = &np->properties;
**allnextpp = np; **allnextpp = np;
*allnextpp = &np->allnext; *allnextpp = &np->allnext;
if (dad != NULL) { if (dad != NULL) {
np->parent = dad; np->parent = dad;
/* we temporarily use the `next' field as `last_child'. */ /* we temporarily use the next field as `last_child'*/
if (dad->next == 0) if (dad->next == 0)
dad->child = np; dad->child = np;
else else
...@@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, ...@@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
char *pname; char *pname;
tag = *((u32 *)(*p)); tag = *((u32 *)(*p));
if (tag == OF_DT_NOP) {
*p += 4;
continue;
}
if (tag != OF_DT_PROP) if (tag != OF_DT_PROP)
break; break;
*p += 4; *p += 4;
sz = *((u32 *)(*p)); sz = *((u32 *)(*p));
noff = *((u32 *)((*p) + 4)); noff = *((u32 *)((*p) + 4));
*p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); *p += 8;
if (initial_boot_params->version < 0x10)
*p = _ALIGN(*p, sz >= 8 ? 8 : 4);
pname = find_flat_dt_string(noff); pname = find_flat_dt_string(noff);
if (pname == NULL) { if (pname == NULL) {
printk("Can't find property name in list !\n"); printk("Can't find property name in list !\n");
break; break;
} }
if (strcmp(pname, "name") == 0)
has_name = 1;
l = strlen(pname) + 1; l = strlen(pname) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property), pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property)); __alignof__(struct property));
...@@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, ...@@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
} }
*p = _ALIGN((*p) + sz, 4); *p = _ALIGN((*p) + sz, 4);
} }
/* with version 0x10 we may not have the name property, recreate
* it here from the unit name if absent
*/
if (!has_name) {
char *p = pathp, *ps = pathp, *pa = NULL;
int sz;
while (*p) {
if ((*p) == '@')
pa = p;
if ((*p) == '/')
ps = p + 1;
p++;
}
if (pa < ps)
pa = p;
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 = (unsigned char *)(pp + 1);
*prev_pp = pp;
prev_pp = &pp->next;
memcpy(pp->value, ps, sz - 1);
((char *)pp->value)[sz - 1] = 0;
DBG("fixed up name for %s -> %s\n", pathp, pp->value);
}
}
if (allnextpp) { if (allnextpp) {
*prev_pp = NULL; *prev_pp = NULL;
np->name = get_property(np, "name", NULL); np->name = get_property(np, "name", NULL);
...@@ -812,7 +914,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, ...@@ -812,7 +914,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
np->type = "<NULL>"; np->type = "<NULL>";
} }
while (tag == OF_DT_BEGIN_NODE) { while (tag == OF_DT_BEGIN_NODE) {
mem = unflatten_dt_node(mem, p, np, allnextpp); mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
tag = *((u32 *)(*p)); tag = *((u32 *)(*p));
} }
if (tag != OF_DT_END_NODE) { if (tag != OF_DT_END_NODE) {
...@@ -842,21 +944,27 @@ void __init unflatten_device_tree(void) ...@@ -842,21 +944,27 @@ void __init unflatten_device_tree(void)
/* First pass, scan for size */ /* First pass, scan for size */
start = ((unsigned long)initial_boot_params) + start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct; initial_boot_params->off_dt_struct;
size = unflatten_dt_node(0, &start, NULL, NULL); size = unflatten_dt_node(0, &start, NULL, NULL, 0);
size = (size | 3) + 1;
DBG(" size is %lx, allocating...\n", size); DBG(" size is %lx, allocating...\n", size);
/* Allocate memory for the expanded device tree */ /* Allocate memory for the expanded device tree */
mem = (unsigned long)abs_to_virt(lmb_alloc(size, mem = (unsigned long)abs_to_virt(lmb_alloc(size + 4,
__alignof__(struct device_node))); __alignof__(struct device_node)));
((u32 *)mem)[size / 4] = 0xdeadbeef;
DBG(" unflattening...\n", mem); DBG(" unflattening...\n", mem);
/* Second pass, do actual unflattening */ /* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) + start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct; initial_boot_params->off_dt_struct;
unflatten_dt_node(mem, &start, NULL, &allnextp); unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
if (*((u32 *)start) != OF_DT_END) if (*((u32 *)start) != OF_DT_END)
printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
if (((u32 *)mem)[size / 4] != 0xdeadbeef)
printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
((u32 *)mem)[size / 4] );
*allnextp = NULL; *allnextp = NULL;
/* Get pointer to OF "/chosen" node for use everywhere */ /* Get pointer to OF "/chosen" node for use everywhere */
...@@ -880,7 +988,7 @@ void __init unflatten_device_tree(void) ...@@ -880,7 +988,7 @@ void __init unflatten_device_tree(void)
static int __init early_init_dt_scan_cpus(unsigned long node, static int __init early_init_dt_scan_cpus(unsigned long node,
const char *full_path, void *data) const char *uname, int depth, void *data)
{ {
char *type = get_flat_dt_prop(node, "device_type", NULL); char *type = get_flat_dt_prop(node, "device_type", NULL);
u32 *prop; u32 *prop;
...@@ -947,13 +1055,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node, ...@@ -947,13 +1055,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
} }
static int __init early_init_dt_scan_chosen(unsigned long node, static int __init early_init_dt_scan_chosen(unsigned long node,
const char *full_path, void *data) const char *uname, int depth, void *data)
{ {
u32 *prop; u32 *prop;
u64 *prop64; u64 *prop64;
extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
if (strcmp(full_path, "/chosen") != 0) DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
if (depth != 1 || strcmp(uname, "chosen") != 0)
return 0; return 0;
/* get platform type */ /* get platform type */
...@@ -1003,18 +1113,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node, ...@@ -1003,18 +1113,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
} }
static int __init early_init_dt_scan_root(unsigned long node, static int __init early_init_dt_scan_root(unsigned long node,
const char *full_path, void *data) const char *uname, int depth, void *data)
{ {
u32 *prop; u32 *prop;
if (strcmp(full_path, "/") != 0) if (depth != 0)
return 0; return 0;
prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
dt_root_size_cells = (prop == NULL) ? 1 : *prop; dt_root_size_cells = (prop == NULL) ? 1 : *prop;
DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
dt_root_addr_cells = (prop == NULL) ? 2 : *prop; dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
/* break now */ /* break now */
return 1; return 1;
...@@ -1042,7 +1154,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) ...@@ -1042,7 +1154,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
static int __init early_init_dt_scan_memory(unsigned long node, static int __init early_init_dt_scan_memory(unsigned long node,
const char *full_path, void *data) const char *uname, int depth, void *data)
{ {
char *type = get_flat_dt_prop(node, "device_type", NULL); char *type = get_flat_dt_prop(node, "device_type", NULL);
cell_t *reg, *endp; cell_t *reg, *endp;
...@@ -1058,7 +1170,9 @@ static int __init early_init_dt_scan_memory(unsigned long node, ...@@ -1058,7 +1170,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
endp = reg + (l / sizeof(cell_t)); endp = reg + (l / sizeof(cell_t));
DBG("memory scan node %s ...\n", full_path); DBG("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)) { while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
unsigned long base, size; unsigned long base, size;
...@@ -1469,10 +1583,11 @@ struct device_node *of_find_node_by_path(const char *path) ...@@ -1469,10 +1583,11 @@ struct device_node *of_find_node_by_path(const char *path)
struct device_node *np = allnodes; struct device_node *np = allnodes;
read_lock(&devtree_lock); read_lock(&devtree_lock);
for (; np != 0; np = np->allnext) for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
&& of_node_get(np)) && of_node_get(np))
break; break;
}
read_unlock(&devtree_lock); read_unlock(&devtree_lock);
return np; return np;
} }
......
...@@ -1534,7 +1534,8 @@ static unsigned long __init dt_find_string(char *str) ...@@ -1534,7 +1534,8 @@ static unsigned long __init dt_find_string(char *str)
*/ */
#define MAX_PROPERTY_NAME 64 #define MAX_PROPERTY_NAME 64
static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, static void __init scan_dt_build_strings(phandle node,
unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
...@@ -1547,16 +1548,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, ...@@ -1547,16 +1548,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* get and store all property names */ /* get and store all property names */
prev_name = RELOC(""); prev_name = RELOC("");
for (;;) { for (;;) {
int rc;
/* 64 is max len of name including nul. */ /* 64 is max len of name including nul. */
namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
rc = call_prom("nextprop", 3, 1, node, prev_name, namep); if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
if (rc != 1) {
/* No more nodes: unwind alloc */ /* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep; *mem_start = (unsigned long)namep;
break; break;
} }
/* skip "name" */
if (strcmp(namep, RELOC("name")) == 0) {
*mem_start = (unsigned long)namep;
prev_name = RELOC("name");
continue;
}
/* get/create string entry */
soff = dt_find_string(namep); soff = dt_find_string(namep);
if (soff != 0) { if (soff != 0) {
*mem_start = (unsigned long)namep; *mem_start = (unsigned long)namep;
...@@ -1571,7 +1577,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, ...@@ -1571,7 +1577,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* do all our children */ /* do all our children */
child = call_prom("child", 1, 1, node); child = call_prom("child", 1, 1, node);
while (child != (phandle)0) { while (child != 0) {
scan_dt_build_strings(child, mem_start, mem_end); scan_dt_build_strings(child, mem_start, mem_end);
child = call_prom("peer", 1, 1, child); child = call_prom("peer", 1, 1, child);
} }
...@@ -1580,16 +1586,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, ...@@ -1580,16 +1586,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
int l, align;
phandle child; phandle child;
char *namep, *prev_name, *sstart, *p, *ep; char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
unsigned long soff; unsigned long soff;
unsigned char *valp; unsigned char *valp;
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
char pname[MAX_PROPERTY_NAME]; static char pname[MAX_PROPERTY_NAME];
char *path; int l;
path = RELOC(prom_scratch);
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
...@@ -1599,23 +1602,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1599,23 +1602,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
namep, *mem_end - *mem_start); namep, *mem_end - *mem_start);
if (l >= 0) { if (l >= 0) {
/* Didn't fit? Get more room. */ /* Didn't fit? Get more room. */
if (l+1 > *mem_end - *mem_start) { if ((l+1) > (*mem_end - *mem_start)) {
namep = make_room(mem_start, mem_end, l+1, 1); namep = make_room(mem_start, mem_end, l+1, 1);
call_prom("package-to-path", 3, 1, node, namep, l); call_prom("package-to-path", 3, 1, node, namep, l);
} }
namep[l] = '\0'; namep[l] = '\0';
/* Fixup an Apple bug where they have bogus \0 chars in the /* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties * middle of the path in some properties
*/ */
for (p = namep, ep = namep + l; p < ep; p++) for (p = namep, ep = namep + l; p < ep; p++)
if (*p == '\0') { if (*p == '\0') {
memmove(p, p+1, ep - p); memmove(p, p+1, ep - p);
ep--; l--; ep--; l--; p--;
} }
*mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
/* now try to extract the unit name in that mess */
for (p = namep, lp = NULL; *p; p++)
if (*p == '/')
lp = p + 1;
if (lp != NULL)
memmove(namep, lp, strlen(lp) + 1);
*mem_start = _ALIGN(((unsigned long) namep) +
strlen(namep) + 1, 4);
} }
/* get it again for debugging */ /* get it again for debugging */
path = RELOC(prom_scratch);
memset(path, 0, PROM_SCRATCH_SIZE); memset(path, 0, PROM_SCRATCH_SIZE);
call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
...@@ -1623,23 +1636,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1623,23 +1636,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prev_name = RELOC(""); prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start); sstart = (char *)RELOC(dt_string_start);
for (;;) { for (;;) {
int rc; if (call_prom("nextprop", 3, 1, node, prev_name,
RELOC(pname)) != 1)
rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
if (rc != 1)
break; break;
/* skip "name" */
if (strcmp(RELOC(pname), RELOC("name")) == 0) {
prev_name = RELOC("name");
continue;
}
/* find string offset */ /* find string offset */
soff = dt_find_string(pname); soff = dt_find_string(RELOC(pname));
if (soff == 0) { if (soff == 0) {
prom_printf("WARNING: Can't find string index for <%s>, node %s\n", prom_printf("WARNING: Can't find string index for"
pname, path); " <%s>, node %s\n", RELOC(pname), path);
break; break;
} }
prev_name = sstart + soff; prev_name = sstart + soff;
/* get length */ /* get length */
l = call_prom("getproplen", 2, 1, node, pname); l = call_prom("getproplen", 2, 1, node, RELOC(pname));
/* sanity checks */ /* sanity checks */
if (l == PROM_ERROR) if (l == PROM_ERROR)
...@@ -1648,7 +1665,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1648,7 +1665,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prom_printf("WARNING: ignoring large property "); prom_printf("WARNING: ignoring large property ");
/* It seems OF doesn't null-terminate the path :-( */ /* It seems OF doesn't null-terminate the path :-( */
prom_printf("[%s] ", path); prom_printf("[%s] ", path);
prom_printf("%s length 0x%x\n", pname, l); prom_printf("%s length 0x%x\n", RELOC(pname), l);
continue; continue;
} }
...@@ -1658,17 +1675,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1658,17 +1675,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
dt_push_token(soff, mem_start, mem_end); dt_push_token(soff, mem_start, mem_end);
/* push property content */ /* push property content */
align = (l >= 8) ? 8 : 4; valp = make_room(mem_start, mem_end, l, 4);
valp = make_room(mem_start, mem_end, l, align); call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
call_prom("getprop", 4, 1, node, pname, valp, l);
*mem_start = _ALIGN(*mem_start, 4); *mem_start = _ALIGN(*mem_start, 4);
} }
/* Add a "linux,phandle" property. */ /* Add a "linux,phandle" property. */
soff = dt_find_string(RELOC("linux,phandle")); soff = dt_find_string(RELOC("linux,phandle"));
if (soff == 0) if (soff == 0)
prom_printf("WARNING: Can't find string index for <linux-phandle>" prom_printf("WARNING: Can't find string index for"
" node %s\n", path); " <linux-phandle> node %s\n", path);
else { else {
dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(OF_DT_PROP, mem_start, mem_end);
dt_push_token(4, mem_start, mem_end); dt_push_token(4, mem_start, mem_end);
...@@ -1679,7 +1695,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1679,7 +1695,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
/* do all our children */ /* do all our children */
child = call_prom("child", 1, 1, node); child = call_prom("child", 1, 1, node);
while (child != (phandle)0) { while (child != 0) {
scan_dt_build_struct(child, mem_start, mem_end); scan_dt_build_struct(child, mem_start, mem_end);
child = call_prom("peer", 1, 1, child); child = call_prom("peer", 1, 1, child);
} }
...@@ -1718,7 +1734,8 @@ static void __init flatten_device_tree(void) ...@@ -1718,7 +1734,8 @@ static void __init flatten_device_tree(void)
/* Build header and make room for mem rsv map */ /* Build header and make room for mem rsv map */
mem_start = _ALIGN(mem_start, 4); mem_start = _ALIGN(mem_start, 4);
hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); hdr = make_room(&mem_start, &mem_end,
sizeof(struct boot_param_header), 4);
RELOC(dt_header_start) = (unsigned long)hdr; RELOC(dt_header_start) = (unsigned long)hdr;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
...@@ -1731,11 +1748,11 @@ static void __init flatten_device_tree(void) ...@@ -1731,11 +1748,11 @@ static void __init flatten_device_tree(void)
namep = make_room(&mem_start, &mem_end, 16, 1); namep = make_room(&mem_start, &mem_end, 16, 1);
strcpy(namep, RELOC("linux,phandle")); strcpy(namep, RELOC("linux,phandle"));
mem_start = (unsigned long)namep + strlen(namep) + 1; mem_start = (unsigned long)namep + strlen(namep) + 1;
RELOC(dt_string_end) = mem_start;
/* Build string array */ /* Build string array */
prom_printf("Building dt strings...\n"); prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end); scan_dt_build_strings(root, &mem_start, &mem_end);
RELOC(dt_string_end) = mem_start;
/* Build structure */ /* Build structure */
mem_start = PAGE_ALIGN(mem_start); mem_start = PAGE_ALIGN(mem_start);
...@@ -1750,9 +1767,11 @@ static void __init flatten_device_tree(void) ...@@ -1750,9 +1767,11 @@ static void __init flatten_device_tree(void)
hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
hdr->version = OF_DT_VERSION; hdr->version = OF_DT_VERSION;
hdr->last_comp_version = 1; /* Version 16 is not backward compatible */
hdr->last_comp_version = 0x10;
/* Reserve the whole thing and copy the reserve map in, we /* Reserve the whole thing and copy the reserve map in, we
* also bump mem_reserve_cnt to cause further reservations to * also bump mem_reserve_cnt to cause further reservations to
...@@ -1808,6 +1827,9 @@ static void __init fixup_device_tree(void) ...@@ -1808,6 +1827,9 @@ static void __init fixup_device_tree(void)
/* does it need fixup ? */ /* does it need fixup ? */
if (prom_getproplen(i2c, "interrupts") > 0) if (prom_getproplen(i2c, "interrupts") > 0)
return; return;
prom_printf("fixing up bogus interrupts for u3 i2c...\n");
/* interrupt on this revision of u3 is number 0 and level */ /* interrupt on this revision of u3 is number 0 and level */
interrupts[0] = 0; interrupts[0] = 0;
interrupts[1] = 1; interrupts[1] = 1;
......
...@@ -22,13 +22,15 @@ ...@@ -22,13 +22,15 @@
#define RELOC(x) (*PTRRELOC(&(x))) #define RELOC(x) (*PTRRELOC(&(x)))
/* Definitions used by the flattened device tree */ /* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ #define OF_DT_HEADER 0xd00dfeed /* marker */
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ #define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off, size, content */ #define OF_DT_PROP 0x3 /* Property: name off, size,
* content */
#define OF_DT_NOP 0x4 /* nop */
#define OF_DT_END 0x9 #define OF_DT_END 0x9
#define OF_DT_VERSION 1 #define OF_DT_VERSION 0x10
/* /*
* This is what gets passed to the kernel by prom_init or kexec * This is what gets passed to the kernel by prom_init or kexec
...@@ -54,7 +56,9 @@ struct boot_param_header ...@@ -54,7 +56,9 @@ struct boot_param_header
u32 version; /* format version */ u32 version; /* format version */
u32 last_comp_version; /* last compatible version */ u32 last_comp_version; /* last compatible version */
/* version 2 fields below */ /* version 2 fields below */
u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
/* version 3 fields below */
u32 dt_strings_size; /* size of the DT strings block */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment