1
2
3
4
5
6
7
8
9
10
11
12#include <linux/types.h>
13#include <linux/init.h>
14#include <linux/kernel_stat.h>
15#include <linux/interrupt.h>
16
17#include <asm/irq_cpu.h>
18#include <asm/sgi/hpc3.h>
19#include <asm/sgi/ip22.h>
20
21
22#undef USE_LIO3_IRQ
23
24struct sgint_regs *sgint;
25
26static char lc0msk_to_irqnr[256];
27static char lc1msk_to_irqnr[256];
28static char lc2msk_to_irqnr[256];
29static char lc3msk_to_irqnr[256];
30
31extern int ip22_eisa_init(void);
32
33static void enable_local0_irq(unsigned int irq)
34{
35
36
37 if (irq != SGI_MAP_0_IRQ)
38 sgint->imask0 |= (1 << (irq - SGINT_LOCAL0));
39}
40
41static void disable_local0_irq(unsigned int irq)
42{
43 sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0));
44}
45
46static struct irq_chip ip22_local0_irq_type = {
47 .name = "IP22 local 0",
48 .ack = disable_local0_irq,
49 .mask = disable_local0_irq,
50 .mask_ack = disable_local0_irq,
51 .unmask = enable_local0_irq,
52};
53
54static void enable_local1_irq(unsigned int irq)
55{
56
57
58 if (irq != SGI_MAP_1_IRQ)
59 sgint->imask1 |= (1 << (irq - SGINT_LOCAL1));
60}
61
62static void disable_local1_irq(unsigned int irq)
63{
64 sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1));
65}
66
67static struct irq_chip ip22_local1_irq_type = {
68 .name = "IP22 local 1",
69 .ack = disable_local1_irq,
70 .mask = disable_local1_irq,
71 .mask_ack = disable_local1_irq,
72 .unmask = enable_local1_irq,
73};
74
75static void enable_local2_irq(unsigned int irq)
76{
77 sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
78 sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2));
79}
80
81static void disable_local2_irq(unsigned int irq)
82{
83 sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2));
84 if (!sgint->cmeimask0)
85 sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
86}
87
88static struct irq_chip ip22_local2_irq_type = {
89 .name = "IP22 local 2",
90 .ack = disable_local2_irq,
91 .mask = disable_local2_irq,
92 .mask_ack = disable_local2_irq,
93 .unmask = enable_local2_irq,
94};
95
96static void enable_local3_irq(unsigned int irq)
97{
98 sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
99 sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3));
100}
101
102static void disable_local3_irq(unsigned int irq)
103{
104 sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3));
105 if (!sgint->cmeimask1)
106 sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
107}
108
109static struct irq_chip ip22_local3_irq_type = {
110 .name = "IP22 local 3",
111 .ack = disable_local3_irq,
112 .mask = disable_local3_irq,
113 .mask_ack = disable_local3_irq,
114 .unmask = enable_local3_irq,
115};
116
117static void indy_local0_irqdispatch(void)
118{
119 u8 mask = sgint->istat0 & sgint->imask0;
120 u8 mask2;
121 int irq;
122
123 if (mask & SGINT_ISTAT0_LIO2) {
124 mask2 = sgint->vmeistat & sgint->cmeimask0;
125 irq = lc2msk_to_irqnr[mask2];
126 } else
127 irq = lc0msk_to_irqnr[mask];
128
129
130 if (irq)
131 do_IRQ(irq);
132}
133
134static void indy_local1_irqdispatch(void)
135{
136 u8 mask = sgint->istat1 & sgint->imask1;
137 u8 mask2;
138 int irq;
139
140 if (mask & SGINT_ISTAT1_LIO3) {
141 mask2 = sgint->vmeistat & sgint->cmeimask1;
142 irq = lc3msk_to_irqnr[mask2];
143 } else
144 irq = lc1msk_to_irqnr[mask];
145
146
147 if (irq)
148 do_IRQ(irq);
149}
150
151extern void ip22_be_interrupt(int irq);
152
153static void indy_buserror_irq(void)
154{
155 int irq = SGI_BUSERR_IRQ;
156
157 irq_enter();
158 kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
159 ip22_be_interrupt(irq);
160 irq_exit();
161}
162
163static struct irqaction local0_cascade = {
164 .handler = no_action,
165 .flags = IRQF_DISABLED,
166 .name = "local0 cascade",
167};
168
169static struct irqaction local1_cascade = {
170 .handler = no_action,
171 .flags = IRQF_DISABLED,
172 .name = "local1 cascade",
173};
174
175static struct irqaction buserr = {
176 .handler = no_action,
177 .flags = IRQF_DISABLED,
178 .name = "Bus Error",
179};
180
181static struct irqaction map0_cascade = {
182 .handler = no_action,
183 .flags = IRQF_DISABLED,
184 .name = "mapable0 cascade",
185};
186
187#ifdef USE_LIO3_IRQ
188static struct irqaction map1_cascade = {
189 .handler = no_action,
190 .flags = IRQF_DISABLED,
191 .name = "mapable1 cascade",
192};
193#define SGI_INTERRUPTS SGINT_END
194#else
195#define SGI_INTERRUPTS SGINT_LOCAL3
196#endif
197
198extern void indy_8254timer_irq(void);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228asmlinkage void plat_irq_dispatch(void)
229{
230 unsigned int pending = read_c0_status() & read_c0_cause();
231
232
233
234
235 if (pending & CAUSEF_IP7)
236 do_IRQ(SGI_TIMER_IRQ);
237 else if (pending & CAUSEF_IP2)
238 indy_local0_irqdispatch();
239 else if (pending & CAUSEF_IP3)
240 indy_local1_irqdispatch();
241 else if (pending & CAUSEF_IP6)
242 indy_buserror_irq();
243 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
244 indy_8254timer_irq();
245}
246
247void __init arch_init_irq(void)
248{
249 int i;
250
251
252 for (i = 0; i < 256; i++) {
253 if (i & 0x80) {
254 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7;
255 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7;
256 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7;
257 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7;
258 } else if (i & 0x40) {
259 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6;
260 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6;
261 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6;
262 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6;
263 } else if (i & 0x20) {
264 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5;
265 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5;
266 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5;
267 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5;
268 } else if (i & 0x10) {
269 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4;
270 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4;
271 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4;
272 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4;
273 } else if (i & 0x08) {
274 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3;
275 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3;
276 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3;
277 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3;
278 } else if (i & 0x04) {
279 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2;
280 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2;
281 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2;
282 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2;
283 } else if (i & 0x02) {
284 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1;
285 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1;
286 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1;
287 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1;
288 } else if (i & 0x01) {
289 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0;
290 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0;
291 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0;
292 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0;
293 } else {
294 lc0msk_to_irqnr[i] = 0;
295 lc1msk_to_irqnr[i] = 0;
296 lc2msk_to_irqnr[i] = 0;
297 lc3msk_to_irqnr[i] = 0;
298 }
299 }
300
301
302 sgint->imask0 = 0;
303 sgint->imask1 = 0;
304 sgint->cmeimask0 = 0;
305 sgint->cmeimask1 = 0;
306
307
308 mips_cpu_irq_init();
309
310 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
311 struct irq_chip *handler;
312
313 if (i < SGINT_LOCAL1)
314 handler = &ip22_local0_irq_type;
315 else if (i < SGINT_LOCAL2)
316 handler = &ip22_local1_irq_type;
317 else if (i < SGINT_LOCAL3)
318 handler = &ip22_local2_irq_type;
319 else
320 handler = &ip22_local3_irq_type;
321
322 set_irq_chip_and_handler(i, handler, handle_level_irq);
323 }
324
325
326 setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade);
327 setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade);
328 setup_irq(SGI_BUSERR_IRQ, &buserr);
329
330
331 setup_irq(SGI_MAP_0_IRQ, &map0_cascade);
332#ifdef USE_LIO3_IRQ
333 setup_irq(SGI_MAP_1_IRQ, &map1_cascade);
334#endif
335
336#ifdef CONFIG_EISA
337 if (ip22_is_fullhouse())
338 ip22_eisa_init();
339#endif
340}
341