1292915Sdim/*	$OpenBSD: isr.c,v 1.12 2020/11/24 13:52:40 mpi Exp $	*/
2292915Sdim/*	$NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $	*/
3292915Sdim
4292915Sdim/*-
5292915Sdim * Copyright (c) 1996 The NetBSD Foundation, Inc.
6292915Sdim * All rights reserved.
7292915Sdim *
8292915Sdim * This code is derived from software contributed to The NetBSD Foundation
9292915Sdim * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe.
10292915Sdim *
11292915Sdim * Redistribution and use in source and binary forms, with or without
12292915Sdim * modification, are permitted provided that the following conditions
13292915Sdim * are met:
14292915Sdim * 1. Redistributions of source code must retain the above copyright
15292915Sdim *    notice, this list of conditions and the following disclaimer.
16292915Sdim * 2. Redistributions in binary form must reproduce the above copyright
17292915Sdim *    notice, this list of conditions and the following disclaimer in the
18309124Sdim *    documentation and/or other materials provided with the distribution.
19292915Sdim *
20309124Sdim * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21292915Sdim * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22292915Sdim * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23309124Sdim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24292915Sdim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25292915Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26292915Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27292915Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28292915Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29292915Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30292915Sdim * POSSIBILITY OF SUCH DAMAGE.
31292915Sdim */
32292915Sdim
33292915Sdim/*
34292915Sdim * Link and dispatch interrupts.
35292915Sdim */
36292915Sdim
37292915Sdim#include <sys/param.h>
38292915Sdim#include <sys/systm.h>
39292915Sdim#include <sys/malloc.h>
40292915Sdim#include <sys/vmmeter.h>
41292915Sdim#include <sys/evcount.h>
42292915Sdim
43292915Sdim#include <uvm/uvm_extern.h>
44309124Sdim
45309124Sdim#include <machine/cpu.h>
46309124Sdim
47292915Sdim#include <luna88k/luna88k/isr.h>
48292915Sdim
49292915Sdimisr_autovec_list_t isr_autovec[NISRAUTOVEC];
50292915Sdim
51292915Sdimvoid
52292915Sdimisrinit()
53292915Sdim{
54292915Sdim	int i;
55292915Sdim
56292915Sdim	/* Initialize the autovector lists. */
57292915Sdim	for (i = 0; i < NISRAUTOVEC; ++i) {
58292915Sdim		LIST_INIT(&isr_autovec[i]);
59292915Sdim	}
60292915Sdim}
61292915Sdim
62292915Sdim/*
63292915Sdim * Establish an autovectored interrupt handler.
64292915Sdim * Called by driver attach functions.
65292915Sdim */
66309124Sdimvoid
67309124Sdimisrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority,
68309124Sdim    const char *name)
69309124Sdim{
70309124Sdim	struct isr_autovec *newisr, *curisr;
71309124Sdim	isr_autovec_list_t *list;
72309124Sdim
73309124Sdim#ifdef DIAGNOSTIC
74309124Sdim	if (ipl < 0 || ipl >= NISRAUTOVEC)
75309124Sdim		panic("isrlink_autovec: bad ipl %d", ipl);
76292915Sdim#endif
77292915Sdim
78292915Sdim	newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
79292915Sdim	    M_DEVBUF, M_NOWAIT);
80292915Sdim	if (newisr == NULL)
81309124Sdim		panic("isrlink_autovec: can't allocate space for isr");
82292915Sdim
83292915Sdim	/* Fill in the new entry. */
84292915Sdim	newisr->isr_func = func;
85292915Sdim	newisr->isr_arg = arg;
86292915Sdim	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 */
141void
142isrdispatch_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