diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-06-15 17:19:32 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-06-28 05:16:37 -0400 |
commit | 9263e85aa9e9d341ef238fffc040f586674d1709 (patch) | |
tree | 51054ba00b9283f8c70125b87968a9bf3274a7f8 | |
parent | 83bb643d0714b0006ab99dbd195ec51b55a97f4e (diff) |
[POWERPC] PS3: Kexec support
Fixup the core platform parts needed for kexec to work on the PS3.
- Setup ps3_hpte_clear correctly.
- Mask interrupts on irq removal.
- Release all hypervisor resources.
- Create new routine ps3_shutdown_IRQ()
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/ps3/htab.c | 13 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 68 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 29 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 2 |
5 files changed, 70 insertions, 43 deletions
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index d741edd96a24..5d2e176a1b18 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c | |||
@@ -234,10 +234,17 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, | |||
234 | 234 | ||
235 | static void ps3_hpte_clear(void) | 235 | static void ps3_hpte_clear(void) |
236 | { | 236 | { |
237 | /* Make sure to clean up the frame buffer device first */ | 237 | int result; |
238 | ps3fb_cleanup(); | ||
239 | 238 | ||
240 | lv1_unmap_htab(htab_addr); | 239 | DBG(" -> %s:%d\n", __func__, __LINE__); |
240 | |||
241 | result = lv1_unmap_htab(htab_addr); | ||
242 | BUG_ON(result); | ||
243 | |||
244 | ps3_mm_shutdown(); | ||
245 | ps3_mm_vas_destroy(); | ||
246 | |||
247 | DBG(" <- %s:%d\n", __func__, __LINE__); | ||
241 | } | 248 | } |
242 | 249 | ||
243 | void __init ps3_hpte_init(unsigned long htab_size) | 250 | void __init ps3_hpte_init(unsigned long htab_size) |
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 2a0a422cea14..462eacc55c97 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -220,6 +220,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, | |||
220 | goto fail_set; | 220 | goto fail_set; |
221 | } | 221 | } |
222 | 222 | ||
223 | ps3_chip_mask(*virq); | ||
224 | |||
223 | return result; | 225 | return result; |
224 | 226 | ||
225 | fail_set: | 227 | fail_set: |
@@ -311,6 +313,8 @@ int ps3_irq_plug_destroy(unsigned int virq) | |||
311 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | 313 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, |
312 | pd->node, pd->cpu, virq); | 314 | pd->node, pd->cpu, virq); |
313 | 315 | ||
316 | ps3_chip_mask(virq); | ||
317 | |||
314 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | 318 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); |
315 | 319 | ||
316 | if (result) | 320 | if (result) |
@@ -368,7 +372,9 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
368 | { | 372 | { |
369 | int result; | 373 | int result; |
370 | 374 | ||
371 | pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq); | 375 | pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); |
376 | |||
377 | ps3_chip_mask(virq); | ||
372 | 378 | ||
373 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); | 379 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); |
374 | 380 | ||
@@ -376,17 +382,14 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
376 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", | 382 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", |
377 | __func__, __LINE__, ps3_result(result)); | 383 | __func__, __LINE__, ps3_result(result)); |
378 | 384 | ||
379 | /* lv1_destruct_event_receive_port() destroys the IRQ plug, | 385 | /* |
380 | * so don't call ps3_irq_plug_destroy() here. | 386 | * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() |
387 | * calls from interrupt context (smp_call_function) when kexecing. | ||
381 | */ | 388 | */ |
382 | 389 | ||
383 | result = ps3_virq_destroy(virq); | ||
384 | BUG_ON(result); | ||
385 | |||
386 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 390 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
387 | return result; | 391 | return result; |
388 | } | 392 | } |
389 | EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy); | ||
390 | 393 | ||
391 | int ps3_send_event_locally(unsigned int virq) | 394 | int ps3_send_event_locally(unsigned int virq) |
392 | { | 395 | { |
@@ -458,6 +461,14 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, | |||
458 | result = ps3_event_receive_port_destroy(virq); | 461 | result = ps3_event_receive_port_destroy(virq); |
459 | BUG_ON(result); | 462 | BUG_ON(result); |
460 | 463 | ||
464 | /* | ||
465 | * ps3_event_receive_port_destroy() destroys the IRQ plug, | ||
466 | * so don't call ps3_irq_plug_destroy() here. | ||
467 | */ | ||
468 | |||
469 | result = ps3_virq_destroy(virq); | ||
470 | BUG_ON(result); | ||
471 | |||
461 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 472 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
462 | return result; | 473 | return result; |
463 | } | 474 | } |
@@ -498,16 +509,24 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup); | |||
498 | int ps3_io_irq_destroy(unsigned int virq) | 509 | int ps3_io_irq_destroy(unsigned int virq) |
499 | { | 510 | { |
500 | int result; | 511 | int result; |
512 | unsigned long outlet = virq_to_hw(virq); | ||
501 | 513 | ||
502 | result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); | 514 | ps3_chip_mask(virq); |
503 | 515 | ||
504 | if (result) | 516 | /* |
505 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | 517 | * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, |
506 | __func__, __LINE__, ps3_result(result)); | 518 | * so call ps3_irq_plug_destroy() first. |
519 | */ | ||
507 | 520 | ||
508 | result = ps3_irq_plug_destroy(virq); | 521 | result = ps3_irq_plug_destroy(virq); |
509 | BUG_ON(result); | 522 | BUG_ON(result); |
510 | 523 | ||
524 | result = lv1_destruct_io_irq_outlet(outlet); | ||
525 | |||
526 | if (result) | ||
527 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | ||
528 | __func__, __LINE__, ps3_result(result)); | ||
529 | |||
511 | return result; | 530 | return result; |
512 | } | 531 | } |
513 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); | 532 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); |
@@ -552,6 +571,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) | |||
552 | { | 571 | { |
553 | int result; | 572 | int result; |
554 | 573 | ||
574 | ps3_chip_mask(virq); | ||
555 | result = lv1_deconfigure_virtual_uart_irq(); | 575 | result = lv1_deconfigure_virtual_uart_irq(); |
556 | 576 | ||
557 | if (result) { | 577 | if (result) { |
@@ -600,9 +620,14 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, | |||
600 | 620 | ||
601 | int ps3_spe_irq_destroy(unsigned int virq) | 621 | int ps3_spe_irq_destroy(unsigned int virq) |
602 | { | 622 | { |
603 | int result = ps3_irq_plug_destroy(virq); | 623 | int result; |
624 | |||
625 | ps3_chip_mask(virq); | ||
626 | |||
627 | result = ps3_irq_plug_destroy(virq); | ||
604 | BUG_ON(result); | 628 | BUG_ON(result); |
605 | return 0; | 629 | |
630 | return result; | ||
606 | } | 631 | } |
607 | 632 | ||
608 | 633 | ||
@@ -662,7 +687,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, | |||
662 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, | 687 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, |
663 | virq); | 688 | virq); |
664 | 689 | ||
665 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); | 690 | set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); |
666 | 691 | ||
667 | return 0; | 692 | return 0; |
668 | } | 693 | } |
@@ -682,7 +707,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | |||
682 | cpu, virq, pd->bmp.ipi_debug_brk_mask); | 707 | cpu, virq, pd->bmp.ipi_debug_brk_mask); |
683 | } | 708 | } |
684 | 709 | ||
685 | unsigned int ps3_get_irq(void) | 710 | static unsigned int ps3_get_irq(void) |
686 | { | 711 | { |
687 | struct ps3_private *pd = &__get_cpu_var(ps3_private); | 712 | struct ps3_private *pd = &__get_cpu_var(ps3_private); |
688 | u64 x = (pd->bmp.status & pd->bmp.mask); | 713 | u64 x = (pd->bmp.status & pd->bmp.mask); |
@@ -747,3 +772,16 @@ void __init ps3_init_IRQ(void) | |||
747 | 772 | ||
748 | ppc_md.get_irq = ps3_get_irq; | 773 | ppc_md.get_irq = ps3_get_irq; |
749 | } | 774 | } |
775 | |||
776 | void ps3_shutdown_IRQ(int cpu) | ||
777 | { | ||
778 | int result; | ||
779 | u64 ppe_id; | ||
780 | u64 thread_id = get_hard_smp_processor_id(cpu); | ||
781 | |||
782 | lv1_get_logical_ppe_id(&ppe_id); | ||
783 | result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); | ||
784 | |||
785 | DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__, | ||
786 | __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); | ||
787 | } | ||
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index ca04f03305c7..0b93665829db 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -41,6 +41,7 @@ void ps3_mm_shutdown(void); | |||
41 | /* irq */ | 41 | /* irq */ |
42 | 42 | ||
43 | void ps3_init_IRQ(void); | 43 | void ps3_init_IRQ(void); |
44 | void ps3_shutdown_IRQ(int cpu); | ||
44 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); | 45 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); |
45 | 46 | ||
46 | /* smp */ | 47 | /* smp */ |
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 8854af184dd4..96ad4263bd29 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c | |||
@@ -209,31 +209,12 @@ static int __init ps3_probe(void) | |||
209 | #if defined(CONFIG_KEXEC) | 209 | #if defined(CONFIG_KEXEC) |
210 | static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) | 210 | static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) |
211 | { | 211 | { |
212 | DBG(" -> %s:%d\n", __func__, __LINE__); | 212 | int cpu = smp_processor_id(); |
213 | |||
214 | if (secondary) { | ||
215 | int cpu; | ||
216 | for_each_online_cpu(cpu) | ||
217 | if (cpu) | ||
218 | ps3_smp_cleanup_cpu(cpu); | ||
219 | } else | ||
220 | ps3_smp_cleanup_cpu(0); | ||
221 | |||
222 | DBG(" <- %s:%d\n", __func__, __LINE__); | ||
223 | } | ||
224 | |||
225 | static void ps3_machine_kexec(struct kimage *image) | ||
226 | { | ||
227 | unsigned long ppe_id; | ||
228 | |||
229 | DBG(" -> %s:%d\n", __func__, __LINE__); | ||
230 | 213 | ||
231 | lv1_get_logical_ppe_id(&ppe_id); | 214 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); |
232 | lv1_configure_irq_state_bitmap(ppe_id, 0, 0); | ||
233 | ps3_mm_shutdown(); | ||
234 | ps3_mm_vas_destroy(); | ||
235 | 215 | ||
236 | default_machine_kexec(image); | 216 | ps3_smp_cleanup_cpu(cpu); |
217 | ps3_shutdown_IRQ(cpu); | ||
237 | 218 | ||
238 | DBG(" <- %s:%d\n", __func__, __LINE__); | 219 | DBG(" <- %s:%d\n", __func__, __LINE__); |
239 | } | 220 | } |
@@ -255,7 +236,7 @@ define_machine(ps3) { | |||
255 | .power_off = ps3_power_off, | 236 | .power_off = ps3_power_off, |
256 | #if defined(CONFIG_KEXEC) | 237 | #if defined(CONFIG_KEXEC) |
257 | .kexec_cpu_down = ps3_kexec_cpu_down, | 238 | .kexec_cpu_down = ps3_kexec_cpu_down, |
258 | .machine_kexec = ps3_machine_kexec, | 239 | .machine_kexec = default_machine_kexec, |
259 | .machine_kexec_prepare = default_machine_kexec_prepare, | 240 | .machine_kexec_prepare = default_machine_kexec_prepare, |
260 | .machine_crash_shutdown = default_machine_crash_shutdown, | 241 | .machine_crash_shutdown = default_machine_crash_shutdown, |
261 | #endif | 242 | #endif |
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index d84371382030..f0b12f212363 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c | |||
@@ -138,7 +138,7 @@ void ps3_smp_cleanup_cpu(int cpu) | |||
138 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); | 138 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); |
139 | 139 | ||
140 | for (i = 0; i < MSG_COUNT; i++) { | 140 | for (i = 0; i < MSG_COUNT; i++) { |
141 | free_irq(virqs[i], (void*)(long)i); | 141 | /* Can't call free_irq from interrupt context. */ |
142 | ps3_event_receive_port_destroy(virqs[i]); | 142 | ps3_event_receive_port_destroy(virqs[i]); |
143 | virqs[i] = NO_IRQ; | 143 | virqs[i] = NO_IRQ; |
144 | } | 144 | } |