xref: /openbmc/linux/arch/alpha/kernel/irq_srm.c (revision 1da177e4)
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 }
80