xref: /openbsd/sys/arch/luna88k/luna88k/isr.c (revision f6aab3d8)
1 /*	$OpenBSD: isr.c,v 1.12 2020/11/24 13:52:40 mpi Exp $	*/
2 /*	$NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $	*/
3 
4 /*-
5  * Copyright (c) 1996 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Link and dispatch interrupts.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/vmmeter.h>
41 #include <sys/evcount.h>
42 
43 #include <uvm/uvm_extern.h>
44 
45 #include <machine/cpu.h>
46 
47 #include <luna88k/luna88k/isr.h>
48 
49 isr_autovec_list_t isr_autovec[NISRAUTOVEC];
50 
51 void
52 isrinit()
53 {
54 	int i;
55 
56 	/* Initialize the autovector lists. */
57 	for (i = 0; i < NISRAUTOVEC; ++i) {
58 		LIST_INIT(&isr_autovec[i]);
59 	}
60 }
61 
62 /*
63  * Establish an autovectored interrupt handler.
64  * Called by driver attach functions.
65  */
66 void
67 isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority,
68     const char *name)
69 {
70 	struct isr_autovec *newisr, *curisr;
71 	isr_autovec_list_t *list;
72 
73 #ifdef DIAGNOSTIC
74 	if (ipl < 0 || ipl >= NISRAUTOVEC)
75 		panic("isrlink_autovec: bad ipl %d", ipl);
76 #endif
77 
78 	newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
79 	    M_DEVBUF, M_NOWAIT);
80 	if (newisr == NULL)
81 		panic("isrlink_autovec: can't allocate space for isr");
82 
83 	/* Fill in the new entry. */
84 	newisr->isr_func = func;
85 	newisr->isr_arg = arg;
86 	newisr->isr_ipl = ipl;
87 	newisr->isr_priority = priority;
88 	evcount_attach(&newisr->isr_count, name, &newisr->isr_ipl);
89 
90 	/*
91 	 * Some devices are particularly sensitive to interrupt
92 	 * handling latency.  The SCC, for example, can lose many
93 	 * characters if its interrupt isn't handled with reasonable
94 	 * speed.
95 	 *
96 	 * To work around this problem, each device can give itself a
97 	 * "priority".  An unbuffered SCC would give itself a higher
98 	 * priority than a SCSI device, for example.
99 	 *
100 	 * This solution was originally developed for the hp300, which
101 	 * has a flat spl scheme (by necessity).  Thankfully, the
102 	 * MVME systems don't have this problem, though this may serve
103 	 * a useful purpose in any case.
104 	 */
105 
106 	/*
107 	 * Get the appropriate ISR list.  If the list is empty, no
108 	 * additional work is necessary; we simply insert ourselves
109 	 * at the head of the list.
110 	 */
111 	list = &isr_autovec[ipl];
112 	if (LIST_EMPTY(list)) {
113 		LIST_INSERT_HEAD(list, newisr, isr_link);
114 		return;
115 	}
116 
117 	/*
118 	 * A little extra work is required.  We traverse the list
119 	 * and place ourselves after any ISRs with our current (or
120 	 * higher) priority.
121 	 */
122 	for (curisr = LIST_FIRST(list); LIST_NEXT(curisr, isr_link) != NULL;
123 	    curisr = LIST_NEXT(curisr, isr_link)) {
124 		if (newisr->isr_priority > curisr->isr_priority) {
125 			LIST_INSERT_BEFORE(curisr, newisr, isr_link);
126 			return;
127 		}
128 	}
129 
130 	/*
131 	 * We're the least important entry, it seems.  We just go
132 	 * on the end.
133 	 */
134 	LIST_INSERT_AFTER(curisr, newisr, isr_link);
135 }
136 
137 /*
138  * This is the dispatcher called by the low-level
139  * assembly language autovectored interrupt routine.
140  */
141 void
142 isrdispatch_autovec(int ipl)
143 {
144 	struct isr_autovec *isr;
145 	isr_autovec_list_t *list;
146 	int rc, handled = 0;
147 	static int straycount, unexpected;
148 
149 #ifdef DIAGNOSTIC
150 	if (ipl < 0 || ipl >= NISRAUTOVEC)
151 		panic("isrdispatch_autovec: bad ipl %d", ipl);
152 #endif
153 
154 	list = &isr_autovec[ipl];
155 	if (LIST_EMPTY(list)) {
156 		printf("isrdispatch_autovec: ipl %d unexpected\n", ipl);
157 		if (++unexpected > 10)
158 			panic("too many unexpected interrupts");
159 		return;
160 	}
161 
162 	/* Give all the handlers a chance. */
163 	LIST_FOREACH(isr, list, isr_link) {
164 #ifdef MULTIPROCESSOR
165 		if (isr->isr_ipl < IPL_CLOCK)
166 			__mp_lock(&kernel_lock);
167 #endif
168 		rc = (*isr->isr_func)(isr->isr_arg);
169 #ifdef MULTIPROCESSOR
170 		if (isr->isr_ipl < IPL_CLOCK)
171 			__mp_unlock(&kernel_lock);
172 #endif
173 		if (rc != 0)
174 			isr->isr_count.ec_count++;
175 		handled |= rc;
176 	}
177 
178 	if (handled)
179 		straycount = 0;
180 	else if (++straycount > 50)
181 		panic("isr_dispatch_autovec: too many stray interrupts");
182 	else
183 		printf("isrdispatch_autovec: stray level %d interrupt\n", ipl);
184 }
185