diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc64/kernel/setup.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc64/kernel/setup.c')
-rw-r--r-- | arch/ppc64/kernel/setup.c | 1392 |
1 files changed, 1392 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c new file mode 100644 index 000000000000..21c57f539c29 --- /dev/null +++ b/arch/ppc64/kernel/setup.c | |||
@@ -0,0 +1,1392 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Common boot and setup code. | ||
4 | * | ||
5 | * Copyright (C) 2001 PPC64 Team, IBM Corp | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #undef DEBUG | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/reboot.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/initrd.h> | ||
24 | #include <linux/ide.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <linux/version.h> | ||
29 | #include <linux/tty.h> | ||
30 | #include <linux/root_dev.h> | ||
31 | #include <linux/notifier.h> | ||
32 | #include <linux/cpu.h> | ||
33 | #include <linux/unistd.h> | ||
34 | #include <linux/serial.h> | ||
35 | #include <linux/serial_8250.h> | ||
36 | #include <asm/io.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/processor.h> | ||
39 | #include <asm/pgtable.h> | ||
40 | #include <asm/bootinfo.h> | ||
41 | #include <asm/smp.h> | ||
42 | #include <asm/elf.h> | ||
43 | #include <asm/machdep.h> | ||
44 | #include <asm/iSeries/LparData.h> | ||
45 | #include <asm/paca.h> | ||
46 | #include <asm/ppcdebug.h> | ||
47 | #include <asm/time.h> | ||
48 | #include <asm/cputable.h> | ||
49 | #include <asm/sections.h> | ||
50 | #include <asm/btext.h> | ||
51 | #include <asm/nvram.h> | ||
52 | #include <asm/setup.h> | ||
53 | #include <asm/system.h> | ||
54 | #include <asm/rtas.h> | ||
55 | #include <asm/iommu.h> | ||
56 | #include <asm/serial.h> | ||
57 | #include <asm/cache.h> | ||
58 | #include <asm/page.h> | ||
59 | #include <asm/mmu.h> | ||
60 | |||
61 | #ifdef DEBUG | ||
62 | #define DBG(fmt...) udbg_printf(fmt) | ||
63 | #else | ||
64 | #define DBG(fmt...) | ||
65 | #endif | ||
66 | |||
67 | /* | ||
68 | * Here are some early debugging facilities. You can enable one | ||
69 | * but your kernel will not boot on anything else if you do so | ||
70 | */ | ||
71 | |||
72 | /* This one is for use on LPAR machines that support an HVC console | ||
73 | * on vterm 0 | ||
74 | */ | ||
75 | extern void udbg_init_debug_lpar(void); | ||
76 | /* This one is for use on Apple G5 machines | ||
77 | */ | ||
78 | extern void udbg_init_pmac_realmode(void); | ||
79 | /* That's RTAS panel debug */ | ||
80 | extern void call_rtas_display_status_delay(unsigned char c); | ||
81 | /* Here's maple real mode debug */ | ||
82 | extern void udbg_init_maple_realmode(void); | ||
83 | |||
84 | #define EARLY_DEBUG_INIT() do {} while(0) | ||
85 | |||
86 | #if 0 | ||
87 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() | ||
88 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() | ||
89 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() | ||
90 | #define EARLY_DEBUG_INIT() \ | ||
91 | do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) | ||
92 | #endif | ||
93 | |||
94 | /* extern void *stab; */ | ||
95 | extern unsigned long klimit; | ||
96 | |||
97 | extern void mm_init_ppc64(void); | ||
98 | extern int idle_setup(void); | ||
99 | extern void stab_initialize(unsigned long stab); | ||
100 | extern void htab_initialize(void); | ||
101 | extern void early_init_devtree(void *flat_dt); | ||
102 | extern void unflatten_device_tree(void); | ||
103 | |||
104 | extern void smp_release_cpus(void); | ||
105 | |||
106 | unsigned long decr_overclock = 1; | ||
107 | unsigned long decr_overclock_proc0 = 1; | ||
108 | unsigned long decr_overclock_set = 0; | ||
109 | unsigned long decr_overclock_proc0_set = 0; | ||
110 | |||
111 | int have_of = 1; | ||
112 | int boot_cpuid = 0; | ||
113 | int boot_cpuid_phys = 0; | ||
114 | dev_t boot_dev; | ||
115 | u64 ppc64_pft_size; | ||
116 | u64 ppc64_debug_switch; | ||
117 | |||
118 | struct ppc64_caches ppc64_caches; | ||
119 | EXPORT_SYMBOL_GPL(ppc64_caches); | ||
120 | |||
121 | /* | ||
122 | * These are used in binfmt_elf.c to put aux entries on the stack | ||
123 | * for each elf executable being started. | ||
124 | */ | ||
125 | int dcache_bsize; | ||
126 | int icache_bsize; | ||
127 | int ucache_bsize; | ||
128 | |||
129 | /* The main machine-dep calls structure | ||
130 | */ | ||
131 | struct machdep_calls ppc_md; | ||
132 | EXPORT_SYMBOL(ppc_md); | ||
133 | |||
134 | #ifdef CONFIG_MAGIC_SYSRQ | ||
135 | unsigned long SYSRQ_KEY; | ||
136 | #endif /* CONFIG_MAGIC_SYSRQ */ | ||
137 | |||
138 | |||
139 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); | ||
140 | static struct notifier_block ppc64_panic_block = { | ||
141 | .notifier_call = ppc64_panic_event, | ||
142 | .priority = INT_MIN /* may not return; must be done last */ | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * Perhaps we can put the pmac screen_info[] here | ||
147 | * on pmac as well so we don't need the ifdef's. | ||
148 | * Until we get multiple-console support in here | ||
149 | * that is. -- Cort | ||
150 | * Maybe tie it to serial consoles, since this is really what | ||
151 | * these processors use on existing boards. -- Dan | ||
152 | */ | ||
153 | struct screen_info screen_info = { | ||
154 | .orig_x = 0, | ||
155 | .orig_y = 25, | ||
156 | .orig_video_cols = 80, | ||
157 | .orig_video_lines = 25, | ||
158 | .orig_video_isVGA = 1, | ||
159 | .orig_video_points = 16 | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * Initialize the PPCDBG state. Called before relocation has been enabled. | ||
164 | */ | ||
165 | void __init ppcdbg_initialize(void) | ||
166 | { | ||
167 | ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ | ||
168 | /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Early boot console based on udbg | ||
173 | */ | ||
174 | static struct console udbg_console = { | ||
175 | .name = "udbg", | ||
176 | .write = udbg_console_write, | ||
177 | .flags = CON_PRINTBUFFER, | ||
178 | .index = -1, | ||
179 | }; | ||
180 | static int early_console_initialized; | ||
181 | |||
182 | void __init disable_early_printk(void) | ||
183 | { | ||
184 | if (!early_console_initialized) | ||
185 | return; | ||
186 | unregister_console(&udbg_console); | ||
187 | early_console_initialized = 0; | ||
188 | } | ||
189 | |||
190 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) | ||
191 | |||
192 | static int smt_enabled_cmdline; | ||
193 | |||
194 | /* Look for ibm,smt-enabled OF option */ | ||
195 | static void check_smt_enabled(void) | ||
196 | { | ||
197 | struct device_node *dn; | ||
198 | char *smt_option; | ||
199 | |||
200 | /* Allow the command line to overrule the OF option */ | ||
201 | if (smt_enabled_cmdline) | ||
202 | return; | ||
203 | |||
204 | dn = of_find_node_by_path("/options"); | ||
205 | |||
206 | if (dn) { | ||
207 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); | ||
208 | |||
209 | if (smt_option) { | ||
210 | if (!strcmp(smt_option, "on")) | ||
211 | smt_enabled_at_boot = 1; | ||
212 | else if (!strcmp(smt_option, "off")) | ||
213 | smt_enabled_at_boot = 0; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | /* Look for smt-enabled= cmdline option */ | ||
219 | static int __init early_smt_enabled(char *p) | ||
220 | { | ||
221 | smt_enabled_cmdline = 1; | ||
222 | |||
223 | if (!p) | ||
224 | return 0; | ||
225 | |||
226 | if (!strcmp(p, "on") || !strcmp(p, "1")) | ||
227 | smt_enabled_at_boot = 1; | ||
228 | else if (!strcmp(p, "off") || !strcmp(p, "0")) | ||
229 | smt_enabled_at_boot = 0; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | early_param("smt-enabled", early_smt_enabled); | ||
234 | |||
235 | /** | ||
236 | * setup_cpu_maps - initialize the following cpu maps: | ||
237 | * cpu_possible_map | ||
238 | * cpu_present_map | ||
239 | * cpu_sibling_map | ||
240 | * | ||
241 | * Having the possible map set up early allows us to restrict allocations | ||
242 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. | ||
243 | * | ||
244 | * We do not initialize the online map here; cpus set their own bits in | ||
245 | * cpu_online_map as they come up. | ||
246 | * | ||
247 | * This function is valid only for Open Firmware systems. finish_device_tree | ||
248 | * must be called before using this. | ||
249 | * | ||
250 | * While we're here, we may as well set the "physical" cpu ids in the paca. | ||
251 | */ | ||
252 | static void __init setup_cpu_maps(void) | ||
253 | { | ||
254 | struct device_node *dn = NULL; | ||
255 | int cpu = 0; | ||
256 | int swap_cpuid = 0; | ||
257 | |||
258 | check_smt_enabled(); | ||
259 | |||
260 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { | ||
261 | u32 *intserv; | ||
262 | int j, len = sizeof(u32), nthreads; | ||
263 | |||
264 | intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", | ||
265 | &len); | ||
266 | if (!intserv) | ||
267 | intserv = (u32 *)get_property(dn, "reg", NULL); | ||
268 | |||
269 | nthreads = len / sizeof(u32); | ||
270 | |||
271 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { | ||
272 | cpu_set(cpu, cpu_present_map); | ||
273 | set_hard_smp_processor_id(cpu, intserv[j]); | ||
274 | |||
275 | if (intserv[j] == boot_cpuid_phys) | ||
276 | swap_cpuid = cpu; | ||
277 | cpu_set(cpu, cpu_possible_map); | ||
278 | cpu++; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that | ||
283 | * boot cpu is logical 0. | ||
284 | */ | ||
285 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { | ||
286 | u32 tmp; | ||
287 | tmp = get_hard_smp_processor_id(0); | ||
288 | set_hard_smp_processor_id(0, boot_cpuid_phys); | ||
289 | set_hard_smp_processor_id(swap_cpuid, tmp); | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * On pSeries LPAR, we need to know how many cpus | ||
294 | * could possibly be added to this partition. | ||
295 | */ | ||
296 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | ||
297 | (dn = of_find_node_by_path("/rtas"))) { | ||
298 | int num_addr_cell, num_size_cell, maxcpus; | ||
299 | unsigned int *ireg; | ||
300 | |||
301 | num_addr_cell = prom_n_addr_cells(dn); | ||
302 | num_size_cell = prom_n_size_cells(dn); | ||
303 | |||
304 | ireg = (unsigned int *) | ||
305 | get_property(dn, "ibm,lrdr-capacity", NULL); | ||
306 | |||
307 | if (!ireg) | ||
308 | goto out; | ||
309 | |||
310 | maxcpus = ireg[num_addr_cell + num_size_cell]; | ||
311 | |||
312 | /* Double maxcpus for processors which have SMT capability */ | ||
313 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
314 | maxcpus *= 2; | ||
315 | |||
316 | if (maxcpus > NR_CPUS) { | ||
317 | printk(KERN_WARNING | ||
318 | "Partition configured for %d cpus, " | ||
319 | "operating system maximum is %d.\n", | ||
320 | maxcpus, NR_CPUS); | ||
321 | maxcpus = NR_CPUS; | ||
322 | } else | ||
323 | printk(KERN_INFO "Partition configured for %d cpus.\n", | ||
324 | maxcpus); | ||
325 | |||
326 | for (cpu = 0; cpu < maxcpus; cpu++) | ||
327 | cpu_set(cpu, cpu_possible_map); | ||
328 | out: | ||
329 | of_node_put(dn); | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Do the sibling map; assume only two threads per processor. | ||
334 | */ | ||
335 | for_each_cpu(cpu) { | ||
336 | cpu_set(cpu, cpu_sibling_map[cpu]); | ||
337 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
338 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | ||
339 | } | ||
340 | |||
341 | systemcfg->processorCount = num_present_cpus(); | ||
342 | } | ||
343 | #endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ | ||
344 | |||
345 | |||
346 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
347 | |||
348 | extern struct machdep_calls pSeries_md; | ||
349 | extern struct machdep_calls pmac_md; | ||
350 | extern struct machdep_calls maple_md; | ||
351 | |||
352 | /* Ultimately, stuff them in an elf section like initcalls... */ | ||
353 | static struct machdep_calls __initdata *machines[] = { | ||
354 | #ifdef CONFIG_PPC_PSERIES | ||
355 | &pSeries_md, | ||
356 | #endif /* CONFIG_PPC_PSERIES */ | ||
357 | #ifdef CONFIG_PPC_PMAC | ||
358 | &pmac_md, | ||
359 | #endif /* CONFIG_PPC_PMAC */ | ||
360 | #ifdef CONFIG_PPC_MAPLE | ||
361 | &maple_md, | ||
362 | #endif /* CONFIG_PPC_MAPLE */ | ||
363 | NULL | ||
364 | }; | ||
365 | |||
366 | /* | ||
367 | * Early initialization entry point. This is called by head.S | ||
368 | * with MMU translation disabled. We rely on the "feature" of | ||
369 | * the CPU that ignores the top 2 bits of the address in real | ||
370 | * mode so we can access kernel globals normally provided we | ||
371 | * only toy with things in the RMO region. From here, we do | ||
372 | * some early parsing of the device-tree to setup out LMB | ||
373 | * data structures, and allocate & initialize the hash table | ||
374 | * and segment tables so we can start running with translation | ||
375 | * enabled. | ||
376 | * | ||
377 | * It is this function which will call the probe() callback of | ||
378 | * the various platform types and copy the matching one to the | ||
379 | * global ppc_md structure. Your platform can eventually do | ||
380 | * some very early initializations from the probe() routine, but | ||
381 | * this is not recommended, be very careful as, for example, the | ||
382 | * device-tree is not accessible via normal means at this point. | ||
383 | */ | ||
384 | |||
385 | void __init early_setup(unsigned long dt_ptr) | ||
386 | { | ||
387 | struct paca_struct *lpaca = get_paca(); | ||
388 | static struct machdep_calls **mach; | ||
389 | |||
390 | /* | ||
391 | * Enable early debugging if any specified (see top of | ||
392 | * this file) | ||
393 | */ | ||
394 | EARLY_DEBUG_INIT(); | ||
395 | |||
396 | DBG(" -> early_setup()\n"); | ||
397 | |||
398 | /* | ||
399 | * Fill the default DBG level (do we want to keep | ||
400 | * that old mecanism around forever ?) | ||
401 | */ | ||
402 | ppcdbg_initialize(); | ||
403 | |||
404 | /* | ||
405 | * Do early initializations using the flattened device | ||
406 | * tree, like retreiving the physical memory map or | ||
407 | * calculating/retreiving the hash table size | ||
408 | */ | ||
409 | early_init_devtree(__va(dt_ptr)); | ||
410 | |||
411 | /* | ||
412 | * Iterate all ppc_md structures until we find the proper | ||
413 | * one for the current machine type | ||
414 | */ | ||
415 | DBG("Probing machine type for platform %x...\n", | ||
416 | systemcfg->platform); | ||
417 | |||
418 | for (mach = machines; *mach; mach++) { | ||
419 | if ((*mach)->probe(systemcfg->platform)) | ||
420 | break; | ||
421 | } | ||
422 | /* What can we do if we didn't find ? */ | ||
423 | if (*mach == NULL) { | ||
424 | DBG("No suitable machine found !\n"); | ||
425 | for (;;); | ||
426 | } | ||
427 | ppc_md = **mach; | ||
428 | |||
429 | /* our udbg callbacks got overriden by the above, let's put them | ||
430 | * back in. Ultimately, I want those things to be split from the | ||
431 | * main ppc_md | ||
432 | */ | ||
433 | EARLY_DEBUG_INIT(); | ||
434 | |||
435 | DBG("Found, Initializing memory management...\n"); | ||
436 | |||
437 | /* | ||
438 | * Initialize stab / SLB management | ||
439 | */ | ||
440 | stab_initialize(lpaca->stab_real); | ||
441 | |||
442 | /* | ||
443 | * Initialize the MMU Hash table and create the linear mapping | ||
444 | * of memory | ||
445 | */ | ||
446 | htab_initialize(); | ||
447 | |||
448 | DBG(" <- early_setup()\n"); | ||
449 | } | ||
450 | |||
451 | |||
452 | /* | ||
453 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | ||
454 | * (at least until we get rid of them completely). This is mostly some | ||
455 | * cache informations about the CPU that will be used by cache flush | ||
456 | * routines and/or provided to userland | ||
457 | */ | ||
458 | static void __init initialize_cache_info(void) | ||
459 | { | ||
460 | struct device_node *np; | ||
461 | unsigned long num_cpus = 0; | ||
462 | |||
463 | DBG(" -> initialize_cache_info()\n"); | ||
464 | |||
465 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { | ||
466 | num_cpus += 1; | ||
467 | |||
468 | /* We're assuming *all* of the CPUs have the same | ||
469 | * d-cache and i-cache sizes... -Peter | ||
470 | */ | ||
471 | |||
472 | if ( num_cpus == 1 ) { | ||
473 | u32 *sizep, *lsizep; | ||
474 | u32 size, lsize; | ||
475 | const char *dc, *ic; | ||
476 | |||
477 | /* Then read cache informations */ | ||
478 | if (systemcfg->platform == PLATFORM_POWERMAC) { | ||
479 | dc = "d-cache-block-size"; | ||
480 | ic = "i-cache-block-size"; | ||
481 | } else { | ||
482 | dc = "d-cache-line-size"; | ||
483 | ic = "i-cache-line-size"; | ||
484 | } | ||
485 | |||
486 | size = 0; | ||
487 | lsize = cur_cpu_spec->dcache_bsize; | ||
488 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); | ||
489 | if (sizep != NULL) | ||
490 | size = *sizep; | ||
491 | lsizep = (u32 *) get_property(np, dc, NULL); | ||
492 | if (lsizep != NULL) | ||
493 | lsize = *lsizep; | ||
494 | if (sizep == 0 || lsizep == 0) | ||
495 | DBG("Argh, can't find dcache properties ! " | ||
496 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | ||
497 | |||
498 | systemcfg->dcache_size = ppc64_caches.dsize = size; | ||
499 | systemcfg->dcache_line_size = | ||
500 | ppc64_caches.dline_size = lsize; | ||
501 | ppc64_caches.log_dline_size = __ilog2(lsize); | ||
502 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | ||
503 | |||
504 | size = 0; | ||
505 | lsize = cur_cpu_spec->icache_bsize; | ||
506 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); | ||
507 | if (sizep != NULL) | ||
508 | size = *sizep; | ||
509 | lsizep = (u32 *)get_property(np, ic, NULL); | ||
510 | if (lsizep != NULL) | ||
511 | lsize = *lsizep; | ||
512 | if (sizep == 0 || lsizep == 0) | ||
513 | DBG("Argh, can't find icache properties ! " | ||
514 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | ||
515 | |||
516 | systemcfg->icache_size = ppc64_caches.isize = size; | ||
517 | systemcfg->icache_line_size = | ||
518 | ppc64_caches.iline_size = lsize; | ||
519 | ppc64_caches.log_iline_size = __ilog2(lsize); | ||
520 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | /* Add an eye catcher and the systemcfg layout version number */ | ||
525 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | ||
526 | systemcfg->version.major = SYSTEMCFG_MAJOR; | ||
527 | systemcfg->version.minor = SYSTEMCFG_MINOR; | ||
528 | systemcfg->processor = mfspr(SPRN_PVR); | ||
529 | |||
530 | DBG(" <- initialize_cache_info()\n"); | ||
531 | } | ||
532 | |||
533 | static void __init check_for_initrd(void) | ||
534 | { | ||
535 | #ifdef CONFIG_BLK_DEV_INITRD | ||
536 | u64 *prop; | ||
537 | |||
538 | DBG(" -> check_for_initrd()\n"); | ||
539 | |||
540 | prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); | ||
541 | if (prop != NULL) { | ||
542 | initrd_start = (unsigned long)__va(*prop); | ||
543 | prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); | ||
544 | if (prop != NULL) { | ||
545 | initrd_end = (unsigned long)__va(*prop); | ||
546 | initrd_below_start_ok = 1; | ||
547 | } else | ||
548 | initrd_start = 0; | ||
549 | } | ||
550 | |||
551 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | ||
552 | * look sensible. If not, clear initrd reference. | ||
553 | */ | ||
554 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && | ||
555 | initrd_end > initrd_start) | ||
556 | ROOT_DEV = Root_RAM0; | ||
557 | else | ||
558 | initrd_start = initrd_end = 0; | ||
559 | |||
560 | if (initrd_start) | ||
561 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); | ||
562 | |||
563 | DBG(" <- check_for_initrd()\n"); | ||
564 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
565 | } | ||
566 | |||
567 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
568 | |||
569 | /* | ||
570 | * Do some initial setup of the system. The parameters are those which | ||
571 | * were passed in from the bootloader. | ||
572 | */ | ||
573 | void __init setup_system(void) | ||
574 | { | ||
575 | DBG(" -> setup_system()\n"); | ||
576 | |||
577 | #ifdef CONFIG_PPC_ISERIES | ||
578 | /* pSeries systems are identified in prom.c via OF. */ | ||
579 | if (itLpNaca.xLparInstalled == 1) | ||
580 | systemcfg->platform = PLATFORM_ISERIES_LPAR; | ||
581 | |||
582 | ppc_md.init_early(); | ||
583 | #else /* CONFIG_PPC_ISERIES */ | ||
584 | |||
585 | /* | ||
586 | * Unflatten the device-tree passed by prom_init or kexec | ||
587 | */ | ||
588 | unflatten_device_tree(); | ||
589 | |||
590 | /* | ||
591 | * Fill the ppc64_caches & systemcfg structures with informations | ||
592 | * retreived from the device-tree. Need to be called before | ||
593 | * finish_device_tree() since the later requires some of the | ||
594 | * informations filled up here to properly parse the interrupt | ||
595 | * tree. | ||
596 | * It also sets up the cache line sizes which allows to call | ||
597 | * routines like flush_icache_range (used by the hash init | ||
598 | * later on). | ||
599 | */ | ||
600 | initialize_cache_info(); | ||
601 | |||
602 | #ifdef CONFIG_PPC_RTAS | ||
603 | /* | ||
604 | * Initialize RTAS if available | ||
605 | */ | ||
606 | rtas_initialize(); | ||
607 | #endif /* CONFIG_PPC_RTAS */ | ||
608 | |||
609 | /* | ||
610 | * Check if we have an initrd provided via the device-tree | ||
611 | */ | ||
612 | check_for_initrd(); | ||
613 | |||
614 | /* | ||
615 | * Do some platform specific early initializations, that includes | ||
616 | * setting up the hash table pointers. It also sets up some interrupt-mapping | ||
617 | * related options that will be used by finish_device_tree() | ||
618 | */ | ||
619 | ppc_md.init_early(); | ||
620 | |||
621 | /* | ||
622 | * "Finish" the device-tree, that is do the actual parsing of | ||
623 | * some of the properties like the interrupt map | ||
624 | */ | ||
625 | finish_device_tree(); | ||
626 | |||
627 | /* | ||
628 | * Initialize xmon | ||
629 | */ | ||
630 | #ifdef CONFIG_XMON_DEFAULT | ||
631 | xmon_init(); | ||
632 | #endif | ||
633 | /* | ||
634 | * Register early console | ||
635 | */ | ||
636 | early_console_initialized = 1; | ||
637 | register_console(&udbg_console); | ||
638 | |||
639 | /* Save unparsed command line copy for /proc/cmdline */ | ||
640 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | ||
641 | |||
642 | parse_early_param(); | ||
643 | #endif /* !CONFIG_PPC_ISERIES */ | ||
644 | |||
645 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) | ||
646 | /* | ||
647 | * iSeries has already initialized the cpu maps at this point. | ||
648 | */ | ||
649 | setup_cpu_maps(); | ||
650 | |||
651 | /* Release secondary cpus out of their spinloops at 0x60 now that | ||
652 | * we can map physical -> logical CPU ids | ||
653 | */ | ||
654 | smp_release_cpus(); | ||
655 | #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ | ||
656 | |||
657 | printk("Starting Linux PPC64 %s\n", UTS_RELEASE); | ||
658 | |||
659 | printk("-----------------------------------------------------\n"); | ||
660 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | ||
661 | printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); | ||
662 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | ||
663 | printk("systemcfg = 0x%p\n", systemcfg); | ||
664 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | ||
665 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | ||
666 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | ||
667 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | ||
668 | ppc64_caches.dline_size); | ||
669 | printk("ppc64_caches.icache_line_size = 0x%x\n", | ||
670 | ppc64_caches.iline_size); | ||
671 | printk("htab_address = 0x%p\n", htab_address); | ||
672 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | ||
673 | printk("-----------------------------------------------------\n"); | ||
674 | |||
675 | mm_init_ppc64(); | ||
676 | |||
677 | DBG(" <- setup_system()\n"); | ||
678 | } | ||
679 | |||
680 | |||
681 | void machine_restart(char *cmd) | ||
682 | { | ||
683 | if (ppc_md.nvram_sync) | ||
684 | ppc_md.nvram_sync(); | ||
685 | ppc_md.restart(cmd); | ||
686 | } | ||
687 | |||
688 | EXPORT_SYMBOL(machine_restart); | ||
689 | |||
690 | void machine_power_off(void) | ||
691 | { | ||
692 | if (ppc_md.nvram_sync) | ||
693 | ppc_md.nvram_sync(); | ||
694 | ppc_md.power_off(); | ||
695 | } | ||
696 | |||
697 | EXPORT_SYMBOL(machine_power_off); | ||
698 | |||
699 | void machine_halt(void) | ||
700 | { | ||
701 | if (ppc_md.nvram_sync) | ||
702 | ppc_md.nvram_sync(); | ||
703 | ppc_md.halt(); | ||
704 | } | ||
705 | |||
706 | EXPORT_SYMBOL(machine_halt); | ||
707 | |||
708 | unsigned long ppc_proc_freq; | ||
709 | unsigned long ppc_tb_freq; | ||
710 | |||
711 | static int ppc64_panic_event(struct notifier_block *this, | ||
712 | unsigned long event, void *ptr) | ||
713 | { | ||
714 | ppc_md.panic((char *)ptr); /* May not return */ | ||
715 | return NOTIFY_DONE; | ||
716 | } | ||
717 | |||
718 | |||
719 | #ifdef CONFIG_SMP | ||
720 | DEFINE_PER_CPU(unsigned int, pvr); | ||
721 | #endif | ||
722 | |||
723 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
724 | { | ||
725 | unsigned long cpu_id = (unsigned long)v - 1; | ||
726 | unsigned int pvr; | ||
727 | unsigned short maj; | ||
728 | unsigned short min; | ||
729 | |||
730 | if (cpu_id == NR_CPUS) { | ||
731 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); | ||
732 | |||
733 | if (ppc_md.get_cpuinfo != NULL) | ||
734 | ppc_md.get_cpuinfo(m); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* We only show online cpus: disable preempt (overzealous, I | ||
740 | * knew) to prevent cpu going down. */ | ||
741 | preempt_disable(); | ||
742 | if (!cpu_online(cpu_id)) { | ||
743 | preempt_enable(); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | #ifdef CONFIG_SMP | ||
748 | pvr = per_cpu(pvr, cpu_id); | ||
749 | #else | ||
750 | pvr = mfspr(SPRN_PVR); | ||
751 | #endif | ||
752 | maj = (pvr >> 8) & 0xFF; | ||
753 | min = pvr & 0xFF; | ||
754 | |||
755 | seq_printf(m, "processor\t: %lu\n", cpu_id); | ||
756 | seq_printf(m, "cpu\t\t: "); | ||
757 | |||
758 | if (cur_cpu_spec->pvr_mask) | ||
759 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); | ||
760 | else | ||
761 | seq_printf(m, "unknown (%08x)", pvr); | ||
762 | |||
763 | #ifdef CONFIG_ALTIVEC | ||
764 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | ||
765 | seq_printf(m, ", altivec supported"); | ||
766 | #endif /* CONFIG_ALTIVEC */ | ||
767 | |||
768 | seq_printf(m, "\n"); | ||
769 | |||
770 | /* | ||
771 | * Assume here that all clock rates are the same in a | ||
772 | * smp system. -- Cort | ||
773 | */ | ||
774 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, | ||
775 | ppc_proc_freq % 1000000); | ||
776 | |||
777 | seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); | ||
778 | |||
779 | preempt_enable(); | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
784 | { | ||
785 | return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; | ||
786 | } | ||
787 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
788 | { | ||
789 | ++*pos; | ||
790 | return c_start(m, pos); | ||
791 | } | ||
792 | static void c_stop(struct seq_file *m, void *v) | ||
793 | { | ||
794 | } | ||
795 | struct seq_operations cpuinfo_op = { | ||
796 | .start =c_start, | ||
797 | .next = c_next, | ||
798 | .stop = c_stop, | ||
799 | .show = show_cpuinfo, | ||
800 | }; | ||
801 | |||
802 | /* | ||
803 | * These three variables are used to save values passed to us by prom_init() | ||
804 | * via the device tree. The TCE variables are needed because with a memory_limit | ||
805 | * in force we may need to explicitly map the TCE are at the top of RAM. | ||
806 | */ | ||
807 | unsigned long memory_limit; | ||
808 | unsigned long tce_alloc_start; | ||
809 | unsigned long tce_alloc_end; | ||
810 | |||
811 | #ifdef CONFIG_PPC_ISERIES | ||
812 | /* | ||
813 | * On iSeries we just parse the mem=X option from the command line. | ||
814 | * On pSeries it's a bit more complicated, see prom_init_mem() | ||
815 | */ | ||
816 | static int __init early_parsemem(char *p) | ||
817 | { | ||
818 | if (!p) | ||
819 | return 0; | ||
820 | |||
821 | memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | early_param("mem", early_parsemem); | ||
826 | #endif /* CONFIG_PPC_ISERIES */ | ||
827 | |||
828 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
829 | static int __init set_preferred_console(void) | ||
830 | { | ||
831 | struct device_node *prom_stdout = NULL; | ||
832 | char *name; | ||
833 | u32 *spd; | ||
834 | int offset = 0; | ||
835 | |||
836 | DBG(" -> set_preferred_console()\n"); | ||
837 | |||
838 | /* The user has requested a console so this is already set up. */ | ||
839 | if (strstr(saved_command_line, "console=")) { | ||
840 | DBG(" console was specified !\n"); | ||
841 | return -EBUSY; | ||
842 | } | ||
843 | |||
844 | if (!of_chosen) { | ||
845 | DBG(" of_chosen is NULL !\n"); | ||
846 | return -ENODEV; | ||
847 | } | ||
848 | /* We are getting a weird phandle from OF ... */ | ||
849 | /* ... So use the full path instead */ | ||
850 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | ||
851 | if (name == NULL) { | ||
852 | DBG(" no linux,stdout-path !\n"); | ||
853 | return -ENODEV; | ||
854 | } | ||
855 | prom_stdout = of_find_node_by_path(name); | ||
856 | if (!prom_stdout) { | ||
857 | DBG(" can't find stdout package %s !\n", name); | ||
858 | return -ENODEV; | ||
859 | } | ||
860 | DBG("stdout is %s\n", prom_stdout->full_name); | ||
861 | |||
862 | name = (char *)get_property(prom_stdout, "name", NULL); | ||
863 | if (!name) { | ||
864 | DBG(" stdout package has no name !\n"); | ||
865 | goto not_found; | ||
866 | } | ||
867 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | ||
868 | |||
869 | if (0) | ||
870 | ; | ||
871 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
872 | else if (strcmp(name, "serial") == 0) { | ||
873 | int i; | ||
874 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); | ||
875 | if (i > 8) { | ||
876 | switch (reg[1]) { | ||
877 | case 0x3f8: | ||
878 | offset = 0; | ||
879 | break; | ||
880 | case 0x2f8: | ||
881 | offset = 1; | ||
882 | break; | ||
883 | case 0x898: | ||
884 | offset = 2; | ||
885 | break; | ||
886 | case 0x890: | ||
887 | offset = 3; | ||
888 | break; | ||
889 | default: | ||
890 | /* We dont recognise the serial port */ | ||
891 | goto not_found; | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | ||
896 | #ifdef CONFIG_PPC_PSERIES | ||
897 | else if (strcmp(name, "vty") == 0) { | ||
898 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); | ||
899 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); | ||
900 | |||
901 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { | ||
902 | /* Host Virtual Serial Interface */ | ||
903 | int offset; | ||
904 | switch (reg[0]) { | ||
905 | case 0x30000000: | ||
906 | offset = 0; | ||
907 | break; | ||
908 | case 0x30000001: | ||
909 | offset = 1; | ||
910 | break; | ||
911 | default: | ||
912 | goto not_found; | ||
913 | } | ||
914 | of_node_put(prom_stdout); | ||
915 | DBG("Found hvsi console at offset %d\n", offset); | ||
916 | return add_preferred_console("hvsi", offset, NULL); | ||
917 | } else { | ||
918 | /* pSeries LPAR virtual console */ | ||
919 | of_node_put(prom_stdout); | ||
920 | DBG("Found hvc console\n"); | ||
921 | return add_preferred_console("hvc", 0, NULL); | ||
922 | } | ||
923 | } | ||
924 | #endif /* CONFIG_PPC_PSERIES */ | ||
925 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | ||
926 | else if (strcmp(name, "ch-a") == 0) | ||
927 | offset = 0; | ||
928 | else if (strcmp(name, "ch-b") == 0) | ||
929 | offset = 1; | ||
930 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | ||
931 | else | ||
932 | goto not_found; | ||
933 | of_node_put(prom_stdout); | ||
934 | |||
935 | DBG("Found serial console at ttyS%d\n", offset); | ||
936 | |||
937 | if (spd) { | ||
938 | static char __initdata opt[16]; | ||
939 | sprintf(opt, "%d", *spd); | ||
940 | return add_preferred_console("ttyS", offset, opt); | ||
941 | } else | ||
942 | return add_preferred_console("ttyS", offset, NULL); | ||
943 | |||
944 | not_found: | ||
945 | DBG("No preferred console found !\n"); | ||
946 | of_node_put(prom_stdout); | ||
947 | return -ENODEV; | ||
948 | } | ||
949 | console_initcall(set_preferred_console); | ||
950 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
951 | |||
952 | #ifdef CONFIG_IRQSTACKS | ||
953 | static void __init irqstack_early_init(void) | ||
954 | { | ||
955 | unsigned int i; | ||
956 | |||
957 | /* | ||
958 | * interrupt stacks must be under 256MB, we cannot afford to take | ||
959 | * SLB misses on them. | ||
960 | */ | ||
961 | for_each_cpu(i) { | ||
962 | softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | ||
963 | THREAD_SIZE, 0x10000000)); | ||
964 | hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | ||
965 | THREAD_SIZE, 0x10000000)); | ||
966 | } | ||
967 | } | ||
968 | #else | ||
969 | #define irqstack_early_init() | ||
970 | #endif | ||
971 | |||
972 | /* | ||
973 | * Stack space used when we detect a bad kernel stack pointer, and | ||
974 | * early in SMP boots before relocation is enabled. | ||
975 | */ | ||
976 | static void __init emergency_stack_init(void) | ||
977 | { | ||
978 | unsigned long limit; | ||
979 | unsigned int i; | ||
980 | |||
981 | /* | ||
982 | * Emergency stacks must be under 256MB, we cannot afford to take | ||
983 | * SLB misses on them. The ABI also requires them to be 128-byte | ||
984 | * aligned. | ||
985 | * | ||
986 | * Since we use these as temporary stacks during secondary CPU | ||
987 | * bringup, we need to get at them in real mode. This means they | ||
988 | * must also be within the RMO region. | ||
989 | */ | ||
990 | limit = min(0x10000000UL, lmb.rmo_size); | ||
991 | |||
992 | for_each_cpu(i) | ||
993 | paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, | ||
994 | limit)) + PAGE_SIZE; | ||
995 | } | ||
996 | |||
997 | /* | ||
998 | * Called from setup_arch to initialize the bitmap of available | ||
999 | * syscalls in the systemcfg page | ||
1000 | */ | ||
1001 | void __init setup_syscall_map(void) | ||
1002 | { | ||
1003 | unsigned int i, count64 = 0, count32 = 0; | ||
1004 | extern unsigned long *sys_call_table; | ||
1005 | extern unsigned long *sys_call_table32; | ||
1006 | extern unsigned long sys_ni_syscall; | ||
1007 | |||
1008 | |||
1009 | for (i = 0; i < __NR_syscalls; i++) { | ||
1010 | if (sys_call_table[i] == sys_ni_syscall) | ||
1011 | continue; | ||
1012 | count64++; | ||
1013 | systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); | ||
1014 | } | ||
1015 | for (i = 0; i < __NR_syscalls; i++) { | ||
1016 | if (sys_call_table32[i] == sys_ni_syscall) | ||
1017 | continue; | ||
1018 | count32++; | ||
1019 | systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); | ||
1020 | } | ||
1021 | printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", | ||
1022 | count32, count64); | ||
1023 | } | ||
1024 | |||
1025 | /* | ||
1026 | * Called into from start_kernel, after lock_kernel has been called. | ||
1027 | * Initializes bootmem, which is unsed to manage page allocation until | ||
1028 | * mem_init is called. | ||
1029 | */ | ||
1030 | void __init setup_arch(char **cmdline_p) | ||
1031 | { | ||
1032 | extern void do_init_bootmem(void); | ||
1033 | |||
1034 | ppc64_boot_msg(0x12, "Setup Arch"); | ||
1035 | |||
1036 | *cmdline_p = cmd_line; | ||
1037 | |||
1038 | /* | ||
1039 | * Set cache line size based on type of cpu as a default. | ||
1040 | * Systems with OF can look in the properties on the cpu node(s) | ||
1041 | * for a possibly more accurate value. | ||
1042 | */ | ||
1043 | dcache_bsize = ppc64_caches.dline_size; | ||
1044 | icache_bsize = ppc64_caches.iline_size; | ||
1045 | |||
1046 | /* reboot on panic */ | ||
1047 | panic_timeout = 180; | ||
1048 | |||
1049 | if (ppc_md.panic) | ||
1050 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); | ||
1051 | |||
1052 | init_mm.start_code = PAGE_OFFSET; | ||
1053 | init_mm.end_code = (unsigned long) _etext; | ||
1054 | init_mm.end_data = (unsigned long) _edata; | ||
1055 | init_mm.brk = klimit; | ||
1056 | |||
1057 | irqstack_early_init(); | ||
1058 | emergency_stack_init(); | ||
1059 | |||
1060 | /* set up the bootmem stuff with available memory */ | ||
1061 | do_init_bootmem(); | ||
1062 | |||
1063 | /* initialize the syscall map in systemcfg */ | ||
1064 | setup_syscall_map(); | ||
1065 | |||
1066 | ppc_md.setup_arch(); | ||
1067 | |||
1068 | /* Select the correct idle loop for the platform. */ | ||
1069 | idle_setup(); | ||
1070 | |||
1071 | paging_init(); | ||
1072 | ppc64_boot_msg(0x15, "Setup Done"); | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | /* ToDo: do something useful if ppc_md is not yet setup. */ | ||
1077 | #define PPC64_LINUX_FUNCTION 0x0f000000 | ||
1078 | #define PPC64_IPL_MESSAGE 0xc0000000 | ||
1079 | #define PPC64_TERM_MESSAGE 0xb0000000 | ||
1080 | #define PPC64_ATTN_MESSAGE 0xa0000000 | ||
1081 | #define PPC64_DUMP_MESSAGE 0xd0000000 | ||
1082 | |||
1083 | static void ppc64_do_msg(unsigned int src, const char *msg) | ||
1084 | { | ||
1085 | if (ppc_md.progress) { | ||
1086 | char buf[32]; | ||
1087 | |||
1088 | sprintf(buf, "%08x \n", src); | ||
1089 | ppc_md.progress(buf, 0); | ||
1090 | sprintf(buf, "%-16s", msg); | ||
1091 | ppc_md.progress(buf, 0); | ||
1092 | } | ||
1093 | } | ||
1094 | |||
1095 | /* Print a boot progress message. */ | ||
1096 | void ppc64_boot_msg(unsigned int src, const char *msg) | ||
1097 | { | ||
1098 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); | ||
1099 | printk("[boot]%04x %s\n", src, msg); | ||
1100 | } | ||
1101 | |||
1102 | /* Print a termination message (print only -- does not stop the kernel) */ | ||
1103 | void ppc64_terminate_msg(unsigned int src, const char *msg) | ||
1104 | { | ||
1105 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); | ||
1106 | printk("[terminate]%04x %s\n", src, msg); | ||
1107 | } | ||
1108 | |||
1109 | /* Print something that needs attention (device error, etc) */ | ||
1110 | void ppc64_attention_msg(unsigned int src, const char *msg) | ||
1111 | { | ||
1112 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); | ||
1113 | printk("[attention]%04x %s\n", src, msg); | ||
1114 | } | ||
1115 | |||
1116 | /* Print a dump progress message. */ | ||
1117 | void ppc64_dump_msg(unsigned int src, const char *msg) | ||
1118 | { | ||
1119 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); | ||
1120 | printk("[dump]%04x %s\n", src, msg); | ||
1121 | } | ||
1122 | |||
1123 | int set_spread_lpevents( char * str ) | ||
1124 | { | ||
1125 | /* The parameter is the number of processors to share in processing lp events */ | ||
1126 | unsigned long i; | ||
1127 | unsigned long val = simple_strtoul( str, NULL, 0 ); | ||
1128 | if ( ( val > 0 ) && ( val <= NR_CPUS ) ) { | ||
1129 | for ( i=1; i<val; ++i ) | ||
1130 | paca[i].lpqueue_ptr = paca[0].lpqueue_ptr; | ||
1131 | printk("lpevent processing spread over %ld processors\n", val); | ||
1132 | } | ||
1133 | else | ||
1134 | printk("invalid spreaqd_lpevents %ld\n", val); | ||
1135 | return 1; | ||
1136 | } | ||
1137 | |||
1138 | /* This should only be called on processor 0 during calibrate decr */ | ||
1139 | void setup_default_decr(void) | ||
1140 | { | ||
1141 | struct paca_struct *lpaca = get_paca(); | ||
1142 | |||
1143 | if ( decr_overclock_set && !decr_overclock_proc0_set ) | ||
1144 | decr_overclock_proc0 = decr_overclock; | ||
1145 | |||
1146 | lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0; | ||
1147 | lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; | ||
1148 | } | ||
1149 | |||
1150 | int set_decr_overclock_proc0( char * str ) | ||
1151 | { | ||
1152 | unsigned long val = simple_strtoul( str, NULL, 0 ); | ||
1153 | if ( ( val >= 1 ) && ( val <= 48 ) ) { | ||
1154 | decr_overclock_proc0_set = 1; | ||
1155 | decr_overclock_proc0 = val; | ||
1156 | printk("proc 0 decrementer overclock factor of %ld\n", val); | ||
1157 | } | ||
1158 | else | ||
1159 | printk("invalid proc 0 decrementer overclock factor of %ld\n", val); | ||
1160 | return 1; | ||
1161 | } | ||
1162 | |||
1163 | int set_decr_overclock( char * str ) | ||
1164 | { | ||
1165 | unsigned long val = simple_strtoul( str, NULL, 0 ); | ||
1166 | if ( ( val >= 1 ) && ( val <= 48 ) ) { | ||
1167 | decr_overclock_set = 1; | ||
1168 | decr_overclock = val; | ||
1169 | printk("decrementer overclock factor of %ld\n", val); | ||
1170 | } | ||
1171 | else | ||
1172 | printk("invalid decrementer overclock factor of %ld\n", val); | ||
1173 | return 1; | ||
1174 | |||
1175 | } | ||
1176 | |||
1177 | __setup("spread_lpevents=", set_spread_lpevents ); | ||
1178 | __setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); | ||
1179 | __setup("decr_overclock=", set_decr_overclock ); | ||
1180 | |||
1181 | #ifndef CONFIG_PPC_ISERIES | ||
1182 | /* | ||
1183 | * This function can be used by platforms to "find" legacy serial ports. | ||
1184 | * It works for "serial" nodes under an "isa" node, and will try to | ||
1185 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | ||
1186 | * ports. | ||
1187 | */ | ||
1188 | |||
1189 | #define MAX_LEGACY_SERIAL_PORTS 8 | ||
1190 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | ||
1191 | static unsigned int old_serial_count; | ||
1192 | |||
1193 | void __init generic_find_legacy_serial_ports(u64 *physport, | ||
1194 | unsigned int *default_speed) | ||
1195 | { | ||
1196 | struct device_node *np; | ||
1197 | u32 *sizeprop; | ||
1198 | |||
1199 | struct isa_reg_property { | ||
1200 | u32 space; | ||
1201 | u32 address; | ||
1202 | u32 size; | ||
1203 | }; | ||
1204 | struct pci_reg_property { | ||
1205 | struct pci_address addr; | ||
1206 | u32 size_hi; | ||
1207 | u32 size_lo; | ||
1208 | }; | ||
1209 | |||
1210 | DBG(" -> generic_find_legacy_serial_port()\n"); | ||
1211 | |||
1212 | *physport = 0; | ||
1213 | if (default_speed) | ||
1214 | *default_speed = 0; | ||
1215 | |||
1216 | np = of_find_node_by_path("/"); | ||
1217 | if (!np) | ||
1218 | return; | ||
1219 | |||
1220 | /* First fill our array */ | ||
1221 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | ||
1222 | struct device_node *isa, *pci; | ||
1223 | struct isa_reg_property *reg; | ||
1224 | unsigned long phys_size, addr_size, io_base; | ||
1225 | u32 *rangesp; | ||
1226 | u32 *interrupts, *clk, *spd; | ||
1227 | char *typep; | ||
1228 | int index, rlen, rentsize; | ||
1229 | |||
1230 | /* Ok, first check if it's under an "isa" parent */ | ||
1231 | isa = of_get_parent(np); | ||
1232 | if (!isa || strcmp(isa->name, "isa")) { | ||
1233 | DBG("%s: no isa parent found\n", np->full_name); | ||
1234 | continue; | ||
1235 | } | ||
1236 | |||
1237 | /* Now look for an "ibm,aix-loc" property that gives us ordering | ||
1238 | * if any... | ||
1239 | */ | ||
1240 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | ||
1241 | |||
1242 | /* Get the ISA port number */ | ||
1243 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | ||
1244 | if (reg == NULL) | ||
1245 | goto next_port; | ||
1246 | /* We assume the interrupt number isn't translated ... */ | ||
1247 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | ||
1248 | /* get clock freq. if present */ | ||
1249 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | ||
1250 | /* get default speed if present */ | ||
1251 | spd = (u32 *)get_property(np, "current-speed", NULL); | ||
1252 | /* Default to locate at end of array */ | ||
1253 | index = old_serial_count; /* end of the array by default */ | ||
1254 | |||
1255 | /* If we have a location index, then use it */ | ||
1256 | if (typep && *typep == 'S') { | ||
1257 | index = simple_strtol(typep+1, NULL, 0) - 1; | ||
1258 | /* if index is out of range, use end of array instead */ | ||
1259 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
1260 | index = old_serial_count; | ||
1261 | /* if our index is still out of range, that mean that | ||
1262 | * array is full, we could scan for a free slot but that | ||
1263 | * make little sense to bother, just skip the port | ||
1264 | */ | ||
1265 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
1266 | goto next_port; | ||
1267 | if (index >= old_serial_count) | ||
1268 | old_serial_count = index + 1; | ||
1269 | /* Check if there is a port who already claimed our slot */ | ||
1270 | if (serial_ports[index].iobase != 0) { | ||
1271 | /* if we still have some room, move it, else override */ | ||
1272 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | ||
1273 | DBG("Moved legacy port %d -> %d\n", index, | ||
1274 | old_serial_count); | ||
1275 | serial_ports[old_serial_count++] = | ||
1276 | serial_ports[index]; | ||
1277 | } else { | ||
1278 | DBG("Replacing legacy port %d\n", index); | ||
1279 | } | ||
1280 | } | ||
1281 | } | ||
1282 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
1283 | goto next_port; | ||
1284 | if (index >= old_serial_count) | ||
1285 | old_serial_count = index + 1; | ||
1286 | |||
1287 | /* Now fill the entry */ | ||
1288 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | ||
1289 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | ||
1290 | serial_ports[index].iobase = reg->address; | ||
1291 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | ||
1292 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | ||
1293 | |||
1294 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | ||
1295 | index, | ||
1296 | serial_ports[index].iobase, | ||
1297 | serial_ports[index].irq, | ||
1298 | serial_ports[index].uartclk); | ||
1299 | |||
1300 | /* Get phys address of IO reg for port 1 */ | ||
1301 | if (index != 0) | ||
1302 | goto next_port; | ||
1303 | |||
1304 | pci = of_get_parent(isa); | ||
1305 | if (!pci) { | ||
1306 | DBG("%s: no pci parent found\n", np->full_name); | ||
1307 | goto next_port; | ||
1308 | } | ||
1309 | |||
1310 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | ||
1311 | if (rangesp == NULL) { | ||
1312 | of_node_put(pci); | ||
1313 | goto next_port; | ||
1314 | } | ||
1315 | rlen /= 4; | ||
1316 | |||
1317 | /* we need the #size-cells of the PCI bridge node itself */ | ||
1318 | phys_size = 1; | ||
1319 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | ||
1320 | if (sizeprop != NULL) | ||
1321 | phys_size = *sizeprop; | ||
1322 | /* we need the parent #addr-cells */ | ||
1323 | addr_size = prom_n_addr_cells(pci); | ||
1324 | rentsize = 3 + addr_size + phys_size; | ||
1325 | io_base = 0; | ||
1326 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | ||
1327 | if (((rangesp[0] >> 24) & 0x3) != 1) | ||
1328 | continue; /* not IO space */ | ||
1329 | io_base = rangesp[3]; | ||
1330 | if (addr_size == 2) | ||
1331 | io_base = (io_base << 32) | rangesp[4]; | ||
1332 | } | ||
1333 | if (io_base != 0) { | ||
1334 | *physport = io_base + reg->address; | ||
1335 | if (default_speed && spd) | ||
1336 | *default_speed = *spd; | ||
1337 | } | ||
1338 | of_node_put(pci); | ||
1339 | next_port: | ||
1340 | of_node_put(isa); | ||
1341 | } | ||
1342 | |||
1343 | DBG(" <- generic_find_legacy_serial_port()\n"); | ||
1344 | } | ||
1345 | |||
1346 | static struct platform_device serial_device = { | ||
1347 | .name = "serial8250", | ||
1348 | .id = 0, | ||
1349 | .dev = { | ||
1350 | .platform_data = serial_ports, | ||
1351 | }, | ||
1352 | }; | ||
1353 | |||
1354 | static int __init serial_dev_init(void) | ||
1355 | { | ||
1356 | return platform_device_register(&serial_device); | ||
1357 | } | ||
1358 | arch_initcall(serial_dev_init); | ||
1359 | |||
1360 | #endif /* CONFIG_PPC_ISERIES */ | ||
1361 | |||
1362 | int check_legacy_ioport(unsigned long base_port) | ||
1363 | { | ||
1364 | if (ppc_md.check_legacy_ioport == NULL) | ||
1365 | return 0; | ||
1366 | return ppc_md.check_legacy_ioport(base_port); | ||
1367 | } | ||
1368 | EXPORT_SYMBOL(check_legacy_ioport); | ||
1369 | |||
1370 | #ifdef CONFIG_XMON | ||
1371 | static int __init early_xmon(char *p) | ||
1372 | { | ||
1373 | /* ensure xmon is enabled */ | ||
1374 | if (p) { | ||
1375 | if (strncmp(p, "on", 2) == 0) | ||
1376 | xmon_init(); | ||
1377 | if (strncmp(p, "early", 5) != 0) | ||
1378 | return 0; | ||
1379 | } | ||
1380 | xmon_init(); | ||
1381 | debugger(NULL); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | early_param("xmon", early_xmon); | ||
1386 | #endif | ||
1387 | |||
1388 | void cpu_die(void) | ||
1389 | { | ||
1390 | if (ppc_md.cpu_die) | ||
1391 | ppc_md.cpu_die(); | ||
1392 | } | ||