diff options
author | Milton Miller <miltonm@bga.com> | 2011-05-24 16:34:18 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-05-25 23:38:58 -0400 |
commit | 7ef71d753ea0286bfeb4251b9ba592716ebdd9e8 (patch) | |
tree | 60b9cbc4ab3a6d1e60d5170debdc8ee1575e6310 | |
parent | ce2a40458ebf9c2e47fa0806fec31f845bfcb9d5 (diff) |
powerpc/cell: Use common smp ipi actions
The cell iic interrupt controller has enough software caused interrupts
to use a unique interrupt for each of the 4 messages powerpc uses.
This means each interrupt gets its own irq action/data combination.
Use the seperate, optimized, arch common ipi action functions
registered via the helper smp_request_message_ipi instead passing the
message as action data to a single action that then demultipexes to
the required acton via a switch statement.
smp_request_message_ipi will register the action as IRQF_PER_CPU
and IRQF_DISABLED, and WARN if the allocation fails for some reason,
so no need to print on that failure. It will return positive if
the message will not be used by the kernel, in which case we can
free the virq.
In addition to elimiating inefficient code, this also corrects the
error that a kernel built with kexec but without a debugger would
not register the ipi for kdump to notify the other cpus of a crash.
This also restores the debugger action to be static to kernel/smp.c.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/include/asm/smp.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 45 |
3 files changed, 14 insertions, 35 deletions
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 880b8c1e6e53..11eb404b5606 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h | |||
@@ -191,8 +191,6 @@ extern unsigned long __secondary_hold_spinloop; | |||
191 | extern unsigned long __secondary_hold_acknowledge; | 191 | extern unsigned long __secondary_hold_acknowledge; |
192 | extern char __secondary_hold; | 192 | extern char __secondary_hold; |
193 | 193 | ||
194 | extern irqreturn_t debug_ipi_action(int irq, void *data); | ||
195 | |||
196 | #endif /* __ASSEMBLY__ */ | 194 | #endif /* __ASSEMBLY__ */ |
197 | 195 | ||
198 | #endif /* __KERNEL__ */ | 196 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 4a6f2ec7e761..8ebc6700b98d 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -129,7 +129,7 @@ static irqreturn_t call_function_single_action(int irq, void *data) | |||
129 | return IRQ_HANDLED; | 129 | return IRQ_HANDLED; |
130 | } | 130 | } |
131 | 131 | ||
132 | irqreturn_t debug_ipi_action(int irq, void *data) | 132 | static irqreturn_t debug_ipi_action(int irq, void *data) |
133 | { | 133 | { |
134 | if (crash_ipi_function_ptr) { | 134 | if (crash_ipi_function_ptr) { |
135 | crash_ipi_function_ptr(get_irq_regs()); | 135 | crash_ipi_function_ptr(get_irq_regs()); |
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 449c08c15862..4469be609a31 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -192,50 +192,31 @@ struct irq_host *iic_get_irq_host(int node) | |||
192 | } | 192 | } |
193 | EXPORT_SYMBOL_GPL(iic_get_irq_host); | 193 | EXPORT_SYMBOL_GPL(iic_get_irq_host); |
194 | 194 | ||
195 | static irqreturn_t iic_ipi_action(int irq, void *dev_id) | 195 | static void iic_request_ipi(int ipi) |
196 | { | ||
197 | int ipi = (int)(long)dev_id; | ||
198 | |||
199 | switch(ipi) { | ||
200 | case PPC_MSG_CALL_FUNCTION: | ||
201 | generic_smp_call_function_interrupt(); | ||
202 | break; | ||
203 | case PPC_MSG_RESCHEDULE: | ||
204 | scheduler_ipi(); | ||
205 | break; | ||
206 | case PPC_MSG_CALL_FUNC_SINGLE: | ||
207 | generic_smp_call_function_single_interrupt(); | ||
208 | break; | ||
209 | case PPC_MSG_DEBUGGER_BREAK: | ||
210 | debug_ipi_action(0, NULL); | ||
211 | break; | ||
212 | } | ||
213 | return IRQ_HANDLED; | ||
214 | } | ||
215 | static void iic_request_ipi(int ipi, const char *name) | ||
216 | { | 196 | { |
217 | int virq; | 197 | int virq; |
218 | 198 | ||
219 | virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi)); | 199 | virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi)); |
220 | if (virq == NO_IRQ) { | 200 | if (virq == NO_IRQ) { |
221 | printk(KERN_ERR | 201 | printk(KERN_ERR |
222 | "iic: failed to map IPI %s\n", name); | 202 | "iic: failed to map IPI %s\n", smp_ipi_name[ipi]); |
223 | return; | 203 | return; |
224 | } | 204 | } |
225 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name, | 205 | |
226 | (void *)(long)ipi)) | 206 | /* |
227 | printk(KERN_ERR | 207 | * If smp_request_message_ipi encounters an error it will notify |
228 | "iic: failed to request IPI %s\n", name); | 208 | * the error. If a message is not needed it will return non-zero. |
209 | */ | ||
210 | if (smp_request_message_ipi(virq, ipi)) | ||
211 | irq_dispose_mapping(virq); | ||
229 | } | 212 | } |
230 | 213 | ||
231 | void iic_request_IPIs(void) | 214 | void iic_request_IPIs(void) |
232 | { | 215 | { |
233 | iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call"); | 216 | iic_request_ipi(PPC_MSG_CALL_FUNCTION); |
234 | iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched"); | 217 | iic_request_ipi(PPC_MSG_RESCHEDULE); |
235 | iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE, "IPI-call-single"); | 218 | iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE); |
236 | #ifdef CONFIG_DEBUGGER | 219 | iic_request_ipi(PPC_MSG_DEBUGGER_BREAK); |
237 | iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); | ||
238 | #endif /* CONFIG_DEBUGGER */ | ||
239 | } | 220 | } |
240 | 221 | ||
241 | #endif /* CONFIG_SMP */ | 222 | #endif /* CONFIG_SMP */ |