/* $OpenBSD: softintr.c,v 1.2 2008/06/26 05:42:10 ray Exp $ */ /* $NetBSD: softintr.c,v 1.1 2003/02/26 21:26:12 fvdl Exp $ */ /*- * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Generic soft interrupt implementation for NetBSD/x86. */ #include #include #include #include struct i386_soft_intr i386_soft_intrs[I386_NSOFTINTR]; const int i386_soft_intr_to_ssir[I386_NSOFTINTR] = { SIR_CLOCK, SIR_NET, SIR_TTY, }; /* * softintr_init: * * Initialize the software interrupt system. */ void softintr_init(void) { struct i386_soft_intr *si; int i; for (i = 0; i < I386_NSOFTINTR; i++) { si = &i386_soft_intrs[i]; TAILQ_INIT(&si->softintr_q); simple_lock_init(&si->softintr_slock); si->softintr_ssir = i386_soft_intr_to_ssir[i]; } } /* * softintr_dispatch: * * Process pending software interrupts. */ void softintr_dispatch(int which) { struct i386_soft_intr *si = &i386_soft_intrs[which]; struct i386_soft_intrhand *sih; int s; for (;;) { i386_softintr_lock(si, s); sih = TAILQ_FIRST(&si->softintr_q); if (sih == NULL) { i386_softintr_unlock(si, s); break; } TAILQ_REMOVE(&si->softintr_q, sih, sih_q); sih->sih_pending = 0; i386_softintr_unlock(si, s); uvmexp.softs++; (*sih->sih_fn)(sih->sih_arg); } } /* * softintr_establish: [interface] * * Register a software interrupt handler. */ void * softintr_establish(int ipl, void (*func)(void *), void *arg) { struct i386_soft_intr *si; struct i386_soft_intrhand *sih; int which; switch (ipl) { case IPL_SOFTCLOCK: which = I386_SOFTINTR_SOFTCLOCK; break; case IPL_SOFTNET: which = I386_SOFTINTR_SOFTNET; break; case IPL_TTY: case IPL_SOFTTTY: which = I386_SOFTINTR_SOFTTTY; break; default: panic("softintr_establish"); } si = &i386_soft_intrs[which]; sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT); if (__predict_true(sih != NULL)) { sih->sih_intrhead = si; sih->sih_fn = func; sih->sih_arg = arg; sih->sih_pending = 0; } return (sih); } /* * softintr_disestablish: [interface] * * Unregister a software interrupt handler. */ void softintr_disestablish(void *arg) { struct i386_soft_intrhand *sih = arg; struct i386_soft_intr *si = sih->sih_intrhead; int s; i386_softintr_lock(si, s); if (sih->sih_pending) { TAILQ_REMOVE(&si->softintr_q, sih, sih_q); sih->sih_pending = 0; } i386_softintr_unlock(si, s); free(sih, M_DEVBUF); }