xref: /linux/arch/sh/kernel/cpu/irq/imask.c (revision bf3a00f88c926635932c91afd90b4a0907dfbe78)
1*bf3a00f8SPaul Mundt /*
2*bf3a00f8SPaul Mundt  * arch/sh/kernel/cpu/irq/imask.c
3*bf3a00f8SPaul Mundt  *
4*bf3a00f8SPaul Mundt  * Copyright (C) 1999, 2000  Niibe Yutaka
5*bf3a00f8SPaul Mundt  *
6*bf3a00f8SPaul Mundt  * Simple interrupt handling using IMASK of SR register.
7*bf3a00f8SPaul Mundt  *
8*bf3a00f8SPaul Mundt  */
9*bf3a00f8SPaul Mundt /* NOTE: Will not work on level 15 */
10*bf3a00f8SPaul Mundt #include <linux/ptrace.h>
11*bf3a00f8SPaul Mundt #include <linux/errno.h>
12*bf3a00f8SPaul Mundt #include <linux/kernel_stat.h>
13*bf3a00f8SPaul Mundt #include <linux/signal.h>
14*bf3a00f8SPaul Mundt #include <linux/sched.h>
15*bf3a00f8SPaul Mundt #include <linux/interrupt.h>
16*bf3a00f8SPaul Mundt #include <linux/init.h>
17*bf3a00f8SPaul Mundt #include <linux/bitops.h>
18*bf3a00f8SPaul Mundt #include <linux/spinlock.h>
19*bf3a00f8SPaul Mundt #include <linux/cache.h>
20*bf3a00f8SPaul Mundt #include <linux/irq.h>
21*bf3a00f8SPaul Mundt #include <asm/system.h>
22*bf3a00f8SPaul Mundt #include <asm/irq.h>
23*bf3a00f8SPaul Mundt 
24*bf3a00f8SPaul Mundt /* Bitmap of IRQ masked */
25*bf3a00f8SPaul Mundt static unsigned long imask_mask = 0x7fff;
26*bf3a00f8SPaul Mundt static int interrupt_priority = 0;
27*bf3a00f8SPaul Mundt 
28*bf3a00f8SPaul Mundt static void enable_imask_irq(unsigned int irq);
29*bf3a00f8SPaul Mundt static void disable_imask_irq(unsigned int irq);
30*bf3a00f8SPaul Mundt static void shutdown_imask_irq(unsigned int irq);
31*bf3a00f8SPaul Mundt static void mask_and_ack_imask(unsigned int);
32*bf3a00f8SPaul Mundt static void end_imask_irq(unsigned int irq);
33*bf3a00f8SPaul Mundt 
34*bf3a00f8SPaul Mundt #define IMASK_PRIORITY	15
35*bf3a00f8SPaul Mundt 
36*bf3a00f8SPaul Mundt static unsigned int startup_imask_irq(unsigned int irq)
37*bf3a00f8SPaul Mundt {
38*bf3a00f8SPaul Mundt 	/* Nothing to do */
39*bf3a00f8SPaul Mundt 	return 0; /* never anything pending */
40*bf3a00f8SPaul Mundt }
41*bf3a00f8SPaul Mundt 
42*bf3a00f8SPaul Mundt static struct hw_interrupt_type imask_irq_type = {
43*bf3a00f8SPaul Mundt 	.typename = "SR.IMASK",
44*bf3a00f8SPaul Mundt 	.startup = startup_imask_irq,
45*bf3a00f8SPaul Mundt 	.shutdown = shutdown_imask_irq,
46*bf3a00f8SPaul Mundt 	.enable = enable_imask_irq,
47*bf3a00f8SPaul Mundt 	.disable = disable_imask_irq,
48*bf3a00f8SPaul Mundt 	.ack = mask_and_ack_imask,
49*bf3a00f8SPaul Mundt 	.end = end_imask_irq
50*bf3a00f8SPaul Mundt };
51*bf3a00f8SPaul Mundt 
52*bf3a00f8SPaul Mundt void static inline set_interrupt_registers(int ip)
53*bf3a00f8SPaul Mundt {
54*bf3a00f8SPaul Mundt 	unsigned long __dummy;
55*bf3a00f8SPaul Mundt 
56*bf3a00f8SPaul Mundt 	asm volatile("ldc	%2, r6_bank\n\t"
57*bf3a00f8SPaul Mundt 		     "stc	sr, %0\n\t"
58*bf3a00f8SPaul Mundt 		     "and	#0xf0, %0\n\t"
59*bf3a00f8SPaul Mundt 		     "shlr2	%0\n\t"
60*bf3a00f8SPaul Mundt 		     "cmp/eq	#0x3c, %0\n\t"
61*bf3a00f8SPaul Mundt 		     "bt/s	1f	! CLI-ed\n\t"
62*bf3a00f8SPaul Mundt 		     " stc	sr, %0\n\t"
63*bf3a00f8SPaul Mundt 		     "and	%1, %0\n\t"
64*bf3a00f8SPaul Mundt 		     "or	%2, %0\n\t"
65*bf3a00f8SPaul Mundt 		     "ldc	%0, sr\n"
66*bf3a00f8SPaul Mundt 		     "1:"
67*bf3a00f8SPaul Mundt 		     : "=&z" (__dummy)
68*bf3a00f8SPaul Mundt 		     : "r" (~0xf0), "r" (ip << 4)
69*bf3a00f8SPaul Mundt 		     : "t");
70*bf3a00f8SPaul Mundt }
71*bf3a00f8SPaul Mundt 
72*bf3a00f8SPaul Mundt static void disable_imask_irq(unsigned int irq)
73*bf3a00f8SPaul Mundt {
74*bf3a00f8SPaul Mundt 	clear_bit(irq, &imask_mask);
75*bf3a00f8SPaul Mundt 	if (interrupt_priority < IMASK_PRIORITY - irq)
76*bf3a00f8SPaul Mundt 		interrupt_priority = IMASK_PRIORITY - irq;
77*bf3a00f8SPaul Mundt 
78*bf3a00f8SPaul Mundt 	set_interrupt_registers(interrupt_priority);
79*bf3a00f8SPaul Mundt }
80*bf3a00f8SPaul Mundt 
81*bf3a00f8SPaul Mundt static void enable_imask_irq(unsigned int irq)
82*bf3a00f8SPaul Mundt {
83*bf3a00f8SPaul Mundt 	set_bit(irq, &imask_mask);
84*bf3a00f8SPaul Mundt 	interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
85*bf3a00f8SPaul Mundt 
86*bf3a00f8SPaul Mundt 	set_interrupt_registers(interrupt_priority);
87*bf3a00f8SPaul Mundt }
88*bf3a00f8SPaul Mundt 
89*bf3a00f8SPaul Mundt static void mask_and_ack_imask(unsigned int irq)
90*bf3a00f8SPaul Mundt {
91*bf3a00f8SPaul Mundt 	disable_imask_irq(irq);
92*bf3a00f8SPaul Mundt }
93*bf3a00f8SPaul Mundt 
94*bf3a00f8SPaul Mundt static void end_imask_irq(unsigned int irq)
95*bf3a00f8SPaul Mundt {
96*bf3a00f8SPaul Mundt 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
97*bf3a00f8SPaul Mundt 		enable_imask_irq(irq);
98*bf3a00f8SPaul Mundt }
99*bf3a00f8SPaul Mundt 
100*bf3a00f8SPaul Mundt static void shutdown_imask_irq(unsigned int irq)
101*bf3a00f8SPaul Mundt {
102*bf3a00f8SPaul Mundt 	/* Nothing to do */
103*bf3a00f8SPaul Mundt }
104*bf3a00f8SPaul Mundt 
105*bf3a00f8SPaul Mundt void make_imask_irq(unsigned int irq)
106*bf3a00f8SPaul Mundt {
107*bf3a00f8SPaul Mundt 	disable_irq_nosync(irq);
108*bf3a00f8SPaul Mundt 	irq_desc[irq].handler = &imask_irq_type;
109*bf3a00f8SPaul Mundt 	enable_irq(irq);
110*bf3a00f8SPaul Mundt }
111