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