blob: 14a07b9e00d1c2e319b8d077cfe9d66b0f1f7210 [file] [log] [blame]
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001/*
2 * Procedures for creating, accessing and interpreting the device tree.
3 *
4 * Paul Mackerras August 1996.
5 * Copyright (C) 1996-2005 Paul Mackerras.
6 *
7 * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8 * {engebret|bergner}@us.ibm.com
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 */
15
16#undef DEBUG
17
18#include <stdarg.h>
Paul Mackerras9b6b5632005-10-06 12:06:20 +100019#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/init.h>
22#include <linux/threads.h>
23#include <linux/spinlock.h>
24#include <linux/types.h>
25#include <linux/pci.h>
26#include <linux/stringify.h>
27#include <linux/delay.h>
28#include <linux/initrd.h>
29#include <linux/bitops.h>
30#include <linux/module.h>
Michael Ellermandcee3032005-12-04 18:39:48 +110031#include <linux/kexec.h>
Michael Ellerman7a4571a2006-06-23 18:16:03 +100032#include <linux/debugfs.h>
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +100033#include <linux/irq.h>
David S. Millerd9b2b2a2008-02-13 16:56:49 -080034#include <linux/lmb.h>
Paul Mackerras9b6b5632005-10-06 12:06:20 +100035
36#include <asm/prom.h>
37#include <asm/rtas.h>
Paul Mackerras9b6b5632005-10-06 12:06:20 +100038#include <asm/page.h>
39#include <asm/processor.h>
40#include <asm/irq.h>
41#include <asm/io.h>
Michael Ellerman0cc47462005-12-04 18:39:37 +110042#include <asm/kdump.h>
Paul Mackerras9b6b5632005-10-06 12:06:20 +100043#include <asm/smp.h>
44#include <asm/system.h>
45#include <asm/mmu.h>
46#include <asm/pgtable.h>
47#include <asm/pci.h>
48#include <asm/iommu.h>
49#include <asm/btext.h>
50#include <asm/sections.h>
51#include <asm/machdep.h>
52#include <asm/pSeries_reconfig.h>
Paul Mackerras40ef8cb2005-10-10 22:50:37 +100053#include <asm/pci-bridge.h>
Manish Ahuja6ac26c82008-03-22 10:37:08 +110054#include <asm/phyp_dump.h>
Michael Ellerman2babf5c2006-05-17 18:00:46 +100055#include <asm/kexec.h>
Kumar Gala37dd2ba2008-04-22 04:22:34 +100056#include <mm/mmu_decl.h>
Paul Mackerras9b6b5632005-10-06 12:06:20 +100057
58#ifdef DEBUG
59#define DBG(fmt...) printk(KERN_ERR fmt)
60#else
61#define DBG(fmt...)
62#endif
63
Paul Mackerras9b6b5632005-10-06 12:06:20 +100064
Paul Mackerras9b6b5632005-10-06 12:06:20 +100065static int __initdata dt_root_addr_cells;
66static int __initdata dt_root_size_cells;
67
68#ifdef CONFIG_PPC64
Olof Johansson28897732006-04-12 21:52:33 -050069int __initdata iommu_is_off;
Paul Mackerras9b6b5632005-10-06 12:06:20 +100070int __initdata iommu_force_on;
Paul Mackerrascf00a8d2005-10-31 13:07:02 +110071unsigned long tce_alloc_start, tce_alloc_end;
Paul Mackerras9b6b5632005-10-06 12:06:20 +100072#endif
73
74typedef u32 cell_t;
75
Stephen Rothwell1ef4d422007-04-24 17:57:33 +100076extern struct device_node *allnodes; /* temporary while merging */
Paul Mackerras9b6b5632005-10-06 12:06:20 +100077
Stephen Rothwell581b6052007-04-24 16:46:53 +100078extern rwlock_t devtree_lock; /* temporary while merging */
Paul Mackerras9b6b5632005-10-06 12:06:20 +100079
80/* export that to outside world */
81struct device_node *of_chosen;
82
Benjamin Herrenschmidte8222502006-03-28 23:15:54 +110083unsigned long __init of_get_flat_dt_root(void)
84{
85 unsigned long p = ((unsigned long)initial_boot_params) +
86 initial_boot_params->off_dt_struct;
87
88 while(*((u32 *)p) == OF_DT_NOP)
89 p += 4;
90 BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE);
91 p += 4;
92 return _ALIGN(p + strlen((char *)p) + 1, 4);
93}
94
Paul Mackerras9b6b5632005-10-06 12:06:20 +100095/**
96 * This function can be used within scan_flattened_dt callback to get
97 * access to properties
98 */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +110099void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
100 unsigned long *size)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000101{
102 unsigned long p = node;
103
104 do {
105 u32 tag = *((u32 *)p);
106 u32 sz, noff;
107 const char *nstr;
108
109 p += 4;
110 if (tag == OF_DT_NOP)
111 continue;
112 if (tag != OF_DT_PROP)
113 return NULL;
114
115 sz = *((u32 *)p);
116 noff = *((u32 *)(p + 4));
117 p += 8;
118 if (initial_boot_params->version < 0x10)
119 p = _ALIGN(p, sz >= 8 ? 8 : 4);
120
121 nstr = find_flat_dt_string(noff);
122 if (nstr == NULL) {
123 printk(KERN_WARNING "Can't find property index"
124 " name !\n");
125 return NULL;
126 }
127 if (strcmp(name, nstr) == 0) {
128 if (size)
129 *size = sz;
130 return (void *)p;
131 }
132 p += sz;
133 p = _ALIGN(p, 4);
134 } while(1);
135}
136
Benjamin Herrenschmidte8222502006-03-28 23:15:54 +1100137int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
138{
139 const char* cp;
140 unsigned long cplen, l;
141
142 cp = of_get_flat_dt_prop(node, "compatible", &cplen);
143 if (cp == NULL)
144 return 0;
145 while (cplen > 0) {
146 if (strncasecmp(cp, compat, strlen(compat)) == 0)
147 return 1;
148 l = strlen(cp) + 1;
149 cp += l;
150 cplen -= l;
151 }
152
153 return 0;
154}
155
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000156static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
157 unsigned long align)
158{
159 void *res;
160
161 *mem = _ALIGN(*mem, align);
162 res = (void *)*mem;
163 *mem += size;
164
165 return res;
166}
167
168static unsigned long __init unflatten_dt_node(unsigned long mem,
169 unsigned long *p,
170 struct device_node *dad,
171 struct device_node ***allnextpp,
172 unsigned long fpsize)
173{
174 struct device_node *np;
175 struct property *pp, **prev_pp = NULL;
176 char *pathp;
177 u32 tag;
178 unsigned int l, allocl;
179 int has_name = 0;
180 int new_format = 0;
181
182 tag = *((u32 *)(*p));
183 if (tag != OF_DT_BEGIN_NODE) {
184 printk("Weird tag at start of node: %x\n", tag);
185 return mem;
186 }
187 *p += 4;
188 pathp = (char *)*p;
189 l = allocl = strlen(pathp) + 1;
190 *p = _ALIGN(*p + l, 4);
191
192 /* version 0x10 has a more compact unit name here instead of the full
193 * path. we accumulate the full path size using "fpsize", we'll rebuild
194 * it later. We detect this because the first character of the name is
195 * not '/'.
196 */
197 if ((*pathp) != '/') {
198 new_format = 1;
199 if (fpsize == 0) {
200 /* root node: special case. fpsize accounts for path
201 * plus terminating zero. root node only has '/', so
202 * fpsize should be 2, but we want to avoid the first
203 * level nodes to have two '/' so we use fpsize 1 here
204 */
205 fpsize = 1;
206 allocl = 2;
207 } else {
208 /* account for '/' and path size minus terminal 0
209 * already in 'l'
210 */
211 fpsize += l;
212 allocl = fpsize;
213 }
214 }
215
216
217 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
218 __alignof__(struct device_node));
219 if (allnextpp) {
220 memset(np, 0, sizeof(*np));
221 np->full_name = ((char*)np) + sizeof(struct device_node);
222 if (new_format) {
223 char *p = np->full_name;
224 /* rebuild full path for new format */
225 if (dad && dad->parent) {
226 strcpy(p, dad->full_name);
227#ifdef DEBUG
228 if ((strlen(p) + l + 1) != allocl) {
229 DBG("%s: p: %d, l: %d, a: %d\n",
Benjamin Herrenschmidte8222502006-03-28 23:15:54 +1100230 pathp, (int)strlen(p), l, allocl);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000231 }
232#endif
233 p += strlen(p);
234 }
235 *(p++) = '/';
236 memcpy(p, pathp, l);
237 } else
238 memcpy(np->full_name, pathp, l);
239 prev_pp = &np->properties;
240 **allnextpp = np;
241 *allnextpp = &np->allnext;
242 if (dad != NULL) {
243 np->parent = dad;
244 /* we temporarily use the next field as `last_child'*/
245 if (dad->next == 0)
246 dad->child = np;
247 else
248 dad->next->sibling = np;
249 dad->next = np;
250 }
251 kref_init(&np->kref);
252 }
253 while(1) {
254 u32 sz, noff;
255 char *pname;
256
257 tag = *((u32 *)(*p));
258 if (tag == OF_DT_NOP) {
259 *p += 4;
260 continue;
261 }
262 if (tag != OF_DT_PROP)
263 break;
264 *p += 4;
265 sz = *((u32 *)(*p));
266 noff = *((u32 *)((*p) + 4));
267 *p += 8;
268 if (initial_boot_params->version < 0x10)
269 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
270
271 pname = find_flat_dt_string(noff);
272 if (pname == NULL) {
273 printk("Can't find property name in list !\n");
274 break;
275 }
276 if (strcmp(pname, "name") == 0)
277 has_name = 1;
278 l = strlen(pname) + 1;
279 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
280 __alignof__(struct property));
281 if (allnextpp) {
282 if (strcmp(pname, "linux,phandle") == 0) {
283 np->node = *((u32 *)*p);
284 if (np->linux_phandle == 0)
285 np->linux_phandle = np->node;
286 }
287 if (strcmp(pname, "ibm,phandle") == 0)
288 np->linux_phandle = *((u32 *)*p);
289 pp->name = pname;
290 pp->length = sz;
291 pp->value = (void *)*p;
292 *prev_pp = pp;
293 prev_pp = &pp->next;
294 }
295 *p = _ALIGN((*p) + sz, 4);
296 }
297 /* with version 0x10 we may not have the name property, recreate
298 * it here from the unit name if absent
299 */
300 if (!has_name) {
301 char *p = pathp, *ps = pathp, *pa = NULL;
302 int sz;
303
304 while (*p) {
305 if ((*p) == '@')
306 pa = p;
307 if ((*p) == '/')
308 ps = p + 1;
309 p++;
310 }
311 if (pa < ps)
312 pa = p;
313 sz = (pa - ps) + 1;
314 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
315 __alignof__(struct property));
316 if (allnextpp) {
317 pp->name = "name";
318 pp->length = sz;
Stephen Rothwell1a381472007-04-03 10:58:52 +1000319 pp->value = pp + 1;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000320 *prev_pp = pp;
321 prev_pp = &pp->next;
322 memcpy(pp->value, ps, sz - 1);
323 ((char *)pp->value)[sz - 1] = 0;
Stephen Rothwell1a381472007-04-03 10:58:52 +1000324 DBG("fixed up name for %s -> %s\n", pathp,
325 (char *)pp->value);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000326 }
327 }
328 if (allnextpp) {
329 *prev_pp = NULL;
Stephen Rothwell0e56efc2007-04-03 10:54:01 +1000330 np->name = of_get_property(np, "name", NULL);
331 np->type = of_get_property(np, "device_type", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000332
333 if (!np->name)
334 np->name = "<NULL>";
335 if (!np->type)
336 np->type = "<NULL>";
337 }
338 while (tag == OF_DT_BEGIN_NODE) {
339 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
340 tag = *((u32 *)(*p));
341 }
342 if (tag != OF_DT_END_NODE) {
343 printk("Weird tag at end of node: %x\n", tag);
344 return mem;
345 }
346 *p += 4;
347 return mem;
348}
349
Michael Ellerman2babf5c2006-05-17 18:00:46 +1000350static int __init early_parse_mem(char *p)
351{
352 if (!p)
353 return 1;
354
355 memory_limit = PAGE_ALIGN(memparse(p, &p));
Becky Bruce49a84962009-05-08 12:19:27 +0000356 DBG("memory limit = 0x%llx\n", (unsigned long long)memory_limit);
Michael Ellerman2babf5c2006-05-17 18:00:46 +1000357
358 return 0;
359}
360early_param("mem", early_parse_mem);
361
Linas Vepstas3c607ce2007-09-07 03:47:29 +1000362/**
363 * move_device_tree - move tree to an unused area, if needed.
364 *
365 * The device tree may be allocated beyond our memory limit, or inside the
366 * crash kernel region for kdump. If so, move it out of the way.
Michael Ellerman2babf5c2006-05-17 18:00:46 +1000367 */
Geert Uytterhoeven18f032c2008-03-29 03:07:45 +1100368static void __init move_device_tree(void)
Michael Ellerman2babf5c2006-05-17 18:00:46 +1000369{
370 unsigned long start, size;
371 void *p;
372
373 DBG("-> move_device_tree\n");
374
375 start = __pa(initial_boot_params);
376 size = initial_boot_params->totalsize;
377
378 if ((memory_limit && (start + size) > memory_limit) ||
379 overlaps_crashkernel(start, size)) {
380 p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size));
381 memcpy(p, initial_boot_params, size);
382 initial_boot_params = (struct boot_param_header *)p;
383 DBG("Moved device tree to 0x%p\n", p);
384 }
385
386 DBG("<- move_device_tree\n");
387}
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000388
389/**
390 * unflattens the device-tree passed by the firmware, creating the
391 * tree of struct device_node. It also fills the "name" and "type"
392 * pointers of the nodes so the normal device-tree walking functions
393 * can be used (this used to be done by finish_device_tree)
394 */
395void __init unflatten_device_tree(void)
396{
397 unsigned long start, mem, size;
398 struct device_node **allnextp = &allnodes;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000399
400 DBG(" -> unflatten_device_tree()\n");
401
402 /* First pass, scan for size */
403 start = ((unsigned long)initial_boot_params) +
404 initial_boot_params->off_dt_struct;
405 size = unflatten_dt_node(0, &start, NULL, NULL, 0);
406 size = (size | 3) + 1;
407
408 DBG(" size is %lx, allocating...\n", size);
409
410 /* Allocate memory for the expanded device tree */
411 mem = lmb_alloc(size + 4, __alignof__(struct device_node));
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000412 mem = (unsigned long) __va(mem);
413
414 ((u32 *)mem)[size / 4] = 0xdeadbeef;
415
416 DBG(" unflattening %lx...\n", mem);
417
418 /* Second pass, do actual unflattening */
419 start = ((unsigned long)initial_boot_params) +
420 initial_boot_params->off_dt_struct;
421 unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
422 if (*((u32 *)start) != OF_DT_END)
423 printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
424 if (((u32 *)mem)[size / 4] != 0xdeadbeef)
425 printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
426 ((u32 *)mem)[size / 4] );
427 *allnextp = NULL;
428
429 /* Get pointer to OF "/chosen" node for use everywhere */
430 of_chosen = of_find_node_by_path("/chosen");
Paul Mackerrasa575b802005-10-23 17:23:21 +1000431 if (of_chosen == NULL)
432 of_chosen = of_find_node_by_path("/chosen@0");
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000433
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000434 DBG(" <- unflatten_device_tree()\n");
435}
436
Paul Mackerrasd2058192006-05-03 23:04:37 +1000437/*
438 * ibm,pa-features is a per-cpu property that contains a string of
439 * attribute descriptors, each of which has a 2 byte header plus up
440 * to 254 bytes worth of processor attribute bits. First header
441 * byte specifies the number of bytes following the header.
442 * Second header byte is an "attribute-specifier" type, of which
443 * zero is the only currently-defined value.
444 * Implementation: Pass in the byte and bit offset for the feature
445 * that we are interested in. The function will return -1 if the
446 * pa-features property is missing, or a 1/0 to indicate if the feature
447 * is supported/not supported. Note that the bit numbers are
448 * big-endian to match the definition in PAPR.
449 */
450static struct ibm_pa_feature {
451 unsigned long cpu_features; /* CPU_FTR_xxx bit */
452 unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */
453 unsigned char pabyte; /* byte number in ibm,pa-features */
454 unsigned char pabit; /* bit number (big-endian) */
455 unsigned char invert; /* if 1, pa bit set => clear feature */
456} ibm_pa_features[] __initdata = {
457 {0, PPC_FEATURE_HAS_MMU, 0, 0, 0},
458 {0, PPC_FEATURE_HAS_FPU, 0, 1, 0},
459 {CPU_FTR_SLB, 0, 0, 2, 0},
460 {CPU_FTR_CTRL, 0, 0, 3, 0},
461 {CPU_FTR_NOEXECUTE, 0, 0, 6, 0},
462 {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1},
463 {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0},
Paul Mackerras339d76c2006-06-29 17:12:30 +1000464 {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
Paul Mackerrasd2058192006-05-03 23:04:37 +1000465};
466
Paul Mackerras974a76f2006-11-10 20:38:53 +1100467static void __init scan_features(unsigned long node, unsigned char *ftrs,
468 unsigned long tablelen,
469 struct ibm_pa_feature *fp,
470 unsigned long ft_size)
Paul Mackerrasd2058192006-05-03 23:04:37 +1000471{
Paul Mackerras974a76f2006-11-10 20:38:53 +1100472 unsigned long i, len, bit;
Paul Mackerrasd2058192006-05-03 23:04:37 +1000473
474 /* find descriptor with type == 0 */
475 for (;;) {
476 if (tablelen < 3)
477 return;
Paul Mackerras974a76f2006-11-10 20:38:53 +1100478 len = 2 + ftrs[0];
Paul Mackerrasd2058192006-05-03 23:04:37 +1000479 if (tablelen < len)
480 return; /* descriptor 0 not found */
Paul Mackerras974a76f2006-11-10 20:38:53 +1100481 if (ftrs[1] == 0)
Paul Mackerrasd2058192006-05-03 23:04:37 +1000482 break;
483 tablelen -= len;
Paul Mackerras974a76f2006-11-10 20:38:53 +1100484 ftrs += len;
Paul Mackerrasd2058192006-05-03 23:04:37 +1000485 }
486
487 /* loop over bits we know about */
Paul Mackerras974a76f2006-11-10 20:38:53 +1100488 for (i = 0; i < ft_size; ++i, ++fp) {
489 if (fp->pabyte >= ftrs[0])
Paul Mackerrasd2058192006-05-03 23:04:37 +1000490 continue;
Paul Mackerras974a76f2006-11-10 20:38:53 +1100491 bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1;
Paul Mackerrasd2058192006-05-03 23:04:37 +1000492 if (bit ^ fp->invert) {
493 cur_cpu_spec->cpu_features |= fp->cpu_features;
494 cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
495 } else {
496 cur_cpu_spec->cpu_features &= ~fp->cpu_features;
497 cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs;
498 }
499 }
500}
501
Paul Mackerras974a76f2006-11-10 20:38:53 +1100502static void __init check_cpu_pa_features(unsigned long node)
503{
504 unsigned char *pa_ftrs;
505 unsigned long tablelen;
506
507 pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
508 if (pa_ftrs == NULL)
509 return;
510
511 scan_features(node, pa_ftrs, tablelen,
512 ibm_pa_features, ARRAY_SIZE(ibm_pa_features));
513}
514
Benjamin Herrenschmidt94491682009-06-02 21:17:45 +0000515#ifdef CONFIG_PPC_STD_MMU_64
Michael Neuling584f8b72007-12-06 17:24:48 +1100516static void __init check_cpu_slb_size(unsigned long node)
517{
518 u32 *slb_size_ptr;
519
Michael Neulingb60c31d2009-01-14 13:42:41 +0000520 slb_size_ptr = of_get_flat_dt_prop(node, "slb-size", NULL);
521 if (slb_size_ptr != NULL) {
522 mmu_slb_size = *slb_size_ptr;
523 return;
524 }
Michael Neuling584f8b72007-12-06 17:24:48 +1100525 slb_size_ptr = of_get_flat_dt_prop(node, "ibm,slb-size", NULL);
526 if (slb_size_ptr != NULL) {
527 mmu_slb_size = *slb_size_ptr;
528 }
529}
530#else
531#define check_cpu_slb_size(node) do { } while(0)
532#endif
533
Paul Mackerras974a76f2006-11-10 20:38:53 +1100534static struct feature_property {
535 const char *name;
536 u32 min_value;
537 unsigned long cpu_feature;
538 unsigned long cpu_user_ftr;
539} feature_properties[] __initdata = {
540#ifdef CONFIG_ALTIVEC
541 {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
542 {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
543#endif /* CONFIG_ALTIVEC */
Michael Neulingb962ce92008-06-25 14:07:18 +1000544#ifdef CONFIG_VSX
545 /* Yes, this _really_ is ibm,vmx == 2 to enable VSX */
546 {"ibm,vmx", 2, CPU_FTR_VSX, PPC_FEATURE_HAS_VSX},
547#endif /* CONFIG_VSX */
Paul Mackerras974a76f2006-11-10 20:38:53 +1100548#ifdef CONFIG_PPC64
549 {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP},
550 {"ibm,purr", 1, CPU_FTR_PURR, 0},
551 {"ibm,spurr", 1, CPU_FTR_SPURR, 0},
552#endif /* CONFIG_PPC64 */
553};
554
Valentine Barshak14b3d922007-12-22 03:24:02 +1100555#if defined(CONFIG_44x) && defined(CONFIG_PPC_FPU)
556static inline void identical_pvr_fixup(unsigned long node)
557{
558 unsigned int pvr;
559 char *model = of_get_flat_dt_prop(node, "model", NULL);
560
561 /*
562 * Since 440GR(x)/440EP(x) processors have the same pvr,
563 * we check the node path and set bit 28 in the cur_cpu_spec
564 * pvr for EP(x) processor version. This bit is always 0 in
565 * the "real" pvr. Then we call identify_cpu again with
566 * the new logical pvr to enable FPU support.
567 */
568 if (model && strstr(model, "440EP")) {
569 pvr = cur_cpu_spec->pvr_value | 0x8;
570 identify_cpu(0, pvr);
571 DBG("Using logical pvr %x for %s\n", pvr, model);
572 }
573}
574#else
575#define identical_pvr_fixup(node) do { } while(0)
576#endif
577
Paul Mackerras974a76f2006-11-10 20:38:53 +1100578static void __init check_cpu_feature_properties(unsigned long node)
579{
580 unsigned long i;
581 struct feature_property *fp = feature_properties;
582 const u32 *prop;
583
584 for (i = 0; i < ARRAY_SIZE(feature_properties); ++i, ++fp) {
585 prop = of_get_flat_dt_prop(node, fp->name, NULL);
586 if (prop && *prop >= fp->min_value) {
587 cur_cpu_spec->cpu_features |= fp->cpu_feature;
588 cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftr;
589 }
590 }
591}
592
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000593static int __init early_init_dt_scan_cpus(unsigned long node,
Anton Blanchard4df20462006-03-25 17:25:17 +1100594 const char *uname, int depth,
595 void *data)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000596{
Anton Blanchard4df20462006-03-25 17:25:17 +1100597 static int logical_cpuid = 0;
598 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
Paul Mackerras974a76f2006-11-10 20:38:53 +1100599 const u32 *prop;
600 const u32 *intserv;
Anton Blanchard4df20462006-03-25 17:25:17 +1100601 int i, nthreads;
602 unsigned long len;
603 int found = 0;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000604
605 /* We are scanning "cpu" nodes only */
606 if (type == NULL || strcmp(type, "cpu") != 0)
607 return 0;
608
Anton Blanchard4df20462006-03-25 17:25:17 +1100609 /* Get physical cpuid */
610 intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len);
611 if (intserv) {
612 nthreads = len / sizeof(int);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000613 } else {
Anton Blanchard4df20462006-03-25 17:25:17 +1100614 intserv = of_get_flat_dt_prop(node, "reg", NULL);
615 nthreads = 1;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000616 }
Anton Blanchard4df20462006-03-25 17:25:17 +1100617
618 /*
619 * Now see if any of these threads match our boot cpu.
620 * NOTE: This must match the parsing done in smp_setup_cpu_maps.
621 */
622 for (i = 0; i < nthreads; i++) {
623 /*
624 * version 2 of the kexec param format adds the phys cpuid of
625 * booted proc.
626 */
627 if (initial_boot_params && initial_boot_params->version >= 2) {
628 if (intserv[i] ==
629 initial_boot_params->boot_cpuid_phys) {
630 found = 1;
631 break;
632 }
633 } else {
634 /*
635 * Check if it's the boot-cpu, set it's hw index now,
636 * unfortunately this format did not support booting
637 * off secondary threads.
638 */
639 if (of_get_flat_dt_prop(node,
640 "linux,boot-cpu", NULL) != NULL) {
641 found = 1;
642 break;
643 }
644 }
645
646#ifdef CONFIG_SMP
647 /* logical cpu id is always 0 on UP kernels */
648 logical_cpuid++;
649#endif
650 }
651
652 if (found) {
653 DBG("boot cpu: logical %d physical %d\n", logical_cpuid,
654 intserv[i]);
655 boot_cpuid = logical_cpuid;
656 set_hard_smp_processor_id(boot_cpuid, intserv[i]);
Paul Mackerras974a76f2006-11-10 20:38:53 +1100657
658 /*
659 * PAPR defines "logical" PVR values for cpus that
660 * meet various levels of the architecture:
661 * 0x0f000001 Architecture version 2.04
662 * 0x0f000002 Architecture version 2.05
663 * If the cpu-version property in the cpu node contains
664 * such a value, we call identify_cpu again with the
665 * logical PVR value in order to use the cpu feature
666 * bits appropriate for the architecture level.
667 *
668 * A POWER6 partition in "POWER6 architected" mode
669 * uses the 0x0f000002 PVR value; in POWER5+ mode
670 * it uses 0x0f000001.
671 */
672 prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
673 if (prop && (*prop & 0xff000000) == 0x0f000000)
674 identify_cpu(0, *prop);
Valentine Barshak14b3d922007-12-22 03:24:02 +1100675
676 identical_pvr_fixup(node);
Anton Blanchard4df20462006-03-25 17:25:17 +1100677 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000678
Paul Mackerras974a76f2006-11-10 20:38:53 +1100679 check_cpu_feature_properties(node);
Paul Mackerrasd2058192006-05-03 23:04:37 +1000680 check_cpu_pa_features(node);
Michael Neuling584f8b72007-12-06 17:24:48 +1100681 check_cpu_slb_size(node);
Paul Mackerrasd2058192006-05-03 23:04:37 +1000682
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000683#ifdef CONFIG_PPC_PSERIES
Anton Blanchard4df20462006-03-25 17:25:17 +1100684 if (nthreads > 1)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000685 cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
Anton Blanchard4df20462006-03-25 17:25:17 +1100686 else
687 cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000688#endif
689
690 return 0;
691}
692
Michael Ellerman40472a52007-05-10 17:06:30 +1000693#ifdef CONFIG_BLK_DEV_INITRD
694static void __init early_init_dt_check_for_initrd(unsigned long node)
695{
696 unsigned long l;
697 u32 *prop;
698
699 DBG("Looking for initrd properties... ");
700
701 prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
702 if (prop) {
703 initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
704
705 prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
706 if (prop) {
707 initrd_end = (unsigned long)
708 __va(of_read_ulong(prop, l/4));
709 initrd_below_start_ok = 1;
710 } else {
711 initrd_start = 0;
712 }
713 }
714
715 DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
716}
717#else
718static inline void early_init_dt_check_for_initrd(unsigned long node)
719{
720}
721#endif /* CONFIG_BLK_DEV_INITRD */
722
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000723static int __init early_init_dt_scan_chosen(unsigned long node,
724 const char *uname, int depth, void *data)
725{
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000726 unsigned long *lprop;
Kumar Gala329dda02006-02-24 10:54:52 -0600727 unsigned long l;
728 char *p;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000729
730 DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
731
Paul Mackerrasa575b802005-10-23 17:23:21 +1000732 if (depth != 1 ||
733 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000734 return 0;
735
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000736#ifdef CONFIG_PPC64
737 /* check if iommu is forced on or off */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100738 if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000739 iommu_is_off = 1;
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100740 if (of_get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000741 iommu_force_on = 1;
742#endif
743
Michael Ellerman2babf5c2006-05-17 18:00:46 +1000744 /* mem=x on the command line is the preferred mechanism */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100745 lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000746 if (lprop)
747 memory_limit = *lprop;
748
749#ifdef CONFIG_PPC64
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100750 lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000751 if (lprop)
752 tce_alloc_start = *lprop;
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100753 lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000754 if (lprop)
755 tce_alloc_end = *lprop;
756#endif
757
Michael Ellermandcee3032005-12-04 18:39:48 +1100758#ifdef CONFIG_KEXEC
Stephen Rothwell63277162009-01-06 13:54:25 +0000759 lprop = of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
Linas Vepstas70c6cc32007-09-07 03:46:15 +1000760 if (lprop)
761 crashk_res.start = *lprop;
Michael Ellermandcee3032005-12-04 18:39:48 +1100762
Stephen Rothwell63277162009-01-06 13:54:25 +0000763 lprop = of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL);
Linas Vepstas70c6cc32007-09-07 03:46:15 +1000764 if (lprop)
765 crashk_res.end = crashk_res.start + *lprop - 1;
Michael Ellermandcee3032005-12-04 18:39:48 +1100766#endif
767
Michael Ellerman40472a52007-05-10 17:06:30 +1000768 early_init_dt_check_for_initrd(node);
David Gibson30437b32007-02-28 14:12:29 +1100769
Kumar Gala329dda02006-02-24 10:54:52 -0600770 /* Retreive command line */
771 p = of_get_flat_dt_prop(node, "bootargs", &l);
772 if (p != NULL && l > 0)
773 strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
774
775#ifdef CONFIG_CMDLINE
Geoff Levandc1ce4642006-10-05 11:35:16 -0700776 if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
Kumar Gala329dda02006-02-24 10:54:52 -0600777 strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
778#endif /* CONFIG_CMDLINE */
779
780 DBG("Command line is: %s\n", cmd_line);
781
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000782 /* break now */
783 return 1;
784}
785
786static int __init early_init_dt_scan_root(unsigned long node,
787 const char *uname, int depth, void *data)
788{
789 u32 *prop;
790
791 if (depth != 0)
792 return 0;
793
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100794 prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000795 dt_root_size_cells = (prop == NULL) ? 1 : *prop;
796 DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
797
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100798 prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000799 dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
800 DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
801
802 /* break now */
803 return 1;
804}
805
Becky Bruceabe76882008-02-16 05:17:14 +1100806static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000807{
808 cell_t *p = *cellp;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000809
Paul Mackerrasa4dc7ff2006-09-19 14:06:27 +1000810 *cellp = p + s;
Becky Bruceabe76882008-02-16 05:17:14 +1100811 return of_read_number(p, s);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000812}
813
Paul Mackerras02045682006-11-29 22:27:42 +1100814#ifdef CONFIG_PPC_PSERIES
815/*
816 * Interpret the ibm,dynamic-memory property in the
817 * /ibm,dynamic-reconfiguration-memory node.
818 * This contains a list of memory blocks along with NUMA affinity
819 * information.
820 */
821static int __init early_init_dt_scan_drconf_memory(unsigned long node)
822{
Chandrucf000852008-08-30 00:28:16 +1000823 cell_t *dm, *ls, *usm;
Becky Bruceabe76882008-02-16 05:17:14 +1100824 unsigned long l, n, flags;
825 u64 base, size, lmb_size;
Chandrucf000852008-08-30 00:28:16 +1000826 unsigned int is_kexec_kdump = 0, rngs;
Paul Mackerras02045682006-11-29 22:27:42 +1100827
Stephen Rothwell63277162009-01-06 13:54:25 +0000828 ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
Paul Mackerras02045682006-11-29 22:27:42 +1100829 if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
830 return 0;
831 lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
832
Stephen Rothwell63277162009-01-06 13:54:25 +0000833 dm = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
Paul Mackerras02045682006-11-29 22:27:42 +1100834 if (dm == NULL || l < sizeof(cell_t))
835 return 0;
836
837 n = *dm++; /* number of entries */
838 if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
839 return 0;
840
Chandrucf000852008-08-30 00:28:16 +1000841 /* check if this is a kexec/kdump kernel. */
Stephen Rothwell63277162009-01-06 13:54:25 +0000842 usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
Chandrucf000852008-08-30 00:28:16 +1000843 &l);
844 if (usm != NULL)
845 is_kexec_kdump = 1;
846
Paul Mackerras02045682006-11-29 22:27:42 +1100847 for (; n != 0; --n) {
848 base = dt_mem_next_cell(dt_root_addr_cells, &dm);
849 flags = dm[3];
850 /* skip DRC index, pad, assoc. list index, flags */
851 dm += 4;
852 /* skip this block if the reserved bit is set in flags (0x80)
853 or if the block is not assigned to this partition (0x8) */
854 if ((flags & 0x80) || !(flags & 0x8))
855 continue;
856 size = lmb_size;
Chandrucf000852008-08-30 00:28:16 +1000857 rngs = 1;
858 if (is_kexec_kdump) {
859 /*
860 * For each lmb in ibm,dynamic-memory, a corresponding
861 * entry in linux,drconf-usable-memory property contains
862 * a counter 'p' followed by 'p' (base, size) duple.
863 * Now read the counter from
864 * linux,drconf-usable-memory property
865 */
866 rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
867 if (!rngs) /* there are no (base, size) duple */
Paul Mackerras02045682006-11-29 22:27:42 +1100868 continue;
Paul Mackerras02045682006-11-29 22:27:42 +1100869 }
Chandrucf000852008-08-30 00:28:16 +1000870 do {
871 if (is_kexec_kdump) {
872 base = dt_mem_next_cell(dt_root_addr_cells,
873 &usm);
874 size = dt_mem_next_cell(dt_root_size_cells,
875 &usm);
876 }
877 if (iommu_is_off) {
878 if (base >= 0x80000000ul)
879 continue;
880 if ((base + size) > 0x80000000ul)
881 size = 0x80000000ul - base;
882 }
883 lmb_add(base, size);
884 } while (--rngs);
Paul Mackerras02045682006-11-29 22:27:42 +1100885 }
886 lmb_dump_all();
887 return 0;
888}
889#else
890#define early_init_dt_scan_drconf_memory(node) 0
891#endif /* CONFIG_PPC_PSERIES */
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000892
893static int __init early_init_dt_scan_memory(unsigned long node,
894 const char *uname, int depth, void *data)
895{
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +1100896 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000897 cell_t *reg, *endp;
898 unsigned long l;
899
Paul Mackerras02045682006-11-29 22:27:42 +1100900 /* Look for the ibm,dynamic-reconfiguration-memory node */
901 if (depth == 1 &&
902 strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
903 return early_init_dt_scan_drconf_memory(node);
904
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000905 /* We are scanning "memory" nodes only */
Paul Mackerrasa23414b2005-11-10 12:00:55 +1100906 if (type == NULL) {
907 /*
908 * The longtrail doesn't have a device_type on the
909 * /memory node, so look for the node called /memory@0.
910 */
911 if (depth != 1 || strcmp(uname, "memory@0") != 0)
912 return 0;
913 } else if (strcmp(type, "memory") != 0)
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000914 return 0;
915
Stephen Rothwell63277162009-01-06 13:54:25 +0000916 reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
Michael Ellermanba759482005-12-04 18:39:55 +1100917 if (reg == NULL)
Stephen Rothwell63277162009-01-06 13:54:25 +0000918 reg = of_get_flat_dt_prop(node, "reg", &l);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000919 if (reg == NULL)
920 return 0;
921
922 endp = reg + (l / sizeof(cell_t));
923
Michael Ellerman358c86f2005-11-03 15:39:09 +1100924 DBG("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000925 uname, l, reg[0], reg[1], reg[2], reg[3]);
926
927 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
Becky Bruceabe76882008-02-16 05:17:14 +1100928 u64 base, size;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000929
930 base = dt_mem_next_cell(dt_root_addr_cells, &reg);
931 size = dt_mem_next_cell(dt_root_size_cells, &reg);
932
933 if (size == 0)
934 continue;
Becky Bruceabe76882008-02-16 05:17:14 +1100935 DBG(" - %llx , %llx\n", (unsigned long long)base,
936 (unsigned long long)size);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000937#ifdef CONFIG_PPC64
938 if (iommu_is_off) {
939 if (base >= 0x80000000ul)
940 continue;
941 if ((base + size) > 0x80000000ul)
942 size = 0x80000000ul - base;
943 }
944#endif
945 lmb_add(base, size);
Kumar Gala37dd2ba2008-04-22 04:22:34 +1000946
947 memstart_addr = min((u64)memstart_addr, base);
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000948 }
Kumar Gala37dd2ba2008-04-22 04:22:34 +1000949
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000950 return 0;
951}
952
953static void __init early_reserve_mem(void)
954{
Kumar Galacbbcf342006-01-11 17:57:13 -0600955 u64 base, size;
956 u64 *reserve_map;
Jon Loeliger8a300882006-06-17 17:51:09 -0500957 unsigned long self_base;
958 unsigned long self_size;
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000959
Kumar Galacbbcf342006-01-11 17:57:13 -0600960 reserve_map = (u64 *)(((unsigned long)initial_boot_params) +
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000961 initial_boot_params->off_mem_rsvmap);
Jimi Xenidis4d1f3f22006-05-18 17:03:05 -0500962
963 /* before we do anything, lets reserve the dt blob */
Jon Loeliger8a300882006-06-17 17:51:09 -0500964 self_base = __pa((unsigned long)initial_boot_params);
965 self_size = initial_boot_params->totalsize;
966 lmb_reserve(self_base, self_size);
Jimi Xenidis4d1f3f22006-05-18 17:03:05 -0500967
David Gibson30437b32007-02-28 14:12:29 +1100968#ifdef CONFIG_BLK_DEV_INITRD
969 /* then reserve the initrd, if any */
970 if (initrd_start && (initrd_end > initrd_start))
971 lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
972#endif /* CONFIG_BLK_DEV_INITRD */
973
Kumar Galacbbcf342006-01-11 17:57:13 -0600974#ifdef CONFIG_PPC32
975 /*
976 * Handle the case where we might be booting from an old kexec
977 * image that setup the mem_rsvmap as pairs of 32-bit values
978 */
979 if (*reserve_map > 0xffffffffull) {
980 u32 base_32, size_32;
981 u32 *reserve_map_32 = (u32 *)reserve_map;
982
983 while (1) {
984 base_32 = *(reserve_map_32++);
985 size_32 = *(reserve_map_32++);
986 if (size_32 == 0)
987 break;
Jon Loeliger8a300882006-06-17 17:51:09 -0500988 /* skip if the reservation is for the blob */
989 if (base_32 == self_base && size_32 == self_size)
990 continue;
Kumar Gala329dda02006-02-24 10:54:52 -0600991 DBG("reserving: %x -> %x\n", base_32, size_32);
Kumar Galacbbcf342006-01-11 17:57:13 -0600992 lmb_reserve(base_32, size_32);
993 }
994 return;
995 }
996#endif
Paul Mackerras9b6b5632005-10-06 12:06:20 +1000997 while (1) {
998 base = *(reserve_map++);
999 size = *(reserve_map++);
1000 if (size == 0)
1001 break;
Kumar Galacbbcf342006-01-11 17:57:13 -06001002 DBG("reserving: %llx -> %llx\n", base, size);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001003 lmb_reserve(base, size);
1004 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001005}
1006
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001007#ifdef CONFIG_PHYP_DUMP
1008/**
Manish Ahuja37ddd5d2008-04-12 09:31:52 +10001009 * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg
1010 *
1011 * Function to find the largest size we need to reserve
1012 * during early boot process.
1013 *
1014 * It either looks for boot param and returns that OR
1015 * returns larger of 256 or 5% rounded down to multiples of 256MB.
1016 *
1017 */
1018static inline unsigned long phyp_dump_calculate_reserve_size(void)
1019{
1020 unsigned long tmp;
1021
1022 if (phyp_dump_info->reserve_bootvar)
1023 return phyp_dump_info->reserve_bootvar;
1024
1025 /* divide by 20 to get 5% of value */
1026 tmp = lmb_end_of_DRAM();
1027 do_div(tmp, 20);
1028
1029 /* round it down in multiples of 256 */
1030 tmp = tmp & ~0x0FFFFFFFUL;
1031
1032 return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END);
1033}
1034
1035/**
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001036 * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
1037 *
1038 * This routine may reserve memory regions in the kernel only
1039 * if the system is supported and a dump was taken in last
1040 * boot instance or if the hardware is supported and the
1041 * scratch area needs to be setup. In other instances it returns
1042 * without reserving anything. The memory in case of dump being
1043 * active is freed when the dump is collected (by userland tools).
1044 */
1045static void __init phyp_dump_reserve_mem(void)
1046{
1047 unsigned long base, size;
Manish Ahuja37ddd5d2008-04-12 09:31:52 +10001048 unsigned long variable_reserve_size;
1049
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001050 if (!phyp_dump_info->phyp_dump_configured) {
1051 printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
1052 return;
1053 }
1054
Manish Ahuja654f5962008-03-22 11:38:59 +11001055 if (!phyp_dump_info->phyp_dump_at_boot) {
1056 printk(KERN_INFO "Phyp-dump disabled at boot time\n");
1057 return;
1058 }
1059
Manish Ahuja37ddd5d2008-04-12 09:31:52 +10001060 variable_reserve_size = phyp_dump_calculate_reserve_size();
1061
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001062 if (phyp_dump_info->phyp_dump_is_active) {
1063 /* Reserve *everything* above RMR.Area freed by userland tools*/
Manish Ahuja37ddd5d2008-04-12 09:31:52 +10001064 base = variable_reserve_size;
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001065 size = lmb_end_of_DRAM() - base;
1066
1067 /* XXX crashed_ram_end is wrong, since it may be beyond
1068 * the memory_limit, it will need to be adjusted. */
1069 lmb_reserve(base, size);
1070
1071 phyp_dump_info->init_reserve_start = base;
1072 phyp_dump_info->init_reserve_size = size;
1073 } else {
1074 size = phyp_dump_info->cpu_state_size +
1075 phyp_dump_info->hpte_region_size +
Manish Ahuja37ddd5d2008-04-12 09:31:52 +10001076 variable_reserve_size;
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001077 base = lmb_end_of_DRAM() - size;
1078 lmb_reserve(base, size);
1079 phyp_dump_info->init_reserve_start = base;
1080 phyp_dump_info->init_reserve_size = size;
1081 }
1082}
1083#else
1084static inline void __init phyp_dump_reserve_mem(void) {}
1085#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */
1086
1087
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001088void __init early_init_devtree(void *params)
1089{
Becky Bruce49a84962009-05-08 12:19:27 +00001090 phys_addr_t limit;
Hollis Blanchard6ca4f742008-11-26 10:19:26 -06001091
Geoff Levand44348102007-06-16 08:06:14 +10001092 DBG(" -> early_init_devtree(%p)\n", params);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001093
1094 /* Setup flat device-tree pointer */
1095 initial_boot_params = params;
1096
Michael Ellerman458148c2006-06-23 18:20:13 +10001097#ifdef CONFIG_PPC_RTAS
1098 /* Some machines might need RTAS info for debugging, grab it now. */
1099 of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
1100#endif
1101
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001102#ifdef CONFIG_PHYP_DUMP
1103 /* scan tree to see if dump occured during last boot */
1104 of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
1105#endif
1106
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001107 /* Retrieve various informations from the /chosen node of the
1108 * device-tree, including the platform type, initrd location and
1109 * size, TCE reserve, and more ...
1110 */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +11001111 of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001112
1113 /* Scan memory nodes and rebuild LMBs */
1114 lmb_init();
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +11001115 of_scan_flat_dt(early_init_dt_scan_root, NULL);
1116 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
Michael Ellerman846f77b2006-05-17 18:00:45 +10001117
1118 /* Save command line for /proc/cmdline and then parse parameters */
Alon Bar-Levb8757b22007-02-12 00:54:17 -08001119 strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
Michael Ellerman846f77b2006-05-17 18:00:45 +10001120 parse_early_param();
1121
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001122 /* Reserve LMB regions used by kernel, initrd, dt, etc... */
Michael Ellerman0cc47462005-12-04 18:39:37 +11001123 lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
Paul Mackerras549e8152008-08-30 11:43:47 +10001124 /* If relocatable, reserve first 32k for interrupt vectors etc. */
1125 if (PHYSICAL_START > MEMORY_START)
1126 lmb_reserve(MEMORY_START, 0x8000);
Michael Ellerman47310412006-05-17 18:00:49 +10001127 reserve_kdump_trampoline();
Michael Ellerman35dd5432006-05-18 11:16:11 +10001128 reserve_crashkernel();
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001129 early_reserve_mem();
Manish Ahuja6ac26c82008-03-22 10:37:08 +11001130 phyp_dump_reserve_mem();
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001131
Hollis Blanchard6ca4f742008-11-26 10:19:26 -06001132 limit = memory_limit;
1133 if (! limit) {
Becky Bruce49a84962009-05-08 12:19:27 +00001134 phys_addr_t memsize;
Hollis Blanchard6ca4f742008-11-26 10:19:26 -06001135
1136 /* Ensure that total memory size is page-aligned, because
1137 * otherwise mark_bootmem() gets upset. */
1138 lmb_analyze();
1139 memsize = lmb_phys_mem_size();
1140 if ((memsize & PAGE_MASK) != memsize)
1141 limit = memsize & PAGE_MASK;
1142 }
1143 lmb_enforce_memory_limit(limit);
1144
Michael Ellerman2babf5c2006-05-17 18:00:46 +10001145 lmb_analyze();
Michael Ellerman059f1342009-01-14 20:46:01 +00001146 lmb_dump_all();
Michael Ellerman2babf5c2006-05-17 18:00:46 +10001147
Becky Bruce49a84962009-05-08 12:19:27 +00001148 DBG("Phys. mem: %llx\n", lmb_phys_mem_size());
Michael Ellerman2babf5c2006-05-17 18:00:46 +10001149
1150 /* We may need to relocate the flat tree, do it now.
1151 * FIXME .. and the initrd too? */
1152 move_device_tree();
1153
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001154 DBG("Scanning CPUs ...\n");
1155
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +11001156 /* Retreive CPU related informations from the flat tree
1157 * (altivec support, boot CPU ID, ...)
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001158 */
Benjamin Herrenschmidt3c726f82005-11-07 11:06:55 +11001159 of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001160
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001161 DBG(" <- early_init_devtree()\n");
1162}
1163
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001164
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001165/**
1166 * Indicates whether the root node has a given value in its
1167 * compatible property.
1168 */
1169int machine_is_compatible(const char *compat)
1170{
1171 struct device_node *root;
1172 int rc = 0;
1173
1174 root = of_find_node_by_path("/");
1175 if (root) {
Stephen Rothwell7a92f742007-04-03 10:55:39 +10001176 rc = of_device_is_compatible(root, compat);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001177 of_node_put(root);
1178 }
1179 return rc;
1180}
1181EXPORT_SYMBOL(machine_is_compatible);
1182
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001183/*******
1184 *
1185 * New implementation of the OF "find" APIs, return a refcounted
1186 * object, call of_node_put() when done. The device tree and list
1187 * are protected by a rw_lock.
1188 *
1189 * Note that property management will need some locking as well,
1190 * this isn't dealt with yet.
1191 *
1192 *******/
1193
1194/**
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001195 * of_find_node_by_phandle - Find a node given a phandle
1196 * @handle: phandle of the node to find
1197 *
1198 * Returns a node pointer with refcount incremented, use
1199 * of_node_put() on it when done.
1200 */
1201struct device_node *of_find_node_by_phandle(phandle handle)
1202{
1203 struct device_node *np;
1204
1205 read_lock(&devtree_lock);
1206 for (np = allnodes; np != 0; np = np->allnext)
1207 if (np->linux_phandle == handle)
1208 break;
Mariusz Kozlowskib13740512007-01-02 12:31:47 +01001209 of_node_get(np);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001210 read_unlock(&devtree_lock);
1211 return np;
1212}
1213EXPORT_SYMBOL(of_find_node_by_phandle);
1214
1215/**
Nathan Lynche523f722008-12-10 14:46:04 +00001216 * of_find_next_cache_node - Find a node's subsidiary cache
1217 * @np: node of type "cpu" or "cache"
1218 *
1219 * Returns a node pointer with refcount incremented, use
1220 * of_node_put() on it when done. Caller should hold a reference
1221 * to np.
1222 */
1223struct device_node *of_find_next_cache_node(struct device_node *np)
1224{
1225 struct device_node *child;
1226 const phandle *handle;
1227
1228 handle = of_get_property(np, "l2-cache", NULL);
1229 if (!handle)
1230 handle = of_get_property(np, "next-level-cache", NULL);
1231
1232 if (handle)
1233 return of_find_node_by_phandle(*handle);
1234
1235 /* OF on pmac has nodes instead of properties named "l2-cache"
1236 * beneath CPU nodes.
1237 */
1238 if (!strcmp(np->type, "cpu"))
1239 for_each_child_of_node(np, child)
1240 if (!strcmp(child->type, "cache"))
1241 return child;
1242
1243 return NULL;
1244}
1245
1246/**
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001247 * of_node_get - Increment refcount of a node
1248 * @node: Node to inc refcount, NULL is supported to
1249 * simplify writing of callers
1250 *
1251 * Returns node.
1252 */
1253struct device_node *of_node_get(struct device_node *node)
1254{
1255 if (node)
1256 kref_get(&node->kref);
1257 return node;
1258}
1259EXPORT_SYMBOL(of_node_get);
1260
1261static inline struct device_node * kref_to_device_node(struct kref *kref)
1262{
1263 return container_of(kref, struct device_node, kref);
1264}
1265
1266/**
1267 * of_node_release - release a dynamically allocated node
1268 * @kref: kref element of the node to be released
1269 *
1270 * In of_node_put() this function is passed to kref_put()
1271 * as the destructor.
1272 */
1273static void of_node_release(struct kref *kref)
1274{
1275 struct device_node *node = kref_to_device_node(kref);
1276 struct property *prop = node->properties;
1277
Michael Ellerman6a2818562007-06-19 16:08:00 +10001278 /* We should never be releasing nodes that haven't been detached. */
1279 if (!of_node_check_flag(node, OF_DETACHED)) {
1280 printk("WARNING: Bad of_node_put() on %s\n", node->full_name);
1281 dump_stack();
1282 kref_init(&node->kref);
1283 return;
1284 }
1285
Michael Ellermand3b814b2007-06-19 16:07:58 +10001286 if (!of_node_check_flag(node, OF_DYNAMIC))
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001287 return;
Michael Ellerman6a2818562007-06-19 16:08:00 +10001288
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001289 while (prop) {
1290 struct property *next = prop->next;
1291 kfree(prop->name);
1292 kfree(prop->value);
1293 kfree(prop);
1294 prop = next;
Dave C Boutcher088186d2006-01-12 16:08:27 -06001295
1296 if (!prop) {
1297 prop = node->deadprops;
1298 node->deadprops = NULL;
1299 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001300 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001301 kfree(node->full_name);
1302 kfree(node->data);
1303 kfree(node);
1304}
1305
1306/**
1307 * of_node_put - Decrement refcount of a node
1308 * @node: Node to dec refcount, NULL is supported to
1309 * simplify writing of callers
1310 *
1311 */
1312void of_node_put(struct device_node *node)
1313{
1314 if (node)
1315 kref_put(&node->kref, of_node_release);
1316}
1317EXPORT_SYMBOL(of_node_put);
1318
1319/*
1320 * Plug a device node into the tree and global list.
1321 */
1322void of_attach_node(struct device_node *np)
1323{
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001324 unsigned long flags;
1325
1326 write_lock_irqsave(&devtree_lock, flags);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001327 np->sibling = np->parent->child;
1328 np->allnext = allnodes;
1329 np->parent->child = np;
1330 allnodes = np;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001331 write_unlock_irqrestore(&devtree_lock, flags);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001332}
1333
1334/*
1335 * "Unplug" a node from the device tree. The caller must hold
1336 * a reference to the node. The memory associated with the node
1337 * is not freed until its refcount goes to zero.
1338 */
Segher Boessenkool34f329d2007-07-20 15:58:38 +10001339void of_detach_node(struct device_node *np)
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001340{
1341 struct device_node *parent;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001342 unsigned long flags;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001343
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001344 write_lock_irqsave(&devtree_lock, flags);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001345
1346 parent = np->parent;
Michael Ellerman972d17c2007-06-19 16:07:56 +10001347 if (!parent)
1348 goto out_unlock;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001349
1350 if (allnodes == np)
1351 allnodes = np->allnext;
1352 else {
1353 struct device_node *prev;
1354 for (prev = allnodes;
1355 prev->allnext != np;
1356 prev = prev->allnext)
1357 ;
1358 prev->allnext = np->allnext;
1359 }
1360
1361 if (parent->child == np)
1362 parent->child = np->sibling;
1363 else {
1364 struct device_node *prevsib;
1365 for (prevsib = np->parent->child;
1366 prevsib->sibling != np;
1367 prevsib = prevsib->sibling)
1368 ;
1369 prevsib->sibling = np->sibling;
1370 }
1371
Michael Ellerman6a2818562007-06-19 16:08:00 +10001372 of_node_set_flag(np, OF_DETACHED);
1373
Michael Ellerman972d17c2007-06-19 16:07:56 +10001374out_unlock:
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001375 write_unlock_irqrestore(&devtree_lock, flags);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001376}
1377
1378#ifdef CONFIG_PPC_PSERIES
1379/*
1380 * Fix up the uninitialized fields in a new device node:
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +10001381 * name, type and pci-specific fields
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001382 */
1383
Benjamin Herrenschmidtcc5d0182005-12-13 18:01:21 +11001384static int of_finish_dynamic_node(struct device_node *node)
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001385{
1386 struct device_node *parent = of_get_parent(node);
1387 int err = 0;
Jeremy Kerra7f67bd2006-07-12 15:35:54 +10001388 const phandle *ibm_phandle;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001389
Stephen Rothwell0e56efc2007-04-03 10:54:01 +10001390 node->name = of_get_property(node, "name", NULL);
1391 node->type = of_get_property(node, "device_type", NULL);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001392
Benjamin Herrenschmidt847f5972007-05-16 16:57:24 +10001393 if (!node->name)
1394 node->name = "<NULL>";
1395 if (!node->type)
1396 node->type = "<NULL>";
1397
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001398 if (!parent) {
1399 err = -ENODEV;
1400 goto out;
1401 }
1402
1403 /* We don't support that function on PowerMac, at least
1404 * not yet
1405 */
Benjamin Herrenschmidte8222502006-03-28 23:15:54 +11001406 if (machine_is(powermac))
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001407 return -ENODEV;
1408
1409 /* fix up new node's linux_phandle field */
Stephen Rothwell0e56efc2007-04-03 10:54:01 +10001410 if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001411 node->linux_phandle = *ibm_phandle;
1412
1413out:
1414 of_node_put(parent);
1415 return err;
1416}
1417
1418static int prom_reconfig_notifier(struct notifier_block *nb,
1419 unsigned long action, void *node)
1420{
1421 int err;
1422
1423 switch (action) {
1424 case PSERIES_RECONFIG_ADD:
Benjamin Herrenschmidtcc5d0182005-12-13 18:01:21 +11001425 err = of_finish_dynamic_node(node);
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001426 if (err < 0) {
1427 printk(KERN_ERR "finish_node returned %d\n", err);
1428 err = NOTIFY_BAD;
1429 }
1430 break;
1431 default:
1432 err = NOTIFY_DONE;
1433 break;
1434 }
1435 return err;
1436}
1437
1438static struct notifier_block prom_reconfig_nb = {
1439 .notifier_call = prom_reconfig_notifier,
1440 .priority = 10, /* This one needs to run first */
1441};
1442
1443static int __init prom_reconfig_setup(void)
1444{
1445 return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
1446}
1447__initcall(prom_reconfig_setup);
1448#endif
1449
Dave C Boutcherecaa8b02006-01-12 16:09:29 -06001450/*
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001451 * Add a property to a node
1452 */
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001453int prom_add_property(struct device_node* np, struct property* prop)
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001454{
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001455 struct property **next;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001456 unsigned long flags;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001457
1458 prop->next = NULL;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001459 write_lock_irqsave(&devtree_lock, flags);
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001460 next = &np->properties;
1461 while (*next) {
1462 if (strcmp(prop->name, (*next)->name) == 0) {
1463 /* duplicate ! don't insert it */
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001464 write_unlock_irqrestore(&devtree_lock, flags);
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001465 return -1;
1466 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001467 next = &(*next)->next;
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001468 }
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001469 *next = prop;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001470 write_unlock_irqrestore(&devtree_lock, flags);
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001471
Paul Mackerras799d6042005-11-10 13:37:51 +11001472#ifdef CONFIG_PROC_DEVICETREE
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001473 /* try to add to proc as well if it was initialized */
1474 if (np->pde)
1475 proc_device_tree_add_prop(np->pde, prop);
Paul Mackerras799d6042005-11-10 13:37:51 +11001476#endif /* CONFIG_PROC_DEVICETREE */
Benjamin Herrenschmidt183d0202005-11-07 14:29:02 +11001477
1478 return 0;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001479}
1480
Dave C Boutcher088186d2006-01-12 16:08:27 -06001481/*
1482 * Remove a property from a node. Note that we don't actually
1483 * remove it, since we have given out who-knows-how-many pointers
1484 * to the data using get-property. Instead we just move the property
1485 * to the "dead properties" list, so it won't be found any more.
1486 */
1487int prom_remove_property(struct device_node *np, struct property *prop)
1488{
1489 struct property **next;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001490 unsigned long flags;
Dave C Boutcher088186d2006-01-12 16:08:27 -06001491 int found = 0;
Paul Mackerras9b6b5632005-10-06 12:06:20 +10001492
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001493 write_lock_irqsave(&devtree_lock, flags);
Dave C Boutcher088186d2006-01-12 16:08:27 -06001494 next = &np->properties;
1495 while (*next) {
1496 if (*next == prop) {
1497 /* found the node */
1498 *next = prop->next;
1499 prop->next = np->deadprops;
1500 np->deadprops = prop;
1501 found = 1;
1502 break;
1503 }
1504 next = &(*next)->next;
1505 }
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001506 write_unlock_irqrestore(&devtree_lock, flags);
Dave C Boutcher088186d2006-01-12 16:08:27 -06001507
1508 if (!found)
1509 return -ENODEV;
1510
1511#ifdef CONFIG_PROC_DEVICETREE
1512 /* try to remove the proc node as well */
1513 if (np->pde)
1514 proc_device_tree_remove_prop(np->pde, prop);
1515#endif /* CONFIG_PROC_DEVICETREE */
1516
1517 return 0;
1518}
1519
1520/*
1521 * Update a property in a node. Note that we don't actually
1522 * remove it, since we have given out who-knows-how-many pointers
1523 * to the data using get-property. Instead we just move the property
1524 * to the "dead properties" list, and add the new property to the
1525 * property list
1526 */
1527int prom_update_property(struct device_node *np,
1528 struct property *newprop,
1529 struct property *oldprop)
1530{
1531 struct property **next;
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001532 unsigned long flags;
Dave C Boutcher088186d2006-01-12 16:08:27 -06001533 int found = 0;
1534
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001535 write_lock_irqsave(&devtree_lock, flags);
Dave C Boutcher088186d2006-01-12 16:08:27 -06001536 next = &np->properties;
1537 while (*next) {
1538 if (*next == oldprop) {
1539 /* found the node */
1540 newprop->next = oldprop->next;
1541 *next = newprop;
1542 oldprop->next = np->deadprops;
1543 np->deadprops = oldprop;
1544 found = 1;
1545 break;
1546 }
1547 next = &(*next)->next;
1548 }
Benjamin Herrenschmidtf4ac7b5e2008-04-09 17:21:36 +10001549 write_unlock_irqrestore(&devtree_lock, flags);
Dave C Boutcher088186d2006-01-12 16:08:27 -06001550
1551 if (!found)
1552 return -ENODEV;
1553
1554#ifdef CONFIG_PROC_DEVICETREE
1555 /* try to add to proc as well if it was initialized */
1556 if (np->pde)
1557 proc_device_tree_update_prop(np->pde, newprop, oldprop);
1558#endif /* CONFIG_PROC_DEVICETREE */
1559
1560 return 0;
1561}
Michael Ellermanb68239e2006-02-03 19:05:47 +11001562
Benjamin Herrenschmidtacf7d762006-06-19 20:33:16 +02001563
1564/* Find the device node for a given logical cpu number, also returns the cpu
1565 * local thread number (index in ibm,interrupt-server#s) if relevant and
1566 * asked for (non NULL)
1567 */
1568struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
1569{
1570 int hardid;
1571 struct device_node *np;
1572
1573 hardid = get_hard_smp_processor_id(cpu);
1574
1575 for_each_node_by_type(np, "cpu") {
Jeremy Kerra7f67bd2006-07-12 15:35:54 +10001576 const u32 *intserv;
Benjamin Herrenschmidtacf7d762006-06-19 20:33:16 +02001577 unsigned int plen, t;
1578
1579 /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
1580 * fallback to "reg" property and assume no threads
1581 */
Stephen Rothwell0e56efc2007-04-03 10:54:01 +10001582 intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
Jeremy Kerra7f67bd2006-07-12 15:35:54 +10001583 &plen);
Benjamin Herrenschmidtacf7d762006-06-19 20:33:16 +02001584 if (intserv == NULL) {
Stephen Rothwell0e56efc2007-04-03 10:54:01 +10001585 const u32 *reg = of_get_property(np, "reg", NULL);
Benjamin Herrenschmidtacf7d762006-06-19 20:33:16 +02001586 if (reg == NULL)
1587 continue;
1588 if (*reg == hardid) {
1589 if (thread)
1590 *thread = 0;
1591 return np;
1592 }
1593 } else {
1594 plen /= sizeof(u32);
1595 for (t = 0; t < plen; t++) {
1596 if (hardid == intserv[t]) {
1597 if (thread)
1598 *thread = t;
1599 return np;
1600 }
1601 }
1602 }
1603 }
1604 return NULL;
1605}
Christian Krafft36ca4ba2006-10-24 18:39:45 +02001606EXPORT_SYMBOL(of_get_cpu_node);
Michael Ellerman7a4571a2006-06-23 18:16:03 +10001607
Michael Ellerman94a38072007-06-20 10:54:19 +10001608#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
Michael Ellerman7a4571a2006-06-23 18:16:03 +10001609static struct debugfs_blob_wrapper flat_dt_blob;
1610
1611static int __init export_flat_device_tree(void)
1612{
1613 struct dentry *d;
1614
Michael Ellerman7a4571a2006-06-23 18:16:03 +10001615 flat_dt_blob.data = initial_boot_params;
1616 flat_dt_blob.size = initial_boot_params->totalsize;
1617
1618 d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
Michael Ellerman94a38072007-06-20 10:54:19 +10001619 powerpc_debugfs_root, &flat_dt_blob);
Michael Ellerman7a4571a2006-06-23 18:16:03 +10001620 if (!d)
1621 return 1;
1622
1623 return 0;
1624}
1625__initcall(export_flat_device_tree);
1626#endif