Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 6186
b: refs/heads/master
c: 34153fa
h: refs/heads/master
v: v3
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Aug 29, 2005
1 parent 3b78f08 commit bf1c77f
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 69 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e28f7faf05159f1cfd564596f5e6178edba6bd49
refs/heads/master: 34153fa3af45d84f3221d9b67ba2ab7e8a220d28
175 changes: 145 additions & 30 deletions trunk/arch/ppc64/kernel/prom.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,8 @@ void __init finish_device_tree(void)

static inline char *find_flat_dt_string(u32 offset)
{
return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings
+ offset;
return ((char *)initial_boot_params) +
initial_boot_params->off_dt_strings + offset;
}

/**
Expand All @@ -635,26 +635,33 @@ static inline char *find_flat_dt_string(u32 offset)
* 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_NOP)
continue;
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
u32 sz = *((u32 *)p);
p += 8;
p = _ALIGN(p, sz >= 8 ? 8 : 4);
if (initial_boot_params->version < 0x10)
p = _ALIGN(p, sz >= 8 ? 8 : 4);
p += sz;
p = _ALIGN(p, 4);
continue;
Expand All @@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node,
" 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);
Expand All @@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
const char *nstr;

p += 4;
if (tag == OF_DT_NOP)
continue;
if (tag != OF_DT_PROP)
return NULL;

sz = *((u32 *)p);
noff = *((u32 *)(p + 4));
p += 8;
p = _ALIGN(p, sz >= 8 ? 8 : 4);
if (initial_boot_params->version < 0x10)
p = _ALIGN(p, sz >= 8 ? 8 : 4);

nstr = find_flat_dt_string(noff);
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;
}
if (strcmp(name, nstr) == 0) {
Expand All @@ -713,7 +733,7 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
}

static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
unsigned long align)
unsigned long align)
{
void *res;

Expand All @@ -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,
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) {
Expand All @@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
}
*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);
#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);
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
Expand All @@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
char *pname;

tag = *((u32 *)(*p));
if (tag == OF_DT_NOP) {
*p += 4;
continue;
}
if (tag != OF_DT_PROP)
break;
*p += 4;
sz = *((u32 *)(*p));
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);
if (pname == NULL) {
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));
Expand All @@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
}
*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) {
*prev_pp = NULL;
np->name = get_property(np, "name", NULL);
Expand All @@ -812,7 +914,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
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) {
Expand Down Expand Up @@ -842,21 +944,27 @@ void __init unflatten_device_tree(void)
/* 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);
size = (size | 3) + 1;

DBG(" size is %lx, allocating...\n", size);

/* 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)));
((u32 *)mem)[size / 4] = 0xdeadbeef;

DBG(" unflattening...\n", mem);

/* 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));
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;

/* Get pointer to OF "/chosen" node for use everywhere */
Expand All @@ -880,7 +988,7 @@ void __init unflatten_device_tree(void)


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;
Expand Down Expand Up @@ -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,
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 */
Expand Down Expand Up @@ -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,
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;
Expand Down Expand Up @@ -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,
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;
Expand All @@ -1058,7 +1170,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,

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;

Expand Down Expand Up @@ -1469,10 +1583,11 @@ struct device_node *of_find_node_by_path(const char *path)
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;
}
Expand Down
Loading

0 comments on commit bf1c77f

Please sign in to comment.