intr_machdep.c revision 173799
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) 2001 Jake Burkholder.
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
61#include <sys/cdefs.h>
62__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/intr_machdep.c 173799 2007-11-21 04:03:51Z scottl $");
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/queue.h>
67#include <sys/bus.h>
68#include <sys/errno.h>
69#include <sys/interrupt.h>
70#include <sys/ktr.h>
71#include <sys/lock.h>
72#include <sys/mutex.h>
73#include <sys/pcpu.h>
74#include <sys/proc.h>
75#include <sys/vmmeter.h>
76
77#include <machine/frame.h>
78#include <machine/intr_machdep.h>
79
80#define	MAX_STRAY_LOG	5
81
82CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
83
84ih_func_t *intr_handlers[PIL_MAX];
85uint16_t pil_countp[PIL_MAX];
86
87struct intr_vector intr_vectors[IV_MAX];
88uint16_t intr_countp[IV_MAX];
89static u_long intr_stray_count[IV_MAX];
90
91static const char *pil_names[] = {
92	"stray",
93	"low",		/* PIL_LOW */
94	"ithrd",	/* PIL_ITHREAD */
95	"rndzvs",	/* PIL_RENDEZVOUS */
96	"ast",		/* PIL_AST */
97	"stop",		/* PIL_STOP */
98	"stray", "stray", "stray", "stray", "stray", "stray", "stray",
99	"fast",		/* PIL_FAST */
100	"tick",		/* PIL_TICK */
101};
102
103/* protect the intr_vectors table */
104static struct mtx intr_table_lock;
105
106static void intr_enable_eoi(void *);
107static void intr_execute_handlers(void *);
108static void intr_stray_level(struct trapframe *);
109static void intr_stray_vector(void *);
110static int intrcnt_setname(const char *, int);
111static void intrcnt_updatename(int, const char *, int);
112
113/*
114 * not MPSAFE
115 */
116static void
117intrcnt_updatename(int vec, const char *name, int ispil)
118{
119	static int intrcnt_index, stray_pil_index, stray_vec_index;
120	int name_index;
121
122	if (intrnames[0] == '\0') {
123		/* for bitbucket */
124		if (bootverbose)
125			printf("initalizing intr_countp\n");
126		intrcnt_setname("???", intrcnt_index++);
127
128		stray_vec_index = intrcnt_index++;
129		intrcnt_setname("stray", stray_vec_index);
130		for (name_index = 0; name_index < IV_MAX; name_index++)
131			intr_countp[name_index] = stray_vec_index;
132
133		stray_pil_index = intrcnt_index++;
134		intrcnt_setname("pil", stray_pil_index);
135		for (name_index = 0; name_index < PIL_MAX; name_index++)
136			pil_countp[name_index] = stray_pil_index;
137	}
138
139	if (name == NULL)
140		name = "???";
141
142	if (!ispil && intr_countp[vec] != stray_vec_index)
143		name_index = intr_countp[vec];
144	else if (ispil && pil_countp[vec] != stray_pil_index)
145		name_index = pil_countp[vec];
146	else
147		name_index = intrcnt_index++;
148
149	if (intrcnt_setname(name, name_index))
150		name_index = 0;
151
152	if (!ispil)
153		intr_countp[vec] = name_index;
154	else
155		pil_countp[vec] = name_index;
156}
157
158static int
159intrcnt_setname(const char *name, int index)
160{
161
162	if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
163		return (E2BIG);
164	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
165	    MAXCOMLEN, name);
166	return (0);
167}
168
169void
170intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
171{
172	char pilname[MAXCOMLEN + 1];
173	u_long ps;
174
175	ps = intr_disable();
176	if (vec != -1) {
177		intr_vectors[vec].iv_func = ivf;
178		intr_vectors[vec].iv_arg = iva;
179		intr_vectors[vec].iv_pri = pri;
180		intr_vectors[vec].iv_vec = vec;
181	}
182	snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
183	intrcnt_updatename(pri, pilname, 1);
184	intr_handlers[pri] = ihf;
185	intr_restore(ps);
186}
187
188static void
189intr_stray_level(struct trapframe *tf)
190{
191
192	printf("stray level interrupt %ld\n", tf->tf_level);
193}
194
195static void
196intr_stray_vector(void *cookie)
197{
198	struct intr_vector *iv;
199
200	iv = cookie;
201	if (intr_stray_count[iv->iv_vec] < MAX_STRAY_LOG) {
202		printf("stray vector interrupt %d\n", iv->iv_vec);
203		intr_stray_count[iv->iv_vec]++;
204		if (intr_stray_count[iv->iv_vec] >= MAX_STRAY_LOG)
205			printf("got %d stray interrupt %d's: not logging "
206			    "anymore\n", MAX_STRAY_LOG, iv->iv_vec);
207	}
208}
209
210void
211intr_init1()
212{
213	int i;
214
215	/* Mark all interrupts as being stray. */
216	for (i = 0; i < PIL_MAX; i++)
217		intr_handlers[i] = intr_stray_level;
218	for (i = 0; i < IV_MAX; i++) {
219		intr_vectors[i].iv_func = intr_stray_vector;
220		intr_vectors[i].iv_arg = &intr_vectors[i];
221		intr_vectors[i].iv_pri = PIL_LOW;
222		intr_vectors[i].iv_vec = i;
223		intr_vectors[i].iv_refcnt = 0;
224	}
225	intr_handlers[PIL_LOW] = intr_fast;
226}
227
228void
229intr_init2()
230{
231
232	mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
233}
234
235static void
236intr_enable_eoi(void *arg)
237{
238	struct intr_vector *iv;
239	const struct intr_controller *ic;
240
241	iv = arg;
242	ic = iv->iv_ic;
243	ic->ic_enable(iv);
244	ic->ic_eoi(iv);
245}
246
247static void
248intr_execute_handlers(void *cookie)
249{
250	struct intr_vector *iv;
251#ifndef INTR_FILTER
252	struct intr_event *ie;
253	struct intr_handler *ih;
254	int error, thread, ret;
255#endif
256
257	iv = cookie;
258#ifndef INTR_FILTER
259	ie = iv->iv_event;
260	if (iv->iv_ic == NULL || ie == NULL) {
261		intr_stray_vector(iv);
262		return;
263	}
264
265	/* Execute fast interrupt handlers directly. */
266	ret = 0;
267	thread = 0;
268	critical_enter();
269	TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
270		if (ih->ih_filter == NULL) {
271			thread = 1;
272			continue;
273		}
274		MPASS(ih->ih_filter != NULL && ih->ih_argument != NULL);
275		CTR3(KTR_INTR, "%s: executing handler %p(%p)", __func__,
276		    ih->ih_filter, ih->ih_argument);
277		ret = ih->ih_filter(ih->ih_argument);
278		/*
279		 * Wrapper handler special case: see
280		 * i386/intr_machdep.c::intr_execute_handlers()
281		 */
282		if (!thread) {
283			if (ret == FILTER_SCHEDULE_THREAD)
284				thread = 1;
285		}
286	}
287	if (!thread)
288		intr_enable_eoi(iv);
289
290	/* Schedule a heavyweight interrupt process. */
291	if (thread)
292		error = intr_event_schedule_thread(ie);
293	else if (TAILQ_EMPTY(&ie->ie_handlers))
294		error = EINVAL;
295	else
296		error = 0;
297	critical_exit();
298	if (error == EINVAL)
299#else
300	if (intr_event_handle(iv->iv_event, NULL) != 0)
301#endif
302		intr_stray_vector(iv);
303}
304
305int
306intr_controller_register(int vec, const struct intr_controller *ic,
307    void *icarg)
308{
309	struct intr_event *ie;
310	struct intr_vector *iv;
311	int error;
312
313	iv = &intr_vectors[vec];
314	mtx_lock_spin(&intr_table_lock);
315	ie = iv->iv_event;
316	mtx_unlock_spin(&intr_table_lock);
317	if (ie != NULL)
318		return (EEXIST);
319	/*
320	 * Testing shows that at least with the interrupt controllers of
321	 * Psycho and Schizo bridges enabling an interrupt doesn't cause
322	 * an outstanding interrupt to be issued to the CPU. Thus we can't
323	 * use a function doing disable+EOI for the "disable" pointer as
324	 * done on other architectures because this would lead to a lost
325	 * interrupt if it triggers while we are still processing the
326	 * previous one. Instead we use an enable+EOI approach because as
327	 * outlined in the Tomatillo documentation clearing an interrupt
328	 * in the interrupt controller causes it to be (re)issued to the
329	 * CPU as long as the source of a level sensitive interrupt is
330	 * not cleared.
331	 */
332	error = intr_event_create(&ie, iv, 0, intr_enable_eoi,
333#ifdef INTR_FILTER
334	    ic->ic_eoi, ic->ic_disable, "vec%d:", vec);
335#else
336	    "vec%d:", vec);
337#endif
338	if (error != 0)
339		return (error);
340	mtx_lock_spin(&intr_table_lock);
341	if (iv->iv_event != NULL) {
342		mtx_unlock_spin(&intr_table_lock);
343		intr_event_destroy(ie);
344		return (EEXIST);
345	}
346	iv->iv_ic = ic;
347	iv->iv_icarg = icarg;
348	iv->iv_event = ie;
349	iv->iv_mid = PCPU_GET(mid);
350	mtx_unlock_spin(&intr_table_lock);
351	return (0);
352}
353
354int
355inthand_add(const char *name, int vec, driver_filter_t *filt,
356    driver_intr_t *handler, void *arg, int flags, void **cookiep)
357{
358	const struct intr_controller *ic;
359	struct intr_event *ie;
360	struct intr_handler *ih;
361	struct intr_vector *iv;
362	int error, fast;
363
364	iv = &intr_vectors[vec];
365	mtx_lock_spin(&intr_table_lock);
366	ic = iv->iv_ic;
367	ie = iv->iv_event;
368	mtx_unlock_spin(&intr_table_lock);
369	if (ic == NULL || ie == NULL)
370		return (EINVAL);
371
372	error = intr_event_add_handler(ie, name, filt, handler, arg,
373	    intr_priority(flags), flags, cookiep);
374	if (error != 0)
375		return (error);
376
377	mtx_lock_spin(&intr_table_lock);
378	/* Disable the interrupt while we fiddle with it. */
379	ic->ic_disable(iv);
380	iv->iv_refcnt++;
381	if (iv->iv_refcnt == 1)
382		intr_setup(filt != NULL ? PIL_FAST : PIL_ITHREAD, intr_fast,
383		    vec, intr_execute_handlers, iv);
384	else if (filt != NULL) {
385		/*
386		 * Check if we need to upgrade from PIL_ITHREAD to PIL_FAST.
387		 * Given that apart from the on-board SCCs and UARTs shared
388		 * interrupts are rather uncommon on sparc64 this sould be
389		 * pretty rare in practice.
390		 */
391		fast = 0;
392		TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
393			if (ih->ih_filter != NULL && ih->ih_filter != filt) {
394				fast = 1;
395				break;
396			}
397		}
398		if (fast == 0)
399			intr_setup(PIL_FAST, intr_fast, vec,
400			    intr_execute_handlers, iv);
401	}
402	intr_stray_count[vec] = 0;
403	intrcnt_updatename(vec, ie->ie_fullname, 0);
404	/* Ensure the interrupt is cleared, it might have triggered before. */
405	intr_enable_eoi(iv);
406	mtx_unlock_spin(&intr_table_lock);
407	return (0);
408}
409
410int
411inthand_remove(int vec, void *cookie)
412{
413	struct intr_vector *iv;
414	int error;
415
416	error = intr_event_remove_handler(cookie);
417	if (error == 0) {
418		/*
419		 * XXX: maybe this should be done regardless of whether
420		 * intr_event_remove_handler() succeeded?
421		 */
422		iv = &intr_vectors[vec];
423		mtx_lock_spin(&intr_table_lock);
424		iv->iv_refcnt--;
425		if (iv->iv_refcnt == 0) {
426			/*
427			 * Don't disable the interrupt for now, so that
428			 * stray interrupts get detected...
429			 */
430			intr_setup(PIL_LOW, intr_fast, vec,
431			    intr_stray_vector, iv);
432		}
433		mtx_unlock_spin(&intr_table_lock);
434	}
435	return (error);
436}
437