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
isrinit()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
isrlink_autovec(int (* func)(void *),void * arg,int ipl,int priority,const char * name)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
isrdispatch_autovec(int ipl)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