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
This diff is collapsed.
...@@ -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