summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_intr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_intr.c')
-rw-r--r--sys/kern/kern_intr.c406
1 files changed, 1 insertions, 405 deletions
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index 1d6756c..22565f7 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: kern_intr.c,v 1.20 1998/09/26 14:25:31 dfr Exp $
+ * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $
*
*/
@@ -32,38 +32,11 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/errno.h>
-#ifdef RESOURCE_CHECK
-#include <sys/drvresource.h>
-#endif /* RESOURCE_CHECK */
#include <machine/ipl.h>
-#ifdef __i386__
-#include <i386/isa/icu.h>
-#include <i386/isa/intr_machdep.h>
-#endif
-
#include <sys/interrupt.h>
-#include <stddef.h>
-
-#ifdef __i386__
-
-typedef struct intrec {
- intrmask_t mask;
- inthand2_t *handler;
- void *argument;
- struct intrec *next;
- void *devdata;
- int intr;
- intrmask_t *maskptr;
- int flags;
-} intrec;
-
-static intrec *intreclist_head[NHWI];
-
-#endif
-
struct swilist {
swihand_t *sl_handler;
struct swilist *sl_next;
@@ -71,383 +44,6 @@ struct swilist {
static struct swilist swilists[NSWI];
-#ifdef __i386__
-
-/*
- * The interrupt multiplexer calls each of the handlers in turn,
- * and applies the associated interrupt mask to "cpl", which is
- * defined as a ".long" in /sys/i386/isa/ipl.s
- */
-
-#ifndef SMP
-static __inline intrmask_t
-splq(intrmask_t mask)
-{
- intrmask_t tmp = cpl;
- cpl |= mask;
- return (tmp);
-}
-#endif /* SMP */
-
-static void
-intr_mux(void *arg)
-{
- intrec *p = arg;
-
- while (p != NULL) {
- int oldspl = splq(p->mask);
- p->handler(p->argument);
- splx(oldspl);
- p = p->next;
- }
-}
-
-static intrec*
-find_idesc(unsigned *maskptr, int irq)
-{
- intrec *p = intreclist_head[irq];
-
- while (p && p->maskptr != maskptr)
- p = p->next;
-
- return (p);
-}
-
-static intrec**
-find_pred(intrec *idesc, int irq)
-{
- intrec **pp = &intreclist_head[irq];
- intrec *p = *pp;
-
- while (p != idesc) {
- if (p == NULL)
- return (NULL);
- pp = &p->next;
- p = *pp;
- }
- return (pp);
-}
-
-/*
- * Both the low level handler and the shared interrupt multiplexer
- * block out further interrupts as set in the handlers "mask", while
- * the handler is running. In fact *maskptr should be used for this
- * purpose, but since this requires one more pointer dereference on
- * each interrupt, we rather bother update "mask" whenever *maskptr
- * changes. The function "update_masks" should be called **after**
- * all manipulation of the linked list of interrupt handlers hung
- * off of intrdec_head[irq] is complete, since the chain of handlers
- * will both determine the *maskptr values and the instances of mask
- * that are fixed. This function should be called with the irq for
- * which a new handler has been add blocked, since the masks may not
- * yet know about the use of this irq for a device of a certain class.
- */
-
-static void
-update_mux_masks(void)
-{
- int irq;
- for (irq = 0; irq < ICU_LEN; irq++) {
- intrec *idesc = intreclist_head[irq];
- while (idesc != NULL) {
- if (idesc->maskptr != NULL) {
- /* our copy of *maskptr may be stale, refresh */
- idesc->mask = *idesc->maskptr;
- }
- idesc = idesc->next;
- }
- }
-}
-
-static void
-update_masks(intrmask_t *maskptr, int irq)
-{
- intrmask_t mask = 1 << irq;
-
- if (maskptr == NULL)
- return;
-
- if (find_idesc(maskptr, irq) == NULL) {
- /* no reference to this maskptr was found in this irq's chain */
- if ((*maskptr & mask) == 0)
- return;
- /* the irq was included in the classes mask, remove it */
- INTRUNMASK(*maskptr, mask);
- } else {
- /* a reference to this maskptr was found in this irq's chain */
- if ((*maskptr & mask) != 0)
- return;
- /* put the irq into the classes mask */
- INTRMASK(*maskptr, mask);
- }
- /* we need to update all values in the intr_mask[irq] array */
- update_intr_masks();
- /* update mask in chains of the interrupt multiplex handler as well */
- update_mux_masks();
-}
-
-/*
- * Add interrupt handler to linked list hung off of intreclist_head[irq]
- * and install shared interrupt multiplex handler, if necessary
- */
-
-static int
-add_intrdesc(intrec *idesc)
-{
- int irq = idesc->intr;
-
- intrec *head = intreclist_head[irq];
-
- if (head == NULL) {
- /* first handler for this irq, just install it */
- if (icu_setup(irq, idesc->handler, idesc->argument,
- idesc->maskptr, idesc->flags) != 0)
- return (-1);
-
- update_intrname(irq, (intptr_t)idesc->devdata);
- /* keep reference */
- intreclist_head[irq] = idesc;
- } else {
- if ((idesc->flags & INTR_EXCL) != 0
- || (head->flags & INTR_EXCL) != 0) {
- /*
- * can't append new handler, if either list head or
- * new handler do not allow interrupts to be shared
- */
- if (bootverbose)
- printf("\tdevice combination doesn't support "
- "shared irq%d\n", irq);
- return (-1);
- }
- if (head->next == NULL) {
- /*
- * second handler for this irq, replace device driver's
- * handler by shared interrupt multiplexer function
- */
- icu_unset(irq, head->handler);
- if (icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0) != 0)
- return (-1);
- if (bootverbose)
- printf("\tusing shared irq%d.\n", irq);
- update_intrname(irq, -1);
- }
- /* just append to the end of the chain */
- while (head->next != NULL)
- head = head->next;
- head->next = idesc;
- }
- update_masks(idesc->maskptr, irq);
- return (0);
-}
-
-/*
- * Add the interrupt handler descriptor data structure created by an
- * earlier call of create_intr() to the linked list for its irq and
- * adjust the interrupt masks if necessary.
- *
- * This function effectively activates the handler.
- */
-
-int
-intr_connect(intrec *idesc)
-{
- int errcode = -1;
- int irq;
-
-#ifdef RESOURCE_CHECK
- int resflag;
-#endif /* RESOURCE_CHECK */
-
- if (idesc == NULL)
- return (-1);
-
- irq = idesc->intr;
-#ifdef RESOURCE_CHECK
- resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED;
- if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0)
-#endif /* RESOURCE_CHECK */
- {
- /* block this irq */
- intrmask_t oldspl = splq(1 << irq);
-
- /* add irq to class selected by maskptr */
- errcode = add_intrdesc(idesc);
- splx(oldspl);
- }
- if (errcode != 0 && bootverbose)
- printf("\tintr_connect(irq%d) failed, result=%d\n",
- irq, errcode);
-
- return (errcode);
-}
-
-/*
- * Remove the interrupt handler descriptor data connected created by an
- * earlier call of intr_connect() from the linked list and adjust the
- * interrupt masks if necessary.
- *
- * This function deactivates the handler.
- */
-
-int
-intr_disconnect(intrec *idesc)
-{
- intrec **hook, *head;
- int irq;
- int errcode = 0;
-
- if (idesc == NULL)
- return (-1);
-
- irq = idesc->intr;
-
- /* find pointer that keeps the reference to this interrupt descriptor */
- hook = find_pred(idesc, irq);
- if (hook == NULL)
- return (-1);
-
- /* make copy of original list head, the line after may overwrite it */
- head = intreclist_head[irq];
-
- /* unlink: make predecessor point to idesc->next instead of to idesc */
- *hook = idesc->next;
-
- /* now check whether the element we removed was the list head */
- if (idesc == head) {
- intrmask_t oldspl = splq(1 << irq);
-
- /* we want to remove the list head, which was known to intr_mux */
- icu_unset(irq, (inthand2_t*)intr_mux);
-
- /* check whether the new list head is the only element on list */
- head = intreclist_head[irq];
- if (head != NULL) {
- if (head->next != NULL) {
- /* install the multiplex handler with new list head as argument */
- errcode = icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0);
- if (errcode == 0)
- update_intrname(irq, -1);
- } else {
- /* install the one remaining handler for this irq */
- errcode = icu_setup(irq, head->handler,
- head->argument,
- head->maskptr, head->flags);
- if (errcode == 0)
- update_intrname(irq, (intptr_t)head->devdata);
- }
- }
- splx(oldspl);
- }
- update_masks(idesc->maskptr, irq);
-#ifdef RESOURCE_CHECK
- resource_free(idesc->devdata);
-#endif /* RESOURCE_CHECK */
- return (0);
-}
-
-/*
- * Create an interrupt handler descriptor data structure, which later can
- * be activated or deactivated at will by calls of [dis]connect(intrec*).
- *
- * The dev_instance pointer is required for resource management, and will
- * only be passed through to resource_claim().
- *
- * The interrupt handler takes an argument of type (void*), which is not
- * what is currently used for ISA devices. But since the unit number passed
- * to an ISA interrupt handler can be stored in a (void*) variable, this
- * causes no problems. Eventually all the ISA interrupt handlers should be
- * modified to accept the pointer to their private data, too, instead of
- * an integer index.
- *
- * There will be functions that derive a driver and unit name from a
- * dev_instance variable, and those functions will be used to maintain the
- * interrupt counter label array referenced by systat and vmstat to report
- * device interrupt rates (->update_intrlabels).
- */
-
-intrec *
-intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg,
- intrmask_t *maskptr, int flags)
-{
- intrec *idesc;
-
- if (ICU_LEN > 8 * sizeof *maskptr) {
- printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
- ICU_LEN, 8 * sizeof *maskptr);
- return (NULL);
- }
- if ((unsigned)irq >= ICU_LEN) {
- printf("create_intr: requested irq%d too high, limit is %d\n",
- irq, ICU_LEN -1);
- return (NULL);
- }
-
- idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
- if (idesc) {
- idesc->next = NULL;
- bzero(idesc, sizeof *idesc);
-
- idesc->devdata = dev_instance;
- idesc->handler = handler;
- idesc->argument = arg;
- idesc->maskptr = maskptr;
- idesc->intr = irq;
- idesc->flags = flags;
- }
- return (idesc);
-}
-
-/*
- * Return the memory held by the interrupt handler descriptor data structure
- * to the system. Make sure, the handler is not actively used anymore, before.
- */
-
-int
-intr_destroy(intrec *rec)
-{
- if (intr_disconnect(rec) != 0)
- return (-1);
- free(rec, M_DEVBUF);
- return (0);
-}
-
-/*
- * Emulate the register_intr() call previously defined as low level function.
- * That function (now icu_setup()) may no longer be directly called, since
- * a conflict between an ISA and PCI interrupt might go by unnocticed, else.
- */
-
-int
-register_intr(int intr, int device_id, u_int flags,
- inthand2_t handler, u_int *maskptr, int unit)
-{
- /* XXX modify to include isa_device instead of device_id */
- intrec *idesc;
-
- flags |= INTR_EXCL;
- idesc = intr_create((void *)(intptr_t)device_id, intr, handler,
- (void*)(intptr_t)unit, maskptr, flags);
- return (intr_connect(idesc));
-}
-
-/*
- * Emulate the old unregister_intr() low level function.
- * Make sure there is just one interrupt, that it was
- * registered as non-shared, and that the handlers match.
- */
-
-int
-unregister_intr(int intr, inthand2_t handler)
-{
- intrec *p = intreclist_head[intr];
-
- if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler)
- return (intr_destroy(p));
- return (EINVAL);
-}
-
-#endif /* __i386__ */
-
void
register_swi(intr, handler)
int intr;
OpenPOWER on IntegriCloud