aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2011-05-01 20:08:54 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-16 16:07:44 -0400
commit55dd23eca666876e6028aa35d5e391cfced54871 (patch)
tree7f1006b68c8f04f4590c5442e5822b71d87e761d /arch
parentecbc42b70acbc6327adefe9635db93fcf62bf59d (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc/kernel/irq.h6
-rw-r--r--arch/sparc/kernel/sun4d_irq.c9
-rw-r--r--arch/sparc/kernel/sun4d_smp.c79
3 files changed, 94 insertions, 0 deletions
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index a189c273f638..100b9c204e78 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -86,4 +86,10 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
86#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level) 86#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
87#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level) 87#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
88#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) 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
93extern void sun4d_ipi_interrupt(void);
94
89#endif 95#endif
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index b830914e32d3..a9ea60eb2c10 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -156,6 +156,15 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs)
156 156
157 cc_set_iclr(1 << pil); 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 old_regs = set_irq_regs(regs); 168 old_regs = set_irq_regs(regs);
160 irq_enter(); 169 irq_enter();
161 if (sbusl == 0) { 170 if (sbusl == 0) {
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 38423a05ae41..30ca6245692f 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -32,6 +32,7 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon
32 return val; 32 return val;
33} 33}
34 34
35static void smp4d_ipi_init(void);
35static void smp_setup_percpu_timer(void); 36static void smp_setup_percpu_timer(void);
36 37
37static unsigned char cpu_leds[32]; 38static unsigned char cpu_leds[32];
@@ -118,6 +119,7 @@ void __cpuinit smp4d_callin(void)
118 */ 119 */
119void __init smp4d_boot_cpus(void) 120void __init smp4d_boot_cpus(void)
120{ 121{
122 smp4d_ipi_init();
121 if (boot_cpu_id) 123 if (boot_cpu_id)
122 current_set[0] = NULL; 124 current_set[0] = NULL;
123 smp_setup_percpu_timer(); 125 smp_setup_percpu_timer();
@@ -189,6 +191,80 @@ void __init smp4d_smp_done(void)
189 sun4d_distribute_irqs(); 191 sun4d_distribute_irqs();
190} 192}
191 193
194/* Memory structure giving interrupt handler information about IPI generated */
195struct sun4d_ipi_work {
196 int single;
197 int msk;
198 int resched;
199};
200
201static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work);
202
203/* Initialize IPIs on the SUN4D SMP machine */
204static 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
217void 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
235static 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
246static 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
257static 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
192static struct smp_funcall { 268static struct smp_funcall {
193 smpfunc_t func; 269 smpfunc_t func;
194 unsigned long arg1; 270 unsigned long arg1;
@@ -354,6 +430,9 @@ void __init sun4d_init_smp(void)
354 BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); 430 BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
355 BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); 431 BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
356 BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); 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 for (i = 0; i < NR_CPUS; i++) { 437 for (i = 0; i < NR_CPUS; i++) {
359 ccall_info.processors_in[i] = 1; 438 ccall_info.processors_in[i] = 1;