diff options
author | James Bottomley <jejb@parisc-linux.org> | 2005-11-17 16:27:02 -0500 |
---|---|---|
committer | Kyle McMartin <kyle@parisc-linux.org> | 2005-11-17 16:27:02 -0500 |
commit | d911aed8adf74e1fae88d082b8474b2175b7f1da (patch) | |
tree | dc3271e33b2951a8fd43824300b790610c7cd221 /arch/parisc/kernel/irq.c | |
parent | 3f902886a81c6d4e6c399760936b645b5c7a7342 (diff) |
[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: James Bottomley <jejb@parisc-linux.org>
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Diffstat (limited to 'arch/parisc/kernel/irq.c')
-rw-r--r-- | arch/parisc/kernel/irq.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 21a9c5ad580b..3998c0cb925b 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c | |||
@@ -43,26 +43,34 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); | |||
43 | */ | 43 | */ |
44 | static volatile unsigned long cpu_eiem = 0; | 44 | static volatile unsigned long cpu_eiem = 0; |
45 | 45 | ||
46 | static void cpu_set_eiem(void *info) | 46 | static void cpu_disable_irq(unsigned int irq) |
47 | { | ||
48 | set_eiem((unsigned long) info); | ||
49 | } | ||
50 | |||
51 | static inline void cpu_disable_irq(unsigned int irq) | ||
52 | { | 47 | { |
53 | unsigned long eirr_bit = EIEM_MASK(irq); | 48 | unsigned long eirr_bit = EIEM_MASK(irq); |
54 | 49 | ||
55 | cpu_eiem &= ~eirr_bit; | 50 | cpu_eiem &= ~eirr_bit; |
56 | on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1); | 51 | /* Do nothing on the other CPUs. If they get this interrupt, |
52 | * The & cpu_eiem in the do_cpu_irq_mask() ensures they won't | ||
53 | * handle it, and the set_eiem() at the bottom will ensure it | ||
54 | * then gets disabled */ | ||
57 | } | 55 | } |
58 | 56 | ||
59 | static void cpu_enable_irq(unsigned int irq) | 57 | static void cpu_enable_irq(unsigned int irq) |
60 | { | 58 | { |
61 | unsigned long eirr_bit = EIEM_MASK(irq); | 59 | unsigned long eirr_bit = EIEM_MASK(irq); |
62 | 60 | ||
63 | mtctl(eirr_bit, 23); /* clear EIRR bit before unmasking */ | ||
64 | cpu_eiem |= eirr_bit; | 61 | cpu_eiem |= eirr_bit; |
65 | on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1); | 62 | |
63 | /* FIXME: while our interrupts aren't nested, we cannot reset | ||
64 | * the eiem mask if we're already in an interrupt. Once we | ||
65 | * implement nested interrupts, this can go away | ||
66 | */ | ||
67 | if (!in_interrupt()) | ||
68 | set_eiem(cpu_eiem); | ||
69 | |||
70 | /* This is just a simple NOP IPI. But what it does is cause | ||
71 | * all the other CPUs to do a set_eiem(cpu_eiem) at the end | ||
72 | * of the interrupt handler */ | ||
73 | smp_send_all_nop(); | ||
66 | } | 74 | } |
67 | 75 | ||
68 | static unsigned int cpu_startup_irq(unsigned int irq) | 76 | static unsigned int cpu_startup_irq(unsigned int irq) |