kern_intr.c revision 157728
1139804Simp/*-
226156Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
326156Sse * All rights reserved.
426156Sse *
526156Sse * Redistribution and use in source and binary forms, with or without
626156Sse * modification, are permitted provided that the following conditions
726156Sse * are met:
826156Sse * 1. Redistributions of source code must retain the above copyright
926156Sse *    notice unmodified, this list of conditions, and the following
1026156Sse *    disclaimer.
1126156Sse * 2. Redistributions in binary form must reproduce the above copyright
1226156Sse *    notice, this list of conditions and the following disclaimer in the
1326156Sse *    documentation and/or other materials provided with the distribution.
1426156Sse *
1526156Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1626156Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1726156Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1826156Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1926156Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2026156Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2126156Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2226156Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2326156Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2426156Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2526156Sse */
2626156Sse
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_intr.c 157728 2006-04-13 17:29:04Z jhb $");
2936887Sdfr
30121482Sjhb#include "opt_ddb.h"
31121482Sjhb
3241059Speter#include <sys/param.h>
3365822Sjhb#include <sys/bus.h>
34110860Salfred#include <sys/conf.h>
3565822Sjhb#include <sys/rtprio.h>
3641059Speter#include <sys/systm.h>
3766698Sjhb#include <sys/interrupt.h>
3866698Sjhb#include <sys/kernel.h>
3966698Sjhb#include <sys/kthread.h>
4066698Sjhb#include <sys/ktr.h>
41130128Sbde#include <sys/limits.h>
4274914Sjhb#include <sys/lock.h>
4326156Sse#include <sys/malloc.h>
4467365Sjhb#include <sys/mutex.h>
4566698Sjhb#include <sys/proc.h>
4672759Sjhb#include <sys/random.h>
4772237Sjhb#include <sys/resourcevar.h>
48139451Sjhb#include <sys/sched.h>
4977582Stmm#include <sys/sysctl.h>
5066698Sjhb#include <sys/unistd.h>
5166698Sjhb#include <sys/vmmeter.h>
5266698Sjhb#include <machine/atomic.h>
5366698Sjhb#include <machine/cpu.h>
5467551Sjhb#include <machine/md_var.h>
5572237Sjhb#include <machine/stdarg.h>
56121482Sjhb#ifdef DDB
57121482Sjhb#include <ddb/ddb.h>
58121482Sjhb#include <ddb/db_sym.h>
59121482Sjhb#endif
6026156Sse
61151658Sjhb/*
62151658Sjhb * Describe an interrupt thread.  There is one of these per interrupt event.
63151658Sjhb */
64151658Sjhbstruct intr_thread {
65151658Sjhb	struct intr_event *it_event;
66151658Sjhb	struct thread *it_thread;	/* Kernel thread. */
67151658Sjhb	int	it_flags;		/* (j) IT_* flags. */
68151658Sjhb	int	it_need;		/* Needs service. */
6972759Sjhb};
7072759Sjhb
71151658Sjhb/* Interrupt thread flags kept in it_flags */
72151658Sjhb#define	IT_DEAD		0x000001	/* Thread is waiting to exit. */
73151658Sjhb
74151658Sjhbstruct	intr_entropy {
75151658Sjhb	struct	thread *td;
76151658Sjhb	uintptr_t event;
77151658Sjhb};
78151658Sjhb
79151658Sjhbstruct	intr_event *clk_intr_event;
80151658Sjhbstruct	intr_event *tty_intr_event;
81128339Sbdevoid	*softclock_ih;
82128339Sbdevoid	*vm_ih;
8338244Sbde
8472237Sjhbstatic MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
8572237Sjhb
86128331Sjhbstatic int intr_storm_threshold = 500;
87128331SjhbTUNABLE_INT("hw.intr_storm_threshold", &intr_storm_threshold);
88128331SjhbSYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold, CTLFLAG_RW,
89128331Sjhb    &intr_storm_threshold, 0,
90128339Sbde    "Number of consecutive interrupts before storm protection is enabled");
91151658Sjhbstatic TAILQ_HEAD(, intr_event) event_list =
92151658Sjhb    TAILQ_HEAD_INITIALIZER(event_list);
93128331Sjhb
94151658Sjhbstatic void	intr_event_update(struct intr_event *ie);
95151658Sjhbstatic struct intr_thread *ithread_create(const char *name);
96151658Sjhbstatic void	ithread_destroy(struct intr_thread *ithread);
97151658Sjhbstatic void	ithread_execute_handlers(struct proc *p, struct intr_event *ie);
98128339Sbdestatic void	ithread_loop(void *);
99151658Sjhbstatic void	ithread_update(struct intr_thread *ithd);
100128339Sbdestatic void	start_softintr(void *);
101128339Sbde
10272237Sjhbu_char
103151658Sjhbintr_priority(enum intr_type flags)
10465822Sjhb{
10572237Sjhb	u_char pri;
10665822Sjhb
10772237Sjhb	flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
10878365Speter	    INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV);
10965822Sjhb	switch (flags) {
11072237Sjhb	case INTR_TYPE_TTY:
11165822Sjhb		pri = PI_TTYLOW;
11265822Sjhb		break;
11365822Sjhb	case INTR_TYPE_BIO:
11465822Sjhb		/*
11565822Sjhb		 * XXX We need to refine this.  BSD/OS distinguishes
11665822Sjhb		 * between tape and disk priorities.
11765822Sjhb		 */
11865822Sjhb		pri = PI_DISK;
11965822Sjhb		break;
12065822Sjhb	case INTR_TYPE_NET:
12165822Sjhb		pri = PI_NET;
12265822Sjhb		break;
12365822Sjhb	case INTR_TYPE_CAM:
12465822Sjhb		pri = PI_DISK;          /* XXX or PI_CAM? */
12565822Sjhb		break;
12678365Speter	case INTR_TYPE_AV:		/* Audio/video */
12778365Speter		pri = PI_AV;
12878365Speter		break;
12972237Sjhb	case INTR_TYPE_CLK:
13072237Sjhb		pri = PI_REALTIME;
13172237Sjhb		break;
13265822Sjhb	case INTR_TYPE_MISC:
13365822Sjhb		pri = PI_DULL;          /* don't care */
13465822Sjhb		break;
13565822Sjhb	default:
13672237Sjhb		/* We didn't specify an interrupt level. */
137151658Sjhb		panic("intr_priority: no interrupt type in flags");
13865822Sjhb	}
13965822Sjhb
14065822Sjhb	return pri;
14165822Sjhb}
14265822Sjhb
14372237Sjhb/*
144151658Sjhb * Update an ithread based on the associated intr_event.
14572237Sjhb */
14672237Sjhbstatic void
147151658Sjhbithread_update(struct intr_thread *ithd)
14872237Sjhb{
149151658Sjhb	struct intr_event *ie;
15083366Sjulian	struct thread *td;
151151658Sjhb	u_char pri;
15267551Sjhb
153151658Sjhb	ie = ithd->it_event;
154151658Sjhb	td = ithd->it_thread;
15572237Sjhb
156151658Sjhb	/* Determine the overall priority of this event. */
157151658Sjhb	if (TAILQ_EMPTY(&ie->ie_handlers))
158151658Sjhb		pri = PRI_MAX_ITHD;
159151658Sjhb	else
160151658Sjhb		pri = TAILQ_FIRST(&ie->ie_handlers)->ih_pri;
161105354Srobert
162151658Sjhb	/* Update name and priority. */
163151658Sjhb	strlcpy(td->td_proc->p_comm, ie->ie_fullname,
164151658Sjhb	    sizeof(td->td_proc->p_comm));
16594457Sjhb	mtx_lock_spin(&sched_lock);
166151658Sjhb	sched_prio(td, pri);
16794457Sjhb	mtx_unlock_spin(&sched_lock);
168151658Sjhb}
169151658Sjhb
170151658Sjhb/*
171151658Sjhb * Regenerate the full name of an interrupt event and update its priority.
172151658Sjhb */
173151658Sjhbstatic void
174151658Sjhbintr_event_update(struct intr_event *ie)
175151658Sjhb{
176151658Sjhb	struct intr_handler *ih;
177151658Sjhb	char *last;
178151658Sjhb	int missed, space;
179151658Sjhb
180151658Sjhb	/* Start off with no entropy and just the name of the event. */
181151658Sjhb	mtx_assert(&ie->ie_lock, MA_OWNED);
182151658Sjhb	strlcpy(ie->ie_fullname, ie->ie_name, sizeof(ie->ie_fullname));
183151658Sjhb	ie->ie_flags &= ~IE_ENTROPY;
184137267Sjhb	missed = 0;
185151658Sjhb	space = 1;
186151658Sjhb
187151658Sjhb	/* Run through all the handlers updating values. */
188151658Sjhb	TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
189151658Sjhb		if (strlen(ie->ie_fullname) + strlen(ih->ih_name) + 1 <
190151658Sjhb		    sizeof(ie->ie_fullname)) {
191151658Sjhb			strcat(ie->ie_fullname, " ");
192151658Sjhb			strcat(ie->ie_fullname, ih->ih_name);
193151658Sjhb			space = 0;
194137267Sjhb		} else
195137267Sjhb			missed++;
196137267Sjhb		if (ih->ih_flags & IH_ENTROPY)
197151658Sjhb			ie->ie_flags |= IE_ENTROPY;
198137267Sjhb	}
199151658Sjhb
200151658Sjhb	/*
201151658Sjhb	 * If the handler names were too long, add +'s to indicate missing
202151658Sjhb	 * names. If we run out of room and still have +'s to add, change
203151658Sjhb	 * the last character from a + to a *.
204151658Sjhb	 */
205151658Sjhb	last = &ie->ie_fullname[sizeof(ie->ie_fullname) - 2];
206137267Sjhb	while (missed-- > 0) {
207151658Sjhb		if (strlen(ie->ie_fullname) + 1 == sizeof(ie->ie_fullname)) {
208151658Sjhb			if (*last == '+') {
209151658Sjhb				*last = '*';
210151658Sjhb				break;
211151658Sjhb			} else
212151658Sjhb				*last = '+';
213151658Sjhb		} else if (space) {
214151658Sjhb			strcat(ie->ie_fullname, " +");
215151658Sjhb			space = 0;
21672237Sjhb		} else
217151658Sjhb			strcat(ie->ie_fullname, "+");
21872237Sjhb	}
219151658Sjhb
220151658Sjhb	/*
221151658Sjhb	 * If this event has an ithread, update it's priority and
222151658Sjhb	 * name.
223151658Sjhb	 */
224151658Sjhb	if (ie->ie_thread != NULL)
225151658Sjhb		ithread_update(ie->ie_thread);
226151658Sjhb	CTR2(KTR_INTR, "%s: updated %s", __func__, ie->ie_fullname);
22772237Sjhb}
22872237Sjhb
22972237Sjhbint
230151658Sjhbintr_event_create(struct intr_event **event, void *source, int flags,
231151658Sjhb    void (*enable)(void *), const char *fmt, ...)
23266698Sjhb{
233151658Sjhb	struct intr_event *ie;
23472237Sjhb	va_list ap;
23572237Sjhb
236151658Sjhb	/* The only valid flag during creation is IE_SOFT. */
237151658Sjhb	if ((flags & ~IE_SOFT) != 0)
23872759Sjhb		return (EINVAL);
239151658Sjhb	ie = malloc(sizeof(struct intr_event), M_ITHREAD, M_WAITOK | M_ZERO);
240151658Sjhb	ie->ie_source = source;
241151658Sjhb	ie->ie_enable = enable;
242151658Sjhb	ie->ie_flags = flags;
243151658Sjhb	TAILQ_INIT(&ie->ie_handlers);
244151658Sjhb	mtx_init(&ie->ie_lock, "intr event", NULL, MTX_DEF);
24572759Sjhb
24672237Sjhb	va_start(ap, fmt);
247151658Sjhb	vsnprintf(ie->ie_name, sizeof(ie->ie_name), fmt, ap);
24872237Sjhb	va_end(ap);
249151658Sjhb	strlcpy(ie->ie_fullname, ie->ie_name, sizeof(ie->ie_fullname));
250151658Sjhb	mtx_pool_lock(mtxpool_sleep, &event_list);
251151658Sjhb	TAILQ_INSERT_TAIL(&event_list, ie, ie_list);
252151658Sjhb	mtx_pool_unlock(mtxpool_sleep, &event_list);
253151658Sjhb	if (event != NULL)
254151658Sjhb		*event = ie;
255151658Sjhb	CTR2(KTR_INTR, "%s: created %s", __func__, ie->ie_name);
256151658Sjhb	return (0);
257151658Sjhb}
25872237Sjhb
259151658Sjhbint
260151658Sjhbintr_event_destroy(struct intr_event *ie)
261151658Sjhb{
262151658Sjhb
263151658Sjhb	mtx_lock(&ie->ie_lock);
264151658Sjhb	if (!TAILQ_EMPTY(&ie->ie_handlers)) {
265151658Sjhb		mtx_unlock(&ie->ie_lock);
266151658Sjhb		return (EBUSY);
267151658Sjhb	}
268151658Sjhb	mtx_pool_lock(mtxpool_sleep, &event_list);
269151658Sjhb	TAILQ_REMOVE(&event_list, ie, ie_list);
270151658Sjhb	mtx_pool_unlock(mtxpool_sleep, &event_list);
271157728Sjhb#ifndef notyet
272157728Sjhb	if (ie->ie_thread != NULL) {
273157728Sjhb		ithread_destroy(ie->ie_thread);
274157728Sjhb		ie->ie_thread = NULL;
275157728Sjhb	}
276157728Sjhb#endif
277151658Sjhb	mtx_unlock(&ie->ie_lock);
278151658Sjhb	mtx_destroy(&ie->ie_lock);
279151658Sjhb	free(ie, M_ITHREAD);
280151658Sjhb	return (0);
281151658Sjhb}
282151658Sjhb
283151658Sjhbstatic struct intr_thread *
284151658Sjhbithread_create(const char *name)
285151658Sjhb{
286151658Sjhb	struct intr_thread *ithd;
287151658Sjhb	struct thread *td;
288151658Sjhb	struct proc *p;
289151658Sjhb	int error;
290151658Sjhb
291151658Sjhb	ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO);
292151658Sjhb
29372237Sjhb	error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID,
294151658Sjhb	    0, "%s", name);
295151658Sjhb	if (error)
296151658Sjhb		panic("kthread_create() failed with %d", error);
29790361Sjulian	td = FIRST_THREAD_IN_PROC(p);	/* XXXKSE */
298113629Sjhb	mtx_lock_spin(&sched_lock);
29990538Sjulian	td->td_ksegrp->kg_pri_class = PRI_ITHD;
300103216Sjulian	TD_SET_IWAIT(td);
301113629Sjhb	mtx_unlock_spin(&sched_lock);
302151658Sjhb	td->td_pflags |= TDP_ITHREAD;
303151658Sjhb	ithd->it_thread = td;
304151658Sjhb	CTR2(KTR_INTR, "%s: created %s", __func__, name);
305151658Sjhb	return (ithd);
30672237Sjhb}
30772237Sjhb
308151658Sjhbstatic void
309151658Sjhbithread_destroy(struct intr_thread *ithread)
31072237Sjhb{
31183366Sjulian	struct thread *td;
31272237Sjhb
313157728Sjhb	CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_name);
314151658Sjhb	td = ithread->it_thread;
315151658Sjhb	mtx_lock_spin(&sched_lock);
31676771Sjhb	ithread->it_flags |= IT_DEAD;
317103216Sjulian	if (TD_AWAITING_INTR(td)) {
318103216Sjulian		TD_CLR_IWAIT(td);
319134586Sjulian		setrunqueue(td, SRQ_INTR);
32072237Sjhb	}
32172237Sjhb	mtx_unlock_spin(&sched_lock);
32272237Sjhb}
32372237Sjhb
32472237Sjhbint
325151658Sjhbintr_event_add_handler(struct intr_event *ie, const char *name,
32672237Sjhb    driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
32772237Sjhb    void **cookiep)
32872237Sjhb{
329151658Sjhb	struct intr_handler *ih, *temp_ih;
330151658Sjhb	struct intr_thread *it;
33172237Sjhb
332151658Sjhb	if (ie == NULL || name == NULL || handler == NULL)
33372237Sjhb		return (EINVAL);
33472237Sjhb
335151658Sjhb	/* Allocate and populate an interrupt handler structure. */
336151658Sjhb	ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
33772237Sjhb	ih->ih_handler = handler;
33872237Sjhb	ih->ih_argument = arg;
33972237Sjhb	ih->ih_name = name;
340151658Sjhb	ih->ih_event = ie;
34172237Sjhb	ih->ih_pri = pri;
34272237Sjhb	if (flags & INTR_FAST)
343122002Sjhb		ih->ih_flags = IH_FAST;
34472237Sjhb	else if (flags & INTR_EXCL)
34572237Sjhb		ih->ih_flags = IH_EXCLUSIVE;
34672237Sjhb	if (flags & INTR_MPSAFE)
34772237Sjhb		ih->ih_flags |= IH_MPSAFE;
34872237Sjhb	if (flags & INTR_ENTROPY)
34972237Sjhb		ih->ih_flags |= IH_ENTROPY;
35072237Sjhb
351151658Sjhb	/* We can only have one exclusive handler in a event. */
352151658Sjhb	mtx_lock(&ie->ie_lock);
353151658Sjhb	if (!TAILQ_EMPTY(&ie->ie_handlers)) {
354151658Sjhb		if ((flags & INTR_EXCL) ||
355151658Sjhb		    (TAILQ_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) {
356151658Sjhb			mtx_unlock(&ie->ie_lock);
357151658Sjhb			free(ih, M_ITHREAD);
358151658Sjhb			return (EINVAL);
359151658Sjhb		}
360122002Sjhb	}
36172237Sjhb
362151658Sjhb	/* Add the new handler to the event in priority order. */
363151658Sjhb	TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
364151658Sjhb		if (temp_ih->ih_pri > ih->ih_pri)
365151658Sjhb			break;
366151658Sjhb	}
36772237Sjhb	if (temp_ih == NULL)
368151658Sjhb		TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
36972237Sjhb	else
37072237Sjhb		TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
371151658Sjhb	intr_event_update(ie);
37272237Sjhb
373151658Sjhb	/* Create a thread if we need one. */
374151658Sjhb	while (ie->ie_thread == NULL && !(flags & INTR_FAST)) {
375151658Sjhb		if (ie->ie_flags & IE_ADDING_THREAD)
376151658Sjhb			msleep(ie, &ie->ie_lock, curthread->td_priority,
377151658Sjhb			    "ithread", 0);
378151658Sjhb		else {
379151658Sjhb			ie->ie_flags |= IE_ADDING_THREAD;
380151658Sjhb			mtx_unlock(&ie->ie_lock);
381151658Sjhb			it = ithread_create("intr: newborn");
382151658Sjhb			mtx_lock(&ie->ie_lock);
383151658Sjhb			ie->ie_flags &= ~IE_ADDING_THREAD;
384151658Sjhb			ie->ie_thread = it;
385151658Sjhb			it->it_event = ie;
386151658Sjhb			ithread_update(it);
387151658Sjhb			wakeup(ie);
388151658Sjhb		}
389151658Sjhb	}
390151658Sjhb	CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
391151658Sjhb	    ie->ie_name);
392151658Sjhb	mtx_unlock(&ie->ie_lock);
393151658Sjhb
39472237Sjhb	if (cookiep != NULL)
39572237Sjhb		*cookiep = ih;
39672237Sjhb	return (0);
39772237Sjhb}
39872237Sjhb
39972237Sjhbint
400151658Sjhbintr_event_remove_handler(void *cookie)
40172237Sjhb{
402151658Sjhb	struct intr_handler *handler = (struct intr_handler *)cookie;
403151658Sjhb	struct intr_event *ie;
40472237Sjhb#ifdef INVARIANTS
405151658Sjhb	struct intr_handler *ih;
40672237Sjhb#endif
407151658Sjhb#ifdef notyet
408151658Sjhb	int dead;
409151658Sjhb#endif
41072237Sjhb
41172759Sjhb	if (handler == NULL)
41272237Sjhb		return (EINVAL);
413151658Sjhb	ie = handler->ih_event;
414151658Sjhb	KASSERT(ie != NULL,
415151658Sjhb	    ("interrupt handler \"%s\" has a NULL interrupt event",
41672759Sjhb		handler->ih_name));
417151658Sjhb	mtx_lock(&ie->ie_lock);
41887593Sobrien	CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
419151658Sjhb	    ie->ie_name);
42072237Sjhb#ifdef INVARIANTS
421151658Sjhb	TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
42272759Sjhb		if (ih == handler)
42372759Sjhb			goto ok;
424151658Sjhb	mtx_unlock(&ie->ie_lock);
425151658Sjhb	panic("interrupt handler \"%s\" not found in interrupt event \"%s\"",
426151658Sjhb	    ih->ih_name, ie->ie_name);
42772759Sjhbok:
42872237Sjhb#endif
42972839Sjhb	/*
430151658Sjhb	 * If there is no ithread, then just remove the handler and return.
431151658Sjhb	 * XXX: Note that an INTR_FAST handler might be running on another
432151658Sjhb	 * CPU!
433151658Sjhb	 */
434151658Sjhb	if (ie->ie_thread == NULL) {
435151658Sjhb		TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
436151658Sjhb		mtx_unlock(&ie->ie_lock);
437151658Sjhb		free(handler, M_ITHREAD);
438151658Sjhb		return (0);
439151658Sjhb	}
440151658Sjhb
441151658Sjhb	/*
44272839Sjhb	 * If the interrupt thread is already running, then just mark this
44372839Sjhb	 * handler as being dead and let the ithread do the actual removal.
444124505Struckman	 *
445124505Struckman	 * During a cold boot while cold is set, msleep() does not sleep,
446124505Struckman	 * so we have to remove the handler here rather than letting the
447124505Struckman	 * thread do it.
44872839Sjhb	 */
44972839Sjhb	mtx_lock_spin(&sched_lock);
450151658Sjhb	if (!TD_AWAITING_INTR(ie->ie_thread->it_thread) && !cold) {
45172839Sjhb		handler->ih_flags |= IH_DEAD;
45272839Sjhb
45372839Sjhb		/*
45472839Sjhb		 * Ensure that the thread will process the handler list
45572839Sjhb		 * again and remove this handler if it has already passed
45672839Sjhb		 * it on the list.
45772839Sjhb		 */
458151658Sjhb		ie->ie_thread->it_need = 1;
459151658Sjhb	} else
460151658Sjhb		TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
46172839Sjhb	mtx_unlock_spin(&sched_lock);
462151658Sjhb	while (handler->ih_flags & IH_DEAD)
463151658Sjhb		msleep(handler, &ie->ie_lock, curthread->td_priority, "iev_rmh",
464151658Sjhb		    0);
465151658Sjhb	intr_event_update(ie);
466151658Sjhb#ifdef notyet
467151658Sjhb	/*
468151658Sjhb	 * XXX: This could be bad in the case of ppbus(8).  Also, I think
469151658Sjhb	 * this could lead to races of stale data when servicing an
470151658Sjhb	 * interrupt.
471151658Sjhb	 */
472151658Sjhb	dead = 1;
473151658Sjhb	TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
474151658Sjhb		if (!(ih->ih_flags & IH_FAST)) {
475151658Sjhb			dead = 0;
476151658Sjhb			break;
477151658Sjhb		}
478151658Sjhb	}
479151658Sjhb	if (dead) {
480151658Sjhb		ithread_destroy(ie->ie_thread);
481151658Sjhb		ie->ie_thread = NULL;
482151658Sjhb	}
483151658Sjhb#endif
484151658Sjhb	mtx_unlock(&ie->ie_lock);
48576771Sjhb	free(handler, M_ITHREAD);
48672237Sjhb	return (0);
48772237Sjhb}
48872237Sjhb
48972237Sjhbint
490151658Sjhbintr_event_schedule_thread(struct intr_event *ie)
49172759Sjhb{
492151658Sjhb	struct intr_entropy entropy;
493151658Sjhb	struct intr_thread *it;
49483366Sjulian	struct thread *td;
495101176Sjulian	struct thread *ctd;
49672759Sjhb	struct proc *p;
49772759Sjhb
49872759Sjhb	/*
49972759Sjhb	 * If no ithread or no handlers, then we have a stray interrupt.
50072759Sjhb	 */
501151658Sjhb	if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) ||
502151658Sjhb	    ie->ie_thread == NULL)
50372759Sjhb		return (EINVAL);
50472759Sjhb
505101176Sjulian	ctd = curthread;
506151658Sjhb	it = ie->ie_thread;
507151658Sjhb	td = it->it_thread;
508133191Srwatson	p = td->td_proc;
509151658Sjhb
51072759Sjhb	/*
51172759Sjhb	 * If any of the handlers for this ithread claim to be good
51272759Sjhb	 * sources of entropy, then gather some.
51372759Sjhb	 */
514151658Sjhb	if (harvest.interrupt && ie->ie_flags & IE_ENTROPY) {
515133191Srwatson		CTR3(KTR_INTR, "%s: pid %d (%s) gathering entropy", __func__,
516133191Srwatson		    p->p_pid, p->p_comm);
517151658Sjhb		entropy.event = (uintptr_t)ie;
518151658Sjhb		entropy.td = ctd;
51972759Sjhb		random_harvest(&entropy, sizeof(entropy), 2, 0,
52072759Sjhb		    RANDOM_INTERRUPT);
52172759Sjhb	}
52272759Sjhb
523151658Sjhb	KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
52472759Sjhb
52572759Sjhb	/*
52672759Sjhb	 * Set it_need to tell the thread to keep running if it is already
52772759Sjhb	 * running.  Then, grab sched_lock and see if we actually need to
528131481Sjhb	 * put this thread on the runqueue.
52972759Sjhb	 */
530151658Sjhb	it->it_need = 1;
53172759Sjhb	mtx_lock_spin(&sched_lock);
532103216Sjulian	if (TD_AWAITING_INTR(td)) {
533151658Sjhb		CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid,
534151658Sjhb		    p->p_comm);
535103216Sjulian		TD_CLR_IWAIT(td);
536134586Sjulian		setrunqueue(td, SRQ_INTR);
53772759Sjhb	} else {
538151658Sjhb		CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
539151658Sjhb		    __func__, p->p_pid, p->p_comm, it->it_need, td->td_state);
54072759Sjhb	}
54172759Sjhb	mtx_unlock_spin(&sched_lock);
54272759Sjhb
54372759Sjhb	return (0);
54472759Sjhb}
54572759Sjhb
546151699Sjhb/*
547151699Sjhb * Add a software interrupt handler to a specified event.  If a given event
548151699Sjhb * is not specified, then a new event is created.
549151699Sjhb */
55072759Sjhbint
551151658Sjhbswi_add(struct intr_event **eventp, const char *name, driver_intr_t handler,
55272237Sjhb	    void *arg, int pri, enum intr_type flags, void **cookiep)
55372237Sjhb{
554151658Sjhb	struct intr_event *ie;
55572237Sjhb	int error;
55666698Sjhb
55772759Sjhb	if (flags & (INTR_FAST | INTR_ENTROPY))
55872759Sjhb		return (EINVAL);
55972759Sjhb
560151658Sjhb	ie = (eventp != NULL) ? *eventp : NULL;
56166698Sjhb
562151658Sjhb	if (ie != NULL) {
563151658Sjhb		if (!(ie->ie_flags & IE_SOFT))
564151658Sjhb			return (EINVAL);
56572759Sjhb	} else {
566151658Sjhb		error = intr_event_create(&ie, NULL, IE_SOFT, NULL,
56772237Sjhb		    "swi%d:", pri);
56867551Sjhb		if (error)
56972237Sjhb			return (error);
570151658Sjhb		if (eventp != NULL)
571151658Sjhb			*eventp = ie;
57266698Sjhb	}
573151658Sjhb	return (intr_event_add_handler(ie, name, handler, arg,
57472376Sjake		    (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
575134791Sjulian		    /* XXKSE.. think of a better way to get separate queues */
57666698Sjhb}
57766698Sjhb
57866698Sjhb/*
579151658Sjhb * Schedule a software interrupt thread.
58066698Sjhb */
58167551Sjhbvoid
58272237Sjhbswi_sched(void *cookie, int flags)
58366698Sjhb{
584151658Sjhb	struct intr_handler *ih = (struct intr_handler *)cookie;
585151658Sjhb	struct intr_event *ie = ih->ih_event;
58672759Sjhb	int error;
58766698Sjhb
588144971Sjhb	PCPU_LAZY_INC(cnt.v_intr);
58967551Sjhb
590151658Sjhb	CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name,
591151658Sjhb	    ih->ih_need);
592151658Sjhb
59367551Sjhb	/*
59472759Sjhb	 * Set ih_need for this handler so that if the ithread is already
59572759Sjhb	 * running it will execute this handler on the next pass.  Otherwise,
59672759Sjhb	 * it will execute it the next time it runs.
59767551Sjhb	 */
59872237Sjhb	atomic_store_rel_int(&ih->ih_need, 1);
59972237Sjhb	if (!(flags & SWI_DELAY)) {
600151658Sjhb		error = intr_event_schedule_thread(ie);
60172759Sjhb		KASSERT(error == 0, ("stray software interrupt"));
60266698Sjhb	}
60366698Sjhb}
60466698Sjhb
605151699Sjhb/*
606151699Sjhb * Remove a software interrupt handler.  Currently this code does not
607151699Sjhb * remove the associated interrupt event if it becomes empty.  Calling code
608151699Sjhb * may do so manually via intr_event_destroy(), but that's not really
609151699Sjhb * an optimal interface.
610151699Sjhb */
611151699Sjhbint
612151699Sjhbswi_remove(void *cookie)
613151699Sjhb{
614151699Sjhb
615151699Sjhb	return (intr_event_remove_handler(cookie));
616151699Sjhb}
617151699Sjhb
618151658Sjhbstatic void
619151658Sjhbithread_execute_handlers(struct proc *p, struct intr_event *ie)
620151658Sjhb{
621151658Sjhb	struct intr_handler *ih, *ihn;
622151658Sjhb
623151658Sjhb	/* Interrupt handlers should not sleep. */
624151658Sjhb	if (!(ie->ie_flags & IE_SOFT))
625151658Sjhb		THREAD_NO_SLEEPING();
626151658Sjhb	TAILQ_FOREACH_SAFE(ih, &ie->ie_handlers, ih_next, ihn) {
627151658Sjhb
628151658Sjhb		/*
629151658Sjhb		 * If this handler is marked for death, remove it from
630151658Sjhb		 * the list of handlers and wake up the sleeper.
631151658Sjhb		 */
632151658Sjhb		if (ih->ih_flags & IH_DEAD) {
633151658Sjhb			mtx_lock(&ie->ie_lock);
634151658Sjhb			TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next);
635151658Sjhb			ih->ih_flags &= ~IH_DEAD;
636151658Sjhb			wakeup(ih);
637151658Sjhb			mtx_unlock(&ie->ie_lock);
638151658Sjhb			continue;
639151658Sjhb		}
640151658Sjhb
641151658Sjhb		/*
642151658Sjhb		 * For software interrupt threads, we only execute
643151658Sjhb		 * handlers that have their need flag set.  Hardware
644151658Sjhb		 * interrupt threads always invoke all of their handlers.
645151658Sjhb		 */
646151658Sjhb		if (ie->ie_flags & IE_SOFT) {
647151658Sjhb			if (!ih->ih_need)
648151658Sjhb				continue;
649151658Sjhb			else
650151658Sjhb				atomic_store_rel_int(&ih->ih_need, 0);
651151658Sjhb		}
652151658Sjhb
653151658Sjhb		/* Fast handlers are handled in primary interrupt context. */
654151658Sjhb		if (ih->ih_flags & IH_FAST)
655151658Sjhb			continue;
656151658Sjhb
657151658Sjhb		/* Execute this handler. */
658151658Sjhb		CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x",
659151658Sjhb		    __func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument,
660151658Sjhb		    ih->ih_name, ih->ih_flags);
661151658Sjhb
662151658Sjhb		if (!(ih->ih_flags & IH_MPSAFE))
663151658Sjhb			mtx_lock(&Giant);
664151658Sjhb		ih->ih_handler(ih->ih_argument);
665151658Sjhb		if (!(ih->ih_flags & IH_MPSAFE))
666151658Sjhb			mtx_unlock(&Giant);
667151658Sjhb	}
668151658Sjhb	if (!(ie->ie_flags & IE_SOFT))
669151658Sjhb		THREAD_SLEEPING_OK();
670151658Sjhb
671151658Sjhb	/*
672151658Sjhb	 * Interrupt storm handling:
673151658Sjhb	 *
674151658Sjhb	 * If this interrupt source is currently storming, then throttle
675151658Sjhb	 * it to only fire the handler once  per clock tick.
676151658Sjhb	 *
677151658Sjhb	 * If this interrupt source is not currently storming, but the
678151658Sjhb	 * number of back to back interrupts exceeds the storm threshold,
679151658Sjhb	 * then enter storming mode.
680151658Sjhb	 */
681151658Sjhb	if (intr_storm_threshold != 0 && ie->ie_count >= intr_storm_threshold) {
682151658Sjhb		if (ie->ie_warned == 0) {
683151658Sjhb			printf(
684151658Sjhb	"Interrupt storm detected on \"%s\"; throttling interrupt source\n",
685151658Sjhb			    ie->ie_name);
686151658Sjhb			ie->ie_warned = 1;
687151658Sjhb		}
688151658Sjhb		tsleep(&ie->ie_count, curthread->td_priority, "istorm", 1);
689151658Sjhb	} else
690151658Sjhb		ie->ie_count++;
691151658Sjhb
692151658Sjhb	/*
693151658Sjhb	 * Now that all the handlers have had a chance to run, reenable
694151658Sjhb	 * the interrupt source.
695151658Sjhb	 */
696151658Sjhb	if (ie->ie_enable != NULL)
697151658Sjhb		ie->ie_enable(ie->ie_source);
698151658Sjhb}
699151658Sjhb
70066698Sjhb/*
70172237Sjhb * This is the main code for interrupt threads.
70266698Sjhb */
703104094Sphkstatic void
70472237Sjhbithread_loop(void *arg)
70566698Sjhb{
706151658Sjhb	struct intr_thread *ithd;
707151658Sjhb	struct intr_event *ie;
70883366Sjulian	struct thread *td;
70972237Sjhb	struct proc *p;
710151658Sjhb
71183366Sjulian	td = curthread;
71283366Sjulian	p = td->td_proc;
713151658Sjhb	ithd = (struct intr_thread *)arg;
714151658Sjhb	KASSERT(ithd->it_thread == td,
71587593Sobrien	    ("%s: ithread and proc linkage out of sync", __func__));
716151658Sjhb	ie = ithd->it_event;
717151658Sjhb	ie->ie_count = 0;
71866698Sjhb
71967551Sjhb	/*
72067551Sjhb	 * As long as we have interrupts outstanding, go through the
72167551Sjhb	 * list of handlers, giving each one a go at it.
72267551Sjhb	 */
72366698Sjhb	for (;;) {
72472237Sjhb		/*
72572237Sjhb		 * If we are an orphaned thread, then just die.
72672237Sjhb		 */
72772237Sjhb		if (ithd->it_flags & IT_DEAD) {
728151658Sjhb			CTR3(KTR_INTR, "%s: pid %d (%s) exiting", __func__,
72972237Sjhb			    p->p_pid, p->p_comm);
73072237Sjhb			free(ithd, M_ITHREAD);
73172237Sjhb			kthread_exit(0);
73272237Sjhb		}
73372237Sjhb
734151658Sjhb		/*
735151658Sjhb		 * Service interrupts.  If another interrupt arrives while
736151658Sjhb		 * we are running, it will set it_need to note that we
737151658Sjhb		 * should make another pass.
738151658Sjhb		 */
73972237Sjhb		while (ithd->it_need) {
74067551Sjhb			/*
741151658Sjhb			 * This might need a full read and write barrier
742151658Sjhb			 * to make sure that this write posts before any
743151658Sjhb			 * of the memory or device accesses in the
744151658Sjhb			 * handlers.
74567551Sjhb			 */
74672237Sjhb			atomic_store_rel_int(&ithd->it_need, 0);
747151658Sjhb			ithread_execute_handlers(p, ie);
74866698Sjhb		}
749128331Sjhb		WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
750128331Sjhb		mtx_assert(&Giant, MA_NOTOWNED);
75167551Sjhb
75266698Sjhb		/*
75366698Sjhb		 * Processed all our interrupts.  Now get the sched
75467551Sjhb		 * lock.  This may take a while and it_need may get
75566698Sjhb		 * set again, so we have to check it again.
75666698Sjhb		 */
75772200Sbmilekic		mtx_lock_spin(&sched_lock);
758151658Sjhb		if (!ithd->it_need && !(ithd->it_flags & IT_DEAD)) {
759128331Sjhb			TD_SET_IWAIT(td);
760151658Sjhb			ie->ie_count = 0;
761131473Sjhb			mi_switch(SW_VOL, NULL);
76266698Sjhb		}
76372200Sbmilekic		mtx_unlock_spin(&sched_lock);
76466698Sjhb	}
76566698Sjhb}
76666698Sjhb
767121482Sjhb#ifdef DDB
76872237Sjhb/*
769121482Sjhb * Dump details about an interrupt handler
770121482Sjhb */
771121482Sjhbstatic void
772151658Sjhbdb_dump_intrhand(struct intr_handler *ih)
773121482Sjhb{
774121482Sjhb	int comma;
775121482Sjhb
776121482Sjhb	db_printf("\t%-10s ", ih->ih_name);
777121482Sjhb	switch (ih->ih_pri) {
778121482Sjhb	case PI_REALTIME:
779121482Sjhb		db_printf("CLK ");
780121482Sjhb		break;
781121482Sjhb	case PI_AV:
782121482Sjhb		db_printf("AV  ");
783121482Sjhb		break;
784121482Sjhb	case PI_TTYHIGH:
785121482Sjhb	case PI_TTYLOW:
786121482Sjhb		db_printf("TTY ");
787121482Sjhb		break;
788121482Sjhb	case PI_TAPE:
789121482Sjhb		db_printf("TAPE");
790121482Sjhb		break;
791121482Sjhb	case PI_NET:
792121482Sjhb		db_printf("NET ");
793121482Sjhb		break;
794121482Sjhb	case PI_DISK:
795121482Sjhb	case PI_DISKLOW:
796121482Sjhb		db_printf("DISK");
797121482Sjhb		break;
798121482Sjhb	case PI_DULL:
799121482Sjhb		db_printf("DULL");
800121482Sjhb		break;
801121482Sjhb	default:
802121482Sjhb		if (ih->ih_pri >= PI_SOFT)
803121482Sjhb			db_printf("SWI ");
804121482Sjhb		else
805121482Sjhb			db_printf("%4u", ih->ih_pri);
806121482Sjhb		break;
807121482Sjhb	}
808121482Sjhb	db_printf(" ");
809121482Sjhb	db_printsym((uintptr_t)ih->ih_handler, DB_STGY_PROC);
810121482Sjhb	db_printf("(%p)", ih->ih_argument);
811121482Sjhb	if (ih->ih_need ||
812121482Sjhb	    (ih->ih_flags & (IH_FAST | IH_EXCLUSIVE | IH_ENTROPY | IH_DEAD |
813121482Sjhb	    IH_MPSAFE)) != 0) {
814121482Sjhb		db_printf(" {");
815121482Sjhb		comma = 0;
816121482Sjhb		if (ih->ih_flags & IH_FAST) {
817121482Sjhb			db_printf("FAST");
818121482Sjhb			comma = 1;
819121482Sjhb		}
820121482Sjhb		if (ih->ih_flags & IH_EXCLUSIVE) {
821121482Sjhb			if (comma)
822121482Sjhb				db_printf(", ");
823121482Sjhb			db_printf("EXCL");
824121482Sjhb			comma = 1;
825121482Sjhb		}
826121482Sjhb		if (ih->ih_flags & IH_ENTROPY) {
827121482Sjhb			if (comma)
828121482Sjhb				db_printf(", ");
829121482Sjhb			db_printf("ENTROPY");
830121482Sjhb			comma = 1;
831121482Sjhb		}
832121482Sjhb		if (ih->ih_flags & IH_DEAD) {
833121482Sjhb			if (comma)
834121482Sjhb				db_printf(", ");
835121482Sjhb			db_printf("DEAD");
836121482Sjhb			comma = 1;
837121482Sjhb		}
838121482Sjhb		if (ih->ih_flags & IH_MPSAFE) {
839121482Sjhb			if (comma)
840121482Sjhb				db_printf(", ");
841121482Sjhb			db_printf("MPSAFE");
842121482Sjhb			comma = 1;
843121482Sjhb		}
844121482Sjhb		if (ih->ih_need) {
845121482Sjhb			if (comma)
846121482Sjhb				db_printf(", ");
847121482Sjhb			db_printf("NEED");
848121482Sjhb		}
849121482Sjhb		db_printf("}");
850121482Sjhb	}
851121482Sjhb	db_printf("\n");
852121482Sjhb}
853121482Sjhb
854121482Sjhb/*
855151658Sjhb * Dump details about a event.
856121482Sjhb */
857121482Sjhbvoid
858151658Sjhbdb_dump_intr_event(struct intr_event *ie, int handlers)
859121482Sjhb{
860151658Sjhb	struct intr_handler *ih;
861151658Sjhb	struct intr_thread *it;
862121482Sjhb	int comma;
863121482Sjhb
864151658Sjhb	db_printf("%s ", ie->ie_fullname);
865151658Sjhb	it = ie->ie_thread;
866151658Sjhb	if (it != NULL)
867151658Sjhb		db_printf("(pid %d)", it->it_thread->td_proc->p_pid);
868151658Sjhb	else
869151658Sjhb		db_printf("(no thread)");
870151658Sjhb	if ((ie->ie_flags & (IE_SOFT | IE_ENTROPY | IE_ADDING_THREAD)) != 0 ||
871151658Sjhb	    (it != NULL && it->it_need)) {
872121482Sjhb		db_printf(" {");
873121482Sjhb		comma = 0;
874151658Sjhb		if (ie->ie_flags & IE_SOFT) {
875121482Sjhb			db_printf("SOFT");
876121482Sjhb			comma = 1;
877121482Sjhb		}
878151658Sjhb		if (ie->ie_flags & IE_ENTROPY) {
879121482Sjhb			if (comma)
880121482Sjhb				db_printf(", ");
881121482Sjhb			db_printf("ENTROPY");
882121482Sjhb			comma = 1;
883121482Sjhb		}
884151658Sjhb		if (ie->ie_flags & IE_ADDING_THREAD) {
885121482Sjhb			if (comma)
886121482Sjhb				db_printf(", ");
887151658Sjhb			db_printf("ADDING_THREAD");
888121482Sjhb			comma = 1;
889121482Sjhb		}
890151658Sjhb		if (it != NULL && it->it_need) {
891121482Sjhb			if (comma)
892121482Sjhb				db_printf(", ");
893121482Sjhb			db_printf("NEED");
894121482Sjhb		}
895121482Sjhb		db_printf("}");
896121482Sjhb	}
897121482Sjhb	db_printf("\n");
898121482Sjhb
899121482Sjhb	if (handlers)
900151658Sjhb		TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
901121482Sjhb		    db_dump_intrhand(ih);
902121482Sjhb}
903151658Sjhb
904151658Sjhb/*
905151658Sjhb * Dump data about interrupt handlers
906151658Sjhb */
907151658SjhbDB_SHOW_COMMAND(intr, db_show_intr)
908151658Sjhb{
909151658Sjhb	struct intr_event *ie;
910151658Sjhb	int quit, all, verbose;
911151658Sjhb
912151658Sjhb	quit = 0;
913151658Sjhb	verbose = index(modif, 'v') != NULL;
914151658Sjhb	all = index(modif, 'a') != NULL;
915151658Sjhb	db_setup_paging(db_simple_pager, &quit, db_lines_per_page);
916151658Sjhb	TAILQ_FOREACH(ie, &event_list, ie_list) {
917151658Sjhb		if (!all && TAILQ_EMPTY(&ie->ie_handlers))
918151658Sjhb			continue;
919151658Sjhb		db_dump_intr_event(ie, verbose);
920151658Sjhb	}
921151658Sjhb}
922121482Sjhb#endif /* DDB */
923121482Sjhb
924121482Sjhb/*
92567551Sjhb * Start standard software interrupt threads
92666698Sjhb */
92767551Sjhbstatic void
92872237Sjhbstart_softintr(void *dummy)
92967551Sjhb{
930113613Sjhb	struct proc *p;
93172237Sjhb
932151658Sjhb	if (swi_add(&clk_intr_event, "clock", softclock, NULL, SWI_CLOCK,
93372237Sjhb		INTR_MPSAFE, &softclock_ih) ||
934117128Sscottl	    swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih))
93572237Sjhb		panic("died while creating standard software ithreads");
93672759Sjhb
937151658Sjhb	p = clk_intr_event->ie_thread->it_thread->td_proc;
938113613Sjhb	PROC_LOCK(p);
939113613Sjhb	p->p_flag |= P_NOLOAD;
940113613Sjhb	PROC_UNLOCK(p);
94166698Sjhb}
94272237SjhbSYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL)
94366698Sjhb
944151658Sjhb/*
94577582Stmm * Sysctls used by systat and others: hw.intrnames and hw.intrcnt.
94677582Stmm * The data for this machine dependent, and the declarations are in machine
94777582Stmm * dependent code.  The layout of intrnames and intrcnt however is machine
94877582Stmm * independent.
94977582Stmm *
95077582Stmm * We do not know the length of intrcnt and intrnames at compile time, so
95177582Stmm * calculate things at run time.
95277582Stmm */
95377582Stmmstatic int
95477582Stmmsysctl_intrnames(SYSCTL_HANDLER_ARGS)
95577582Stmm{
956151658Sjhb	return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames,
95777582Stmm	   req));
95877582Stmm}
95977582Stmm
96077582StmmSYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD,
96177582Stmm    NULL, 0, sysctl_intrnames, "", "Interrupt Names");
96277582Stmm
96377582Stmmstatic int
96477582Stmmsysctl_intrcnt(SYSCTL_HANDLER_ARGS)
96577582Stmm{
966151658Sjhb	return (sysctl_handle_opaque(oidp, intrcnt,
96777582Stmm	    (char *)eintrcnt - (char *)intrcnt, req));
96877582Stmm}
96977582Stmm
97077582StmmSYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD,
97177582Stmm    NULL, 0, sysctl_intrcnt, "", "Interrupt Counts");
972121482Sjhb
973121482Sjhb#ifdef DDB
974121482Sjhb/*
975121482Sjhb * DDB command to dump the interrupt statistics.
976121482Sjhb */
977121482SjhbDB_SHOW_COMMAND(intrcnt, db_show_intrcnt)
978121482Sjhb{
979121482Sjhb	u_long *i;
980121482Sjhb	char *cp;
981121482Sjhb	int quit;
982121482Sjhb
983121482Sjhb	cp = intrnames;
984137117Sjhb	db_setup_paging(db_simple_pager, &quit, db_lines_per_page);
985121482Sjhb	for (i = intrcnt, quit = 0; i != eintrcnt && !quit; i++) {
986121482Sjhb		if (*cp == '\0')
987121482Sjhb			break;
988121482Sjhb		if (*i != 0)
989121482Sjhb			db_printf("%s\t%lu\n", cp, *i);
990121482Sjhb		cp += strlen(cp) + 1;
991121482Sjhb	}
992121482Sjhb}
993121482Sjhb#endif
994