diff options
Diffstat (limited to 'arch/alpha/kernel/irq_srm.c')
-rw-r--r-- | arch/alpha/kernel/irq_srm.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c new file mode 100644 index 000000000000..0a87e466918c --- /dev/null +++ b/arch/alpha/kernel/irq_srm.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Handle interrupts from the SRM, assuming no additional weirdness. | ||
3 | */ | ||
4 | |||
5 | #include <linux/init.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <linux/irq.h> | ||
8 | |||
9 | #include "proto.h" | ||
10 | #include "irq_impl.h" | ||
11 | |||
12 | |||
13 | /* | ||
14 | * Is the palcode SMP safe? In other words: can we call cserve_ena/dis | ||
15 | * at the same time in multiple CPUs? To be safe I added a spinlock | ||
16 | * but it can be removed trivially if the palcode is robust against smp. | ||
17 | */ | ||
18 | DEFINE_SPINLOCK(srm_irq_lock); | ||
19 | |||
20 | static inline void | ||
21 | srm_enable_irq(unsigned int irq) | ||
22 | { | ||
23 | spin_lock(&srm_irq_lock); | ||
24 | cserve_ena(irq - 16); | ||
25 | spin_unlock(&srm_irq_lock); | ||
26 | } | ||
27 | |||
28 | static void | ||
29 | srm_disable_irq(unsigned int irq) | ||
30 | { | ||
31 | spin_lock(&srm_irq_lock); | ||
32 | cserve_dis(irq - 16); | ||
33 | spin_unlock(&srm_irq_lock); | ||
34 | } | ||
35 | |||
36 | static unsigned int | ||
37 | srm_startup_irq(unsigned int irq) | ||
38 | { | ||
39 | srm_enable_irq(irq); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static void | ||
44 | srm_end_irq(unsigned int irq) | ||
45 | { | ||
46 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
47 | srm_enable_irq(irq); | ||
48 | } | ||
49 | |||
50 | /* Handle interrupts from the SRM, assuming no additional weirdness. */ | ||
51 | static struct hw_interrupt_type srm_irq_type = { | ||
52 | .typename = "SRM", | ||
53 | .startup = srm_startup_irq, | ||
54 | .shutdown = srm_disable_irq, | ||
55 | .enable = srm_enable_irq, | ||
56 | .disable = srm_disable_irq, | ||
57 | .ack = srm_disable_irq, | ||
58 | .end = srm_end_irq, | ||
59 | }; | ||
60 | |||
61 | void __init | ||
62 | init_srm_irqs(long max, unsigned long ignore_mask) | ||
63 | { | ||
64 | long i; | ||
65 | |||
66 | for (i = 16; i < max; ++i) { | ||
67 | if (i < 64 && ((ignore_mask >> i) & 1)) | ||
68 | continue; | ||
69 | irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; | ||
70 | irq_desc[i].handler = &srm_irq_type; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void | ||
75 | srm_device_interrupt(unsigned long vector, struct pt_regs * regs) | ||
76 | { | ||
77 | int irq = (vector - 0x800) >> 4; | ||
78 | handle_irq(irq, regs); | ||
79 | } | ||