kern_intr.c revision 74914
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 74914 2001-03-28 09:17:56Z jhb $
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/ipl.h>
3666698Sjhb#include <sys/interrupt.h>
3766698Sjhb#include <sys/kernel.h>
3866698Sjhb#include <sys/kthread.h>
3966698Sjhb#include <sys/ktr.h>
4074914Sjhb#include <sys/lock.h>
4126156Sse#include <sys/malloc.h>
4267365Sjhb#include <sys/mutex.h>
4366698Sjhb#include <sys/proc.h>
4472759Sjhb#include <sys/random.h>
4572237Sjhb#include <sys/resourcevar.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 struct	mtx ithread_list_lock;
6766698Sjhb
6872237Sjhbstatic MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
6972237Sjhb
7072237Sjhbstatic void	ithread_update(struct ithd *);
7172237Sjhbstatic void	ithread_loop(void *);
7272237Sjhbstatic void	ithread_init(void *);
7372237Sjhbstatic void	start_softintr(void *);
7472237Sjhbstatic void	swi_net(void *);
7572237Sjhb
7672237Sjhbu_char
7772237Sjhbithread_priority(enum intr_type flags)
7865822Sjhb{
7972237Sjhb	u_char pri;
8065822Sjhb
8172237Sjhb	flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
8272237Sjhb	    INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK);
8365822Sjhb	switch (flags) {
8472237Sjhb	case INTR_TYPE_TTY:
8565822Sjhb		pri = PI_TTYLOW;
8665822Sjhb		break;
8765822Sjhb	case INTR_TYPE_BIO:
8865822Sjhb		/*
8965822Sjhb		 * XXX We need to refine this.  BSD/OS distinguishes
9065822Sjhb		 * between tape and disk priorities.
9165822Sjhb		 */
9265822Sjhb		pri = PI_DISK;
9365822Sjhb		break;
9465822Sjhb	case INTR_TYPE_NET:
9565822Sjhb		pri = PI_NET;
9665822Sjhb		break;
9765822Sjhb	case INTR_TYPE_CAM:
9865822Sjhb		pri = PI_DISK;          /* XXX or PI_CAM? */
9965822Sjhb		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;
12172237Sjhb	struct proc *p;
12272237Sjhb	int entropy;
12367551Sjhb
12472237Sjhb	p = ithd->it_proc;
12572237Sjhb	if (p == NULL)
12672237Sjhb		return;
12772237Sjhb
12872237Sjhb	strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name));
12972237Sjhb	ih = TAILQ_FIRST(&ithd->it_handlers);
13072237Sjhb	if (ih == NULL) {
13172376Sjake		p->p_pri.pri_level = PRI_MAX_ITHD;
13272237Sjhb		ithd->it_flags &= ~IT_ENTROPY;
13372237Sjhb		return;
13472237Sjhb	}
13572237Sjhb
13672237Sjhb	entropy = 0;
13772376Sjake	p->p_pri.pri_level = ih->ih_pri;
13873205Sjake	p->p_pri.pri_native = ih->ih_pri;
13972237Sjhb	TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
14072237Sjhb		if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 <
14172237Sjhb		    sizeof(p->p_comm)) {
14272237Sjhb			strcat(p->p_comm, " ");
14372237Sjhb			strcat(p->p_comm, ih->ih_name);
14472237Sjhb		} else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) {
14572237Sjhb			if (p->p_comm[sizeof(p->p_comm) - 2] == '+')
14672237Sjhb				p->p_comm[sizeof(p->p_comm) - 2] = '*';
14772237Sjhb			else
14872237Sjhb				p->p_comm[sizeof(p->p_comm) - 2] = '+';
14972237Sjhb		} else
15072237Sjhb			strcat(p->p_comm, "+");
15172237Sjhb		if (ih->ih_flags & IH_ENTROPY)
15272237Sjhb			entropy++;
15372237Sjhb	}
15472237Sjhb
15572759Sjhb	if (entropy)
15672237Sjhb		ithd->it_flags |= IT_ENTROPY;
15772237Sjhb	else
15872237Sjhb		ithd->it_flags &= ~IT_ENTROPY;
15972837Sjhb
16072837Sjhb	CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm);
16172237Sjhb}
16272237Sjhb
16372237Sjhbint
16472237Sjhbithread_create(struct ithd **ithread, int vector, int flags,
16572237Sjhb    void (*disable)(int), void (*enable)(int), const char *fmt, ...)
16666698Sjhb{
16772237Sjhb	struct ithd *ithd;
16867551Sjhb	struct proc *p;
16972237Sjhb	int error;
17072237Sjhb	va_list ap;
17172237Sjhb
17272759Sjhb	/* The only valid flag during creation is IT_SOFT. */
17372759Sjhb	if ((flags & ~IT_SOFT) != 0)
17472759Sjhb		return (EINVAL);
17572759Sjhb
17672237Sjhb	ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO);
17772237Sjhb	ithd->it_vector = vector;
17872237Sjhb	ithd->it_disable = disable;
17972237Sjhb	ithd->it_enable = enable;
18072237Sjhb	ithd->it_flags = flags;
18172237Sjhb	TAILQ_INIT(&ithd->it_handlers);
18272237Sjhb
18372237Sjhb	va_start(ap, fmt);
18472237Sjhb	vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap);
18572237Sjhb	va_end(ap);
18672237Sjhb
18772237Sjhb	error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID,
18874734Sjhb	    "%s", ithd->it_name);
18972237Sjhb	if (error) {
19072237Sjhb		free(ithd, M_ITHREAD);
19172237Sjhb		return (error);
19272237Sjhb	}
19372376Sjake	p->p_pri.pri_class = PRI_ITHD;
19472376Sjake	p->p_pri.pri_level = PRI_MAX_ITHD;
19572237Sjhb	p->p_stat = SWAIT;
19672237Sjhb	ithd->it_proc = p;
19772237Sjhb	p->p_ithd = ithd;
19872237Sjhb	if (ithread != NULL)
19972237Sjhb		*ithread = ithd;
20072237Sjhb
20172837Sjhb	CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name);
20272237Sjhb	return (0);
20372237Sjhb}
20472237Sjhb
20572237Sjhbint
20672237Sjhbithread_destroy(struct ithd *ithread)
20772237Sjhb{
20872237Sjhb
20972237Sjhb	if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers))
21072237Sjhb		return (EINVAL);
21172237Sjhb
21272237Sjhb	mtx_lock_spin(&sched_lock);
21372237Sjhb	ithread->it_flags |= IT_DEAD;
21472237Sjhb	if (ithread->it_proc->p_stat == SWAIT) {
21572237Sjhb		ithread->it_proc->p_stat = SRUN;
21672237Sjhb		setrunqueue(ithread->it_proc);
21772237Sjhb	}
21872237Sjhb	mtx_unlock_spin(&sched_lock);
21972837Sjhb	CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name);
22072237Sjhb	return (0);
22172237Sjhb}
22272237Sjhb
22372237Sjhbint
22472237Sjhbithread_add_handler(struct ithd* ithread, const char *name,
22572237Sjhb    driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
22672237Sjhb    void **cookiep)
22772237Sjhb{
22872237Sjhb	struct intrhand *ih, *temp_ih;
22972237Sjhb
23072237Sjhb	if (ithread == NULL || name == NULL || handler == NULL)
23172237Sjhb		return (EINVAL);
23272237Sjhb	if ((flags & INTR_FAST) !=0)
23372237Sjhb		flags |= INTR_EXCL;
23472237Sjhb
23572237Sjhb	ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO);
23672237Sjhb	ih->ih_handler = handler;
23772237Sjhb	ih->ih_argument = arg;
23872237Sjhb	ih->ih_name = name;
23972237Sjhb	ih->ih_ithread = ithread;
24072237Sjhb	ih->ih_pri = pri;
24172237Sjhb	if (flags & INTR_FAST)
24272237Sjhb		ih->ih_flags = IH_FAST | IH_EXCLUSIVE;
24372237Sjhb	else if (flags & INTR_EXCL)
24472237Sjhb		ih->ih_flags = IH_EXCLUSIVE;
24572237Sjhb	if (flags & INTR_MPSAFE)
24672237Sjhb		ih->ih_flags |= IH_MPSAFE;
24772237Sjhb	if (flags & INTR_ENTROPY)
24872237Sjhb		ih->ih_flags |= IH_ENTROPY;
24972237Sjhb
25072237Sjhb	mtx_lock_spin(&ithread_list_lock);
25172237Sjhb	if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers))
25272237Sjhb		goto fail;
25372237Sjhb	if (!TAILQ_EMPTY(&ithread->it_handlers) &&
25472237Sjhb	    (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0)
25572237Sjhb		goto fail;
25672237Sjhb
25772237Sjhb	TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next)
25872237Sjhb	    if (temp_ih->ih_pri > ih->ih_pri)
25972237Sjhb		    break;
26072237Sjhb	if (temp_ih == NULL)
26172237Sjhb		TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next);
26272237Sjhb	else
26372237Sjhb		TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
26472237Sjhb	ithread_update(ithread);
26572237Sjhb	mtx_unlock_spin(&ithread_list_lock);
26672237Sjhb
26772237Sjhb	if (cookiep != NULL)
26872237Sjhb		*cookiep = ih;
26972837Sjhb	CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name,
27072837Sjhb	    ithread->it_name);
27172237Sjhb	return (0);
27272237Sjhb
27372237Sjhbfail:
27472237Sjhb	mtx_unlock_spin(&ithread_list_lock);
27572237Sjhb	free(ih, M_ITHREAD);
27672237Sjhb	return (EINVAL);
27772237Sjhb}
27872237Sjhb
27972237Sjhbint
28072237Sjhbithread_remove_handler(void *cookie)
28172237Sjhb{
28272237Sjhb	struct intrhand *handler = (struct intrhand *)cookie;
28372237Sjhb	struct ithd *ithread;
28472237Sjhb#ifdef INVARIANTS
28572237Sjhb	struct intrhand *ih;
28672237Sjhb#endif
28772237Sjhb
28872759Sjhb	if (handler == NULL)
28972237Sjhb		return (EINVAL);
29072827Sjhb	ithread = handler->ih_ithread;
29172827Sjhb	KASSERT(ithread != NULL,
29272759Sjhb	    ("interrupt handler \"%s\" has a NULL interrupt thread",
29372759Sjhb		handler->ih_name));
29472837Sjhb	CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name,
29572837Sjhb	    ithread->it_name);
29672237Sjhb	mtx_lock_spin(&ithread_list_lock);
29772237Sjhb#ifdef INVARIANTS
29872237Sjhb	TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next)
29972759Sjhb		if (ih == handler)
30072759Sjhb			goto ok;
30172759Sjhb	mtx_unlock_spin(&ithread_list_lock);
30272759Sjhb	panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"",
30372759Sjhb	    ih->ih_name, ithread->it_name);
30472759Sjhbok:
30572237Sjhb#endif
30672839Sjhb	/*
30772839Sjhb	 * If the interrupt thread is already running, then just mark this
30872839Sjhb	 * handler as being dead and let the ithread do the actual removal.
30972839Sjhb	 */
31072839Sjhb	mtx_lock_spin(&sched_lock);
31172839Sjhb	if (ithread->it_proc->p_stat != SWAIT) {
31272839Sjhb		handler->ih_flags |= IH_DEAD;
31372839Sjhb
31472839Sjhb		/*
31572839Sjhb		 * Ensure that the thread will process the handler list
31672839Sjhb		 * again and remove this handler if it has already passed
31772839Sjhb		 * it on the list.
31872839Sjhb		 */
31972839Sjhb		ithread->it_need = 1;
32072839Sjhb	} else {
32172839Sjhb		TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
32272839Sjhb		ithread_update(ithread);
32372839Sjhb	}
32472839Sjhb	mtx_unlock_spin(&sched_lock);
32572237Sjhb	mtx_unlock_spin(&ithread_list_lock);
32672237Sjhb
32772839Sjhb	if ((handler->ih_flags & IH_DEAD) == 0)
32872839Sjhb		free(handler, M_ITHREAD);
32972237Sjhb	return (0);
33072237Sjhb}
33172237Sjhb
33272237Sjhbint
33372759Sjhbithread_schedule(struct ithd *ithread, int do_switch)
33472759Sjhb{
33572759Sjhb	struct int_entropy entropy;
33672759Sjhb	struct proc *p;
33774902Sjhb	critical_t savecrit;
33872759Sjhb
33972759Sjhb	/*
34072759Sjhb	 * If no ithread or no handlers, then we have a stray interrupt.
34172759Sjhb	 */
34272759Sjhb	if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers))
34372759Sjhb		return (EINVAL);
34472759Sjhb
34572759Sjhb	/*
34672759Sjhb	 * If any of the handlers for this ithread claim to be good
34772759Sjhb	 * sources of entropy, then gather some.
34872759Sjhb	 */
34972759Sjhb	if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) {
35072759Sjhb		entropy.vector = ithread->it_vector;
35172759Sjhb		entropy.proc = CURPROC;
35272759Sjhb		random_harvest(&entropy, sizeof(entropy), 2, 0,
35372759Sjhb		    RANDOM_INTERRUPT);
35472759Sjhb	}
35572759Sjhb
35672759Sjhb	p = ithread->it_proc;
35773313Sjhb	KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name));
35872759Sjhb	CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm,
35972759Sjhb	    ithread->it_need);
36072759Sjhb
36172759Sjhb	/*
36272759Sjhb	 * Set it_need to tell the thread to keep running if it is already
36372759Sjhb	 * running.  Then, grab sched_lock and see if we actually need to
36472759Sjhb	 * put this thread on the runqueue.  If so and the do_switch flag is
36572759Sjhb	 * true, then switch to the ithread immediately.  Otherwise, use
36672759Sjhb	 * need_resched() to guarantee that this ithread will run before any
36772759Sjhb	 * userland processes.
36872759Sjhb	 */
36972759Sjhb	ithread->it_need = 1;
37072759Sjhb	mtx_lock_spin(&sched_lock);
37172759Sjhb	if (p->p_stat == SWAIT) {
37272759Sjhb		CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid);
37372759Sjhb		p->p_stat = SRUN;
37472759Sjhb		setrunqueue(p);
37573313Sjhb		if (do_switch && curproc->p_stat == SRUN) {
37674902Sjhb			savecrit = sched_lock.mtx_savecrit;
37772759Sjhb			mtx_intr_enable(&sched_lock);
37872759Sjhb			if (curproc != PCPU_GET(idleproc))
37972759Sjhb				setrunqueue(curproc);
38072759Sjhb			curproc->p_stats->p_ru.ru_nvcsw++;
38172759Sjhb			mi_switch();
38274902Sjhb			sched_lock.mtx_savecrit = savecrit;
38372759Sjhb		} else
38472759Sjhb			need_resched();
38572759Sjhb	} else {
38672759Sjhb		CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d",
38772759Sjhb		    p->p_pid, ithread->it_need, p->p_stat);
38872759Sjhb	}
38972759Sjhb	mtx_unlock_spin(&sched_lock);
39072759Sjhb
39172759Sjhb	return (0);
39272759Sjhb}
39372759Sjhb
39472759Sjhbint
39572237Sjhbswi_add(struct ithd **ithdp, const char *name, driver_intr_t handler,
39672237Sjhb	    void *arg, int pri, enum intr_type flags, void **cookiep)
39772237Sjhb{
39867551Sjhb	struct ithd *ithd;
39972237Sjhb	int error;
40066698Sjhb
40172759Sjhb	if (flags & (INTR_FAST | INTR_ENTROPY))
40272759Sjhb		return (EINVAL);
40372759Sjhb
40467551Sjhb	ithd = (ithdp != NULL) ? *ithdp : NULL;
40566698Sjhb
40672759Sjhb	if (ithd != NULL) {
40772759Sjhb		if ((ithd->it_flags & IT_SOFT) == 0)
40872759Sjhb			return(EINVAL);
40972759Sjhb	} else {
41072237Sjhb		error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL,
41172237Sjhb		    "swi%d:", pri);
41267551Sjhb		if (error)
41372237Sjhb			return (error);
41472237Sjhb
41567551Sjhb		if (ithdp != NULL)
41667551Sjhb			*ithdp = ithd;
41766698Sjhb	}
41872376Sjake	return (ithread_add_handler(ithd, name, handler, arg,
41972376Sjake		    (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
42066698Sjhb}
42166698Sjhb
42266698Sjhb
42366698Sjhb/*
42467551Sjhb * Schedule a heavyweight software interrupt process.
42566698Sjhb */
42667551Sjhbvoid
42772237Sjhbswi_sched(void *cookie, int flags)
42866698Sjhb{
42972237Sjhb	struct intrhand *ih = (struct intrhand *)cookie;
43072237Sjhb	struct ithd *it = ih->ih_ithread;
43172759Sjhb	int error;
43266698Sjhb
43367551Sjhb	atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
43467551Sjhb
43572237Sjhb	CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d",
43672838Sjhb		it->it_proc->p_pid, it->it_proc->p_comm, it->it_need);
43767551Sjhb
43867551Sjhb	/*
43972759Sjhb	 * Set ih_need for this handler so that if the ithread is already
44072759Sjhb	 * running it will execute this handler on the next pass.  Otherwise,
44172759Sjhb	 * it will execute it the next time it runs.
44267551Sjhb	 */
44372237Sjhb	atomic_store_rel_int(&ih->ih_need, 1);
44472237Sjhb	if (!(flags & SWI_DELAY)) {
44572759Sjhb		error = ithread_schedule(it, !cold && flags & SWI_SWITCH);
44672759Sjhb		KASSERT(error == 0, ("stray software interrupt"));
44766698Sjhb	}
44866698Sjhb}
44966698Sjhb
45066698Sjhb/*
45172237Sjhb * This is the main code for interrupt threads.
45266698Sjhb */
45367551Sjhbvoid
45472237Sjhbithread_loop(void *arg)
45566698Sjhb{
45672237Sjhb	struct ithd *ithd;		/* our thread context */
45767551Sjhb	struct intrhand *ih;		/* and our interrupt handler chain */
45872237Sjhb	struct proc *p;
45967551Sjhb
46072237Sjhb	p = curproc;
46172237Sjhb	ithd = (struct ithd *)arg;	/* point to myself */
46272237Sjhb	KASSERT(ithd->it_proc == p && p->p_ithd == ithd,
46372237Sjhb	    (__func__ ": ithread and proc linkage out of sync"));
46466698Sjhb
46567551Sjhb	/*
46667551Sjhb	 * As long as we have interrupts outstanding, go through the
46767551Sjhb	 * list of handlers, giving each one a go at it.
46867551Sjhb	 */
46966698Sjhb	for (;;) {
47072237Sjhb		/*
47172237Sjhb		 * If we are an orphaned thread, then just die.
47272237Sjhb		 */
47372237Sjhb		if (ithd->it_flags & IT_DEAD) {
47472237Sjhb			CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting",
47572237Sjhb			    p->p_pid, p->p_comm);
47672237Sjhb			p->p_ithd = NULL;
47772237Sjhb			mtx_lock(&Giant);
47872237Sjhb			free(ithd, M_ITHREAD);
47972237Sjhb			kthread_exit(0);
48072237Sjhb		}
48172237Sjhb
48272237Sjhb		CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d",
48372237Sjhb		     p->p_pid, p->p_comm, ithd->it_need);
48472237Sjhb		while (ithd->it_need) {
48567551Sjhb			/*
48667551Sjhb			 * Service interrupts.  If another interrupt
48767551Sjhb			 * arrives while we are running, they will set
48867551Sjhb			 * it_need to denote that we should make
48967551Sjhb			 * another pass.
49067551Sjhb			 */
49172237Sjhb			atomic_store_rel_int(&ithd->it_need, 0);
49272839Sjhbrestart:
49372237Sjhb			TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
49472237Sjhb				if (ithd->it_flags & IT_SOFT && !ih->ih_need)
49567551Sjhb					continue;
49672237Sjhb				atomic_store_rel_int(&ih->ih_need, 0);
49767551Sjhb				CTR5(KTR_INTR,
49872237Sjhb				    __func__ ": pid %d ih=%p: %p(%p) flg=%x",
49967551Sjhb				    p->p_pid, (void *)ih,
50067551Sjhb				    (void *)ih->ih_handler, ih->ih_argument,
50167551Sjhb				    ih->ih_flags);
50266698Sjhb
50372237Sjhb				if ((ih->ih_flags & IH_MPSAFE) == 0)
50472200Sbmilekic					mtx_lock(&Giant);
50572839Sjhb				if ((ih->ih_flags & IH_DEAD) != 0) {
50672839Sjhb					mtx_lock_spin(&ithread_list_lock);
50772839Sjhb					TAILQ_REMOVE(&ithd->it_handlers, ih,
50872839Sjhb					    ih_next);
50972839Sjhb					ithread_update(ithd);
51072839Sjhb					mtx_unlock_spin(&ithread_list_lock);
51172839Sjhb					if (!mtx_owned(&Giant))
51272839Sjhb						mtx_lock(&Giant);
51372839Sjhb					free(ih, M_ITHREAD);
51472839Sjhb					mtx_unlock(&Giant);
51572839Sjhb					goto restart;
51672839Sjhb				}
51767551Sjhb				ih->ih_handler(ih->ih_argument);
51872237Sjhb				if ((ih->ih_flags & IH_MPSAFE) == 0)
51972200Sbmilekic					mtx_unlock(&Giant);
52067551Sjhb			}
52166698Sjhb		}
52267551Sjhb
52366698Sjhb		/*
52466698Sjhb		 * Processed all our interrupts.  Now get the sched
52567551Sjhb		 * lock.  This may take a while and it_need may get
52666698Sjhb		 * set again, so we have to check it again.
52766698Sjhb		 */
52868789Sjhb		mtx_assert(&Giant, MA_NOTOWNED);
52972200Sbmilekic		mtx_lock_spin(&sched_lock);
53072237Sjhb		if (!ithd->it_need) {
53172237Sjhb			/*
53272237Sjhb			 * Should we call this earlier in the loop above?
53372237Sjhb			 */
53472237Sjhb			if (ithd->it_enable != NULL)
53572237Sjhb				ithd->it_enable(ithd->it_vector);
53667551Sjhb			p->p_stat = SWAIT; /* we're idle */
53772237Sjhb			CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid);
53866698Sjhb			mi_switch();
53972237Sjhb			CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid);
54066698Sjhb		}
54172200Sbmilekic		mtx_unlock_spin(&sched_lock);
54266698Sjhb	}
54366698Sjhb}
54466698Sjhb
54572237Sjhb/*
54672237Sjhb * Initialize mutex used to protect ithread handler lists.
54772237Sjhb */
54872237Sjhbstatic void
54972237Sjhbithread_init(void *dummy)
55072237Sjhb{
55167551Sjhb
55272237Sjhb	mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN);
55372237Sjhb}
55472237SjhbSYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL);
55572237Sjhb
55666698Sjhb/*
55767551Sjhb * Start standard software interrupt threads
55866698Sjhb */
55967551Sjhbstatic void
56072237Sjhbstart_softintr(void *dummy)
56167551Sjhb{
56272237Sjhb
56372237Sjhb	if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) ||
56472237Sjhb	    swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK,
56572237Sjhb		INTR_MPSAFE, &softclock_ih) ||
56672237Sjhb	    swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih))
56772237Sjhb		panic("died while creating standard software ithreads");
56872759Sjhb
56972759Sjhb	PROC_LOCK(clk_ithd->it_proc);
57072759Sjhb	clk_ithd->it_proc->p_flag |= P_NOLOAD;
57172759Sjhb	PROC_UNLOCK(clk_ithd->it_proc);
57266698Sjhb}
57372237SjhbSYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL)
57466698Sjhb
57567551Sjhbvoid
57672237Sjhblegacy_setsoftnet(void)
57767551Sjhb{
57872237Sjhb	swi_sched(net_ih, SWI_NOSWITCH);
57966698Sjhb}
58066698Sjhb
58167551Sjhb/*
58267551Sjhb * XXX: This should really be in the network code somewhere and installed
58367551Sjhb * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit.
58467551Sjhb */
58567551Sjhbvoid	(*netisrs[32]) __P((void));
58667551Sjhbu_int	netisr;
58766698Sjhb
58869586Sjakeint
58969586Sjakeregister_netisr(num, handler)
59069586Sjake	int num;
59169586Sjake	netisr_t *handler;
59269586Sjake{
59369586Sjake
59469586Sjake	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
59569586Sjake		printf("register_netisr: bad isr number: %d\n", num);
59669586Sjake		return (EINVAL);
59769586Sjake	}
59869586Sjake	netisrs[num] = handler;
59969586Sjake	return (0);
60069586Sjake}
60169586Sjake
60269586Sjakeint
60369586Sjakeunregister_netisr(num)
60469586Sjake	int num;
60569586Sjake{
60669586Sjake
60769586Sjake	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
60869586Sjake		printf("unregister_netisr: bad isr number: %d\n", num);
60969586Sjake		return (EINVAL);
61069586Sjake	}
61169586Sjake	netisrs[num] = NULL;
61269586Sjake	return (0);
61369586Sjake}
61469586Sjake
61567551Sjhbstatic void
61667551Sjhbswi_net(void *dummy)
61766698Sjhb{
61867551Sjhb	u_int bits;
61967551Sjhb	int i;
62066698Sjhb
62167551Sjhb	bits = atomic_readandclear_int(&netisr);
62267551Sjhb	while ((i = ffs(bits)) != 0) {
62367551Sjhb		i--;
62470531Stanimura		if (netisrs[i] != NULL)
62570531Stanimura			netisrs[i]();
62670531Stanimura		else
62770531Stanimura			printf("swi_net: unregistered isr number: %d.\n", i);
62867551Sjhb		bits &= ~(1 << i);
62966698Sjhb	}
63066698Sjhb}
631