aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeoff Levand <geoffrey.levand@am.sony.com>2007-06-15 17:19:32 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-28 05:16:37 -0400
commit9263e85aa9e9d341ef238fffc040f586674d1709 (patch)
tree51054ba00b9283f8c70125b87968a9bf3274a7f8
parent83bb643d0714b0006ab99dbd195ec51b55a97f4e (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.c13
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c68
-rw-r--r--arch/powerpc/platforms/ps3/platform.h1
-rw-r--r--arch/powerpc/platforms/ps3/setup.c29
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
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
235static void ps3_hpte_clear(void) 235static 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
243void __init ps3_hpte_init(unsigned long htab_size) 250void __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
225fail_set: 227fail_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}
389EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
390 393
391int ps3_send_event_locally(unsigned int virq) 394int 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);
498int ps3_io_irq_destroy(unsigned int virq) 509int 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}
513EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); 532EXPORT_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
601int ps3_spe_irq_destroy(unsigned int virq) 621int 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
685unsigned int ps3_get_irq(void) 710static 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
776void 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
43void ps3_init_IRQ(void); 43void ps3_init_IRQ(void);
44void ps3_shutdown_IRQ(int cpu);
44void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); 45void __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)
210static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) 210static 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
225static 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 }