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
49isr_autovec_list_t isr_autovec[NISRAUTOVEC];
50
51void
52isrinit()
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 */
66void
67isrlink_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 */
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