From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: linuxppc64-dev@ozlabs.org
Cc: linuxppc-dev list <linuxppc-dev@ozlabs.org>,
Tzachi Perelstein <tzachi@marvell.com>,
u-boot-users@lists.sourceforge.net
Subject: Re: Booting the Linux/ppc64 kernel without Open Firmware HOWTO (v3)
Date: Tue, 24 May 2005 14:35:51 +1000 [thread overview]
Message-ID: <1116909351.4992.19.camel@gaston> (raw)
In-Reply-To: <1116909286.4992.17.camel@gaston>
On Tue, 2005-05-24 at 14:34 +1000, Benjamin Herrenschmidt wrote:
> Hi !
>
> Here's revision 3 of the spec for the booting of linux/ppc64 with a
> flattened device-tree. The novelty is that I added a new more compact
> format. A followup mail will have the kernel patches to add support to
> this new format, I'll submit them upstream for after 2.6.12 I think.
>
> David and I are still working on sample code & tools. We have a
> prototype of a device-tree "compiler" that can build the flattened blob
> from a textual representation. We'll release that soon, hopefully this
> week.
And here is the patch:
Index: linux-work/arch/ppc64/kernel/prom_init.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom_init.c 2005-05-24 14:10:00.000000000 +1000
@@ -1514,7 +1514,14 @@
return 0;
}
-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+/*
+ * The Open Firmware 1275 specification states properties must be 31 bytes or
+ * less, however not all firmwares obey this. Make it 64 bytes to be safe.
+ */
+#define MAX_PROPERTY_NAME 64
+
+static void __init scan_dt_build_strings(phandle node,
+ unsigned long *mem_start,
unsigned long *mem_end)
{
unsigned long offset = reloc_offset();
@@ -1527,14 +1534,19 @@
/* get and store all property names */
prev_name = RELOC("");
for (;;) {
-
- /* 32 is max len of name including nul. */
- namep = make_room(mem_start, mem_end, 32, 1);
+ namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) {
/* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep;
break;
}
+
+ /* skip "name" */
+ if (strcmp(namep, RELOC("name")) == 0) {
+ *mem_start = (unsigned long)namep;
+ prev_name = RELOC("name");
+ continue;
+ }
soff = dt_find_string(namep);
if (soff != 0) {
*mem_start = (unsigned long)namep;
@@ -1555,12 +1567,6 @@
}
}
-/*
- * The Open Firmware 1275 specification states properties must be 31 bytes or
- * less, however not all firmwares obey this. Make it 64 bytes to be safe.
- */
-#define MAX_PROPERTY_NAME 64
-
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end)
{
@@ -1570,10 +1576,8 @@
unsigned long soff;
unsigned char *valp;
unsigned long offset = reloc_offset();
- char pname[MAX_PROPERTY_NAME];
- char *path;
-
- path = RELOC(prom_scratch);
+ static char pname[MAX_PROPERTY_NAME] __initdata;
+ char *path, *p, *lp;
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
@@ -1588,10 +1592,20 @@
call_prom("package-to-path", 3, 1, node, namep, l);
}
namep[l] = '\0';
- *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+ /* now try to find the unit name in that mess */
+ p = namep;
+ lp = NULL;
+ for (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 */
+ path = RELOC(prom_scratch);
memset(path, 0, PROM_SCRATCH_SIZE);
call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
@@ -1599,20 +1613,24 @@
prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start);
for (;;) {
- if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0)
+ if (call_prom("nextprop", 3, 1, node, prev_name,
+ RELOC(pname)) <= 0)
break;
-
+ if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+ prev_name = RELOC("name");
+ continue;
+ }
/* find string offset */
- soff = dt_find_string(pname);
+ soff = dt_find_string(RELOC(pname));
if (soff == 0) {
- prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
- pname, path);
+ prom_printf("WARNING: Can't find string index "
+ "for <%s>, node %s\n", RELOC(pname), path);
break;
}
prev_name = sstart + soff;
/* get length */
- l = call_prom("getproplen", 2, 1, node, pname);
+ l = call_prom("getproplen", 2, 1, node, RELOC(pname));
/* sanity checks */
if (l < 0)
@@ -1621,7 +1639,7 @@
prom_printf("WARNING: ignoring large property ");
/* It seems OF doesn't null-terminate the 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;
}
@@ -1633,15 +1651,15 @@
/* push property content */
align = (l >= 8) ? 8 : 4;
valp = make_room(mem_start, mem_end, l, align);
- call_prom("getprop", 4, 1, node, pname, valp, l);
+ call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
*mem_start = _ALIGN(*mem_start, 4);
}
/* Add a "linux,phandle" property. */
soff = dt_find_string(RELOC("linux,phandle"));
if (soff == 0)
- prom_printf("WARNING: Can't find string index for <linux-phandle>"
- " node %s\n", path);
+ prom_printf("WARNING: Can't find string index for"
+ " <linux-phandle> node %s\n", path);
else {
dt_push_token(OF_DT_PROP, mem_start, mem_end);
dt_push_token(4, mem_start, mem_end);
@@ -1691,7 +1709,8 @@
/* Build header and make room for mem rsv map */
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;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
@@ -1704,11 +1723,11 @@
namep = make_room(&mem_start, &mem_end, 16, 1);
strcpy(namep, RELOC("linux,phandle"));
mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = mem_start;
/* Build string array */
prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end);
+ RELOC(dt_string_end) = mem_start;
/* Build structure */
mem_start = PAGE_ALIGN(mem_start);
@@ -1723,9 +1742,11 @@
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_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->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
* also bump mem_reserve_cnt to cause further reservations to
Index: linux-work/arch/ppc64/kernel/setup.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/setup.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/setup.c 2005-05-23 18:16:09.000000000 +1000
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <linux/config.h>
#include <linux/module.h>
Index: linux-work/arch/ppc64/kernel/prom.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom.c 2005-05-24 14:12:35.000000000 +1000
@@ -15,7 +15,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <stdarg.h>
#include <linux/config.h>
@@ -635,20 +635,23 @@
* unflatten the tree
*/
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)
{
unsigned long p = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
int rc = 0;
+ int depth = -1;
do {
u32 tag = *((u32 *)p);
char *pathp;
p += 4;
- if (tag == OF_DT_END_NODE)
+ if (tag == OF_DT_END_NODE) {
+ depth --;
continue;
+ }
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
@@ -664,9 +667,18 @@
" device tree !\n", tag);
return -EINVAL;
}
+ depth++;
pathp = (char *)p;
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)
break;
} while(1);
@@ -727,13 +739,16 @@
static unsigned long __init unflatten_dt_node(unsigned long mem,
unsigned long *p,
struct device_node *dad,
- struct device_node ***allnextpp)
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
- unsigned int l;
+ unsigned int l, allocl;
+ int has_name = 0;
+ int new_format = 0;
tag = *((u32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +757,56 @@
}
*p += 4;
pathp = (char *)*p;
- l = strlen(pathp) + 1;
+ l = allocl = strlen(pathp) + 1;
*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));
if (allnextpp) {
memset(np, 0, sizeof(*np));
np->full_name = ((char*)np) + sizeof(struct device_node);
- memcpy(np->full_name, pathp, l);
+ if (new_format) {
+ char *p = np->full_name;
+ /* rebuild full path for new format */
+ if (dad && dad->parent) {
+ strcpy(p, dad->full_name);
+ p += strlen(p);
+ }
+ *(p++) = '/';
+ memcpy(p, 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'. */
+ /* we temporarily use the next field as `last_child'*/
if (dad->next == 0)
dad->child = np;
else
@@ -782,6 +832,8 @@
printk("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));
@@ -801,6 +853,29 @@
}
*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;
+ int sz;
+
+ DBG("no name, building from %s\n", p);
+ while (*p && (*p) != '@')
+ p++;
+ sz = (p - pathp) + 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, pathp, sz - 1);
+ ((char *)pp->value)[sz - 1] = 0;
+ }
+ }
if (allnextpp) {
*prev_pp = NULL;
np->name = get_property(np, "name", NULL);
@@ -812,7 +887,7 @@
np->type = "<NULL>";
}
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));
}
if (tag != OF_DT_END_NODE) {
@@ -842,7 +917,7 @@
/* First pass, scan for size */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- size = unflatten_dt_node(0, &start, NULL, NULL);
+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);
DBG(" size is %lx, allocating...\n", size);
@@ -854,7 +929,7 @@
/* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) +
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)
printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
*allnextp = NULL;
@@ -880,7 +955,7 @@
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);
u32 *prop;
@@ -933,13 +1008,15 @@
}
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;
u64 *prop64;
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;
/* get platform type */
@@ -989,18 +1066,20 @@
}
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;
- if (strcmp(full_path, "/") != 0)
+ if (depth != 0)
return 0;
prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
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);
dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+ DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
/* break now */
return 1;
@@ -1028,7 +1107,7 @@
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);
cell_t *reg, *endp;
@@ -1044,7 +1123,9 @@
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)) {
unsigned long base, size;
@@ -1455,10 +1536,11 @@
struct device_node *np = allnodes;
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
&& of_node_get(np))
break;
+ }
read_unlock(&devtree_lock);
return np;
}
Index: linux-work/include/asm-ppc64/prom.h
===================================================================
--- linux-work.orig/include/asm-ppc64/prom.h 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/include/asm-ppc64/prom.h 2005-05-23 18:16:09.000000000 +1000
@@ -22,13 +22,14 @@
#define RELOC(x) (*PTRRELOC(&(x)))
/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
-#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#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_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
@@ -54,7 +55,9 @@
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
/* 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 */
};
@@ -169,17 +172,20 @@
*/
#define HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+static inline void set_node_proc_entry(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->pde = de;
}
-static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de)
+static void inline set_node_name_link(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->name_link = de;
}
-static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de)
+static void inline set_node_addr_link(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->addr_link = de;
}
WARNING: multiple messages have this Message-ID (diff)
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] Re: Booting the Linux/ppc64 kernel without Open Firmware HOWTO (v3)
Date: Tue, 24 May 2005 14:35:51 +1000 [thread overview]
Message-ID: <1116909351.4992.19.camel@gaston> (raw)
In-Reply-To: <1116909286.4992.17.camel@gaston>
On Tue, 2005-05-24 at 14:34 +1000, Benjamin Herrenschmidt wrote:
> Hi !
>
> Here's revision 3 of the spec for the booting of linux/ppc64 with a
> flattened device-tree. The novelty is that I added a new more compact
> format. A followup mail will have the kernel patches to add support to
> this new format, I'll submit them upstream for after 2.6.12 I think.
>
> David and I are still working on sample code & tools. We have a
> prototype of a device-tree "compiler" that can build the flattened blob
> from a textual representation. We'll release that soon, hopefully this
> week.
And here is the patch:
Index: linux-work/arch/ppc64/kernel/prom_init.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom_init.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom_init.c 2005-05-24 14:10:00.000000000 +1000
@@ -1514,7 +1514,14 @@
return 0;
}
-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+/*
+ * The Open Firmware 1275 specification states properties must be 31 bytes or
+ * less, however not all firmwares obey this. Make it 64 bytes to be safe.
+ */
+#define MAX_PROPERTY_NAME 64
+
+static void __init scan_dt_build_strings(phandle node,
+ unsigned long *mem_start,
unsigned long *mem_end)
{
unsigned long offset = reloc_offset();
@@ -1527,14 +1534,19 @@
/* get and store all property names */
prev_name = RELOC("");
for (;;) {
-
- /* 32 is max len of name including nul. */
- namep = make_room(mem_start, mem_end, 32, 1);
+ namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) {
/* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep;
break;
}
+
+ /* skip "name" */
+ if (strcmp(namep, RELOC("name")) == 0) {
+ *mem_start = (unsigned long)namep;
+ prev_name = RELOC("name");
+ continue;
+ }
soff = dt_find_string(namep);
if (soff != 0) {
*mem_start = (unsigned long)namep;
@@ -1555,12 +1567,6 @@
}
}
-/*
- * The Open Firmware 1275 specification states properties must be 31 bytes or
- * less, however not all firmwares obey this. Make it 64 bytes to be safe.
- */
-#define MAX_PROPERTY_NAME 64
-
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end)
{
@@ -1570,10 +1576,8 @@
unsigned long soff;
unsigned char *valp;
unsigned long offset = reloc_offset();
- char pname[MAX_PROPERTY_NAME];
- char *path;
-
- path = RELOC(prom_scratch);
+ static char pname[MAX_PROPERTY_NAME] __initdata;
+ char *path, *p, *lp;
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
@@ -1588,10 +1592,20 @@
call_prom("package-to-path", 3, 1, node, namep, l);
}
namep[l] = '\0';
- *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+ /* now try to find the unit name in that mess */
+ p = namep;
+ lp = NULL;
+ for (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 */
+ path = RELOC(prom_scratch);
memset(path, 0, PROM_SCRATCH_SIZE);
call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
@@ -1599,20 +1613,24 @@
prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start);
for (;;) {
- if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0)
+ if (call_prom("nextprop", 3, 1, node, prev_name,
+ RELOC(pname)) <= 0)
break;
-
+ if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+ prev_name = RELOC("name");
+ continue;
+ }
/* find string offset */
- soff = dt_find_string(pname);
+ soff = dt_find_string(RELOC(pname));
if (soff == 0) {
- prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
- pname, path);
+ prom_printf("WARNING: Can't find string index "
+ "for <%s>, node %s\n", RELOC(pname), path);
break;
}
prev_name = sstart + soff;
/* get length */
- l = call_prom("getproplen", 2, 1, node, pname);
+ l = call_prom("getproplen", 2, 1, node, RELOC(pname));
/* sanity checks */
if (l < 0)
@@ -1621,7 +1639,7 @@
prom_printf("WARNING: ignoring large property ");
/* It seems OF doesn't null-terminate the 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;
}
@@ -1633,15 +1651,15 @@
/* push property content */
align = (l >= 8) ? 8 : 4;
valp = make_room(mem_start, mem_end, l, align);
- call_prom("getprop", 4, 1, node, pname, valp, l);
+ call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
*mem_start = _ALIGN(*mem_start, 4);
}
/* Add a "linux,phandle" property. */
soff = dt_find_string(RELOC("linux,phandle"));
if (soff == 0)
- prom_printf("WARNING: Can't find string index for <linux-phandle>"
- " node %s\n", path);
+ prom_printf("WARNING: Can't find string index for"
+ " <linux-phandle> node %s\n", path);
else {
dt_push_token(OF_DT_PROP, mem_start, mem_end);
dt_push_token(4, mem_start, mem_end);
@@ -1691,7 +1709,8 @@
/* Build header and make room for mem rsv map */
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;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
@@ -1704,11 +1723,11 @@
namep = make_room(&mem_start, &mem_end, 16, 1);
strcpy(namep, RELOC("linux,phandle"));
mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = mem_start;
/* Build string array */
prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end);
+ RELOC(dt_string_end) = mem_start;
/* Build structure */
mem_start = PAGE_ALIGN(mem_start);
@@ -1723,9 +1742,11 @@
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_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->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
* also bump mem_reserve_cnt to cause further reservations to
Index: linux-work/arch/ppc64/kernel/setup.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/setup.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/setup.c 2005-05-23 18:16:09.000000000 +1000
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <linux/config.h>
#include <linux/module.h>
Index: linux-work/arch/ppc64/kernel/prom.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/prom.c 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/arch/ppc64/kernel/prom.c 2005-05-24 14:12:35.000000000 +1000
@@ -15,7 +15,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <stdarg.h>
#include <linux/config.h>
@@ -635,20 +635,23 @@
* unflatten the tree
*/
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)
{
unsigned long p = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
int rc = 0;
+ int depth = -1;
do {
u32 tag = *((u32 *)p);
char *pathp;
p += 4;
- if (tag == OF_DT_END_NODE)
+ if (tag == OF_DT_END_NODE) {
+ depth --;
continue;
+ }
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
@@ -664,9 +667,18 @@
" device tree !\n", tag);
return -EINVAL;
}
+ depth++;
pathp = (char *)p;
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)
break;
} while(1);
@@ -727,13 +739,16 @@
static unsigned long __init unflatten_dt_node(unsigned long mem,
unsigned long *p,
struct device_node *dad,
- struct device_node ***allnextpp)
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
- unsigned int l;
+ unsigned int l, allocl;
+ int has_name = 0;
+ int new_format = 0;
tag = *((u32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +757,56 @@
}
*p += 4;
pathp = (char *)*p;
- l = strlen(pathp) + 1;
+ l = allocl = strlen(pathp) + 1;
*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));
if (allnextpp) {
memset(np, 0, sizeof(*np));
np->full_name = ((char*)np) + sizeof(struct device_node);
- memcpy(np->full_name, pathp, l);
+ if (new_format) {
+ char *p = np->full_name;
+ /* rebuild full path for new format */
+ if (dad && dad->parent) {
+ strcpy(p, dad->full_name);
+ p += strlen(p);
+ }
+ *(p++) = '/';
+ memcpy(p, 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'. */
+ /* we temporarily use the next field as `last_child'*/
if (dad->next == 0)
dad->child = np;
else
@@ -782,6 +832,8 @@
printk("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));
@@ -801,6 +853,29 @@
}
*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;
+ int sz;
+
+ DBG("no name, building from %s\n", p);
+ while (*p && (*p) != '@')
+ p++;
+ sz = (p - pathp) + 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, pathp, sz - 1);
+ ((char *)pp->value)[sz - 1] = 0;
+ }
+ }
if (allnextpp) {
*prev_pp = NULL;
np->name = get_property(np, "name", NULL);
@@ -812,7 +887,7 @@
np->type = "<NULL>";
}
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));
}
if (tag != OF_DT_END_NODE) {
@@ -842,7 +917,7 @@
/* First pass, scan for size */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- size = unflatten_dt_node(0, &start, NULL, NULL);
+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);
DBG(" size is %lx, allocating...\n", size);
@@ -854,7 +929,7 @@
/* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) +
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)
printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
*allnextp = NULL;
@@ -880,7 +955,7 @@
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);
u32 *prop;
@@ -933,13 +1008,15 @@
}
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;
u64 *prop64;
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;
/* get platform type */
@@ -989,18 +1066,20 @@
}
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;
- if (strcmp(full_path, "/") != 0)
+ if (depth != 0)
return 0;
prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
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);
dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+ DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
/* break now */
return 1;
@@ -1028,7 +1107,7 @@
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);
cell_t *reg, *endp;
@@ -1044,7 +1123,9 @@
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)) {
unsigned long base, size;
@@ -1455,10 +1536,11 @@
struct device_node *np = allnodes;
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
&& of_node_get(np))
break;
+ }
read_unlock(&devtree_lock);
return np;
}
Index: linux-work/include/asm-ppc64/prom.h
===================================================================
--- linux-work.orig/include/asm-ppc64/prom.h 2005-05-23 18:15:28.000000000 +1000
+++ linux-work/include/asm-ppc64/prom.h 2005-05-23 18:16:09.000000000 +1000
@@ -22,13 +22,14 @@
#define RELOC(x) (*PTRRELOC(&(x)))
/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
-#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#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_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
@@ -54,7 +55,9 @@
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
/* 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 */
};
@@ -169,17 +172,20 @@
*/
#define HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+static inline void set_node_proc_entry(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->pde = de;
}
-static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de)
+static void inline set_node_name_link(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->name_link = de;
}
-static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de)
+static void inline set_node_addr_link(struct device_node *dn,
+ struct proc_dir_entry *de)
{
dn->addr_link = de;
}
next prev parent reply other threads:[~2005-05-24 4:35 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-05-24 4:34 Booting the Linux/ppc64 kernel without Open Firmware HOWTO (v3) Benjamin Herrenschmidt
2005-05-24 4:34 ` [U-Boot-Users] " Benjamin Herrenschmidt
2005-05-24 4:35 ` Benjamin Herrenschmidt [this message]
2005-05-24 4:35 ` [U-Boot-Users] " Benjamin Herrenschmidt
2005-05-24 7:50 ` Segher Boessenkool
2005-05-24 7:50 ` [U-Boot-Users] " Segher Boessenkool
2005-05-24 7:55 ` Benjamin Herrenschmidt
2005-05-24 7:55 ` [U-Boot-Users] " Benjamin Herrenschmidt
2005-05-24 8:01 ` Segher Boessenkool
2005-05-24 8:01 ` [U-Boot-Users] " Segher Boessenkool
2005-05-24 15:11 ` Jon Loeliger
2005-05-24 15:11 ` [U-Boot-Users] " Jon Loeliger
2005-05-24 21:48 ` Benjamin Herrenschmidt
2005-05-24 21:48 ` [U-Boot-Users] " Benjamin Herrenschmidt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1116909351.4992.19.camel@gaston \
--to=benh@kernel.crashing.org \
--cc=linuxppc-dev@ozlabs.org \
--cc=linuxppc64-dev@ozlabs.org \
--cc=tzachi@marvell.com \
--cc=u-boot-users@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.