kern_intr.c revision 101176
126156Sse/*
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 *
2650477Speter * $FreeBSD: head/sys/kern/kern_intr.c 101176 2002-08-01 18:45:10Z julian $
2726156Sse *
2826156Sse */
2926156Sse
3036887Sdfr
3141059Speter#include <sys/param.h>
3265822Sjhb#include <sys/bus.h>
3365822Sjhb#include <sys/rtprio.h>
3441059Speter#include <sys/systm.h>
3566698Sjhb#include <sys/interrupt.h>
3666698Sjhb#include <sys/kernel.h>
3766698Sjhb#include <sys/kthread.h>
3866698Sjhb#include <sys/ktr.h>
3974914Sjhb#include <sys/lock.h>
4026156Sse#include <sys/malloc.h>
4167365Sjhb#include <sys/mutex.h>
4266698Sjhb#include <sys/proc.h>
4372759Sjhb#include <sys/random.h>
4472237Sjhb#include <sys/resourcevar.h>
4577582Stmm#include <sys/sysctl.h>
4666698Sjhb#include <sys/unistd.h>
4766698Sjhb#include <sys/vmmeter.h>
4866698Sjhb#include <machine/atomic.h>
4966698Sjhb#include <machine/cpu.h>
5067551Sjhb#include <machine/md_var.h>
5172237Sjhb#include <machine/stdarg.h>
5226156Sse
5367551Sjhb#include <net/netisr.h>		/* prototype for legacy_setsoftnet */
5438244Sbde
5572759Sjhbstruct	int_entropy {
5672759Sjhb	struct	proc *proc;
5772759Sjhb	int	vector;
5872759Sjhb};
5972759Sjhb
6072237Sjhbvoid	*net_ih;
6172237Sjhbvoid	*vm_ih;
6272237Sjhbvoid	*softclock_ih;
6372237Sjhbstruct	ithd *clk_ithd;
6472237Sjhbstruct	ithd *tty_ithd;
6538244Sbde
6672237Sjhbstatic MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
6772237Sjhb
6872237Sjhbstatic void	ithread_update(struct ithd *);
6972237Sjhbstatic void	ithread_loop(void *);
7072237Sjhbstatic void	start_softintr(void *);
7172237Sjhbstatic void	swi_net(void *);
7272237Sjhb
7372237Sjhbu_char
7472237Sjhbithread_priority(enum intr_type flags)
7565822Sjhb{
7672237Sjhb	u_char pri;
7765822Sjhb
7872237Sjhb	flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
7978365Speter	    INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV);
8065822Sjhb	switch (flags) {
8172237Sjhb	case INTR_TYPE_TTY:
8265822Sjhb		pri = PI_TTYLOW;
8365822Sjhb		break;
8465822Sjhb	case INTR_TYPE_BIO:
8565822Sjhb		/*
8665822Sjhb		 * XXX We need to refine this.  BSD/OS distinguishes
8765822Sjhb		 * between tape and disk priorities.
8865822Sjhb		 */
8965822Sjhb		pri = PI_DISK;
9065822Sjhb		break;
9165822Sjhb	case INTR_TYPE_NET:
9265822Sjhb		pri = PI_NET;
9365822Sjhb		break;
9465822Sjhb	case INTR_TYPE_CAM:
9565822Sjhb		pri = PI_DISK;          /* XXX or PI_CAM? */
9665822Sjhb		break;
9778365Speter	case INTR_TYPE_AV:		/* Audio/video */
9878365Speter		pri = PI_AV;
9978365Speter		break;
10072237Sjhb	case INTR_TYPE_CLK:
10172237Sjhb		pri = PI_REALTIME;
10272237Sjhb		break;
10365822Sjhb	case INTR_TYPE_MISC:
10465822Sjhb		pri = PI_DULL;          /* don't care */
10565822Sjhb		break;
10665822Sjhb	default:
10772237Sjhb		/* We didn't specify an interrupt level. */
10865822Sjhb		panic("ithread_priority: no interrupt type in flags");
10965822Sjhb	}
11065822Sjhb
11165822Sjhb	return pri;
11265822Sjhb}
11365822Sjhb
11472237Sjhb/*
11572237Sjhb * Regenerate the name (p_comm) and priority for a threaded interrupt thread.
11672237Sjhb */
11772237Sjhbstatic void
11872237Sjhbithread_update(struct ithd *ithd)
11972237Sjhb{
12072237Sjhb	struct intrhand *ih;
12183366Sjulian	struct thread *td;
12272237Sjhb	struct proc *p;
12372237Sjhb	int entropy;
12467551Sjhb
12576771Sjhb	mtx_assert(&ithd->it_lock, MA_OWNED);
12683366Sjulian	td = ithd->it_td;
12783366Sjulian	if (td == NULL)
12872237Sjhb		return;
12983366Sjulian	p = td->td_proc;
13072237Sjhb
13172237Sjhb	strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name));
13272237Sjhb	ih = TAILQ_FIRST(&ithd->it_handlers);
13372237Sjhb	if (ih == NULL) {
13494457Sjhb		mtx_lock_spin(&sched_lock);
13590538Sjulian		td->td_priority = PRI_MAX_ITHD;
13694457Sjhb		td->td_base_pri = PRI_MAX_ITHD;
13794457Sjhb		mtx_unlock_spin(&sched_lock);
13872237Sjhb		ithd->it_flags &= ~IT_ENTROPY;
13972237Sjhb		return;
14072237Sjhb	}
14172237Sjhb	entropy = 0;
14294457Sjhb	mtx_lock_spin(&sched_lock);
14390538Sjulian	td->td_priority = ih->ih_pri;
14490538Sjulian	td->td_base_pri = ih->ih_pri;
14594457Sjhb	mtx_unlock_spin(&sched_lock);
14672237Sjhb	TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
14772237Sjhb		if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 <
14872237Sjhb		    sizeof(p->p_comm)) {
14972237Sjhb			strcat(p->p_comm, " ");
15072237Sjhb			strcat(p->p_comm, ih->ih_name);
15172237Sjhb		} else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) {
15272237Sjhb			if (p->p_comm[sizeof(p->p_comm) - 2] == '+')
15372237Sjhb				p->p_comm[sizeof(p->p_comm) - 2] = '*';
15472237Sjhb			else
15572237Sjhb				p->p_comm[sizeof(p->p_comm) - 2] = '+';
15672237Sjhb		} else
15772237Sjhb			strcat(p->p_comm, "+");
15872237Sjhb		if (ih->ih_flags & IH_ENTROPY)
15972237Sjhb			entropy++;
16072237Sjhb	}
16172759Sjhb	if (entropy)
16272237Sjhb		ithd->it_flags |= IT_ENTROPY;
16372237Sjhb	else
16472237Sjhb		ithd->it_flags &= ~IT_ENTROPY;
16587593Sobrien	CTR2(KTR_INTR, "%s: updated %s\n", __func__, p->p_comm);
16672237Sjhb}
16772237Sjhb
16872237Sjhbint
16972237Sjhbithread_create(struct ithd **ithread, int vector, int flags,
17072237Sjhb    void (*disable)(int), void (*enable)(int), const char *fmt, ...)
17166698Sjhb{
17272237Sjhb	struct ithd *ithd;
17383366Sjulian	struct thread *td;
17467551Sjhb	struct proc *p;
17572237Sjhb	int error;
17672237Sjhb	va_list ap;
17772237Sjhb
17872759Sjhb	/* The only valid flag during creation is IT_SOFT. */
17972759Sjhb	if ((flags & ~IT_SOFT) != 0)
18072759Sjhb		return (EINVAL);
18172759Sjhb
18272237Sjhb	ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO);
18372237Sjhb	ithd->it_vector = vector;
18472237Sjhb	ithd->it_disable = disable;
18572237Sjhb	ithd->it_enable = enable;
18672237Sjhb	ithd->it_flags = flags;
18772237Sjhb	TAILQ_INIT(&ithd->it_handlers);
18893818Sjhb	mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF);
18972237Sjhb
19072237Sjhb	va_start(ap, fmt);
19172237Sjhb	vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap);
19272237Sjhb	va_end(ap);
19372237Sjhb
19472237Sjhb	error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID,
19574734Sjhb	    "%s", ithd->it_name);
19672237Sjhb	if (error) {
19776771Sjhb		mtx_destroy(&ithd->it_lock);
19872237Sjhb		free(ithd, M_ITHREAD);
19972237Sjhb		return (error);
20072237Sjhb	}
20190361Sjulian	td = FIRST_THREAD_IN_PROC(p);	/* XXXKSE */
20290538Sjulian	td->td_ksegrp->kg_pri_class = PRI_ITHD;
20390538Sjulian	td->td_priority = PRI_MAX_ITHD;
20499072Sjulian	td->td_state = TDS_IWAIT;
20583366Sjulian	ithd->it_td = td;
20683366Sjulian	td->td_ithd = ithd;
20772237Sjhb	if (ithread != NULL)
20872237Sjhb		*ithread = ithd;
20972237Sjhb
21087593Sobrien	CTR2(KTR_INTR, "%s: created %s", __func__, ithd->it_name);
21172237Sjhb	return (0);
21272237Sjhb}
21372237Sjhb
21472237Sjhbint
21572237Sjhbithread_destroy(struct ithd *ithread)
21672237Sjhb{
21772237Sjhb
21883366Sjulian	struct thread *td;
21983366Sjulian	struct proc *p;
22076771Sjhb	if (ithread == NULL)
22172237Sjhb		return (EINVAL);
22272237Sjhb
22383366Sjulian	td = ithread->it_td;
22483366Sjulian	p = td->td_proc;
22576771Sjhb	mtx_lock(&ithread->it_lock);
22676771Sjhb	if (!TAILQ_EMPTY(&ithread->it_handlers)) {
22776771Sjhb		mtx_unlock(&ithread->it_lock);
22876771Sjhb		return (EINVAL);
22976771Sjhb	}
23076771Sjhb	ithread->it_flags |= IT_DEAD;
23172237Sjhb	mtx_lock_spin(&sched_lock);
23299072Sjulian	if (td->td_state == TDS_IWAIT) {
23383366Sjulian		setrunqueue(td);
23472237Sjhb	}
23572237Sjhb	mtx_unlock_spin(&sched_lock);
23676771Sjhb	mtx_unlock(&ithread->it_lock);
23787593Sobrien	CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_name);
23872237Sjhb	return (0);
23972237Sjhb}
24072237Sjhb
24172237Sjhbint
24272237Sjhbithread_add_handler(struct ithd* ithread, const char *name,
24372237Sjhb    driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
24472237Sjhb    void **cookiep)
24572237Sjhb{
24672237Sjhb	struct intrhand *ih, *temp_ih;
24772237Sjhb
24872237Sjhb	if (ithread == NULL || name == NULL || handler == NULL)
24972237Sjhb		return (EINVAL);
25072237Sjhb	if ((flags & INTR_FAST) !=0)
25172237Sjhb		flags |= INTR_EXCL;
25272237Sjhb
25372237Sjhb	ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO);
25472237Sjhb	ih->ih_handler = handler;
25572237Sjhb	ih->ih_argument = arg;
25672237Sjhb	ih->ih_name = name;
25772237Sjhb	ih->ih_ithread = ithread;
25872237Sjhb	ih->ih_pri = pri;
25972237Sjhb	if (flags & INTR_FAST)
26072237Sjhb		ih->ih_flags = IH_FAST | IH_EXCLUSIVE;
26172237Sjhb	else if (flags & INTR_EXCL)
26272237Sjhb		ih->ih_flags = IH_EXCLUSIVE;
26372237Sjhb	if (flags & INTR_MPSAFE)
26472237Sjhb		ih->ih_flags |= IH_MPSAFE;
26572237Sjhb	if (flags & INTR_ENTROPY)
26672237Sjhb		ih->ih_flags |= IH_ENTROPY;
26772237Sjhb
26876771Sjhb	mtx_lock(&ithread->it_lock);
26972237Sjhb	if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers))
27072237Sjhb		goto fail;
27172237Sjhb	if (!TAILQ_EMPTY(&ithread->it_handlers) &&
27272237Sjhb	    (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0)
27372237Sjhb		goto fail;
27472237Sjhb
27572237Sjhb	TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next)
27672237Sjhb	    if (temp_ih->ih_pri > ih->ih_pri)
27772237Sjhb		    break;
27872237Sjhb	if (temp_ih == NULL)
27972237Sjhb		TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next);
28072237Sjhb	else
28172237Sjhb		TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
28272237Sjhb	ithread_update(ithread);
28376771Sjhb	mtx_unlock(&ithread->it_lock);
28472237Sjhb
28572237Sjhb	if (cookiep != NULL)
28672237Sjhb		*cookiep = ih;
28787593Sobrien	CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
28872837Sjhb	    ithread->it_name);
28972237Sjhb	return (0);
29072237Sjhb
29172237Sjhbfail:
29276771Sjhb	mtx_unlock(&ithread->it_lock);
29372237Sjhb	free(ih, M_ITHREAD);
29472237Sjhb	return (EINVAL);
29572237Sjhb}
29672237Sjhb
29772237Sjhbint
29872237Sjhbithread_remove_handler(void *cookie)
29972237Sjhb{
30072237Sjhb	struct intrhand *handler = (struct intrhand *)cookie;
30172237Sjhb	struct ithd *ithread;
30272237Sjhb#ifdef INVARIANTS
30372237Sjhb	struct intrhand *ih;
30472237Sjhb#endif
30572237Sjhb
30672759Sjhb	if (handler == NULL)
30772237Sjhb		return (EINVAL);
30872827Sjhb	ithread = handler->ih_ithread;
30972827Sjhb	KASSERT(ithread != NULL,
31072759Sjhb	    ("interrupt handler \"%s\" has a NULL interrupt thread",
31172759Sjhb		handler->ih_name));
31287593Sobrien	CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
31372837Sjhb	    ithread->it_name);
31476771Sjhb	mtx_lock(&ithread->it_lock);
31572237Sjhb#ifdef INVARIANTS
31672237Sjhb	TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next)
31772759Sjhb		if (ih == handler)
31872759Sjhb			goto ok;
31976771Sjhb	mtx_unlock(&ithread->it_lock);
32072759Sjhb	panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"",
32172759Sjhb	    ih->ih_name, ithread->it_name);
32272759Sjhbok:
32372237Sjhb#endif
32472839Sjhb	/*
32572839Sjhb	 * If the interrupt thread is already running, then just mark this
32672839Sjhb	 * handler as being dead and let the ithread do the actual removal.
32772839Sjhb	 */
32872839Sjhb	mtx_lock_spin(&sched_lock);
32999072Sjulian	if (ithread->it_td->td_state != TDS_IWAIT) {
33072839Sjhb		handler->ih_flags |= IH_DEAD;
33172839Sjhb
33272839Sjhb		/*
33372839Sjhb		 * Ensure that the thread will process the handler list
33472839Sjhb		 * again and remove this handler if it has already passed
33572839Sjhb		 * it on the list.
33672839Sjhb		 */
33772839Sjhb		ithread->it_need = 1;
33876771Sjhb	} else
33972839Sjhb		TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
34072839Sjhb	mtx_unlock_spin(&sched_lock);
34176771Sjhb	if ((handler->ih_flags & IH_DEAD) != 0)
34276771Sjhb		msleep(handler, &ithread->it_lock, PUSER, "itrmh", 0);
34376771Sjhb	ithread_update(ithread);
34476771Sjhb	mtx_unlock(&ithread->it_lock);
34576771Sjhb	free(handler, M_ITHREAD);
34672237Sjhb	return (0);
34772237Sjhb}
34872237Sjhb
34972237Sjhbint
35072759Sjhbithread_schedule(struct ithd *ithread, int do_switch)
35172759Sjhb{
35272759Sjhb	struct int_entropy entropy;
35383366Sjulian	struct thread *td;
354101176Sjulian	struct thread *ctd;
35572759Sjhb	struct proc *p;
35672759Sjhb
35772759Sjhb	/*
35872759Sjhb	 * If no ithread or no handlers, then we have a stray interrupt.
35972759Sjhb	 */
36072759Sjhb	if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers))
36172759Sjhb		return (EINVAL);
36272759Sjhb
363101176Sjulian	ctd = curthread;
36472759Sjhb	/*
36572759Sjhb	 * If any of the handlers for this ithread claim to be good
36672759Sjhb	 * sources of entropy, then gather some.
36772759Sjhb	 */
36872759Sjhb	if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) {
36972759Sjhb		entropy.vector = ithread->it_vector;
370101176Sjulian		entropy.proc = ctd->td_proc;;
37172759Sjhb		random_harvest(&entropy, sizeof(entropy), 2, 0,
37272759Sjhb		    RANDOM_INTERRUPT);
37372759Sjhb	}
37472759Sjhb
37583366Sjulian	td = ithread->it_td;
37683366Sjulian	p = td->td_proc;
37773313Sjhb	KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name));
37899072Sjulian	CTR4(KTR_INTR, "%s: pid %d: (%s) need = %d",
37999072Sjulian	    __func__, p->p_pid, p->p_comm, ithread->it_need);
38072759Sjhb
38172759Sjhb	/*
38272759Sjhb	 * Set it_need to tell the thread to keep running if it is already
38372759Sjhb	 * running.  Then, grab sched_lock and see if we actually need to
38472759Sjhb	 * put this thread on the runqueue.  If so and the do_switch flag is
38588900Sjhb	 * true and it is safe to switch, then switch to the ithread
38688900Sjhb	 * immediately.  Otherwise, set the needresched flag to guarantee
38788900Sjhb	 * that this ithread will run before any userland processes.
38872759Sjhb	 */
38972759Sjhb	ithread->it_need = 1;
39072759Sjhb	mtx_lock_spin(&sched_lock);
39199072Sjulian	if (td->td_state == TDS_IWAIT) {
39287593Sobrien		CTR2(KTR_INTR, "%s: setrunqueue %d", __func__, p->p_pid);
39399072Sjulian		setrunqueue(td);
39499072Sjulian		if (do_switch &&
395101176Sjulian		    (ctd->td_critnest == 1) ) {
396101176Sjulian			KASSERT((ctd->td_state == TDS_RUNNING),
397101176Sjulian			    ("ithread_schedule: Bad state for curthread."));
398101176Sjulian			ctd->td_proc->p_stats->p_ru.ru_nivcsw++;
399101176Sjulian			if (ctd->td_kse->ke_flags & KEF_IDLEKSE)
400101176Sjulian				ctd->td_state = TDS_UNQUEUED;
40172759Sjhb			mi_switch();
40297515Sjulian		} else {
40383366Sjulian			curthread->td_kse->ke_flags |= KEF_NEEDRESCHED;
40497515Sjulian		}
40572759Sjhb	} else {
40687593Sobrien		CTR4(KTR_INTR, "%s: pid %d: it_need %d, state %d",
40799072Sjulian		    __func__, p->p_pid, ithread->it_need, p->p_state);
40872759Sjhb	}
40972759Sjhb	mtx_unlock_spin(&sched_lock);
41072759Sjhb
41172759Sjhb	return (0);
41272759Sjhb}
41372759Sjhb
41472759Sjhbint
41572237Sjhbswi_add(struct ithd **ithdp, const char *name, driver_intr_t handler,
41672237Sjhb	    void *arg, int pri, enum intr_type flags, void **cookiep)
41772237Sjhb{
41867551Sjhb	struct ithd *ithd;
41972237Sjhb	int error;
42066698Sjhb
42172759Sjhb	if (flags & (INTR_FAST | INTR_ENTROPY))
42272759Sjhb		return (EINVAL);
42372759Sjhb
42467551Sjhb	ithd = (ithdp != NULL) ? *ithdp : NULL;
42566698Sjhb
42672759Sjhb	if (ithd != NULL) {
42772759Sjhb		if ((ithd->it_flags & IT_SOFT) == 0)
42872759Sjhb			return(EINVAL);
42972759Sjhb	} else {
43072237Sjhb		error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL,
43172237Sjhb		    "swi%d:", pri);
43267551Sjhb		if (error)
43372237Sjhb			return (error);
43472237Sjhb
43567551Sjhb		if (ithdp != NULL)
43667551Sjhb			*ithdp = ithd;
43766698Sjhb	}
43872376Sjake	return (ithread_add_handler(ithd, name, handler, arg,
43972376Sjake		    (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
44066698Sjhb}
44166698Sjhb
44266698Sjhb
44366698Sjhb/*
44467551Sjhb * Schedule a heavyweight software interrupt process.
44566698Sjhb */
44667551Sjhbvoid
44772237Sjhbswi_sched(void *cookie, int flags)
44866698Sjhb{
44972237Sjhb	struct intrhand *ih = (struct intrhand *)cookie;
45072237Sjhb	struct ithd *it = ih->ih_ithread;
45172759Sjhb	int error;
45266698Sjhb
45367551Sjhb	atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
45467551Sjhb
45572237Sjhb	CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d",
45683366Sjulian		it->it_td->td_proc->p_pid, it->it_td->td_proc->p_comm, it->it_need);
45767551Sjhb
45867551Sjhb	/*
45972759Sjhb	 * Set ih_need for this handler so that if the ithread is already
46072759Sjhb	 * running it will execute this handler on the next pass.  Otherwise,
46172759Sjhb	 * it will execute it the next time it runs.
46267551Sjhb	 */
46372237Sjhb	atomic_store_rel_int(&ih->ih_need, 1);
46472237Sjhb	if (!(flags & SWI_DELAY)) {
46588900Sjhb		error = ithread_schedule(it, !cold);
46672759Sjhb		KASSERT(error == 0, ("stray software interrupt"));
46766698Sjhb	}
46866698Sjhb}
46966698Sjhb
47066698Sjhb/*
47172237Sjhb * This is the main code for interrupt threads.
47266698Sjhb */
47367551Sjhbvoid
47472237Sjhbithread_loop(void *arg)
47566698Sjhb{
47672237Sjhb	struct ithd *ithd;		/* our thread context */
47767551Sjhb	struct intrhand *ih;		/* and our interrupt handler chain */
47883366Sjulian	struct thread *td;
47972237Sjhb	struct proc *p;
48067551Sjhb
48183366Sjulian	td = curthread;
48283366Sjulian	p = td->td_proc;
48372237Sjhb	ithd = (struct ithd *)arg;	/* point to myself */
48483366Sjulian	KASSERT(ithd->it_td == td && td->td_ithd == ithd,
48587593Sobrien	    ("%s: ithread and proc linkage out of sync", __func__));
48666698Sjhb
48767551Sjhb	/*
48867551Sjhb	 * As long as we have interrupts outstanding, go through the
48967551Sjhb	 * list of handlers, giving each one a go at it.
49067551Sjhb	 */
49166698Sjhb	for (;;) {
49272237Sjhb		/*
49372237Sjhb		 * If we are an orphaned thread, then just die.
49472237Sjhb		 */
49572237Sjhb		if (ithd->it_flags & IT_DEAD) {
49687593Sobrien			CTR3(KTR_INTR, "%s: pid %d: (%s) exiting", __func__,
49772237Sjhb			    p->p_pid, p->p_comm);
49883366Sjulian			td->td_ithd = NULL;
49976771Sjhb			mtx_destroy(&ithd->it_lock);
50072237Sjhb			mtx_lock(&Giant);
50172237Sjhb			free(ithd, M_ITHREAD);
50272237Sjhb			kthread_exit(0);
50372237Sjhb		}
50472237Sjhb
50587593Sobrien		CTR4(KTR_INTR, "%s: pid %d: (%s) need=%d", __func__,
50672237Sjhb		     p->p_pid, p->p_comm, ithd->it_need);
50772237Sjhb		while (ithd->it_need) {
50867551Sjhb			/*
50967551Sjhb			 * Service interrupts.  If another interrupt
51067551Sjhb			 * arrives while we are running, they will set
51167551Sjhb			 * it_need to denote that we should make
51267551Sjhb			 * another pass.
51367551Sjhb			 */
51472237Sjhb			atomic_store_rel_int(&ithd->it_need, 0);
51572839Sjhbrestart:
51672237Sjhb			TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
51772237Sjhb				if (ithd->it_flags & IT_SOFT && !ih->ih_need)
51867551Sjhb					continue;
51972237Sjhb				atomic_store_rel_int(&ih->ih_need, 0);
52087593Sobrien				CTR6(KTR_INTR,
52187593Sobrien				    "%s: pid %d ih=%p: %p(%p) flg=%x", __func__,
52267551Sjhb				    p->p_pid, (void *)ih,
52367551Sjhb				    (void *)ih->ih_handler, ih->ih_argument,
52467551Sjhb				    ih->ih_flags);
52566698Sjhb
52672839Sjhb				if ((ih->ih_flags & IH_DEAD) != 0) {
52776771Sjhb					mtx_lock(&ithd->it_lock);
52872839Sjhb					TAILQ_REMOVE(&ithd->it_handlers, ih,
52972839Sjhb					    ih_next);
53076771Sjhb					wakeup(ih);
53176771Sjhb					mtx_unlock(&ithd->it_lock);
53272839Sjhb					goto restart;
53372839Sjhb				}
53476771Sjhb				if ((ih->ih_flags & IH_MPSAFE) == 0)
53576771Sjhb					mtx_lock(&Giant);
53667551Sjhb				ih->ih_handler(ih->ih_argument);
53772237Sjhb				if ((ih->ih_flags & IH_MPSAFE) == 0)
53872200Sbmilekic					mtx_unlock(&Giant);
53967551Sjhb			}
54066698Sjhb		}
54167551Sjhb
54266698Sjhb		/*
54366698Sjhb		 * Processed all our interrupts.  Now get the sched
54467551Sjhb		 * lock.  This may take a while and it_need may get
54566698Sjhb		 * set again, so we have to check it again.
54666698Sjhb		 */
54768789Sjhb		mtx_assert(&Giant, MA_NOTOWNED);
54872200Sbmilekic		mtx_lock_spin(&sched_lock);
54972237Sjhb		if (!ithd->it_need) {
55072237Sjhb			/*
55172237Sjhb			 * Should we call this earlier in the loop above?
55272237Sjhb			 */
55372237Sjhb			if (ithd->it_enable != NULL)
55472237Sjhb				ithd->it_enable(ithd->it_vector);
55599072Sjulian			td->td_state = TDS_IWAIT; /* we're idle */
55678765Sjhb			p->p_stats->p_ru.ru_nvcsw++;
55787593Sobrien			CTR2(KTR_INTR, "%s: pid %d: done", __func__, p->p_pid);
55866698Sjhb			mi_switch();
55987593Sobrien			CTR2(KTR_INTR, "%s: pid %d: resumed", __func__, p->p_pid);
56066698Sjhb		}
56172200Sbmilekic		mtx_unlock_spin(&sched_lock);
56266698Sjhb	}
56366698Sjhb}
56466698Sjhb
56572237Sjhb/*
56667551Sjhb * Start standard software interrupt threads
56766698Sjhb */
56867551Sjhbstatic void
56972237Sjhbstart_softintr(void *dummy)
57067551Sjhb{
57172237Sjhb
57272237Sjhb	if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) ||
57372237Sjhb	    swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK,
57472237Sjhb		INTR_MPSAFE, &softclock_ih) ||
57572237Sjhb	    swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih))
57672237Sjhb		panic("died while creating standard software ithreads");
57772759Sjhb
57883366Sjulian	PROC_LOCK(clk_ithd->it_td->td_proc);
57983366Sjulian	clk_ithd->it_td->td_proc->p_flag |= P_NOLOAD;
58083366Sjulian	PROC_UNLOCK(clk_ithd->it_td->td_proc);
58166698Sjhb}
58272237SjhbSYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL)
58366698Sjhb
58467551Sjhbvoid
58572237Sjhblegacy_setsoftnet(void)
58667551Sjhb{
58788900Sjhb	swi_sched(net_ih, 0);
58866698Sjhb}
58966698Sjhb
59067551Sjhb/*
59167551Sjhb * XXX: This should really be in the network code somewhere and installed
59267551Sjhb * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit.
59367551Sjhb */
59492723Salfredvoid	(*netisrs[32])(void);
59582844Sobrienvolatile unsigned int	netisr;	/* scheduling bits for network */
59666698Sjhb
59769586Sjakeint
59869586Sjakeregister_netisr(num, handler)
59969586Sjake	int num;
60069586Sjake	netisr_t *handler;
60169586Sjake{
60269586Sjake
60369586Sjake	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
60469586Sjake		printf("register_netisr: bad isr number: %d\n", num);
60569586Sjake		return (EINVAL);
60669586Sjake	}
60769586Sjake	netisrs[num] = handler;
60869586Sjake	return (0);
60969586Sjake}
61069586Sjake
61169586Sjakeint
61269586Sjakeunregister_netisr(num)
61369586Sjake	int num;
61469586Sjake{
61569586Sjake
61669586Sjake	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
61769586Sjake		printf("unregister_netisr: bad isr number: %d\n", num);
61869586Sjake		return (EINVAL);
61969586Sjake	}
62069586Sjake	netisrs[num] = NULL;
62169586Sjake	return (0);
62269586Sjake}
62369586Sjake
62491936Sluigi#ifdef DEVICE_POLLING
62591936Sluigi	void netisr_pollmore(void);
62691936Sluigi#endif
62791936Sluigi
62867551Sjhbstatic void
62967551Sjhbswi_net(void *dummy)
63066698Sjhb{
63167551Sjhb	u_int bits;
63267551Sjhb	int i;
63366698Sjhb
63487902Sluigi#ifdef DEVICE_POLLING
63587902Sluigi    for (;;) {
63687902Sluigi	int pollmore;
63787902Sluigi#endif
63867551Sjhb	bits = atomic_readandclear_int(&netisr);
63987902Sluigi#ifdef DEVICE_POLLING
64087902Sluigi	if (bits == 0)
64187902Sluigi		return;
64287902Sluigi	pollmore = bits & (1 << NETISR_POLL);
64387902Sluigi#endif
64467551Sjhb	while ((i = ffs(bits)) != 0) {
64567551Sjhb		i--;
64670531Stanimura		if (netisrs[i] != NULL)
64770531Stanimura			netisrs[i]();
64870531Stanimura		else
64970531Stanimura			printf("swi_net: unregistered isr number: %d.\n", i);
65067551Sjhb		bits &= ~(1 << i);
65166698Sjhb	}
65287902Sluigi#ifdef DEVICE_POLLING
65387902Sluigi	if (pollmore)
65490550Sluigi		netisr_pollmore();
65587902Sluigi    }
65687902Sluigi#endif
65766698Sjhb}
65877582Stmm
65977582Stmm/*
66077582Stmm * Sysctls used by systat and others: hw.intrnames and hw.intrcnt.
66177582Stmm * The data for this machine dependent, and the declarations are in machine
66277582Stmm * dependent code.  The layout of intrnames and intrcnt however is machine
66377582Stmm * independent.
66477582Stmm *
66577582Stmm * We do not know the length of intrcnt and intrnames at compile time, so
66677582Stmm * calculate things at run time.
66777582Stmm */
66877582Stmmstatic int
66977582Stmmsysctl_intrnames(SYSCTL_HANDLER_ARGS)
67077582Stmm{
67177582Stmm	return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames,
67277582Stmm	   req));
67377582Stmm}
67477582Stmm
67577582StmmSYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD,
67677582Stmm    NULL, 0, sysctl_intrnames, "", "Interrupt Names");
67777582Stmm
67877582Stmmstatic int
67977582Stmmsysctl_intrcnt(SYSCTL_HANDLER_ARGS)
68077582Stmm{
68177582Stmm	return (sysctl_handle_opaque(oidp, intrcnt,
68277582Stmm	    (char *)eintrcnt - (char *)intrcnt, req));
68377582Stmm}
68477582Stmm
68577582StmmSYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD,
68677582Stmm    NULL, 0, sysctl_intrcnt, "", "Interrupt Counts");
687