aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/ps3
diff options
context:
space:
mode:
authorGeoff Levand <geoff@infradead.org>2011-11-08 07:37:26 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-11-15 22:47:54 -0500
commit72f3bea075287785ed32b777b6dd2636aa7002e8 (patch)
tree44ed5dfbfe046d76add301dc8c4555a125a70b3d /arch/powerpc/platforms/ps3
parentde1d9248eadd27539eba449b4d09428252e80c04 (diff)
powerpc/ps3: Fix lost SMP IPIs
Fixes the PS3 bootup hang introduced in 3.0-rc1 by: commit 317f394160e9beb97d19a84c39b7e5eb3d7815a sched: Move the second half of ttwu() to the remote cpu Move the PS3's LV1 EOI call lv1_end_of_interrupt_ext() from ps3_chip_eoi() to ps3_get_irq() for IPI messages. If lv1_send_event_locally() is called between a previous call to lv1_send_event_locally() and the coresponding call to lv1_end_of_interrupt_ext() the second event will not be delivered to the target cpu. The PS3's SMP IPIs are implemented using lv1_send_event_locally(), so if two IPI messages of the same type are sent to the same target in a relatively short period of time the second IPI event can become lost when lv1_end_of_interrupt_ext() is called from ps3_chip_eoi(). CC: stable@kernel.org Signed-off-by: Geoff Levand <geoff@infradead.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/ps3')
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c23
-rw-r--r--arch/powerpc/platforms/ps3/platform.h1
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
3 files changed, 25 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 404bc52b7806..1d6f4f478fe2 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -88,6 +88,7 @@ struct ps3_private {
88 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); 88 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
89 u64 ppe_id; 89 u64 ppe_id;
90 u64 thread_id; 90 u64 thread_id;
91 unsigned long ipi_mask;
91}; 92};
92 93
93static DEFINE_PER_CPU(struct ps3_private, ps3_private); 94static DEFINE_PER_CPU(struct ps3_private, ps3_private);
@@ -144,7 +145,11 @@ static void ps3_chip_unmask(struct irq_data *d)
144static void ps3_chip_eoi(struct irq_data *d) 145static void ps3_chip_eoi(struct irq_data *d)
145{ 146{
146 const struct ps3_private *pd = irq_data_get_irq_chip_data(d); 147 const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
147 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); 148
149 /* non-IPIs are EOIed here. */
150
151 if (!test_bit(63 - d->irq, &pd->ipi_mask))
152 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
148} 153}
149 154
150/** 155/**
@@ -691,6 +696,16 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
691 cpu, virq, pd->bmp.ipi_debug_brk_mask); 696 cpu, virq, pd->bmp.ipi_debug_brk_mask);
692} 697}
693 698
699void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq)
700{
701 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
702
703 set_bit(63 - virq, &pd->ipi_mask);
704
705 DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__,
706 cpu, virq, pd->ipi_mask);
707}
708
694static unsigned int ps3_get_irq(void) 709static unsigned int ps3_get_irq(void)
695{ 710{
696 struct ps3_private *pd = &__get_cpu_var(ps3_private); 711 struct ps3_private *pd = &__get_cpu_var(ps3_private);
@@ -720,6 +735,12 @@ static unsigned int ps3_get_irq(void)
720 BUG(); 735 BUG();
721 } 736 }
722#endif 737#endif
738
739 /* IPIs are EOIed here. */
740
741 if (test_bit(63 - plug, &pd->ipi_mask))
742 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug);
743
723 return plug; 744 return plug;
724} 745}
725 746
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 9a196a88eda7..1a633ed0fe98 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -43,6 +43,7 @@ void ps3_mm_shutdown(void);
43void ps3_init_IRQ(void); 43void ps3_init_IRQ(void);
44void ps3_shutdown_IRQ(int cpu); 44void ps3_shutdown_IRQ(int cpu);
45void __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);
46void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq);
46 47
47/* smp */ 48/* smp */
48 49
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 4c44794faac0..f609345b6c3a 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -94,6 +94,8 @@ static void __init ps3_smp_setup_cpu(int cpu)
94 94
95 if (result) 95 if (result)
96 virqs[i] = NO_IRQ; 96 virqs[i] = NO_IRQ;
97 else
98 ps3_register_ipi_irq(cpu, virqs[i]);
97 } 99 }
98 100
99 ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]); 101 ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);