NetBSD/sys/arch/alpha/common/shared_intr.c
thorpej 0fb6b9a8f8 Rework the interrupt code, shaving some cycles off in the process.
Rather than an "iointr" routine that decomposes a vector into an
IRQ, we maintain a vector table directly, hooking up each "iointr"
routine at the correct vector.  This also allows us to hook device
interrupts up to specific vectors (c.f. Jensen).

We can shave even more cycles off, here, and I will, but it requires
some changes to the alpha_shared_intr stuff.
2001-07-27 00:25:18 +00:00

294 lines
7.0 KiB
C

/* $NetBSD: shared_intr.c,v 1.16 2001/07/27 00:25:19 thorpej Exp $ */
/*
* Copyright (c) 1996 Carnegie-Mellon University.
* All rights reserved.
*
* Authors: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*
* Common shared-interrupt-line functionality.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: shared_intr.c,v 1.16 2001/07/27 00:25:19 thorpej Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <machine/intr.h>
static const char *intr_typename __P((int));
static const char *
intr_typename(int type)
{
switch (type) {
case IST_UNUSABLE:
return ("disabled");
case IST_NONE:
return ("none");
case IST_PULSE:
return ("pulsed");
case IST_EDGE:
return ("edge-triggered");
case IST_LEVEL:
return ("level-triggered");
}
panic("intr_typename: unknown type %d", type);
}
struct alpha_shared_intr *
alpha_shared_intr_alloc(unsigned int n, unsigned int namesize)
{
struct alpha_shared_intr *intr;
unsigned int i;
intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF,
cold ? M_NOWAIT : M_WAITOK);
if (intr == NULL)
panic("alpha_shared_intr_alloc: couldn't malloc intr");
for (i = 0; i < n; i++) {
TAILQ_INIT(&intr[i].intr_q);
intr[i].intr_sharetype = IST_NONE;
intr[i].intr_dfltsharetype = IST_NONE;
intr[i].intr_nstrays = 0;
intr[i].intr_maxstrays = 5;
intr[i].intr_private = NULL;
if (namesize != 0) {
intr[i].intr_string = malloc(namesize, M_DEVBUF,
cold ? M_NOWAIT : M_WAITOK);
if (intr[i].intr_string == NULL)
panic("alpha_shared_intr_alloc: couldn't "
"malloc intr string");
} else
intr[i].intr_string = NULL;
}
return (intr);
}
int
alpha_shared_intr_dispatch(struct alpha_shared_intr *intr, unsigned int num)
{
struct alpha_shared_intrhand *ih;
int rv, handled;
atomic_add_ulong(&intr[num].intr_evcnt.ev_count, 1);
ih = intr[num].intr_q.tqh_first;
handled = 0;
while (ih != NULL) {
/*
* The handler returns one of three values:
* 0: This interrupt wasn't for me.
* 1: This interrupt was for me.
* -1: This interrupt might have been for me, but I can't say
* for sure.
*/
rv = (*ih->ih_fn)(ih->ih_arg);
handled = handled || (rv != 0);
ih = ih->ih_q.tqe_next;
}
return (handled);
}
void *
alpha_shared_intr_establish(struct alpha_shared_intr *intr, unsigned int num,
int type, int level, int (*fn)(void *), void *arg, const char *basename)
{
struct alpha_shared_intrhand *ih;
if (intr[num].intr_sharetype == IST_UNUSABLE) {
printf("alpha_shared_intr_establish: %s %d: unusable\n",
basename, num);
return NULL;
}
/* no point in sleeping unless someone can free memory. */
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
if (ih == NULL)
panic("alpha_shared_intr_establish: can't malloc intrhand");
#ifdef DIAGNOSTIC
if (type == IST_NONE)
panic("alpha_shared_intr_establish: bogus type");
#endif
switch (intr[num].intr_sharetype) {
case IST_EDGE:
case IST_LEVEL:
if (type == intr[num].intr_sharetype)
break;
case IST_PULSE:
if (type != IST_NONE) {
if (intr[num].intr_q.tqh_first == NULL) {
printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n",
basename, num, intr_typename(type),
intr_typename(intr[num].intr_sharetype));
type = intr[num].intr_sharetype;
} else {
panic("alpha_shared_intr_establish: %s %d: can't share %s with %s",
basename, num, intr_typename(type),
intr_typename(intr[num].intr_sharetype));
}
}
break;
case IST_NONE:
/* not currently used; safe */
break;
}
ih->ih_intrhead = intr;
ih->ih_fn = fn;
ih->ih_arg = arg;
ih->ih_level = level;
ih->ih_num = num;
intr[num].intr_sharetype = type;
TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q);
return (ih);
}
void
alpha_shared_intr_disestablish(struct alpha_shared_intr *intr, void *cookie,
const char *basename)
{
struct alpha_shared_intrhand *ih = cookie;
unsigned int num = ih->ih_num;
/*
* Just remove it from the list and free the entry. We let
* the caller deal with resetting the share type, if appropriate.
*/
TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q);
}
int
alpha_shared_intr_get_sharetype(struct alpha_shared_intr *intr,
unsigned int num)
{
return (intr[num].intr_sharetype);
}
int
alpha_shared_intr_isactive(struct alpha_shared_intr *intr, unsigned int num)
{
return (intr[num].intr_q.tqh_first != NULL);
}
int
alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num)
{
return (intr[num].intr_q.tqh_first != NULL &&
intr[num].intr_q.tqh_first->ih_q.tqe_next == NULL);
}
void
alpha_shared_intr_set_dfltsharetype(struct alpha_shared_intr *intr,
unsigned int num, int newdfltsharetype)
{
#ifdef DIAGNOSTIC
if (alpha_shared_intr_isactive(intr, num))
panic("alpha_shared_intr_set_dfltsharetype on active intr");
#endif
intr[num].intr_dfltsharetype = newdfltsharetype;
intr[num].intr_sharetype = intr[num].intr_dfltsharetype;
}
void
alpha_shared_intr_set_maxstrays(struct alpha_shared_intr *intr,
unsigned int num, int newmaxstrays)
{
int s = splhigh();
intr[num].intr_maxstrays = newmaxstrays;
intr[num].intr_nstrays = 0;
splx(s);
}
void
alpha_shared_intr_stray(struct alpha_shared_intr *intr, unsigned int num,
const char *basename)
{
intr[num].intr_nstrays++;
if (intr[num].intr_maxstrays == 0)
return;
if (intr[num].intr_nstrays <= intr[num].intr_maxstrays)
log(LOG_ERR, "stray %s %d%s\n", basename, num,
intr[num].intr_nstrays >= intr[num].intr_maxstrays ?
"; stopped logging" : "");
}
void
alpha_shared_intr_set_private(struct alpha_shared_intr *intr,
unsigned int num, void *v)
{
intr[num].intr_private = v;
}
void *
alpha_shared_intr_get_private(struct alpha_shared_intr *intr,
unsigned int num)
{
return (intr[num].intr_private);
}
struct evcnt *
alpha_shared_intr_evcnt(struct alpha_shared_intr *intr,
unsigned int num)
{
return (&intr[num].intr_evcnt);
}
char *
alpha_shared_intr_string(struct alpha_shared_intr *intr,
unsigned int num)
{
return (intr[num].intr_string);
}