Commit d911aed8 authored by James Bottomley's avatar James Bottomley Committed by Kyle McMartin

[PARISC] Fix our interrupts not to use smp_call_function

Fix our interrupts not to use smp_call_function

On K and D class smp, the generic code calls this under an irq
spinlock, which causes the WARN_ON() message in smp_call_function()
(and is also illegal because it could deadlock).

The fix is to use a new scheme based on the IPI_NOP.
Signed-off-by: default avatarJames Bottomley <jejb@parisc-linux.org>
Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
parent 3f902886
...@@ -43,26 +43,34 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); ...@@ -43,26 +43,34 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
*/ */
static volatile unsigned long cpu_eiem = 0; static volatile unsigned long cpu_eiem = 0;
static void cpu_set_eiem(void *info) static void cpu_disable_irq(unsigned int irq)
{
set_eiem((unsigned long) info);
}
static inline void cpu_disable_irq(unsigned int irq)
{ {
unsigned long eirr_bit = EIEM_MASK(irq); unsigned long eirr_bit = EIEM_MASK(irq);
cpu_eiem &= ~eirr_bit; cpu_eiem &= ~eirr_bit;
on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1); /* Do nothing on the other CPUs. If they get this interrupt,
* The & cpu_eiem in the do_cpu_irq_mask() ensures they won't
* handle it, and the set_eiem() at the bottom will ensure it
* then gets disabled */
} }
static void cpu_enable_irq(unsigned int irq) static void cpu_enable_irq(unsigned int irq)
{ {
unsigned long eirr_bit = EIEM_MASK(irq); unsigned long eirr_bit = EIEM_MASK(irq);
mtctl(eirr_bit, 23); /* clear EIRR bit before unmasking */
cpu_eiem |= eirr_bit; cpu_eiem |= eirr_bit;
on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
/* FIXME: while our interrupts aren't nested, we cannot reset
* the eiem mask if we're already in an interrupt. Once we
* implement nested interrupts, this can go away
*/
if (!in_interrupt())
set_eiem(cpu_eiem);
/* This is just a simple NOP IPI. But what it does is cause
* all the other CPUs to do a set_eiem(cpu_eiem) at the end
* of the interrupt handler */
smp_send_all_nop();
} }
static unsigned int cpu_startup_irq(unsigned int irq) static unsigned int cpu_startup_irq(unsigned int irq)
......
...@@ -181,12 +181,19 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -181,12 +181,19 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while (ops) { while (ops) {
unsigned long which = ffz(~ops); unsigned long which = ffz(~ops);
ops &= ~(1 << which);
switch (which) { switch (which) {
case IPI_NOP:
#if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d IPI_NOP\n",this_cpu);
#endif /* kDEBUG */
break;
case IPI_RESCHEDULE: case IPI_RESCHEDULE:
#if (kDEBUG>=100) #if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu); printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu);
#endif /* kDEBUG */ #endif /* kDEBUG */
ops &= ~(1 << IPI_RESCHEDULE);
/* /*
* Reschedule callback. Everything to be * Reschedule callback. Everything to be
* done is done by the interrupt return path. * done is done by the interrupt return path.
...@@ -197,7 +204,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -197,7 +204,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#if (kDEBUG>=100) #if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu); printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu);
#endif /* kDEBUG */ #endif /* kDEBUG */
ops &= ~(1 << IPI_CALL_FUNC);
{ {
volatile struct smp_call_struct *data; volatile struct smp_call_struct *data;
void (*func)(void *info); void (*func)(void *info);
...@@ -231,7 +237,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -231,7 +237,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#if (kDEBUG>=100) #if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu); printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu);
#endif /* kDEBUG */ #endif /* kDEBUG */
ops &= ~(1 << IPI_CPU_START);
#ifdef ENTRY_SYS_CPUS #ifdef ENTRY_SYS_CPUS
p->state = STATE_RUNNING; p->state = STATE_RUNNING;
#endif #endif
...@@ -241,7 +246,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -241,7 +246,6 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#if (kDEBUG>=100) #if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu); printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu);
#endif /* kDEBUG */ #endif /* kDEBUG */
ops &= ~(1 << IPI_CPU_STOP);
#ifdef ENTRY_SYS_CPUS #ifdef ENTRY_SYS_CPUS
#else #else
halt_processor(); halt_processor();
...@@ -252,13 +256,11 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -252,13 +256,11 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#if (kDEBUG>=100) #if (kDEBUG>=100)
printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu); printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu);
#endif /* kDEBUG */ #endif /* kDEBUG */
ops &= ~(1 << IPI_CPU_TEST);
break; break;
default: default:
printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n", printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
this_cpu, which); this_cpu, which);
ops &= ~(1 << which);
return IRQ_NONE; return IRQ_NONE;
} /* Switch */ } /* Switch */
} /* while (ops) */ } /* while (ops) */
...@@ -312,6 +314,12 @@ smp_send_start(void) { send_IPI_allbutself(IPI_CPU_START); } ...@@ -312,6 +314,12 @@ smp_send_start(void) { send_IPI_allbutself(IPI_CPU_START); }
void void
smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); }
void
smp_send_all_nop(void)
{
send_IPI_allbutself(IPI_NOP);
}
/** /**
* Run a function on all other CPUs. * Run a function on all other CPUs.
......
...@@ -29,6 +29,7 @@ extern cpumask_t cpu_online_map; ...@@ -29,6 +29,7 @@ extern cpumask_t cpu_online_map;
#define cpu_logical_map(cpu) (cpu) #define cpu_logical_map(cpu) (cpu)
extern void smp_send_reschedule(int cpu); extern void smp_send_reschedule(int cpu);
extern void smp_send_all_nop(void);
#endif /* !ASSEMBLY */ #endif /* !ASSEMBLY */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment