Commit 55dd23eca666876e6028aa35d5e391cfced54871
Committed by
David S. Miller
1 parent
ecbc42b70a
Exists in
master
and in
20 other branches
sparc32, sun4d: Implemented SMP IPIs support for SUN4D machines
The sun4d does not seem to have a distingstion between soft and hard IRQs. When generating IPIs the generated IRQ looks like a hard IRQ, this patch adds a "IPI check" in the sun4d irq trap handler at a predefined IRQ number (SUN4D_IPI_IRQ). Before generating an IPI a per-cpu memory structure is modified for the "IPI check" to successfully detect a IPI request to a specific processor, the check clears the IPI work requested. All three IPIs (resched, single and cpu-mask) use the same IRQ number. The IPI IRQ should preferrably be on a separate IRQ and definitly not shared with IRQ handlers requesting IRQ with IRQF_SHARED. Signed-off-by: Daniel Hellstrom <daniel@gaisler.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 3 changed files with 94 additions and 0 deletions Side-by-side Diff
arch/sparc/kernel/irq.h
... | ... | @@ -86,5 +86,11 @@ |
86 | 86 | #define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level) |
87 | 87 | #define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level) |
88 | 88 | #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) |
89 | + | |
90 | +/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ | |
91 | +#define SUN4D_IPI_IRQ 14 | |
92 | + | |
93 | +extern void sun4d_ipi_interrupt(void); | |
94 | + | |
89 | 95 | #endif |
arch/sparc/kernel/sun4d_irq.c
... | ... | @@ -156,6 +156,15 @@ |
156 | 156 | |
157 | 157 | cc_set_iclr(1 << pil); |
158 | 158 | |
159 | +#ifdef CONFIG_SMP | |
160 | + /* | |
161 | + * Check IPI data structures after IRQ has been cleared. Hard and Soft | |
162 | + * IRQ can happen at the same time, so both cases are always handled. | |
163 | + */ | |
164 | + if (pil == SUN4D_IPI_IRQ) | |
165 | + sun4d_ipi_interrupt(); | |
166 | +#endif | |
167 | + | |
159 | 168 | old_regs = set_irq_regs(regs); |
160 | 169 | irq_enter(); |
161 | 170 | if (sbusl == 0) { |
arch/sparc/kernel/sun4d_smp.c
... | ... | @@ -32,6 +32,7 @@ |
32 | 32 | return val; |
33 | 33 | } |
34 | 34 | |
35 | +static void smp4d_ipi_init(void); | |
35 | 36 | static void smp_setup_percpu_timer(void); |
36 | 37 | |
37 | 38 | static unsigned char cpu_leds[32]; |
... | ... | @@ -118,6 +119,7 @@ |
118 | 119 | */ |
119 | 120 | void __init smp4d_boot_cpus(void) |
120 | 121 | { |
122 | + smp4d_ipi_init(); | |
121 | 123 | if (boot_cpu_id) |
122 | 124 | current_set[0] = NULL; |
123 | 125 | smp_setup_percpu_timer(); |
... | ... | @@ -189,6 +191,80 @@ |
189 | 191 | sun4d_distribute_irqs(); |
190 | 192 | } |
191 | 193 | |
194 | +/* Memory structure giving interrupt handler information about IPI generated */ | |
195 | +struct sun4d_ipi_work { | |
196 | + int single; | |
197 | + int msk; | |
198 | + int resched; | |
199 | +}; | |
200 | + | |
201 | +static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work); | |
202 | + | |
203 | +/* Initialize IPIs on the SUN4D SMP machine */ | |
204 | +static void __init smp4d_ipi_init(void) | |
205 | +{ | |
206 | + int cpu; | |
207 | + struct sun4d_ipi_work *work; | |
208 | + | |
209 | + printk(KERN_INFO "smp4d: setup IPI at IRQ %d\n", SUN4D_IPI_IRQ); | |
210 | + | |
211 | + for_each_possible_cpu(cpu) { | |
212 | + work = &per_cpu(sun4d_ipi_work, cpu); | |
213 | + work->single = work->msk = work->resched = 0; | |
214 | + } | |
215 | +} | |
216 | + | |
217 | +void sun4d_ipi_interrupt(void) | |
218 | +{ | |
219 | + struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work); | |
220 | + | |
221 | + if (work->single) { | |
222 | + work->single = 0; | |
223 | + smp_call_function_single_interrupt(); | |
224 | + } | |
225 | + if (work->msk) { | |
226 | + work->msk = 0; | |
227 | + smp_call_function_interrupt(); | |
228 | + } | |
229 | + if (work->resched) { | |
230 | + work->resched = 0; | |
231 | + smp_resched_interrupt(); | |
232 | + } | |
233 | +} | |
234 | + | |
235 | +static void smp4d_ipi_single(int cpu) | |
236 | +{ | |
237 | + struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | |
238 | + | |
239 | + /* Mark work */ | |
240 | + work->single = 1; | |
241 | + | |
242 | + /* Generate IRQ on the CPU */ | |
243 | + sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); | |
244 | +} | |
245 | + | |
246 | +static void smp4d_ipi_mask_one(int cpu) | |
247 | +{ | |
248 | + struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | |
249 | + | |
250 | + /* Mark work */ | |
251 | + work->msk = 1; | |
252 | + | |
253 | + /* Generate IRQ on the CPU */ | |
254 | + sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); | |
255 | +} | |
256 | + | |
257 | +static void smp4d_ipi_resched(int cpu) | |
258 | +{ | |
259 | + struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | |
260 | + | |
261 | + /* Mark work */ | |
262 | + work->resched = 1; | |
263 | + | |
264 | + /* Generate IRQ on the CPU (any IRQ will cause resched) */ | |
265 | + sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); | |
266 | +} | |
267 | + | |
192 | 268 | static struct smp_funcall { |
193 | 269 | smpfunc_t func; |
194 | 270 | unsigned long arg1; |
... | ... | @@ -354,6 +430,9 @@ |
354 | 430 | BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); |
355 | 431 | BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); |
356 | 432 | BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); |
433 | + BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM); | |
434 | + BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM); | |
435 | + BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM); | |
357 | 436 | |
358 | 437 | for (i = 0; i < NR_CPUS; i++) { |
359 | 438 | ccall_info.processors_in[i] = 1; |