diff options
-rw-r--r-- | arch/powerpc/include/asm/smp.h | 7 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 59 |
2 files changed, 66 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 1866cec4f967..c25f73d1d842 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h | |||
@@ -81,6 +81,13 @@ extern int cpu_to_core_id(int cpu); | |||
81 | #define PPC_MSG_CALL_FUNC_SINGLE 2 | 81 | #define PPC_MSG_CALL_FUNC_SINGLE 2 |
82 | #define PPC_MSG_DEBUGGER_BREAK 3 | 82 | #define PPC_MSG_DEBUGGER_BREAK 3 |
83 | 83 | ||
84 | /* | ||
85 | * irq controllers that have dedicated ipis per message and don't | ||
86 | * need additional code in the action handler may use this | ||
87 | */ | ||
88 | extern int smp_request_message_ipi(int virq, int message); | ||
89 | extern const char *smp_ipi_name[]; | ||
90 | |||
84 | void smp_init_iSeries(void); | 91 | void smp_init_iSeries(void); |
85 | void smp_init_pSeries(void); | 92 | void smp_init_pSeries(void); |
86 | void smp_init_cell(void); | 93 | void smp_init_cell(void); |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ff9f7010097d..a59d8d72bb97 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -123,6 +123,65 @@ void smp_message_recv(int msg) | |||
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | static irqreturn_t call_function_action(int irq, void *data) | ||
127 | { | ||
128 | generic_smp_call_function_interrupt(); | ||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | static irqreturn_t reschedule_action(int irq, void *data) | ||
133 | { | ||
134 | /* we just need the return path side effect of checking need_resched */ | ||
135 | return IRQ_HANDLED; | ||
136 | } | ||
137 | |||
138 | static irqreturn_t call_function_single_action(int irq, void *data) | ||
139 | { | ||
140 | generic_smp_call_function_single_interrupt(); | ||
141 | return IRQ_HANDLED; | ||
142 | } | ||
143 | |||
144 | static irqreturn_t debug_ipi_action(int irq, void *data) | ||
145 | { | ||
146 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | ||
147 | return IRQ_HANDLED; | ||
148 | } | ||
149 | |||
150 | static irq_handler_t smp_ipi_action[] = { | ||
151 | [PPC_MSG_CALL_FUNCTION] = call_function_action, | ||
152 | [PPC_MSG_RESCHEDULE] = reschedule_action, | ||
153 | [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action, | ||
154 | [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action, | ||
155 | }; | ||
156 | |||
157 | const char *smp_ipi_name[] = { | ||
158 | [PPC_MSG_CALL_FUNCTION] = "ipi call function", | ||
159 | [PPC_MSG_RESCHEDULE] = "ipi reschedule", | ||
160 | [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single", | ||
161 | [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger", | ||
162 | }; | ||
163 | |||
164 | /* optional function to request ipi, for controllers with >= 4 ipis */ | ||
165 | int smp_request_message_ipi(int virq, int msg) | ||
166 | { | ||
167 | int err; | ||
168 | |||
169 | if (msg < 0 || msg > PPC_MSG_DEBUGGER_BREAK) { | ||
170 | return -EINVAL; | ||
171 | } | ||
172 | #if !defined(CONFIG_DEBUGGER) && !defined(CONFIG_KEXEC) | ||
173 | if (msg == PPC_MSG_DEBUGGER_BREAK) { | ||
174 | return 1; | ||
175 | } | ||
176 | #endif | ||
177 | err = request_irq(virq, smp_ipi_action[msg], IRQF_DISABLED|IRQF_PERCPU, | ||
178 | smp_ipi_name[msg], 0); | ||
179 | WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n", | ||
180 | virq, smp_ipi_name[msg], err); | ||
181 | |||
182 | return err; | ||
183 | } | ||
184 | |||
126 | void smp_send_reschedule(int cpu) | 185 | void smp_send_reschedule(int cpu) |
127 | { | 186 | { |
128 | if (likely(smp_ops)) | 187 | if (likely(smp_ops)) |