xref: /freebsd/sys/powerpc/powerpc/intr_machdep.c (revision 39beb93c)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 /*-
33  * Copyright (c) 2002 Benno Rice.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
58  *	form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
59  *
60  * $FreeBSD$
61  */
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/queue.h>
67 #include <sys/bus.h>
68 #include <sys/interrupt.h>
69 #include <sys/ktr.h>
70 #include <sys/lock.h>
71 #include <sys/malloc.h>
72 #include <sys/mutex.h>
73 #include <sys/pcpu.h>
74 #include <sys/syslog.h>
75 #include <sys/vmmeter.h>
76 #include <sys/proc.h>
77 
78 #include <machine/frame.h>
79 #include <machine/intr_machdep.h>
80 #include <machine/md_var.h>
81 #include <machine/smp.h>
82 #include <machine/trap.h>
83 
84 #include "pic_if.h"
85 
86 #define	MAX_STRAY_LOG	5
87 
88 MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
89 
90 struct powerpc_intr {
91 	struct intr_event *event;
92 	long	*cntp;
93 	enum intr_trigger trig;
94 	enum intr_polarity pol;
95 	u_int	irq;
96 	u_int	vector;
97 };
98 
99 static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
100 static u_int nvectors;		/* Allocated vectors */
101 static u_int stray_count;
102 
103 #ifdef SMP
104 static void *ipi_cookie;
105 #endif
106 
107 static u_int ipi_irq;
108 
109 device_t pic;
110 
111 static void
112 intrcnt_setname(const char *name, int index)
113 {
114 	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
115 	    MAXCOMLEN, name);
116 }
117 
118 static struct powerpc_intr *
119 intr_lookup(u_int irq)
120 {
121 	char intrname[8];
122 	struct powerpc_intr *i, *iscan;
123 	int vector;
124 
125 	for (vector = 0; vector < nvectors; vector++) {
126 		i = powerpc_intrs[vector];
127 		if (i != NULL && i->irq == irq)
128 			return (i);
129 	}
130 
131 	i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
132 	if (i == NULL)
133 		return (NULL);
134 
135 	i->event = NULL;
136 	i->cntp = NULL;
137 	i->trig = INTR_TRIGGER_CONFORM;
138 	i->pol = INTR_POLARITY_CONFORM;
139 	i->irq = irq;
140 	i->vector = -1;
141 
142 	/* XXX LOCK */
143 
144 	for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
145 	    vector++) {
146 		iscan = powerpc_intrs[vector];
147 		if (iscan != NULL && iscan->irq == irq)
148 			break;
149 		if (iscan == NULL && i->vector == -1)
150 			i->vector = vector;
151 		iscan = NULL;
152 	}
153 
154 	if (iscan == NULL && i->vector != -1) {
155 		powerpc_intrs[i->vector] = i;
156 		sprintf(intrname, "irq%u:", i->irq);
157 		intrcnt_setname(intrname, i->vector);
158 		nvectors++;
159 	}
160 
161 	/* XXX UNLOCK */
162 
163 	if (iscan != NULL || i->vector == -1) {
164 		free(i, M_INTR);
165 		i = iscan;
166 	}
167 
168 	return (i);
169 }
170 
171 static void
172 powerpc_intr_eoi(void *arg)
173 {
174 	u_int irq = (uintptr_t)arg;
175 
176 	PIC_EOI(pic, irq);
177 }
178 
179 static void
180 powerpc_intr_mask(void *arg)
181 {
182 	u_int irq = (uintptr_t)arg;
183 
184 	PIC_MASK(pic, irq);
185 }
186 
187 static void
188 powerpc_intr_unmask(void *arg)
189 {
190 	u_int irq = (uintptr_t)arg;
191 
192 	PIC_UNMASK(pic, irq);
193 }
194 
195 void
196 powerpc_register_pic(device_t dev, u_int ipi)
197 {
198 
199 	pic = dev;
200 	ipi_irq = ipi;
201 }
202 
203 int
204 powerpc_enable_intr(void)
205 {
206 	struct powerpc_intr *i;
207 #ifdef SMP
208 	int error;
209 #endif
210 	int vector;
211 
212 	if (pic == NULL)
213 		panic("no PIC detected\n");
214 
215 #ifdef SMP
216 	/* Install an IPI handler. */
217 	error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler,
218 	    NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
219 	if (error) {
220 		printf("unable to setup IPI handler\n");
221 		return (error);
222 	}
223 #endif
224 
225 	for (vector = 0; vector < nvectors; vector++) {
226 		i = powerpc_intrs[vector];
227 		if (i == NULL)
228 			continue;
229 
230 		if (i->trig != INTR_TRIGGER_CONFORM ||
231 		    i->pol != INTR_POLARITY_CONFORM)
232 			PIC_CONFIG(pic, i->irq, i->trig, i->pol);
233 
234 		if (i->event != NULL)
235 			PIC_ENABLE(pic, i->irq, vector);
236 	}
237 
238 	return (0);
239 }
240 
241 int
242 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
243     driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
244 {
245 	struct powerpc_intr *i;
246 	int error, enable = 0;
247 
248 	i = intr_lookup(irq);
249 	if (i == NULL)
250 		return (ENOMEM);
251 
252 	if (i->event == NULL) {
253 		error = intr_event_create(&i->event, (void *)irq, 0, irq,
254 		    powerpc_intr_mask, powerpc_intr_unmask, powerpc_intr_eoi,
255 		    NULL, "irq%u:", irq);
256 		if (error)
257 			return (error);
258 
259 		i->cntp = &intrcnt[i->vector];
260 
261 		enable = 1;
262 	}
263 
264 	error = intr_event_add_handler(i->event, name, filter, handler, arg,
265 	    intr_priority(flags), flags, cookiep);
266 	intrcnt_setname(i->event->ie_fullname, i->vector);
267 
268 	if (!cold && enable)
269 		PIC_ENABLE(pic, i->irq, i->vector);
270 
271 	return (error);
272 }
273 
274 int
275 powerpc_teardown_intr(void *cookie)
276 {
277 
278 	return (intr_event_remove_handler(cookie));
279 }
280 
281 int
282 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
283 {
284 	struct powerpc_intr *i;
285 
286 	if (trig == INTR_TRIGGER_CONFORM && pol == INTR_POLARITY_CONFORM)
287 		return (0);
288 
289 	i = intr_lookup(irq);
290 	if (i == NULL)
291 		return (ENOMEM);
292 
293 	i->trig = trig;
294 	i->pol = pol;
295 
296 	if (!cold)
297 		PIC_CONFIG(pic, irq, trig, pol);
298 
299 	return (0);
300 }
301 
302 void
303 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
304 {
305 	struct powerpc_intr *i;
306 	struct intr_event *ie;
307 
308 	i = powerpc_intrs[vector];
309 	if (i == NULL)
310 		goto stray;
311 
312 	(*i->cntp)++;
313 
314 	ie = i->event;
315 	KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
316 
317 	if (intr_event_handle(ie, tf) != 0) {
318 		goto stray;
319 	}
320 	return;
321 
322 stray:
323 	stray_count++;
324 	if (stray_count <= MAX_STRAY_LOG) {
325 		printf("stray irq %d\n", i ? i->irq : -1);
326 		if (stray_count >= MAX_STRAY_LOG) {
327 			printf("got %d stray interrupts, not logging anymore\n",
328 			    MAX_STRAY_LOG);
329 		}
330 	}
331 	if (i != NULL)
332 		PIC_MASK(pic, i->irq);
333 }
334