xref: /linux/arch/alpha/kernel/irq_srm.c (revision 559300bc0ef7ccd541656f1189d38e7088389559)
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 irq_chip srm_irq_type = {
52 	.name		= "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 	if (NR_IRQS <= 16)
67 		return;
68 	for (i = 16; i < max; ++i) {
69 		if (i < 64 && ((ignore_mask >> i) & 1))
70 			continue;
71 		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
72 		irq_desc[i].chip = &srm_irq_type;
73 	}
74 }
75 
76 void
77 srm_device_interrupt(unsigned long vector)
78 {
79 	int irq = (vector - 0x800) >> 4;
80 	handle_irq(irq);
81 }
82