diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/setup.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 244 |
1 files changed, 133 insertions, 111 deletions
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 999509d28af8..54a52437265c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -76,6 +76,9 @@ | |||
76 | #define DBG(fmt...) | 76 | #define DBG(fmt...) |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | /* move those away to a .h */ | ||
80 | extern void smp_init_pseries_mpic(void); | ||
81 | extern void smp_init_pseries_xics(void); | ||
79 | extern void find_udbg_vterm(void); | 82 | extern void find_udbg_vterm(void); |
80 | 83 | ||
81 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ | 84 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ |
@@ -83,7 +86,7 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ | |||
83 | static void pseries_shared_idle_sleep(void); | 86 | static void pseries_shared_idle_sleep(void); |
84 | static void pseries_dedicated_idle_sleep(void); | 87 | static void pseries_dedicated_idle_sleep(void); |
85 | 88 | ||
86 | struct mpic *pSeries_mpic; | 89 | static struct device_node *pSeries_mpic_node; |
87 | 90 | ||
88 | static void pSeries_show_cpuinfo(struct seq_file *m) | 91 | static void pSeries_show_cpuinfo(struct seq_file *m) |
89 | { | 92 | { |
@@ -118,63 +121,92 @@ static void __init fwnmi_init(void) | |||
118 | fwnmi_active = 1; | 121 | fwnmi_active = 1; |
119 | } | 122 | } |
120 | 123 | ||
121 | static void __init pSeries_init_mpic(void) | 124 | void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc, |
125 | struct pt_regs *regs) | ||
122 | { | 126 | { |
123 | unsigned int *addrp; | 127 | unsigned int cascade_irq = i8259_irq(regs); |
124 | struct device_node *np; | 128 | if (cascade_irq != NO_IRQ) |
125 | unsigned long intack = 0; | 129 | generic_handle_irq(cascade_irq, regs); |
126 | 130 | desc->chip->eoi(irq); | |
127 | /* All ISUs are setup, complete initialization */ | ||
128 | mpic_init(pSeries_mpic); | ||
129 | |||
130 | /* Check what kind of cascade ACK we have */ | ||
131 | if (!(np = of_find_node_by_name(NULL, "pci")) | ||
132 | || !(addrp = (unsigned int *) | ||
133 | get_property(np, "8259-interrupt-acknowledge", NULL))) | ||
134 | printk(KERN_ERR "Cannot find pci to get ack address\n"); | ||
135 | else | ||
136 | intack = addrp[prom_n_addr_cells(np)-1]; | ||
137 | of_node_put(np); | ||
138 | |||
139 | /* Setup the legacy interrupts & controller */ | ||
140 | i8259_init(intack, 0); | ||
141 | |||
142 | /* Hook cascade to mpic */ | ||
143 | mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); | ||
144 | } | 131 | } |
145 | 132 | ||
146 | static void __init pSeries_setup_mpic(void) | 133 | static void __init pseries_mpic_init_IRQ(void) |
147 | { | 134 | { |
135 | struct device_node *np, *old, *cascade = NULL; | ||
136 | unsigned int *addrp; | ||
137 | unsigned long intack = 0; | ||
148 | unsigned int *opprop; | 138 | unsigned int *opprop; |
149 | unsigned long openpic_addr = 0; | 139 | unsigned long openpic_addr = 0; |
150 | unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS]; | 140 | unsigned int cascade_irq; |
151 | struct device_node *root; | 141 | int naddr, n, i, opplen; |
152 | int irq_count; | 142 | struct mpic *mpic; |
153 | 143 | ||
154 | /* Find the Open PIC if present */ | 144 | np = of_find_node_by_path("/"); |
155 | root = of_find_node_by_path("/"); | 145 | naddr = prom_n_addr_cells(np); |
156 | opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); | 146 | opprop = (unsigned int *) get_property(np, "platform-open-pic", &opplen); |
157 | if (opprop != 0) { | 147 | if (opprop != 0) { |
158 | int n = prom_n_addr_cells(root); | 148 | openpic_addr = of_read_number(opprop, naddr); |
159 | |||
160 | for (openpic_addr = 0; n > 0; --n) | ||
161 | openpic_addr = (openpic_addr << 32) + *opprop++; | ||
162 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 149 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
163 | } | 150 | } |
164 | of_node_put(root); | 151 | of_node_put(np); |
165 | 152 | ||
166 | BUG_ON(openpic_addr == 0); | 153 | BUG_ON(openpic_addr == 0); |
167 | 154 | ||
168 | /* Get the sense values from OF */ | ||
169 | prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS); | ||
170 | |||
171 | /* Setup the openpic driver */ | 155 | /* Setup the openpic driver */ |
172 | irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ | 156 | mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, |
173 | pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY, | 157 | MPIC_PRIMARY, |
174 | 16, 16, irq_count, /* isu size, irq offset, irq count */ | 158 | 16, 250, /* isu size, irq count */ |
175 | NR_IRQS - 4, /* ipi offset */ | 159 | " MPIC "); |
176 | senses, irq_count, /* sense & sense size */ | 160 | BUG_ON(mpic == NULL); |
177 | " MPIC "); | 161 | |
162 | /* Add ISUs */ | ||
163 | opplen /= sizeof(u32); | ||
164 | for (n = 0, i = naddr; i < opplen; i += naddr, n++) { | ||
165 | unsigned long isuaddr = of_read_number(opprop + i, naddr); | ||
166 | mpic_assign_isu(mpic, n, isuaddr); | ||
167 | } | ||
168 | |||
169 | /* All ISUs are setup, complete initialization */ | ||
170 | mpic_init(mpic); | ||
171 | |||
172 | /* Look for cascade */ | ||
173 | for_each_node_by_type(np, "interrupt-controller") | ||
174 | if (device_is_compatible(np, "chrp,iic")) { | ||
175 | cascade = np; | ||
176 | break; | ||
177 | } | ||
178 | if (cascade == NULL) | ||
179 | return; | ||
180 | |||
181 | cascade_irq = irq_of_parse_and_map(cascade, 0); | ||
182 | if (cascade == NO_IRQ) { | ||
183 | printk(KERN_ERR "xics: failed to map cascade interrupt"); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | /* Check ACK type */ | ||
188 | for (old = of_node_get(cascade); old != NULL ; old = np) { | ||
189 | np = of_get_parent(old); | ||
190 | of_node_put(old); | ||
191 | if (np == NULL) | ||
192 | break; | ||
193 | if (strcmp(np->name, "pci") != 0) | ||
194 | continue; | ||
195 | addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge", | ||
196 | NULL); | ||
197 | if (addrp == NULL) | ||
198 | continue; | ||
199 | naddr = prom_n_addr_cells(np); | ||
200 | intack = addrp[naddr-1]; | ||
201 | if (naddr > 1) | ||
202 | intack |= ((unsigned long)addrp[naddr-2]) << 32; | ||
203 | } | ||
204 | if (intack) | ||
205 | printk(KERN_DEBUG "mpic: PCI 8259 intack at 0x%016lx\n", | ||
206 | intack); | ||
207 | i8259_init(cascade, intack); | ||
208 | of_node_put(cascade); | ||
209 | set_irq_chained_handler(cascade_irq, pseries_8259_cascade); | ||
178 | } | 210 | } |
179 | 211 | ||
180 | static void pseries_lpar_enable_pmcs(void) | 212 | static void pseries_lpar_enable_pmcs(void) |
@@ -192,23 +224,67 @@ static void pseries_lpar_enable_pmcs(void) | |||
192 | get_lppaca()->pmcregs_in_use = 1; | 224 | get_lppaca()->pmcregs_in_use = 1; |
193 | } | 225 | } |
194 | 226 | ||
195 | static void __init pSeries_setup_arch(void) | 227 | #ifdef CONFIG_KEXEC |
228 | static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) | ||
196 | { | 229 | { |
197 | /* Fixup ppc_md depending on the type of interrupt controller */ | 230 | mpic_teardown_this_cpu(secondary); |
198 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | 231 | } |
199 | ppc_md.init_IRQ = pSeries_init_mpic; | 232 | |
200 | ppc_md.get_irq = mpic_get_irq; | 233 | static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) |
201 | /* Allocate the mpic now, so that find_and_init_phbs() can | 234 | { |
202 | * fill the ISUs */ | 235 | /* Don't risk a hypervisor call if we're crashing */ |
203 | pSeries_setup_mpic(); | 236 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { |
204 | } else { | 237 | unsigned long vpa = __pa(get_lppaca()); |
205 | ppc_md.init_IRQ = xics_init_IRQ; | 238 | |
206 | ppc_md.get_irq = xics_get_irq; | 239 | if (unregister_vpa(hard_smp_processor_id(), vpa)) { |
240 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
241 | "failed\n", smp_processor_id(), | ||
242 | hard_smp_processor_id()); | ||
243 | } | ||
207 | } | 244 | } |
245 | xics_teardown_cpu(secondary); | ||
246 | } | ||
247 | #endif /* CONFIG_KEXEC */ | ||
208 | 248 | ||
249 | static void __init pseries_discover_pic(void) | ||
250 | { | ||
251 | struct device_node *np; | ||
252 | char *typep; | ||
253 | |||
254 | for (np = NULL; (np = of_find_node_by_name(np, | ||
255 | "interrupt-controller"));) { | ||
256 | typep = (char *)get_property(np, "compatible", NULL); | ||
257 | if (strstr(typep, "open-pic")) { | ||
258 | pSeries_mpic_node = of_node_get(np); | ||
259 | ppc_md.init_IRQ = pseries_mpic_init_IRQ; | ||
260 | ppc_md.get_irq = mpic_get_irq; | ||
261 | #ifdef CONFIG_KEXEC | ||
262 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; | ||
263 | #endif | ||
264 | #ifdef CONFIG_SMP | ||
265 | smp_init_pseries_mpic(); | ||
266 | #endif | ||
267 | return; | ||
268 | } else if (strstr(typep, "ppc-xicp")) { | ||
269 | ppc_md.init_IRQ = xics_init_IRQ; | ||
270 | #ifdef CONFIG_KEXEC | ||
271 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; | ||
272 | #endif | ||
209 | #ifdef CONFIG_SMP | 273 | #ifdef CONFIG_SMP |
210 | smp_init_pSeries(); | 274 | smp_init_pseries_xics(); |
211 | #endif | 275 | #endif |
276 | return; | ||
277 | } | ||
278 | } | ||
279 | printk(KERN_ERR "pSeries_discover_pic: failed to recognize" | ||
280 | " interrupt-controller\n"); | ||
281 | } | ||
282 | |||
283 | static void __init pSeries_setup_arch(void) | ||
284 | { | ||
285 | /* Discover PIC type and setup ppc_md accordingly */ | ||
286 | pseries_discover_pic(); | ||
287 | |||
212 | /* openpic global configuration register (64-bit format). */ | 288 | /* openpic global configuration register (64-bit format). */ |
213 | /* openpic Interrupt Source Unit pointer (64-bit format). */ | 289 | /* openpic Interrupt Source Unit pointer (64-bit format). */ |
214 | /* python0 facility area (mmio) (64-bit format) REAL address. */ | 290 | /* python0 facility area (mmio) (64-bit format) REAL address. */ |
@@ -260,41 +336,11 @@ static int __init pSeries_init_panel(void) | |||
260 | } | 336 | } |
261 | arch_initcall(pSeries_init_panel); | 337 | arch_initcall(pSeries_init_panel); |
262 | 338 | ||
263 | static void __init pSeries_discover_pic(void) | ||
264 | { | ||
265 | struct device_node *np; | ||
266 | char *typep; | ||
267 | |||
268 | /* | ||
269 | * Setup interrupt mapping options that are needed for finish_device_tree | ||
270 | * to properly parse the OF interrupt tree & do the virtual irq mapping | ||
271 | */ | ||
272 | __irq_offset_value = NUM_ISA_INTERRUPTS; | ||
273 | ppc64_interrupt_controller = IC_INVALID; | ||
274 | for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { | ||
275 | typep = (char *)get_property(np, "compatible", NULL); | ||
276 | if (strstr(typep, "open-pic")) { | ||
277 | ppc64_interrupt_controller = IC_OPEN_PIC; | ||
278 | break; | ||
279 | } else if (strstr(typep, "ppc-xicp")) { | ||
280 | ppc64_interrupt_controller = IC_PPC_XIC; | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | if (ppc64_interrupt_controller == IC_INVALID) | ||
285 | printk("pSeries_discover_pic: failed to recognize" | ||
286 | " interrupt-controller\n"); | ||
287 | |||
288 | } | ||
289 | |||
290 | static void pSeries_mach_cpu_die(void) | 339 | static void pSeries_mach_cpu_die(void) |
291 | { | 340 | { |
292 | local_irq_disable(); | 341 | local_irq_disable(); |
293 | idle_task_exit(); | 342 | idle_task_exit(); |
294 | /* Some hardware requires clearing the CPPR, while other hardware does not | 343 | xics_teardown_cpu(0); |
295 | * it is safe either way | ||
296 | */ | ||
297 | pSeriesLP_cppr_info(0, 0); | ||
298 | rtas_stop_self(); | 344 | rtas_stop_self(); |
299 | /* Should never get here... */ | 345 | /* Should never get here... */ |
300 | BUG(); | 346 | BUG(); |
@@ -332,8 +378,6 @@ static void __init pSeries_init_early(void) | |||
332 | 378 | ||
333 | iommu_init_early_pSeries(); | 379 | iommu_init_early_pSeries(); |
334 | 380 | ||
335 | pSeries_discover_pic(); | ||
336 | |||
337 | DBG(" <- pSeries_init_early()\n"); | 381 | DBG(" <- pSeries_init_early()\n"); |
338 | } | 382 | } |
339 | 383 | ||
@@ -505,27 +549,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) | |||
505 | return PCI_PROBE_NORMAL; | 549 | return PCI_PROBE_NORMAL; |
506 | } | 550 | } |
507 | 551 | ||
508 | #ifdef CONFIG_KEXEC | ||
509 | static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) | ||
510 | { | ||
511 | /* Don't risk a hypervisor call if we're crashing */ | ||
512 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { | ||
513 | unsigned long vpa = __pa(get_lppaca()); | ||
514 | |||
515 | if (unregister_vpa(hard_smp_processor_id(), vpa)) { | ||
516 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
517 | "failed\n", smp_processor_id(), | ||
518 | hard_smp_processor_id()); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | if (ppc64_interrupt_controller == IC_OPEN_PIC) | ||
523 | mpic_teardown_this_cpu(secondary); | ||
524 | else | ||
525 | xics_teardown_cpu(secondary); | ||
526 | } | ||
527 | #endif | ||
528 | |||
529 | define_machine(pseries) { | 552 | define_machine(pseries) { |
530 | .name = "pSeries", | 553 | .name = "pSeries", |
531 | .probe = pSeries_probe, | 554 | .probe = pSeries_probe, |
@@ -550,7 +573,6 @@ define_machine(pseries) { | |||
550 | .system_reset_exception = pSeries_system_reset_exception, | 573 | .system_reset_exception = pSeries_system_reset_exception, |
551 | .machine_check_exception = pSeries_machine_check_exception, | 574 | .machine_check_exception = pSeries_machine_check_exception, |
552 | #ifdef CONFIG_KEXEC | 575 | #ifdef CONFIG_KEXEC |
553 | .kexec_cpu_down = pseries_kexec_cpu_down, | ||
554 | .machine_kexec = default_machine_kexec, | 576 | .machine_kexec = default_machine_kexec, |
555 | .machine_kexec_prepare = default_machine_kexec_prepare, | 577 | .machine_kexec_prepare = default_machine_kexec_prepare, |
556 | .machine_crash_shutdown = default_machine_crash_shutdown, | 578 | .machine_crash_shutdown = default_machine_crash_shutdown, |