diff options
Diffstat (limited to 'arch/mips/sni/irq.c')
-rw-r--r-- | arch/mips/sni/irq.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c new file mode 100644 index 000000000000..62c760f14674 --- /dev/null +++ b/arch/mips/sni/irq.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1992 Linus Torvalds | ||
7 | * Copyright (C) 1994 - 2000 Ralf Baechle | ||
8 | */ | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | |||
16 | #include <asm/i8259.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/sni.h> | ||
19 | |||
20 | DEFINE_SPINLOCK(pciasic_lock); | ||
21 | |||
22 | extern asmlinkage void sni_rm200_pci_handle_int(void); | ||
23 | |||
24 | static void enable_pciasic_irq(unsigned int irq) | ||
25 | { | ||
26 | unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); | ||
27 | unsigned long flags; | ||
28 | |||
29 | spin_lock_irqsave(&pciasic_lock, flags); | ||
30 | *(volatile u8 *) PCIMT_IRQSEL |= mask; | ||
31 | spin_unlock_irqrestore(&pciasic_lock, flags); | ||
32 | } | ||
33 | |||
34 | static unsigned int startup_pciasic_irq(unsigned int irq) | ||
35 | { | ||
36 | enable_pciasic_irq(irq); | ||
37 | return 0; /* never anything pending */ | ||
38 | } | ||
39 | |||
40 | #define shutdown_pciasic_irq disable_pciasic_irq | ||
41 | |||
42 | void disable_pciasic_irq(unsigned int irq) | ||
43 | { | ||
44 | unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2)); | ||
45 | unsigned long flags; | ||
46 | |||
47 | spin_lock_irqsave(&pciasic_lock, flags); | ||
48 | *(volatile u8 *) PCIMT_IRQSEL &= mask; | ||
49 | spin_unlock_irqrestore(&pciasic_lock, flags); | ||
50 | } | ||
51 | |||
52 | #define mask_and_ack_pciasic_irq disable_pciasic_irq | ||
53 | |||
54 | static void end_pciasic_irq(unsigned int irq) | ||
55 | { | ||
56 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
57 | enable_pciasic_irq(irq); | ||
58 | } | ||
59 | |||
60 | static struct hw_interrupt_type pciasic_irq_type = { | ||
61 | "ASIC-PCI", | ||
62 | startup_pciasic_irq, | ||
63 | shutdown_pciasic_irq, | ||
64 | enable_pciasic_irq, | ||
65 | disable_pciasic_irq, | ||
66 | mask_and_ack_pciasic_irq, | ||
67 | end_pciasic_irq, | ||
68 | NULL | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug | ||
73 | * button interrupts. Later ... | ||
74 | */ | ||
75 | void pciasic_hwint0(struct pt_regs *regs) | ||
76 | { | ||
77 | panic("Received int0 but no handler yet ..."); | ||
78 | } | ||
79 | |||
80 | /* This interrupt was used for the com1 console on the first prototypes. */ | ||
81 | void pciasic_hwint2(struct pt_regs *regs) | ||
82 | { | ||
83 | /* I think this shouldn't happen on production machines. */ | ||
84 | panic("hwint2 and no handler yet"); | ||
85 | } | ||
86 | |||
87 | /* hwint5 is the r4k count / compare interrupt */ | ||
88 | void pciasic_hwint5(struct pt_regs *regs) | ||
89 | { | ||
90 | panic("hwint5 and no handler yet"); | ||
91 | } | ||
92 | |||
93 | static unsigned int ls1bit8(unsigned int x) | ||
94 | { | ||
95 | int b = 7, s; | ||
96 | |||
97 | s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s; | ||
98 | s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s; | ||
99 | s = 1; if ((x & 0x40) == 0) s = 0; b -= s; | ||
100 | |||
101 | return b; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * hwint 1 deals with EISA and SCSI interrupts, | ||
106 | * | ||
107 | * The EISA_INT bit in CSITPEND is high active, all others are low active. | ||
108 | */ | ||
109 | void pciasic_hwint1(struct pt_regs *regs) | ||
110 | { | ||
111 | u8 pend = *(volatile char *)PCIMT_CSITPEND; | ||
112 | unsigned long flags; | ||
113 | |||
114 | if (pend & IT_EISA) { | ||
115 | int irq; | ||
116 | /* | ||
117 | * Note: ASIC PCI's builtin interrupt achknowledge feature is | ||
118 | * broken. Using it may result in loss of some or all i8259 | ||
119 | * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ... | ||
120 | */ | ||
121 | irq = i8259_irq(); | ||
122 | if (unlikely(irq < 0)) | ||
123 | return; | ||
124 | |||
125 | do_IRQ(irq, regs); | ||
126 | } | ||
127 | |||
128 | if (!(pend & IT_SCSI)) { | ||
129 | flags = read_c0_status(); | ||
130 | clear_c0_status(ST0_IM); | ||
131 | do_IRQ(PCIMT_IRQ_SCSI, regs); | ||
132 | write_c0_status(flags); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * hwint 3 should deal with the PCI A - D interrupts, | ||
138 | */ | ||
139 | void pciasic_hwint3(struct pt_regs *regs) | ||
140 | { | ||
141 | u8 pend = *(volatile char *)PCIMT_CSITPEND; | ||
142 | int irq; | ||
143 | |||
144 | pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); | ||
145 | clear_c0_status(IE_IRQ3); | ||
146 | irq = PCIMT_IRQ_INT2 + ls1bit8(pend); | ||
147 | do_IRQ(irq, regs); | ||
148 | set_c0_status(IE_IRQ3); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * hwint 4 is used for only the onboard PCnet 32. | ||
153 | */ | ||
154 | void pciasic_hwint4(struct pt_regs *regs) | ||
155 | { | ||
156 | clear_c0_status(IE_IRQ4); | ||
157 | do_IRQ(PCIMT_IRQ_ETHERNET, regs); | ||
158 | set_c0_status(IE_IRQ4); | ||
159 | } | ||
160 | |||
161 | void __init init_pciasic(void) | ||
162 | { | ||
163 | unsigned long flags; | ||
164 | |||
165 | spin_lock_irqsave(&pciasic_lock, flags); | ||
166 | * (volatile u8 *) PCIMT_IRQSEL = | ||
167 | IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD; | ||
168 | spin_unlock_irqrestore(&pciasic_lock, flags); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * On systems with i8259-style interrupt controllers we assume for | ||
173 | * driver compatibility reasons interrupts 0 - 15 to be the i8295 | ||
174 | * interrupts even if the hardware uses a different interrupt numbering. | ||
175 | */ | ||
176 | void __init arch_init_irq(void) | ||
177 | { | ||
178 | int i; | ||
179 | |||
180 | set_except_vector(0, sni_rm200_pci_handle_int); | ||
181 | |||
182 | init_i8259_irqs(); /* Integrated i8259 */ | ||
183 | init_pciasic(); | ||
184 | |||
185 | /* Actually we've got more interrupts to handle ... */ | ||
186 | for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) { | ||
187 | irq_desc[i].status = IRQ_DISABLED; | ||
188 | irq_desc[i].action = 0; | ||
189 | irq_desc[i].depth = 1; | ||
190 | irq_desc[i].handler = &pciasic_irq_type; | ||
191 | } | ||
192 | |||
193 | change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4); | ||
194 | } | ||