Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/sgi-ip22/ip22-int.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* ip22-int.c: Routines for generic manipulation of the INT[23] ASIC
4
* found on INDY and Indigo2 workstations.
5
*
6
* Copyright (C) 1996 David S. Miller ([email protected])
7
* Copyright (C) 1997, 1998 Ralf Baechle ([email protected])
8
* Copyright (C) 1999 Andrew R. Baker ([email protected])
9
* - Indigo2 changes
10
* - Interrupt handling fixes
11
* Copyright (C) 2001, 2003 Ladislav Michl ([email protected])
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
/* So far nothing hangs here */
24
#undef USE_LIO3_IRQ
25
26
struct sgint_regs *sgint;
27
28
static char lc0msk_to_irqnr[256];
29
static char lc1msk_to_irqnr[256];
30
static char lc2msk_to_irqnr[256];
31
static char lc3msk_to_irqnr[256];
32
33
extern int ip22_eisa_init(void);
34
35
static void enable_local0_irq(struct irq_data *d)
36
{
37
/* don't allow mappable interrupt to be enabled from setup_irq,
38
* we have our own way to do so */
39
if (d->irq != SGI_MAP_0_IRQ)
40
sgint->imask0 |= (1 << (d->irq - SGINT_LOCAL0));
41
}
42
43
static void disable_local0_irq(struct irq_data *d)
44
{
45
sgint->imask0 &= ~(1 << (d->irq - SGINT_LOCAL0));
46
}
47
48
static 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
54
static void enable_local1_irq(struct irq_data *d)
55
{
56
/* don't allow mappable interrupt to be enabled from setup_irq,
57
* we have our own way to do so */
58
if (d->irq != SGI_MAP_1_IRQ)
59
sgint->imask1 |= (1 << (d->irq - SGINT_LOCAL1));
60
}
61
62
static void disable_local1_irq(struct irq_data *d)
63
{
64
sgint->imask1 &= ~(1 << (d->irq - SGINT_LOCAL1));
65
}
66
67
static 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
73
static 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
79
static 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
86
static 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
92
static 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
98
static 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
105
static 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
111
static 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
* workaround for INT2 bug; if irq == 0, INT2 has seen a fifo full
125
* irq, but failed to latch it into status register
126
*/
127
if (irq)
128
do_IRQ(irq);
129
else
130
do_IRQ(SGINT_LOCAL0 + 0);
131
}
132
133
static 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
/* if irq == 0, then the interrupt has already been cleared */
146
if (irq)
147
do_IRQ(irq);
148
}
149
150
extern void ip22_be_interrupt(int irq);
151
152
static 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
168
/*
169
* IRQs on the INDY look basically (barring software IRQs which we don't use
170
* at all) like:
171
*
172
* MIPS IRQ Source
173
* -------- ------
174
* 0 Software (ignored)
175
* 1 Software (ignored)
176
* 2 Local IRQ level zero
177
* 3 Local IRQ level one
178
* 4 8254 Timer zero
179
* 5 8254 Timer one
180
* 6 Bus Error
181
* 7 R4k timer (what we use)
182
*
183
* We handle the IRQ according to _our_ priority which is:
184
*
185
* Highest ---- R4k Timer
186
* Local IRQ zero
187
* Local IRQ one
188
* Bus Error
189
* 8254 Timer zero
190
* Lowest ---- 8254 Timer one
191
*
192
* then we just return, if multiple IRQs are pending then we will just take
193
* another exception, big deal.
194
*/
195
196
asmlinkage void plat_irq_dispatch(void)
197
{
198
unsigned int pending = read_c0_status() & read_c0_cause();
199
200
/*
201
* First we check for r4k counter/timer IRQ.
202
*/
203
if (pending & CAUSEF_IP7)
204
do_IRQ(SGI_TIMER_IRQ);
205
else if (pending & CAUSEF_IP2)
206
indy_local0_irqdispatch();
207
else if (pending & CAUSEF_IP3)
208
indy_local1_irqdispatch();
209
else if (pending & CAUSEF_IP6)
210
indy_buserror_irq();
211
else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
212
indy_8254timer_irq();
213
}
214
215
void __init arch_init_irq(void)
216
{
217
int i;
218
219
/* Init local mask --> irq tables. */
220
for (i = 0; i < 256; i++) {
221
if (i & 0x80) {
222
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7;
223
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7;
224
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7;
225
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7;
226
} else if (i & 0x40) {
227
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6;
228
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6;
229
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6;
230
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6;
231
} else if (i & 0x20) {
232
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5;
233
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5;
234
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5;
235
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5;
236
} else if (i & 0x10) {
237
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4;
238
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4;
239
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4;
240
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4;
241
} else if (i & 0x08) {
242
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3;
243
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3;
244
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3;
245
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3;
246
} else if (i & 0x04) {
247
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2;
248
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2;
249
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2;
250
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2;
251
} else if (i & 0x02) {
252
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1;
253
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1;
254
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1;
255
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1;
256
} else if (i & 0x01) {
257
lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0;
258
lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0;
259
lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0;
260
lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0;
261
} else {
262
lc0msk_to_irqnr[i] = 0;
263
lc1msk_to_irqnr[i] = 0;
264
lc2msk_to_irqnr[i] = 0;
265
lc3msk_to_irqnr[i] = 0;
266
}
267
}
268
269
/* Mask out all interrupts. */
270
sgint->imask0 = 0;
271
sgint->imask1 = 0;
272
sgint->cmeimask0 = 0;
273
sgint->cmeimask1 = 0;
274
275
/* init CPU irqs */
276
mips_cpu_irq_init();
277
278
for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
279
struct irq_chip *handler;
280
281
if (i < SGINT_LOCAL1)
282
handler = &ip22_local0_irq_type;
283
else if (i < SGINT_LOCAL2)
284
handler = &ip22_local1_irq_type;
285
else if (i < SGINT_LOCAL3)
286
handler = &ip22_local2_irq_type;
287
else
288
handler = &ip22_local3_irq_type;
289
290
irq_set_chip_and_handler(i, handler, handle_level_irq);
291
}
292
293
/* vector handler. this register the IRQ as non-sharable */
294
if (request_irq(SGI_LOCAL_0_IRQ, no_action, IRQF_NO_THREAD,
295
"local0 cascade", NULL))
296
pr_err("Failed to register local0 cascade interrupt\n");
297
if (request_irq(SGI_LOCAL_1_IRQ, no_action, IRQF_NO_THREAD,
298
"local1 cascade", NULL))
299
pr_err("Failed to register local1 cascade interrupt\n");
300
if (request_irq(SGI_BUSERR_IRQ, no_action, IRQF_NO_THREAD,
301
"Bus Error", NULL))
302
pr_err("Failed to register Bus Error interrupt\n");
303
304
/* cascade in cascade. i love Indy ;-) */
305
if (request_irq(SGI_MAP_0_IRQ, no_action, IRQF_NO_THREAD,
306
"mapable0 cascade", NULL))
307
pr_err("Failed to register mapable0 cascade interrupt\n");
308
#ifdef USE_LIO3_IRQ
309
if (request_irq(SGI_MAP_1_IRQ, no_action, IRQF_NO_THREAD,
310
"mapable1 cascade", NULL))
311
pr_err("Failed to register mapable1 cascade interrupt\n");
312
#endif
313
314
#ifdef CONFIG_EISA
315
if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */
316
ip22_eisa_init();
317
#endif
318
}
319
320