diff options
Diffstat (limited to 'arch/sparc/kernel/prom_64.c')
-rw-r--r-- | arch/sparc/kernel/prom_64.c | 1684 |
1 files changed, 1684 insertions, 0 deletions
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c new file mode 100644 index 000000000000..dbba82f9b142 --- /dev/null +++ b/arch/sparc/kernel/prom_64.c | |||
@@ -0,0 +1,1684 @@ | |||
1 | /* | ||
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 | * Adapted for sparc64 by David S. Miller davem@davemloft.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/types.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/lmb.h> | ||
24 | #include <linux/of_device.h> | ||
25 | |||
26 | #include <asm/prom.h> | ||
27 | #include <asm/oplib.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/asi.h> | ||
30 | #include <asm/upa.h> | ||
31 | #include <asm/smp.h> | ||
32 | |||
33 | extern struct device_node *allnodes; /* temporary while merging */ | ||
34 | |||
35 | extern rwlock_t devtree_lock; /* temporary while merging */ | ||
36 | |||
37 | struct device_node *of_find_node_by_phandle(phandle handle) | ||
38 | { | ||
39 | struct device_node *np; | ||
40 | |||
41 | for (np = allnodes; np; np = np->allnext) | ||
42 | if (np->node == handle) | ||
43 | break; | ||
44 | |||
45 | return np; | ||
46 | } | ||
47 | EXPORT_SYMBOL(of_find_node_by_phandle); | ||
48 | |||
49 | int of_getintprop_default(struct device_node *np, const char *name, int def) | ||
50 | { | ||
51 | struct property *prop; | ||
52 | int len; | ||
53 | |||
54 | prop = of_find_property(np, name, &len); | ||
55 | if (!prop || len != 4) | ||
56 | return def; | ||
57 | |||
58 | return *(int *) prop->value; | ||
59 | } | ||
60 | EXPORT_SYMBOL(of_getintprop_default); | ||
61 | |||
62 | DEFINE_MUTEX(of_set_property_mutex); | ||
63 | EXPORT_SYMBOL(of_set_property_mutex); | ||
64 | |||
65 | int of_set_property(struct device_node *dp, const char *name, void *val, int len) | ||
66 | { | ||
67 | struct property **prevp; | ||
68 | void *new_val; | ||
69 | int err; | ||
70 | |||
71 | new_val = kmalloc(len, GFP_KERNEL); | ||
72 | if (!new_val) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | memcpy(new_val, val, len); | ||
76 | |||
77 | err = -ENODEV; | ||
78 | |||
79 | write_lock(&devtree_lock); | ||
80 | prevp = &dp->properties; | ||
81 | while (*prevp) { | ||
82 | struct property *prop = *prevp; | ||
83 | |||
84 | if (!strcasecmp(prop->name, name)) { | ||
85 | void *old_val = prop->value; | ||
86 | int ret; | ||
87 | |||
88 | mutex_lock(&of_set_property_mutex); | ||
89 | ret = prom_setprop(dp->node, name, val, len); | ||
90 | mutex_unlock(&of_set_property_mutex); | ||
91 | |||
92 | err = -EINVAL; | ||
93 | if (ret >= 0) { | ||
94 | prop->value = new_val; | ||
95 | prop->length = len; | ||
96 | |||
97 | if (OF_IS_DYNAMIC(prop)) | ||
98 | kfree(old_val); | ||
99 | |||
100 | OF_MARK_DYNAMIC(prop); | ||
101 | |||
102 | err = 0; | ||
103 | } | ||
104 | break; | ||
105 | } | ||
106 | prevp = &(*prevp)->next; | ||
107 | } | ||
108 | write_unlock(&devtree_lock); | ||
109 | |||
110 | /* XXX Upate procfs if necessary... */ | ||
111 | |||
112 | return err; | ||
113 | } | ||
114 | EXPORT_SYMBOL(of_set_property); | ||
115 | |||
116 | int of_find_in_proplist(const char *list, const char *match, int len) | ||
117 | { | ||
118 | while (len > 0) { | ||
119 | int l; | ||
120 | |||
121 | if (!strcmp(list, match)) | ||
122 | return 1; | ||
123 | l = strlen(list) + 1; | ||
124 | list += l; | ||
125 | len -= l; | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | EXPORT_SYMBOL(of_find_in_proplist); | ||
130 | |||
131 | static unsigned int prom_early_allocated __initdata; | ||
132 | |||
133 | static void * __init prom_early_alloc(unsigned long size) | ||
134 | { | ||
135 | unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES); | ||
136 | void *ret; | ||
137 | |||
138 | if (!paddr) { | ||
139 | prom_printf("prom_early_alloc(%lu) failed\n"); | ||
140 | prom_halt(); | ||
141 | } | ||
142 | |||
143 | ret = __va(paddr); | ||
144 | memset(ret, 0, size); | ||
145 | prom_early_allocated += size; | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | #ifdef CONFIG_PCI | ||
151 | /* PSYCHO interrupt mapping support. */ | ||
152 | #define PSYCHO_IMAP_A_SLOT0 0x0c00UL | ||
153 | #define PSYCHO_IMAP_B_SLOT0 0x0c20UL | ||
154 | static unsigned long psycho_pcislot_imap_offset(unsigned long ino) | ||
155 | { | ||
156 | unsigned int bus = (ino & 0x10) >> 4; | ||
157 | unsigned int slot = (ino & 0x0c) >> 2; | ||
158 | |||
159 | if (bus == 0) | ||
160 | return PSYCHO_IMAP_A_SLOT0 + (slot * 8); | ||
161 | else | ||
162 | return PSYCHO_IMAP_B_SLOT0 + (slot * 8); | ||
163 | } | ||
164 | |||
165 | #define PSYCHO_OBIO_IMAP_BASE 0x1000UL | ||
166 | |||
167 | #define PSYCHO_ONBOARD_IRQ_BASE 0x20 | ||
168 | #define psycho_onboard_imap_offset(__ino) \ | ||
169 | (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) | ||
170 | |||
171 | #define PSYCHO_ICLR_A_SLOT0 0x1400UL | ||
172 | #define PSYCHO_ICLR_SCSI 0x1800UL | ||
173 | |||
174 | #define psycho_iclr_offset(ino) \ | ||
175 | ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ | ||
176 | (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) | ||
177 | |||
178 | static unsigned int psycho_irq_build(struct device_node *dp, | ||
179 | unsigned int ino, | ||
180 | void *_data) | ||
181 | { | ||
182 | unsigned long controller_regs = (unsigned long) _data; | ||
183 | unsigned long imap, iclr; | ||
184 | unsigned long imap_off, iclr_off; | ||
185 | int inofixup = 0; | ||
186 | |||
187 | ino &= 0x3f; | ||
188 | if (ino < PSYCHO_ONBOARD_IRQ_BASE) { | ||
189 | /* PCI slot */ | ||
190 | imap_off = psycho_pcislot_imap_offset(ino); | ||
191 | } else { | ||
192 | /* Onboard device */ | ||
193 | imap_off = psycho_onboard_imap_offset(ino); | ||
194 | } | ||
195 | |||
196 | /* Now build the IRQ bucket. */ | ||
197 | imap = controller_regs + imap_off; | ||
198 | |||
199 | iclr_off = psycho_iclr_offset(ino); | ||
200 | iclr = controller_regs + iclr_off; | ||
201 | |||
202 | if ((ino & 0x20) == 0) | ||
203 | inofixup = ino & 0x03; | ||
204 | |||
205 | return build_irq(inofixup, iclr, imap); | ||
206 | } | ||
207 | |||
208 | static void __init psycho_irq_trans_init(struct device_node *dp) | ||
209 | { | ||
210 | const struct linux_prom64_registers *regs; | ||
211 | |||
212 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
213 | dp->irq_trans->irq_build = psycho_irq_build; | ||
214 | |||
215 | regs = of_get_property(dp, "reg", NULL); | ||
216 | dp->irq_trans->data = (void *) regs[2].phys_addr; | ||
217 | } | ||
218 | |||
219 | #define sabre_read(__reg) \ | ||
220 | ({ u64 __ret; \ | ||
221 | __asm__ __volatile__("ldxa [%1] %2, %0" \ | ||
222 | : "=r" (__ret) \ | ||
223 | : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ | ||
224 | : "memory"); \ | ||
225 | __ret; \ | ||
226 | }) | ||
227 | |||
228 | struct sabre_irq_data { | ||
229 | unsigned long controller_regs; | ||
230 | unsigned int pci_first_busno; | ||
231 | }; | ||
232 | #define SABRE_CONFIGSPACE 0x001000000UL | ||
233 | #define SABRE_WRSYNC 0x1c20UL | ||
234 | |||
235 | #define SABRE_CONFIG_BASE(CONFIG_SPACE) \ | ||
236 | (CONFIG_SPACE | (1UL << 24)) | ||
237 | #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ | ||
238 | (((unsigned long)(BUS) << 16) | \ | ||
239 | ((unsigned long)(DEVFN) << 8) | \ | ||
240 | ((unsigned long)(REG))) | ||
241 | |||
242 | /* When a device lives behind a bridge deeper in the PCI bus topology | ||
243 | * than APB, a special sequence must run to make sure all pending DMA | ||
244 | * transfers at the time of IRQ delivery are visible in the coherency | ||
245 | * domain by the cpu. This sequence is to perform a read on the far | ||
246 | * side of the non-APB bridge, then perform a read of Sabre's DMA | ||
247 | * write-sync register. | ||
248 | */ | ||
249 | static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) | ||
250 | { | ||
251 | unsigned int phys_hi = (unsigned int) (unsigned long) _arg1; | ||
252 | struct sabre_irq_data *irq_data = _arg2; | ||
253 | unsigned long controller_regs = irq_data->controller_regs; | ||
254 | unsigned long sync_reg = controller_regs + SABRE_WRSYNC; | ||
255 | unsigned long config_space = controller_regs + SABRE_CONFIGSPACE; | ||
256 | unsigned int bus, devfn; | ||
257 | u16 _unused; | ||
258 | |||
259 | config_space = SABRE_CONFIG_BASE(config_space); | ||
260 | |||
261 | bus = (phys_hi >> 16) & 0xff; | ||
262 | devfn = (phys_hi >> 8) & 0xff; | ||
263 | |||
264 | config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00); | ||
265 | |||
266 | __asm__ __volatile__("membar #Sync\n\t" | ||
267 | "lduha [%1] %2, %0\n\t" | ||
268 | "membar #Sync" | ||
269 | : "=r" (_unused) | ||
270 | : "r" ((u16 *) config_space), | ||
271 | "i" (ASI_PHYS_BYPASS_EC_E_L) | ||
272 | : "memory"); | ||
273 | |||
274 | sabre_read(sync_reg); | ||
275 | } | ||
276 | |||
277 | #define SABRE_IMAP_A_SLOT0 0x0c00UL | ||
278 | #define SABRE_IMAP_B_SLOT0 0x0c20UL | ||
279 | #define SABRE_ICLR_A_SLOT0 0x1400UL | ||
280 | #define SABRE_ICLR_B_SLOT0 0x1480UL | ||
281 | #define SABRE_ICLR_SCSI 0x1800UL | ||
282 | #define SABRE_ICLR_ETH 0x1808UL | ||
283 | #define SABRE_ICLR_BPP 0x1810UL | ||
284 | #define SABRE_ICLR_AU_REC 0x1818UL | ||
285 | #define SABRE_ICLR_AU_PLAY 0x1820UL | ||
286 | #define SABRE_ICLR_PFAIL 0x1828UL | ||
287 | #define SABRE_ICLR_KMS 0x1830UL | ||
288 | #define SABRE_ICLR_FLPY 0x1838UL | ||
289 | #define SABRE_ICLR_SHW 0x1840UL | ||
290 | #define SABRE_ICLR_KBD 0x1848UL | ||
291 | #define SABRE_ICLR_MS 0x1850UL | ||
292 | #define SABRE_ICLR_SER 0x1858UL | ||
293 | #define SABRE_ICLR_UE 0x1870UL | ||
294 | #define SABRE_ICLR_CE 0x1878UL | ||
295 | #define SABRE_ICLR_PCIERR 0x1880UL | ||
296 | |||
297 | static unsigned long sabre_pcislot_imap_offset(unsigned long ino) | ||
298 | { | ||
299 | unsigned int bus = (ino & 0x10) >> 4; | ||
300 | unsigned int slot = (ino & 0x0c) >> 2; | ||
301 | |||
302 | if (bus == 0) | ||
303 | return SABRE_IMAP_A_SLOT0 + (slot * 8); | ||
304 | else | ||
305 | return SABRE_IMAP_B_SLOT0 + (slot * 8); | ||
306 | } | ||
307 | |||
308 | #define SABRE_OBIO_IMAP_BASE 0x1000UL | ||
309 | #define SABRE_ONBOARD_IRQ_BASE 0x20 | ||
310 | #define sabre_onboard_imap_offset(__ino) \ | ||
311 | (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) | ||
312 | |||
313 | #define sabre_iclr_offset(ino) \ | ||
314 | ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ | ||
315 | (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) | ||
316 | |||
317 | static int sabre_device_needs_wsync(struct device_node *dp) | ||
318 | { | ||
319 | struct device_node *parent = dp->parent; | ||
320 | const char *parent_model, *parent_compat; | ||
321 | |||
322 | /* This traversal up towards the root is meant to | ||
323 | * handle two cases: | ||
324 | * | ||
325 | * 1) non-PCI bus sitting under PCI, such as 'ebus' | ||
326 | * 2) the PCI controller interrupts themselves, which | ||
327 | * will use the sabre_irq_build but do not need | ||
328 | * the DMA synchronization handling | ||
329 | */ | ||
330 | while (parent) { | ||
331 | if (!strcmp(parent->type, "pci")) | ||
332 | break; | ||
333 | parent = parent->parent; | ||
334 | } | ||
335 | |||
336 | if (!parent) | ||
337 | return 0; | ||
338 | |||
339 | parent_model = of_get_property(parent, | ||
340 | "model", NULL); | ||
341 | if (parent_model && | ||
342 | (!strcmp(parent_model, "SUNW,sabre") || | ||
343 | !strcmp(parent_model, "SUNW,simba"))) | ||
344 | return 0; | ||
345 | |||
346 | parent_compat = of_get_property(parent, | ||
347 | "compatible", NULL); | ||
348 | if (parent_compat && | ||
349 | (!strcmp(parent_compat, "pci108e,a000") || | ||
350 | !strcmp(parent_compat, "pci108e,a001"))) | ||
351 | return 0; | ||
352 | |||
353 | return 1; | ||
354 | } | ||
355 | |||
356 | static unsigned int sabre_irq_build(struct device_node *dp, | ||
357 | unsigned int ino, | ||
358 | void *_data) | ||
359 | { | ||
360 | struct sabre_irq_data *irq_data = _data; | ||
361 | unsigned long controller_regs = irq_data->controller_regs; | ||
362 | const struct linux_prom_pci_registers *regs; | ||
363 | unsigned long imap, iclr; | ||
364 | unsigned long imap_off, iclr_off; | ||
365 | int inofixup = 0; | ||
366 | int virt_irq; | ||
367 | |||
368 | ino &= 0x3f; | ||
369 | if (ino < SABRE_ONBOARD_IRQ_BASE) { | ||
370 | /* PCI slot */ | ||
371 | imap_off = sabre_pcislot_imap_offset(ino); | ||
372 | } else { | ||
373 | /* onboard device */ | ||
374 | imap_off = sabre_onboard_imap_offset(ino); | ||
375 | } | ||
376 | |||
377 | /* Now build the IRQ bucket. */ | ||
378 | imap = controller_regs + imap_off; | ||
379 | |||
380 | iclr_off = sabre_iclr_offset(ino); | ||
381 | iclr = controller_regs + iclr_off; | ||
382 | |||
383 | if ((ino & 0x20) == 0) | ||
384 | inofixup = ino & 0x03; | ||
385 | |||
386 | virt_irq = build_irq(inofixup, iclr, imap); | ||
387 | |||
388 | /* If the parent device is a PCI<->PCI bridge other than | ||
389 | * APB, we have to install a pre-handler to ensure that | ||
390 | * all pending DMA is drained before the interrupt handler | ||
391 | * is run. | ||
392 | */ | ||
393 | regs = of_get_property(dp, "reg", NULL); | ||
394 | if (regs && sabre_device_needs_wsync(dp)) { | ||
395 | irq_install_pre_handler(virt_irq, | ||
396 | sabre_wsync_handler, | ||
397 | (void *) (long) regs->phys_hi, | ||
398 | (void *) irq_data); | ||
399 | } | ||
400 | |||
401 | return virt_irq; | ||
402 | } | ||
403 | |||
404 | static void __init sabre_irq_trans_init(struct device_node *dp) | ||
405 | { | ||
406 | const struct linux_prom64_registers *regs; | ||
407 | struct sabre_irq_data *irq_data; | ||
408 | const u32 *busrange; | ||
409 | |||
410 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
411 | dp->irq_trans->irq_build = sabre_irq_build; | ||
412 | |||
413 | irq_data = prom_early_alloc(sizeof(struct sabre_irq_data)); | ||
414 | |||
415 | regs = of_get_property(dp, "reg", NULL); | ||
416 | irq_data->controller_regs = regs[0].phys_addr; | ||
417 | |||
418 | busrange = of_get_property(dp, "bus-range", NULL); | ||
419 | irq_data->pci_first_busno = busrange[0]; | ||
420 | |||
421 | dp->irq_trans->data = irq_data; | ||
422 | } | ||
423 | |||
424 | /* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the | ||
425 | * imap/iclr registers are per-PBM. | ||
426 | */ | ||
427 | #define SCHIZO_IMAP_BASE 0x1000UL | ||
428 | #define SCHIZO_ICLR_BASE 0x1400UL | ||
429 | |||
430 | static unsigned long schizo_imap_offset(unsigned long ino) | ||
431 | { | ||
432 | return SCHIZO_IMAP_BASE + (ino * 8UL); | ||
433 | } | ||
434 | |||
435 | static unsigned long schizo_iclr_offset(unsigned long ino) | ||
436 | { | ||
437 | return SCHIZO_ICLR_BASE + (ino * 8UL); | ||
438 | } | ||
439 | |||
440 | static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, | ||
441 | unsigned int ino) | ||
442 | { | ||
443 | |||
444 | return pbm_regs + schizo_iclr_offset(ino); | ||
445 | } | ||
446 | |||
447 | static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, | ||
448 | unsigned int ino) | ||
449 | { | ||
450 | return pbm_regs + schizo_imap_offset(ino); | ||
451 | } | ||
452 | |||
453 | #define schizo_read(__reg) \ | ||
454 | ({ u64 __ret; \ | ||
455 | __asm__ __volatile__("ldxa [%1] %2, %0" \ | ||
456 | : "=r" (__ret) \ | ||
457 | : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ | ||
458 | : "memory"); \ | ||
459 | __ret; \ | ||
460 | }) | ||
461 | #define schizo_write(__reg, __val) \ | ||
462 | __asm__ __volatile__("stxa %0, [%1] %2" \ | ||
463 | : /* no outputs */ \ | ||
464 | : "r" (__val), "r" (__reg), \ | ||
465 | "i" (ASI_PHYS_BYPASS_EC_E) \ | ||
466 | : "memory") | ||
467 | |||
468 | static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) | ||
469 | { | ||
470 | unsigned long sync_reg = (unsigned long) _arg2; | ||
471 | u64 mask = 1UL << (ino & IMAP_INO); | ||
472 | u64 val; | ||
473 | int limit; | ||
474 | |||
475 | schizo_write(sync_reg, mask); | ||
476 | |||
477 | limit = 100000; | ||
478 | val = 0; | ||
479 | while (--limit) { | ||
480 | val = schizo_read(sync_reg); | ||
481 | if (!(val & mask)) | ||
482 | break; | ||
483 | } | ||
484 | if (limit <= 0) { | ||
485 | printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", | ||
486 | val, mask); | ||
487 | } | ||
488 | |||
489 | if (_arg1) { | ||
490 | static unsigned char cacheline[64] | ||
491 | __attribute__ ((aligned (64))); | ||
492 | |||
493 | __asm__ __volatile__("rd %%fprs, %0\n\t" | ||
494 | "or %0, %4, %1\n\t" | ||
495 | "wr %1, 0x0, %%fprs\n\t" | ||
496 | "stda %%f0, [%5] %6\n\t" | ||
497 | "wr %0, 0x0, %%fprs\n\t" | ||
498 | "membar #Sync" | ||
499 | : "=&r" (mask), "=&r" (val) | ||
500 | : "0" (mask), "1" (val), | ||
501 | "i" (FPRS_FEF), "r" (&cacheline[0]), | ||
502 | "i" (ASI_BLK_COMMIT_P)); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | struct schizo_irq_data { | ||
507 | unsigned long pbm_regs; | ||
508 | unsigned long sync_reg; | ||
509 | u32 portid; | ||
510 | int chip_version; | ||
511 | }; | ||
512 | |||
513 | static unsigned int schizo_irq_build(struct device_node *dp, | ||
514 | unsigned int ino, | ||
515 | void *_data) | ||
516 | { | ||
517 | struct schizo_irq_data *irq_data = _data; | ||
518 | unsigned long pbm_regs = irq_data->pbm_regs; | ||
519 | unsigned long imap, iclr; | ||
520 | int ign_fixup; | ||
521 | int virt_irq; | ||
522 | int is_tomatillo; | ||
523 | |||
524 | ino &= 0x3f; | ||
525 | |||
526 | /* Now build the IRQ bucket. */ | ||
527 | imap = schizo_ino_to_imap(pbm_regs, ino); | ||
528 | iclr = schizo_ino_to_iclr(pbm_regs, ino); | ||
529 | |||
530 | /* On Schizo, no inofixup occurs. This is because each | ||
531 | * INO has it's own IMAP register. On Psycho and Sabre | ||
532 | * there is only one IMAP register for each PCI slot even | ||
533 | * though four different INOs can be generated by each | ||
534 | * PCI slot. | ||
535 | * | ||
536 | * But, for JBUS variants (essentially, Tomatillo), we have | ||
537 | * to fixup the lowest bit of the interrupt group number. | ||
538 | */ | ||
539 | ign_fixup = 0; | ||
540 | |||
541 | is_tomatillo = (irq_data->sync_reg != 0UL); | ||
542 | |||
543 | if (is_tomatillo) { | ||
544 | if (irq_data->portid & 1) | ||
545 | ign_fixup = (1 << 6); | ||
546 | } | ||
547 | |||
548 | virt_irq = build_irq(ign_fixup, iclr, imap); | ||
549 | |||
550 | if (is_tomatillo) { | ||
551 | irq_install_pre_handler(virt_irq, | ||
552 | tomatillo_wsync_handler, | ||
553 | ((irq_data->chip_version <= 4) ? | ||
554 | (void *) 1 : (void *) 0), | ||
555 | (void *) irq_data->sync_reg); | ||
556 | } | ||
557 | |||
558 | return virt_irq; | ||
559 | } | ||
560 | |||
561 | static void __init __schizo_irq_trans_init(struct device_node *dp, | ||
562 | int is_tomatillo) | ||
563 | { | ||
564 | const struct linux_prom64_registers *regs; | ||
565 | struct schizo_irq_data *irq_data; | ||
566 | |||
567 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
568 | dp->irq_trans->irq_build = schizo_irq_build; | ||
569 | |||
570 | irq_data = prom_early_alloc(sizeof(struct schizo_irq_data)); | ||
571 | |||
572 | regs = of_get_property(dp, "reg", NULL); | ||
573 | dp->irq_trans->data = irq_data; | ||
574 | |||
575 | irq_data->pbm_regs = regs[0].phys_addr; | ||
576 | if (is_tomatillo) | ||
577 | irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL; | ||
578 | else | ||
579 | irq_data->sync_reg = 0UL; | ||
580 | irq_data->portid = of_getintprop_default(dp, "portid", 0); | ||
581 | irq_data->chip_version = of_getintprop_default(dp, "version#", 0); | ||
582 | } | ||
583 | |||
584 | static void __init schizo_irq_trans_init(struct device_node *dp) | ||
585 | { | ||
586 | __schizo_irq_trans_init(dp, 0); | ||
587 | } | ||
588 | |||
589 | static void __init tomatillo_irq_trans_init(struct device_node *dp) | ||
590 | { | ||
591 | __schizo_irq_trans_init(dp, 1); | ||
592 | } | ||
593 | |||
594 | static unsigned int pci_sun4v_irq_build(struct device_node *dp, | ||
595 | unsigned int devino, | ||
596 | void *_data) | ||
597 | { | ||
598 | u32 devhandle = (u32) (unsigned long) _data; | ||
599 | |||
600 | return sun4v_build_irq(devhandle, devino); | ||
601 | } | ||
602 | |||
603 | static void __init pci_sun4v_irq_trans_init(struct device_node *dp) | ||
604 | { | ||
605 | const struct linux_prom64_registers *regs; | ||
606 | |||
607 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
608 | dp->irq_trans->irq_build = pci_sun4v_irq_build; | ||
609 | |||
610 | regs = of_get_property(dp, "reg", NULL); | ||
611 | dp->irq_trans->data = (void *) (unsigned long) | ||
612 | ((regs->phys_addr >> 32UL) & 0x0fffffff); | ||
613 | } | ||
614 | |||
615 | struct fire_irq_data { | ||
616 | unsigned long pbm_regs; | ||
617 | u32 portid; | ||
618 | }; | ||
619 | |||
620 | #define FIRE_IMAP_BASE 0x001000 | ||
621 | #define FIRE_ICLR_BASE 0x001400 | ||
622 | |||
623 | static unsigned long fire_imap_offset(unsigned long ino) | ||
624 | { | ||
625 | return FIRE_IMAP_BASE + (ino * 8UL); | ||
626 | } | ||
627 | |||
628 | static unsigned long fire_iclr_offset(unsigned long ino) | ||
629 | { | ||
630 | return FIRE_ICLR_BASE + (ino * 8UL); | ||
631 | } | ||
632 | |||
633 | static unsigned long fire_ino_to_iclr(unsigned long pbm_regs, | ||
634 | unsigned int ino) | ||
635 | { | ||
636 | return pbm_regs + fire_iclr_offset(ino); | ||
637 | } | ||
638 | |||
639 | static unsigned long fire_ino_to_imap(unsigned long pbm_regs, | ||
640 | unsigned int ino) | ||
641 | { | ||
642 | return pbm_regs + fire_imap_offset(ino); | ||
643 | } | ||
644 | |||
645 | static unsigned int fire_irq_build(struct device_node *dp, | ||
646 | unsigned int ino, | ||
647 | void *_data) | ||
648 | { | ||
649 | struct fire_irq_data *irq_data = _data; | ||
650 | unsigned long pbm_regs = irq_data->pbm_regs; | ||
651 | unsigned long imap, iclr; | ||
652 | unsigned long int_ctrlr; | ||
653 | |||
654 | ino &= 0x3f; | ||
655 | |||
656 | /* Now build the IRQ bucket. */ | ||
657 | imap = fire_ino_to_imap(pbm_regs, ino); | ||
658 | iclr = fire_ino_to_iclr(pbm_regs, ino); | ||
659 | |||
660 | /* Set the interrupt controller number. */ | ||
661 | int_ctrlr = 1 << 6; | ||
662 | upa_writeq(int_ctrlr, imap); | ||
663 | |||
664 | /* The interrupt map registers do not have an INO field | ||
665 | * like other chips do. They return zero in the INO | ||
666 | * field, and the interrupt controller number is controlled | ||
667 | * in bits 6 to 9. So in order for build_irq() to get | ||
668 | * the INO right we pass it in as part of the fixup | ||
669 | * which will get added to the map register zero value | ||
670 | * read by build_irq(). | ||
671 | */ | ||
672 | ino |= (irq_data->portid << 6); | ||
673 | ino -= int_ctrlr; | ||
674 | return build_irq(ino, iclr, imap); | ||
675 | } | ||
676 | |||
677 | static void __init fire_irq_trans_init(struct device_node *dp) | ||
678 | { | ||
679 | const struct linux_prom64_registers *regs; | ||
680 | struct fire_irq_data *irq_data; | ||
681 | |||
682 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
683 | dp->irq_trans->irq_build = fire_irq_build; | ||
684 | |||
685 | irq_data = prom_early_alloc(sizeof(struct fire_irq_data)); | ||
686 | |||
687 | regs = of_get_property(dp, "reg", NULL); | ||
688 | dp->irq_trans->data = irq_data; | ||
689 | |||
690 | irq_data->pbm_regs = regs[0].phys_addr; | ||
691 | irq_data->portid = of_getintprop_default(dp, "portid", 0); | ||
692 | } | ||
693 | #endif /* CONFIG_PCI */ | ||
694 | |||
695 | #ifdef CONFIG_SBUS | ||
696 | /* INO number to IMAP register offset for SYSIO external IRQ's. | ||
697 | * This should conform to both Sunfire/Wildfire server and Fusion | ||
698 | * desktop designs. | ||
699 | */ | ||
700 | #define SYSIO_IMAP_SLOT0 0x2c00UL | ||
701 | #define SYSIO_IMAP_SLOT1 0x2c08UL | ||
702 | #define SYSIO_IMAP_SLOT2 0x2c10UL | ||
703 | #define SYSIO_IMAP_SLOT3 0x2c18UL | ||
704 | #define SYSIO_IMAP_SCSI 0x3000UL | ||
705 | #define SYSIO_IMAP_ETH 0x3008UL | ||
706 | #define SYSIO_IMAP_BPP 0x3010UL | ||
707 | #define SYSIO_IMAP_AUDIO 0x3018UL | ||
708 | #define SYSIO_IMAP_PFAIL 0x3020UL | ||
709 | #define SYSIO_IMAP_KMS 0x3028UL | ||
710 | #define SYSIO_IMAP_FLPY 0x3030UL | ||
711 | #define SYSIO_IMAP_SHW 0x3038UL | ||
712 | #define SYSIO_IMAP_KBD 0x3040UL | ||
713 | #define SYSIO_IMAP_MS 0x3048UL | ||
714 | #define SYSIO_IMAP_SER 0x3050UL | ||
715 | #define SYSIO_IMAP_TIM0 0x3060UL | ||
716 | #define SYSIO_IMAP_TIM1 0x3068UL | ||
717 | #define SYSIO_IMAP_UE 0x3070UL | ||
718 | #define SYSIO_IMAP_CE 0x3078UL | ||
719 | #define SYSIO_IMAP_SBERR 0x3080UL | ||
720 | #define SYSIO_IMAP_PMGMT 0x3088UL | ||
721 | #define SYSIO_IMAP_GFX 0x3090UL | ||
722 | #define SYSIO_IMAP_EUPA 0x3098UL | ||
723 | |||
724 | #define bogon ((unsigned long) -1) | ||
725 | static unsigned long sysio_irq_offsets[] = { | ||
726 | /* SBUS Slot 0 --> 3, level 1 --> 7 */ | ||
727 | SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, | ||
728 | SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, | ||
729 | SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, | ||
730 | SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, | ||
731 | SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, | ||
732 | SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, | ||
733 | SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, | ||
734 | SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, | ||
735 | |||
736 | /* Onboard devices (not relevant/used on SunFire). */ | ||
737 | SYSIO_IMAP_SCSI, | ||
738 | SYSIO_IMAP_ETH, | ||
739 | SYSIO_IMAP_BPP, | ||
740 | bogon, | ||
741 | SYSIO_IMAP_AUDIO, | ||
742 | SYSIO_IMAP_PFAIL, | ||
743 | bogon, | ||
744 | bogon, | ||
745 | SYSIO_IMAP_KMS, | ||
746 | SYSIO_IMAP_FLPY, | ||
747 | SYSIO_IMAP_SHW, | ||
748 | SYSIO_IMAP_KBD, | ||
749 | SYSIO_IMAP_MS, | ||
750 | SYSIO_IMAP_SER, | ||
751 | bogon, | ||
752 | bogon, | ||
753 | SYSIO_IMAP_TIM0, | ||
754 | SYSIO_IMAP_TIM1, | ||
755 | bogon, | ||
756 | bogon, | ||
757 | SYSIO_IMAP_UE, | ||
758 | SYSIO_IMAP_CE, | ||
759 | SYSIO_IMAP_SBERR, | ||
760 | SYSIO_IMAP_PMGMT, | ||
761 | SYSIO_IMAP_GFX, | ||
762 | SYSIO_IMAP_EUPA, | ||
763 | }; | ||
764 | |||
765 | #undef bogon | ||
766 | |||
767 | #define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets) | ||
768 | |||
769 | /* Convert Interrupt Mapping register pointer to associated | ||
770 | * Interrupt Clear register pointer, SYSIO specific version. | ||
771 | */ | ||
772 | #define SYSIO_ICLR_UNUSED0 0x3400UL | ||
773 | #define SYSIO_ICLR_SLOT0 0x3408UL | ||
774 | #define SYSIO_ICLR_SLOT1 0x3448UL | ||
775 | #define SYSIO_ICLR_SLOT2 0x3488UL | ||
776 | #define SYSIO_ICLR_SLOT3 0x34c8UL | ||
777 | static unsigned long sysio_imap_to_iclr(unsigned long imap) | ||
778 | { | ||
779 | unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; | ||
780 | return imap + diff; | ||
781 | } | ||
782 | |||
783 | static unsigned int sbus_of_build_irq(struct device_node *dp, | ||
784 | unsigned int ino, | ||
785 | void *_data) | ||
786 | { | ||
787 | unsigned long reg_base = (unsigned long) _data; | ||
788 | const struct linux_prom_registers *regs; | ||
789 | unsigned long imap, iclr; | ||
790 | int sbus_slot = 0; | ||
791 | int sbus_level = 0; | ||
792 | |||
793 | ino &= 0x3f; | ||
794 | |||
795 | regs = of_get_property(dp, "reg", NULL); | ||
796 | if (regs) | ||
797 | sbus_slot = regs->which_io; | ||
798 | |||
799 | if (ino < 0x20) | ||
800 | ino += (sbus_slot * 8); | ||
801 | |||
802 | imap = sysio_irq_offsets[ino]; | ||
803 | if (imap == ((unsigned long)-1)) { | ||
804 | prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", | ||
805 | ino); | ||
806 | prom_halt(); | ||
807 | } | ||
808 | imap += reg_base; | ||
809 | |||
810 | /* SYSIO inconsistency. For external SLOTS, we have to select | ||
811 | * the right ICLR register based upon the lower SBUS irq level | ||
812 | * bits. | ||
813 | */ | ||
814 | if (ino >= 0x20) { | ||
815 | iclr = sysio_imap_to_iclr(imap); | ||
816 | } else { | ||
817 | sbus_level = ino & 0x7; | ||
818 | |||
819 | switch(sbus_slot) { | ||
820 | case 0: | ||
821 | iclr = reg_base + SYSIO_ICLR_SLOT0; | ||
822 | break; | ||
823 | case 1: | ||
824 | iclr = reg_base + SYSIO_ICLR_SLOT1; | ||
825 | break; | ||
826 | case 2: | ||
827 | iclr = reg_base + SYSIO_ICLR_SLOT2; | ||
828 | break; | ||
829 | default: | ||
830 | case 3: | ||
831 | iclr = reg_base + SYSIO_ICLR_SLOT3; | ||
832 | break; | ||
833 | }; | ||
834 | |||
835 | iclr += ((unsigned long)sbus_level - 1UL) * 8UL; | ||
836 | } | ||
837 | return build_irq(sbus_level, iclr, imap); | ||
838 | } | ||
839 | |||
840 | static void __init sbus_irq_trans_init(struct device_node *dp) | ||
841 | { | ||
842 | const struct linux_prom64_registers *regs; | ||
843 | |||
844 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
845 | dp->irq_trans->irq_build = sbus_of_build_irq; | ||
846 | |||
847 | regs = of_get_property(dp, "reg", NULL); | ||
848 | dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr; | ||
849 | } | ||
850 | #endif /* CONFIG_SBUS */ | ||
851 | |||
852 | |||
853 | static unsigned int central_build_irq(struct device_node *dp, | ||
854 | unsigned int ino, | ||
855 | void *_data) | ||
856 | { | ||
857 | struct device_node *central_dp = _data; | ||
858 | struct of_device *central_op = of_find_device_by_node(central_dp); | ||
859 | struct resource *res; | ||
860 | unsigned long imap, iclr; | ||
861 | u32 tmp; | ||
862 | |||
863 | if (!strcmp(dp->name, "eeprom")) { | ||
864 | res = ¢ral_op->resource[5]; | ||
865 | } else if (!strcmp(dp->name, "zs")) { | ||
866 | res = ¢ral_op->resource[4]; | ||
867 | } else if (!strcmp(dp->name, "clock-board")) { | ||
868 | res = ¢ral_op->resource[3]; | ||
869 | } else { | ||
870 | return ino; | ||
871 | } | ||
872 | |||
873 | imap = res->start + 0x00UL; | ||
874 | iclr = res->start + 0x10UL; | ||
875 | |||
876 | /* Set the INO state to idle, and disable. */ | ||
877 | upa_writel(0, iclr); | ||
878 | upa_readl(iclr); | ||
879 | |||
880 | tmp = upa_readl(imap); | ||
881 | tmp &= ~0x80000000; | ||
882 | upa_writel(tmp, imap); | ||
883 | |||
884 | return build_irq(0, iclr, imap); | ||
885 | } | ||
886 | |||
887 | static void __init central_irq_trans_init(struct device_node *dp) | ||
888 | { | ||
889 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
890 | dp->irq_trans->irq_build = central_build_irq; | ||
891 | |||
892 | dp->irq_trans->data = dp; | ||
893 | } | ||
894 | |||
895 | struct irq_trans { | ||
896 | const char *name; | ||
897 | void (*init)(struct device_node *); | ||
898 | }; | ||
899 | |||
900 | #ifdef CONFIG_PCI | ||
901 | static struct irq_trans __initdata pci_irq_trans_table[] = { | ||
902 | { "SUNW,sabre", sabre_irq_trans_init }, | ||
903 | { "pci108e,a000", sabre_irq_trans_init }, | ||
904 | { "pci108e,a001", sabre_irq_trans_init }, | ||
905 | { "SUNW,psycho", psycho_irq_trans_init }, | ||
906 | { "pci108e,8000", psycho_irq_trans_init }, | ||
907 | { "SUNW,schizo", schizo_irq_trans_init }, | ||
908 | { "pci108e,8001", schizo_irq_trans_init }, | ||
909 | { "SUNW,schizo+", schizo_irq_trans_init }, | ||
910 | { "pci108e,8002", schizo_irq_trans_init }, | ||
911 | { "SUNW,tomatillo", tomatillo_irq_trans_init }, | ||
912 | { "pci108e,a801", tomatillo_irq_trans_init }, | ||
913 | { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, | ||
914 | { "pciex108e,80f0", fire_irq_trans_init }, | ||
915 | }; | ||
916 | #endif | ||
917 | |||
918 | static unsigned int sun4v_vdev_irq_build(struct device_node *dp, | ||
919 | unsigned int devino, | ||
920 | void *_data) | ||
921 | { | ||
922 | u32 devhandle = (u32) (unsigned long) _data; | ||
923 | |||
924 | return sun4v_build_irq(devhandle, devino); | ||
925 | } | ||
926 | |||
927 | static void __init sun4v_vdev_irq_trans_init(struct device_node *dp) | ||
928 | { | ||
929 | const struct linux_prom64_registers *regs; | ||
930 | |||
931 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
932 | dp->irq_trans->irq_build = sun4v_vdev_irq_build; | ||
933 | |||
934 | regs = of_get_property(dp, "reg", NULL); | ||
935 | dp->irq_trans->data = (void *) (unsigned long) | ||
936 | ((regs->phys_addr >> 32UL) & 0x0fffffff); | ||
937 | } | ||
938 | |||
939 | static void __init irq_trans_init(struct device_node *dp) | ||
940 | { | ||
941 | #ifdef CONFIG_PCI | ||
942 | const char *model; | ||
943 | int i; | ||
944 | #endif | ||
945 | |||
946 | #ifdef CONFIG_PCI | ||
947 | model = of_get_property(dp, "model", NULL); | ||
948 | if (!model) | ||
949 | model = of_get_property(dp, "compatible", NULL); | ||
950 | if (model) { | ||
951 | for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { | ||
952 | struct irq_trans *t = &pci_irq_trans_table[i]; | ||
953 | |||
954 | if (!strcmp(model, t->name)) { | ||
955 | t->init(dp); | ||
956 | return; | ||
957 | } | ||
958 | } | ||
959 | } | ||
960 | #endif | ||
961 | #ifdef CONFIG_SBUS | ||
962 | if (!strcmp(dp->name, "sbus") || | ||
963 | !strcmp(dp->name, "sbi")) { | ||
964 | sbus_irq_trans_init(dp); | ||
965 | return; | ||
966 | } | ||
967 | #endif | ||
968 | if (!strcmp(dp->name, "fhc") && | ||
969 | !strcmp(dp->parent->name, "central")) { | ||
970 | central_irq_trans_init(dp); | ||
971 | return; | ||
972 | } | ||
973 | if (!strcmp(dp->name, "virtual-devices") || | ||
974 | !strcmp(dp->name, "niu")) { | ||
975 | sun4v_vdev_irq_trans_init(dp); | ||
976 | return; | ||
977 | } | ||
978 | } | ||
979 | |||
980 | static int is_root_node(const struct device_node *dp) | ||
981 | { | ||
982 | if (!dp) | ||
983 | return 0; | ||
984 | |||
985 | return (dp->parent == NULL); | ||
986 | } | ||
987 | |||
988 | /* The following routines deal with the black magic of fully naming a | ||
989 | * node. | ||
990 | * | ||
991 | * Certain well known named nodes are just the simple name string. | ||
992 | * | ||
993 | * Actual devices have an address specifier appended to the base name | ||
994 | * string, like this "foo@addr". The "addr" can be in any number of | ||
995 | * formats, and the platform plus the type of the node determine the | ||
996 | * format and how it is constructed. | ||
997 | * | ||
998 | * For children of the ROOT node, the naming convention is fixed and | ||
999 | * determined by whether this is a sun4u or sun4v system. | ||
1000 | * | ||
1001 | * For children of other nodes, it is bus type specific. So | ||
1002 | * we walk up the tree until we discover a "device_type" property | ||
1003 | * we recognize and we go from there. | ||
1004 | * | ||
1005 | * As an example, the boot device on my workstation has a full path: | ||
1006 | * | ||
1007 | * /pci@1e,600000/ide@d/disk@0,0:c | ||
1008 | */ | ||
1009 | static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf) | ||
1010 | { | ||
1011 | struct linux_prom64_registers *regs; | ||
1012 | struct property *rprop; | ||
1013 | u32 high_bits, low_bits, type; | ||
1014 | |||
1015 | rprop = of_find_property(dp, "reg", NULL); | ||
1016 | if (!rprop) | ||
1017 | return; | ||
1018 | |||
1019 | regs = rprop->value; | ||
1020 | if (!is_root_node(dp->parent)) { | ||
1021 | sprintf(tmp_buf, "%s@%x,%x", | ||
1022 | dp->name, | ||
1023 | (unsigned int) (regs->phys_addr >> 32UL), | ||
1024 | (unsigned int) (regs->phys_addr & 0xffffffffUL)); | ||
1025 | return; | ||
1026 | } | ||
1027 | |||
1028 | type = regs->phys_addr >> 60UL; | ||
1029 | high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL; | ||
1030 | low_bits = (regs->phys_addr & 0xffffffffUL); | ||
1031 | |||
1032 | if (type == 0 || type == 8) { | ||
1033 | const char *prefix = (type == 0) ? "m" : "i"; | ||
1034 | |||
1035 | if (low_bits) | ||
1036 | sprintf(tmp_buf, "%s@%s%x,%x", | ||
1037 | dp->name, prefix, | ||
1038 | high_bits, low_bits); | ||
1039 | else | ||
1040 | sprintf(tmp_buf, "%s@%s%x", | ||
1041 | dp->name, | ||
1042 | prefix, | ||
1043 | high_bits); | ||
1044 | } else if (type == 12) { | ||
1045 | sprintf(tmp_buf, "%s@%x", | ||
1046 | dp->name, high_bits); | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf) | ||
1051 | { | ||
1052 | struct linux_prom64_registers *regs; | ||
1053 | struct property *prop; | ||
1054 | |||
1055 | prop = of_find_property(dp, "reg", NULL); | ||
1056 | if (!prop) | ||
1057 | return; | ||
1058 | |||
1059 | regs = prop->value; | ||
1060 | if (!is_root_node(dp->parent)) { | ||
1061 | sprintf(tmp_buf, "%s@%x,%x", | ||
1062 | dp->name, | ||
1063 | (unsigned int) (regs->phys_addr >> 32UL), | ||
1064 | (unsigned int) (regs->phys_addr & 0xffffffffUL)); | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | prop = of_find_property(dp, "upa-portid", NULL); | ||
1069 | if (!prop) | ||
1070 | prop = of_find_property(dp, "portid", NULL); | ||
1071 | if (prop) { | ||
1072 | unsigned long mask = 0xffffffffUL; | ||
1073 | |||
1074 | if (tlb_type >= cheetah) | ||
1075 | mask = 0x7fffff; | ||
1076 | |||
1077 | sprintf(tmp_buf, "%s@%x,%x", | ||
1078 | dp->name, | ||
1079 | *(u32 *)prop->value, | ||
1080 | (unsigned int) (regs->phys_addr & mask)); | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | /* "name@slot,offset" */ | ||
1085 | static void __init sbus_path_component(struct device_node *dp, char *tmp_buf) | ||
1086 | { | ||
1087 | struct linux_prom_registers *regs; | ||
1088 | struct property *prop; | ||
1089 | |||
1090 | prop = of_find_property(dp, "reg", NULL); | ||
1091 | if (!prop) | ||
1092 | return; | ||
1093 | |||
1094 | regs = prop->value; | ||
1095 | sprintf(tmp_buf, "%s@%x,%x", | ||
1096 | dp->name, | ||
1097 | regs->which_io, | ||
1098 | regs->phys_addr); | ||
1099 | } | ||
1100 | |||
1101 | /* "name@devnum[,func]" */ | ||
1102 | static void __init pci_path_component(struct device_node *dp, char *tmp_buf) | ||
1103 | { | ||
1104 | struct linux_prom_pci_registers *regs; | ||
1105 | struct property *prop; | ||
1106 | unsigned int devfn; | ||
1107 | |||
1108 | prop = of_find_property(dp, "reg", NULL); | ||
1109 | if (!prop) | ||
1110 | return; | ||
1111 | |||
1112 | regs = prop->value; | ||
1113 | devfn = (regs->phys_hi >> 8) & 0xff; | ||
1114 | if (devfn & 0x07) { | ||
1115 | sprintf(tmp_buf, "%s@%x,%x", | ||
1116 | dp->name, | ||
1117 | devfn >> 3, | ||
1118 | devfn & 0x07); | ||
1119 | } else { | ||
1120 | sprintf(tmp_buf, "%s@%x", | ||
1121 | dp->name, | ||
1122 | devfn >> 3); | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | /* "name@UPA_PORTID,offset" */ | ||
1127 | static void __init upa_path_component(struct device_node *dp, char *tmp_buf) | ||
1128 | { | ||
1129 | struct linux_prom64_registers *regs; | ||
1130 | struct property *prop; | ||
1131 | |||
1132 | prop = of_find_property(dp, "reg", NULL); | ||
1133 | if (!prop) | ||
1134 | return; | ||
1135 | |||
1136 | regs = prop->value; | ||
1137 | |||
1138 | prop = of_find_property(dp, "upa-portid", NULL); | ||
1139 | if (!prop) | ||
1140 | return; | ||
1141 | |||
1142 | sprintf(tmp_buf, "%s@%x,%x", | ||
1143 | dp->name, | ||
1144 | *(u32 *) prop->value, | ||
1145 | (unsigned int) (regs->phys_addr & 0xffffffffUL)); | ||
1146 | } | ||
1147 | |||
1148 | /* "name@reg" */ | ||
1149 | static void __init vdev_path_component(struct device_node *dp, char *tmp_buf) | ||
1150 | { | ||
1151 | struct property *prop; | ||
1152 | u32 *regs; | ||
1153 | |||
1154 | prop = of_find_property(dp, "reg", NULL); | ||
1155 | if (!prop) | ||
1156 | return; | ||
1157 | |||
1158 | regs = prop->value; | ||
1159 | |||
1160 | sprintf(tmp_buf, "%s@%x", dp->name, *regs); | ||
1161 | } | ||
1162 | |||
1163 | /* "name@addrhi,addrlo" */ | ||
1164 | static void __init ebus_path_component(struct device_node *dp, char *tmp_buf) | ||
1165 | { | ||
1166 | struct linux_prom64_registers *regs; | ||
1167 | struct property *prop; | ||
1168 | |||
1169 | prop = of_find_property(dp, "reg", NULL); | ||
1170 | if (!prop) | ||
1171 | return; | ||
1172 | |||
1173 | regs = prop->value; | ||
1174 | |||
1175 | sprintf(tmp_buf, "%s@%x,%x", | ||
1176 | dp->name, | ||
1177 | (unsigned int) (regs->phys_addr >> 32UL), | ||
1178 | (unsigned int) (regs->phys_addr & 0xffffffffUL)); | ||
1179 | } | ||
1180 | |||
1181 | /* "name@bus,addr" */ | ||
1182 | static void __init i2c_path_component(struct device_node *dp, char *tmp_buf) | ||
1183 | { | ||
1184 | struct property *prop; | ||
1185 | u32 *regs; | ||
1186 | |||
1187 | prop = of_find_property(dp, "reg", NULL); | ||
1188 | if (!prop) | ||
1189 | return; | ||
1190 | |||
1191 | regs = prop->value; | ||
1192 | |||
1193 | /* This actually isn't right... should look at the #address-cells | ||
1194 | * property of the i2c bus node etc. etc. | ||
1195 | */ | ||
1196 | sprintf(tmp_buf, "%s@%x,%x", | ||
1197 | dp->name, regs[0], regs[1]); | ||
1198 | } | ||
1199 | |||
1200 | /* "name@reg0[,reg1]" */ | ||
1201 | static void __init usb_path_component(struct device_node *dp, char *tmp_buf) | ||
1202 | { | ||
1203 | struct property *prop; | ||
1204 | u32 *regs; | ||
1205 | |||
1206 | prop = of_find_property(dp, "reg", NULL); | ||
1207 | if (!prop) | ||
1208 | return; | ||
1209 | |||
1210 | regs = prop->value; | ||
1211 | |||
1212 | if (prop->length == sizeof(u32) || regs[1] == 1) { | ||
1213 | sprintf(tmp_buf, "%s@%x", | ||
1214 | dp->name, regs[0]); | ||
1215 | } else { | ||
1216 | sprintf(tmp_buf, "%s@%x,%x", | ||
1217 | dp->name, regs[0], regs[1]); | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | /* "name@reg0reg1[,reg2reg3]" */ | ||
1222 | static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf) | ||
1223 | { | ||
1224 | struct property *prop; | ||
1225 | u32 *regs; | ||
1226 | |||
1227 | prop = of_find_property(dp, "reg", NULL); | ||
1228 | if (!prop) | ||
1229 | return; | ||
1230 | |||
1231 | regs = prop->value; | ||
1232 | |||
1233 | if (regs[2] || regs[3]) { | ||
1234 | sprintf(tmp_buf, "%s@%08x%08x,%04x%08x", | ||
1235 | dp->name, regs[0], regs[1], regs[2], regs[3]); | ||
1236 | } else { | ||
1237 | sprintf(tmp_buf, "%s@%08x%08x", | ||
1238 | dp->name, regs[0], regs[1]); | ||
1239 | } | ||
1240 | } | ||
1241 | |||
1242 | static void __init __build_path_component(struct device_node *dp, char *tmp_buf) | ||
1243 | { | ||
1244 | struct device_node *parent = dp->parent; | ||
1245 | |||
1246 | if (parent != NULL) { | ||
1247 | if (!strcmp(parent->type, "pci") || | ||
1248 | !strcmp(parent->type, "pciex")) { | ||
1249 | pci_path_component(dp, tmp_buf); | ||
1250 | return; | ||
1251 | } | ||
1252 | if (!strcmp(parent->type, "sbus")) { | ||
1253 | sbus_path_component(dp, tmp_buf); | ||
1254 | return; | ||
1255 | } | ||
1256 | if (!strcmp(parent->type, "upa")) { | ||
1257 | upa_path_component(dp, tmp_buf); | ||
1258 | return; | ||
1259 | } | ||
1260 | if (!strcmp(parent->type, "ebus")) { | ||
1261 | ebus_path_component(dp, tmp_buf); | ||
1262 | return; | ||
1263 | } | ||
1264 | if (!strcmp(parent->name, "usb") || | ||
1265 | !strcmp(parent->name, "hub")) { | ||
1266 | usb_path_component(dp, tmp_buf); | ||
1267 | return; | ||
1268 | } | ||
1269 | if (!strcmp(parent->type, "i2c")) { | ||
1270 | i2c_path_component(dp, tmp_buf); | ||
1271 | return; | ||
1272 | } | ||
1273 | if (!strcmp(parent->type, "firewire")) { | ||
1274 | ieee1394_path_component(dp, tmp_buf); | ||
1275 | return; | ||
1276 | } | ||
1277 | if (!strcmp(parent->type, "virtual-devices")) { | ||
1278 | vdev_path_component(dp, tmp_buf); | ||
1279 | return; | ||
1280 | } | ||
1281 | /* "isa" is handled with platform naming */ | ||
1282 | } | ||
1283 | |||
1284 | /* Use platform naming convention. */ | ||
1285 | if (tlb_type == hypervisor) { | ||
1286 | sun4v_path_component(dp, tmp_buf); | ||
1287 | return; | ||
1288 | } else { | ||
1289 | sun4u_path_component(dp, tmp_buf); | ||
1290 | } | ||
1291 | } | ||
1292 | |||
1293 | static char * __init build_path_component(struct device_node *dp) | ||
1294 | { | ||
1295 | char tmp_buf[64], *n; | ||
1296 | |||
1297 | tmp_buf[0] = '\0'; | ||
1298 | __build_path_component(dp, tmp_buf); | ||
1299 | if (tmp_buf[0] == '\0') | ||
1300 | strcpy(tmp_buf, dp->name); | ||
1301 | |||
1302 | n = prom_early_alloc(strlen(tmp_buf) + 1); | ||
1303 | strcpy(n, tmp_buf); | ||
1304 | |||
1305 | return n; | ||
1306 | } | ||
1307 | |||
1308 | static char * __init build_full_name(struct device_node *dp) | ||
1309 | { | ||
1310 | int len, ourlen, plen; | ||
1311 | char *n; | ||
1312 | |||
1313 | plen = strlen(dp->parent->full_name); | ||
1314 | ourlen = strlen(dp->path_component_name); | ||
1315 | len = ourlen + plen + 2; | ||
1316 | |||
1317 | n = prom_early_alloc(len); | ||
1318 | strcpy(n, dp->parent->full_name); | ||
1319 | if (!is_root_node(dp->parent)) { | ||
1320 | strcpy(n + plen, "/"); | ||
1321 | plen++; | ||
1322 | } | ||
1323 | strcpy(n + plen, dp->path_component_name); | ||
1324 | |||
1325 | return n; | ||
1326 | } | ||
1327 | |||
1328 | static unsigned int unique_id; | ||
1329 | |||
1330 | static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) | ||
1331 | { | ||
1332 | static struct property *tmp = NULL; | ||
1333 | struct property *p; | ||
1334 | |||
1335 | if (tmp) { | ||
1336 | p = tmp; | ||
1337 | memset(p, 0, sizeof(*p) + 32); | ||
1338 | tmp = NULL; | ||
1339 | } else { | ||
1340 | p = prom_early_alloc(sizeof(struct property) + 32); | ||
1341 | p->unique_id = unique_id++; | ||
1342 | } | ||
1343 | |||
1344 | p->name = (char *) (p + 1); | ||
1345 | if (special_name) { | ||
1346 | strcpy(p->name, special_name); | ||
1347 | p->length = special_len; | ||
1348 | p->value = prom_early_alloc(special_len); | ||
1349 | memcpy(p->value, special_val, special_len); | ||
1350 | } else { | ||
1351 | if (prev == NULL) { | ||
1352 | prom_firstprop(node, p->name); | ||
1353 | } else { | ||
1354 | prom_nextprop(node, prev, p->name); | ||
1355 | } | ||
1356 | if (strlen(p->name) == 0) { | ||
1357 | tmp = p; | ||
1358 | return NULL; | ||
1359 | } | ||
1360 | p->length = prom_getproplen(node, p->name); | ||
1361 | if (p->length <= 0) { | ||
1362 | p->length = 0; | ||
1363 | } else { | ||
1364 | p->value = prom_early_alloc(p->length + 1); | ||
1365 | prom_getproperty(node, p->name, p->value, p->length); | ||
1366 | ((unsigned char *)p->value)[p->length] = '\0'; | ||
1367 | } | ||
1368 | } | ||
1369 | return p; | ||
1370 | } | ||
1371 | |||
1372 | static struct property * __init build_prop_list(phandle node) | ||
1373 | { | ||
1374 | struct property *head, *tail; | ||
1375 | |||
1376 | head = tail = build_one_prop(node, NULL, | ||
1377 | ".node", &node, sizeof(node)); | ||
1378 | |||
1379 | tail->next = build_one_prop(node, NULL, NULL, NULL, 0); | ||
1380 | tail = tail->next; | ||
1381 | while(tail) { | ||
1382 | tail->next = build_one_prop(node, tail->name, | ||
1383 | NULL, NULL, 0); | ||
1384 | tail = tail->next; | ||
1385 | } | ||
1386 | |||
1387 | return head; | ||
1388 | } | ||
1389 | |||
1390 | static char * __init get_one_property(phandle node, const char *name) | ||
1391 | { | ||
1392 | char *buf = "<NULL>"; | ||
1393 | int len; | ||
1394 | |||
1395 | len = prom_getproplen(node, name); | ||
1396 | if (len > 0) { | ||
1397 | buf = prom_early_alloc(len); | ||
1398 | prom_getproperty(node, name, buf, len); | ||
1399 | } | ||
1400 | |||
1401 | return buf; | ||
1402 | } | ||
1403 | |||
1404 | static struct device_node * __init create_node(phandle node, struct device_node *parent) | ||
1405 | { | ||
1406 | struct device_node *dp; | ||
1407 | |||
1408 | if (!node) | ||
1409 | return NULL; | ||
1410 | |||
1411 | dp = prom_early_alloc(sizeof(*dp)); | ||
1412 | dp->unique_id = unique_id++; | ||
1413 | dp->parent = parent; | ||
1414 | |||
1415 | kref_init(&dp->kref); | ||
1416 | |||
1417 | dp->name = get_one_property(node, "name"); | ||
1418 | dp->type = get_one_property(node, "device_type"); | ||
1419 | dp->node = node; | ||
1420 | |||
1421 | dp->properties = build_prop_list(node); | ||
1422 | |||
1423 | irq_trans_init(dp); | ||
1424 | |||
1425 | return dp; | ||
1426 | } | ||
1427 | |||
1428 | static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) | ||
1429 | { | ||
1430 | struct device_node *ret = NULL, *prev_sibling = NULL; | ||
1431 | struct device_node *dp; | ||
1432 | |||
1433 | while (1) { | ||
1434 | dp = create_node(node, parent); | ||
1435 | if (!dp) | ||
1436 | break; | ||
1437 | |||
1438 | if (prev_sibling) | ||
1439 | prev_sibling->sibling = dp; | ||
1440 | |||
1441 | if (!ret) | ||
1442 | ret = dp; | ||
1443 | prev_sibling = dp; | ||
1444 | |||
1445 | *(*nextp) = dp; | ||
1446 | *nextp = &dp->allnext; | ||
1447 | |||
1448 | dp->path_component_name = build_path_component(dp); | ||
1449 | dp->full_name = build_full_name(dp); | ||
1450 | |||
1451 | dp->child = build_tree(dp, prom_getchild(node), nextp); | ||
1452 | |||
1453 | node = prom_getsibling(node); | ||
1454 | } | ||
1455 | |||
1456 | return ret; | ||
1457 | } | ||
1458 | |||
1459 | static const char *get_mid_prop(void) | ||
1460 | { | ||
1461 | return (tlb_type == spitfire ? "upa-portid" : "portid"); | ||
1462 | } | ||
1463 | |||
1464 | struct device_node *of_find_node_by_cpuid(int cpuid) | ||
1465 | { | ||
1466 | struct device_node *dp; | ||
1467 | const char *mid_prop = get_mid_prop(); | ||
1468 | |||
1469 | for_each_node_by_type(dp, "cpu") { | ||
1470 | int id = of_getintprop_default(dp, mid_prop, -1); | ||
1471 | const char *this_mid_prop = mid_prop; | ||
1472 | |||
1473 | if (id < 0) { | ||
1474 | this_mid_prop = "cpuid"; | ||
1475 | id = of_getintprop_default(dp, this_mid_prop, -1); | ||
1476 | } | ||
1477 | |||
1478 | if (id < 0) { | ||
1479 | prom_printf("OF: Serious problem, cpu lacks " | ||
1480 | "%s property", this_mid_prop); | ||
1481 | prom_halt(); | ||
1482 | } | ||
1483 | if (cpuid == id) | ||
1484 | return dp; | ||
1485 | } | ||
1486 | return NULL; | ||
1487 | } | ||
1488 | |||
1489 | static void __init of_fill_in_cpu_data(void) | ||
1490 | { | ||
1491 | struct device_node *dp; | ||
1492 | const char *mid_prop = get_mid_prop(); | ||
1493 | |||
1494 | ncpus_probed = 0; | ||
1495 | for_each_node_by_type(dp, "cpu") { | ||
1496 | int cpuid = of_getintprop_default(dp, mid_prop, -1); | ||
1497 | const char *this_mid_prop = mid_prop; | ||
1498 | struct device_node *portid_parent; | ||
1499 | int portid = -1; | ||
1500 | |||
1501 | portid_parent = NULL; | ||
1502 | if (cpuid < 0) { | ||
1503 | this_mid_prop = "cpuid"; | ||
1504 | cpuid = of_getintprop_default(dp, this_mid_prop, -1); | ||
1505 | if (cpuid >= 0) { | ||
1506 | int limit = 2; | ||
1507 | |||
1508 | portid_parent = dp; | ||
1509 | while (limit--) { | ||
1510 | portid_parent = portid_parent->parent; | ||
1511 | if (!portid_parent) | ||
1512 | break; | ||
1513 | portid = of_getintprop_default(portid_parent, | ||
1514 | "portid", -1); | ||
1515 | if (portid >= 0) | ||
1516 | break; | ||
1517 | } | ||
1518 | } | ||
1519 | } | ||
1520 | |||
1521 | if (cpuid < 0) { | ||
1522 | prom_printf("OF: Serious problem, cpu lacks " | ||
1523 | "%s property", this_mid_prop); | ||
1524 | prom_halt(); | ||
1525 | } | ||
1526 | |||
1527 | ncpus_probed++; | ||
1528 | |||
1529 | #ifdef CONFIG_SMP | ||
1530 | if (cpuid >= NR_CPUS) { | ||
1531 | printk(KERN_WARNING "Ignoring CPU %d which is " | ||
1532 | ">= NR_CPUS (%d)\n", | ||
1533 | cpuid, NR_CPUS); | ||
1534 | continue; | ||
1535 | } | ||
1536 | #else | ||
1537 | /* On uniprocessor we only want the values for the | ||
1538 | * real physical cpu the kernel booted onto, however | ||
1539 | * cpu_data() only has one entry at index 0. | ||
1540 | */ | ||
1541 | if (cpuid != real_hard_smp_processor_id()) | ||
1542 | continue; | ||
1543 | cpuid = 0; | ||
1544 | #endif | ||
1545 | |||
1546 | cpu_data(cpuid).clock_tick = | ||
1547 | of_getintprop_default(dp, "clock-frequency", 0); | ||
1548 | |||
1549 | if (portid_parent) { | ||
1550 | cpu_data(cpuid).dcache_size = | ||
1551 | of_getintprop_default(dp, "l1-dcache-size", | ||
1552 | 16 * 1024); | ||
1553 | cpu_data(cpuid).dcache_line_size = | ||
1554 | of_getintprop_default(dp, "l1-dcache-line-size", | ||
1555 | 32); | ||
1556 | cpu_data(cpuid).icache_size = | ||
1557 | of_getintprop_default(dp, "l1-icache-size", | ||
1558 | 8 * 1024); | ||
1559 | cpu_data(cpuid).icache_line_size = | ||
1560 | of_getintprop_default(dp, "l1-icache-line-size", | ||
1561 | 32); | ||
1562 | cpu_data(cpuid).ecache_size = | ||
1563 | of_getintprop_default(dp, "l2-cache-size", 0); | ||
1564 | cpu_data(cpuid).ecache_line_size = | ||
1565 | of_getintprop_default(dp, "l2-cache-line-size", 0); | ||
1566 | if (!cpu_data(cpuid).ecache_size || | ||
1567 | !cpu_data(cpuid).ecache_line_size) { | ||
1568 | cpu_data(cpuid).ecache_size = | ||
1569 | of_getintprop_default(portid_parent, | ||
1570 | "l2-cache-size", | ||
1571 | (4 * 1024 * 1024)); | ||
1572 | cpu_data(cpuid).ecache_line_size = | ||
1573 | of_getintprop_default(portid_parent, | ||
1574 | "l2-cache-line-size", 64); | ||
1575 | } | ||
1576 | |||
1577 | cpu_data(cpuid).core_id = portid + 1; | ||
1578 | cpu_data(cpuid).proc_id = portid; | ||
1579 | #ifdef CONFIG_SMP | ||
1580 | sparc64_multi_core = 1; | ||
1581 | #endif | ||
1582 | } else { | ||
1583 | cpu_data(cpuid).dcache_size = | ||
1584 | of_getintprop_default(dp, "dcache-size", 16 * 1024); | ||
1585 | cpu_data(cpuid).dcache_line_size = | ||
1586 | of_getintprop_default(dp, "dcache-line-size", 32); | ||
1587 | |||
1588 | cpu_data(cpuid).icache_size = | ||
1589 | of_getintprop_default(dp, "icache-size", 16 * 1024); | ||
1590 | cpu_data(cpuid).icache_line_size = | ||
1591 | of_getintprop_default(dp, "icache-line-size", 32); | ||
1592 | |||
1593 | cpu_data(cpuid).ecache_size = | ||
1594 | of_getintprop_default(dp, "ecache-size", | ||
1595 | (4 * 1024 * 1024)); | ||
1596 | cpu_data(cpuid).ecache_line_size = | ||
1597 | of_getintprop_default(dp, "ecache-line-size", 64); | ||
1598 | |||
1599 | cpu_data(cpuid).core_id = 0; | ||
1600 | cpu_data(cpuid).proc_id = -1; | ||
1601 | } | ||
1602 | |||
1603 | #ifdef CONFIG_SMP | ||
1604 | cpu_set(cpuid, cpu_present_map); | ||
1605 | cpu_set(cpuid, cpu_possible_map); | ||
1606 | #endif | ||
1607 | } | ||
1608 | |||
1609 | smp_fill_in_sib_core_maps(); | ||
1610 | } | ||
1611 | |||
1612 | struct device_node *of_console_device; | ||
1613 | EXPORT_SYMBOL(of_console_device); | ||
1614 | |||
1615 | char *of_console_path; | ||
1616 | EXPORT_SYMBOL(of_console_path); | ||
1617 | |||
1618 | char *of_console_options; | ||
1619 | EXPORT_SYMBOL(of_console_options); | ||
1620 | |||
1621 | static void __init of_console_init(void) | ||
1622 | { | ||
1623 | char *msg = "OF stdout device is: %s\n"; | ||
1624 | struct device_node *dp; | ||
1625 | const char *type; | ||
1626 | phandle node; | ||
1627 | |||
1628 | of_console_path = prom_early_alloc(256); | ||
1629 | if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) { | ||
1630 | prom_printf("Cannot obtain path of stdout.\n"); | ||
1631 | prom_halt(); | ||
1632 | } | ||
1633 | of_console_options = strrchr(of_console_path, ':'); | ||
1634 | if (of_console_options) { | ||
1635 | of_console_options++; | ||
1636 | if (*of_console_options == '\0') | ||
1637 | of_console_options = NULL; | ||
1638 | } | ||
1639 | |||
1640 | node = prom_inst2pkg(prom_stdout); | ||
1641 | if (!node) { | ||
1642 | prom_printf("Cannot resolve stdout node from " | ||
1643 | "instance %08x.\n", prom_stdout); | ||
1644 | prom_halt(); | ||
1645 | } | ||
1646 | |||
1647 | dp = of_find_node_by_phandle(node); | ||
1648 | type = of_get_property(dp, "device_type", NULL); | ||
1649 | if (!type) { | ||
1650 | prom_printf("Console stdout lacks device_type property.\n"); | ||
1651 | prom_halt(); | ||
1652 | } | ||
1653 | |||
1654 | if (strcmp(type, "display") && strcmp(type, "serial")) { | ||
1655 | prom_printf("Console device_type is neither display " | ||
1656 | "nor serial.\n"); | ||
1657 | prom_halt(); | ||
1658 | } | ||
1659 | |||
1660 | of_console_device = dp; | ||
1661 | |||
1662 | printk(msg, of_console_path); | ||
1663 | } | ||
1664 | |||
1665 | void __init prom_build_devicetree(void) | ||
1666 | { | ||
1667 | struct device_node **nextp; | ||
1668 | |||
1669 | allnodes = create_node(prom_root_node, NULL); | ||
1670 | allnodes->path_component_name = ""; | ||
1671 | allnodes->full_name = "/"; | ||
1672 | |||
1673 | nextp = &allnodes->allnext; | ||
1674 | allnodes->child = build_tree(allnodes, | ||
1675 | prom_getchild(allnodes->node), | ||
1676 | &nextp); | ||
1677 | of_console_init(); | ||
1678 | |||
1679 | printk("PROM: Built device tree with %u bytes of memory.\n", | ||
1680 | prom_early_allocated); | ||
1681 | |||
1682 | if (tlb_type != hypervisor) | ||
1683 | of_fill_in_cpu_data(); | ||
1684 | } | ||