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