1/* pdt.c: OF PROM device tree support code. 2 * 3 * Paul Mackerras August 1996. 4 * Copyright (C) 1996-2005 Paul Mackerras. 5 * 6 * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. 7 * {engebret|bergner}@us.ibm.com 8 * 9 * Adapted for sparc by David S. Miller davem@davemloft.net 10 * Adapted for multiple architectures by Andres Salomon <dilinger@queued.net> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 15 * 2 of the License, or (at your option) any later version. 16 */ 17 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/errno.h> 21#include <linux/mutex.h> 22#include <linux/slab.h> 23#include <linux/of.h> 24#include <linux/of_pdt.h> 25 26static struct of_pdt_ops *of_pdt_prom_ops __initdata; 27 28void __initdata (*of_pdt_build_more)(struct device_node *dp, 29 struct device_node ***nextp); 30 31#if defined(CONFIG_SPARC) 32unsigned int of_pdt_unique_id __initdata; 33 34#define of_pdt_incr_unique_id(p) do { \ 35 (p)->unique_id = of_pdt_unique_id++; \ 36} while (0) 37 38static char * __init of_pdt_build_full_name(struct device_node *dp) 39{ 40 int len, ourlen, plen; 41 char *n; 42 43 dp->path_component_name = build_path_component(dp); 44 45 plen = strlen(dp->parent->full_name); 46 ourlen = strlen(dp->path_component_name); 47 len = ourlen + plen + 2; 48 49 n = prom_early_alloc(len); 50 strcpy(n, dp->parent->full_name); 51 if (!of_node_is_root(dp->parent)) { 52 strcpy(n + plen, "/"); 53 plen++; 54 } 55 strcpy(n + plen, dp->path_component_name); 56 57 return n; 58} 59 60#else /* CONFIG_SPARC */ 61 62static inline void of_pdt_incr_unique_id(void *p) { } 63static inline void irq_trans_init(struct device_node *dp) { } 64 65static char * __init of_pdt_build_full_name(struct device_node *dp) 66{ 67 static int failsafe_id = 0; /* for generating unique names on failure */ 68 char *buf; 69 int len; 70 71 if (of_pdt_prom_ops->pkg2path(dp->phandle, NULL, 0, &len)) 72 goto failsafe; 73 74 buf = prom_early_alloc(len + 1); 75 if (of_pdt_prom_ops->pkg2path(dp->phandle, buf, len, &len)) 76 goto failsafe; 77 return buf; 78 79 failsafe: 80 buf = prom_early_alloc(strlen(dp->parent->full_name) + 81 strlen(dp->name) + 16); 82 sprintf(buf, "%s/%s@unknown%i", 83 of_node_is_root(dp->parent) ? "" : dp->parent->full_name, 84 dp->name, failsafe_id++); 85 pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf); 86 return buf; 87} 88 89#endif /* !CONFIG_SPARC */ 90 91static struct property * __init of_pdt_build_one_prop(phandle node, char *prev, 92 char *special_name, 93 void *special_val, 94 int special_len) 95{ 96 static struct property *tmp = NULL; 97 struct property *p; 98 int err; 99 100 if (tmp) { 101 p = tmp; 102 memset(p, 0, sizeof(*p) + 32); 103 tmp = NULL; 104 } else { 105 p = prom_early_alloc(sizeof(struct property) + 32); 106 of_pdt_incr_unique_id(p); 107 } 108 109 p->name = (char *) (p + 1); 110 if (special_name) { 111 strcpy(p->name, special_name); 112 p->length = special_len; 113 p->value = prom_early_alloc(special_len); 114 memcpy(p->value, special_val, special_len); 115 } else { 116 err = of_pdt_prom_ops->nextprop(node, prev, p->name); 117 if (err) { 118 tmp = p; 119 return NULL; 120 } 121 p->length = of_pdt_prom_ops->getproplen(node, p->name); 122 if (p->length <= 0) { 123 p->length = 0; 124 } else { 125 int len; 126 127 p->value = prom_early_alloc(p->length + 1); 128 len = of_pdt_prom_ops->getproperty(node, p->name, 129 p->value, p->length); 130 if (len <= 0) 131 p->length = 0; 132 ((unsigned char *)p->value)[p->length] = '\0'; 133 } 134 } 135 return p; 136} 137 138static struct property * __init of_pdt_build_prop_list(phandle node) 139{ 140 struct property *head, *tail; 141 142 head = tail = of_pdt_build_one_prop(node, NULL, 143 ".node", &node, sizeof(node)); 144 145 tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0); 146 tail = tail->next; 147 while(tail) { 148 tail->next = of_pdt_build_one_prop(node, tail->name, 149 NULL, NULL, 0); 150 tail = tail->next; 151 } 152 153 return head; 154} 155 156static char * __init of_pdt_get_one_property(phandle node, const char *name) 157{ 158 char *buf = "<NULL>"; 159 int len; 160 161 len = of_pdt_prom_ops->getproplen(node, name); 162 if (len > 0) { 163 buf = prom_early_alloc(len); 164 len = of_pdt_prom_ops->getproperty(node, name, buf, len); 165 } 166 167 return buf; 168} 169 170static struct device_node * __init of_pdt_create_node(phandle node, 171 struct device_node *parent) 172{ 173 struct device_node *dp; 174 175 if (!node) 176 return NULL; 177 178 dp = prom_early_alloc(sizeof(*dp)); 179 of_node_init(dp); 180 of_pdt_incr_unique_id(dp); 181 dp->parent = parent; 182 183 dp->name = of_pdt_get_one_property(node, "name"); 184 dp->type = of_pdt_get_one_property(node, "device_type"); 185 dp->phandle = node; 186 187 dp->properties = of_pdt_build_prop_list(node); 188 189 irq_trans_init(dp); 190 191 return dp; 192} 193 194static struct device_node * __init of_pdt_build_tree(struct device_node *parent, 195 phandle node, 196 struct device_node ***nextp) 197{ 198 struct device_node *ret = NULL, *prev_sibling = NULL; 199 struct device_node *dp; 200 201 while (1) { 202 dp = of_pdt_create_node(node, parent); 203 if (!dp) 204 break; 205 206 if (prev_sibling) 207 prev_sibling->sibling = dp; 208 209 if (!ret) 210 ret = dp; 211 prev_sibling = dp; 212 213 *(*nextp) = dp; 214 *nextp = &dp->allnext; 215 216 dp->full_name = of_pdt_build_full_name(dp); 217 218 dp->child = of_pdt_build_tree(dp, 219 of_pdt_prom_ops->getchild(node), nextp); 220 221 if (of_pdt_build_more) 222 of_pdt_build_more(dp, nextp); 223 224 node = of_pdt_prom_ops->getsibling(node); 225 } 226 227 return ret; 228} 229 230static void * __init kernel_tree_alloc(u64 size, u64 align) 231{ 232 return prom_early_alloc(size); 233} 234 235void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) 236{ 237 struct device_node **nextp; 238 239 BUG_ON(!ops); 240 of_pdt_prom_ops = ops; 241 242 of_allnodes = of_pdt_create_node(root_node, NULL); 243#if defined(CONFIG_SPARC) 244 of_allnodes->path_component_name = ""; 245#endif 246 of_allnodes->full_name = "/"; 247 248 nextp = &of_allnodes->allnext; 249 of_allnodes->child = of_pdt_build_tree(of_allnodes, 250 of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp); 251 252 /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ 253 of_alias_scan(kernel_tree_alloc); 254} 255