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