Commit 55dd23eca666876e6028aa35d5e391cfced54871

Authored by Daniel Hellstrom
Committed by David S. Miller
1 parent ecbc42b70a

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;