Finish the switch to the softintr(9) framework.

To make this work, we now have to use separate handler lists for hardware
and software interrupts as the soft interrupt handlers do not return
an `interrupt handled' status.

Thanks to Matt Fredette for providing an initial set of patches on port-sparc.
This commit is contained in:
pk 2002-12-09 16:11:50 +00:00
parent 21bf723223
commit c822c6bd84
5 changed files with 192 additions and 119 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: audioamd.c,v 1.13 2002/10/15 13:49:52 jdc Exp $ */
/* $NetBSD: audioamd.c,v 1.14 2002/12/09 16:11:50 pk Exp $ */
/* NetBSD: am7930_sparc.c,v 1.44 1999/03/14 22:29:00 jonathan Exp */
/*
@ -64,20 +64,9 @@
/* interrupt interfaces */
#ifdef AUDIO_C_HANDLER
int am7930hwintr __P((void *));
#if defined(SUN4M)
#define AUDIO_SET_SWINTR do { \
if (CPU_ISSUN4M) \
raise(0, 4); \
else \
ienab_bis(IE_L4); \
} while(0);
#else
#define AUDIO_SET_SWINTR ienab_bis(IE_L4)
#endif /* defined(SUN4M) */
#else
struct auio *auiop;
#endif /* AUDIO_C_HANDLER */
int am7930swintr __P((void *));
struct auio *auiop;
void am7930swintr __P((void *));
/*
* interrupt-handler status
@ -102,6 +91,7 @@ struct audioamd_softc {
/* sc_au is special in that the hardware interrupt handler uses it */
struct auio sc_au; /* recv and xmit buffers, etc */
#define sc_intrcnt sc_au.au_intrcnt /* statistics */
void *sc_sicookie; /* softintr(9) cookie */
};
void audioamd_mainbus_attach __P((struct device *,
@ -306,8 +296,6 @@ audioamd_attach(sc, pri)
int pri;
{
printf(" softpri %d\n", PIL_AUSOFT);
/*
* Set up glue for MI code early; we use some of it here.
*/
@ -315,8 +303,8 @@ audioamd_attach(sc, pri)
am7930_init(&sc->sc_am7930, AUDIOAMD_POLL_MODE);
#ifndef AUDIO_C_HANDLER
auiop = &sc->sc_au;
#ifndef AUDIO_C_HANDLER
(void)bus_intr_establish(sc->sc_bt, pri, IPL_AUDIO,
BUS_INTR_ESTABLISH_FASTTRAP,
(int (*) __P((void *)))amd7930_trap, NULL);
@ -324,9 +312,16 @@ audioamd_attach(sc, pri)
(void)bus_intr_establish(sc->sc_bt, pri, IPL_AUDIO, 0,
am7930hwintr, sc);
#endif
(void)bus_intr_establish(sc->sc_bt, PIL_AUSOFT, IPL_AUDIO,
BUS_INTR_ESTABLISH_SOFTINTR,
am7930swintr, sc);
sc->sc_sicookie = softintr_establish(IPL_SOFTAUDIO, am7930swintr, sc);
if (sc->sc_sicookie == NULL) {
printf("\n%s: cannot establish software interrupt\n",
sc->sc_am7930.sc_dev.dv_xname);
return;
}
printf(" softpri %d\n", IPL_SOFTAUDIO);
evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
sc->sc_am7930.sc_dev.dv_xname, "intr");
@ -436,6 +431,9 @@ am7930hwintr(v)
/* clear interrupt */
k = audioamd_codec_dread(sc, AM7930_DREG_IR);
if ((k & (AM7930_IR_DTTHRSH|AM7930_IR_DRTHRSH|AM7930_IR_DSRI|
AM7930_IR_DERI|AM7930_IR_BBUFF)) == 0)
return (0);
/* receive incoming data */
d = au->au_rdata;
@ -445,7 +443,7 @@ am7930hwintr(v)
au->au_rdata++;
if (d == e) {
DPRINTFN(1, ("am7930hwintr: swintr(r) requested"));
AUDIO_SET_SWINTR;
softintr_schedule(sc->sc_sicookie);
}
}
@ -457,7 +455,7 @@ am7930hwintr(v)
au->au_pdata++;
if (d == e) {
DPRINTFN(1, ("am7930hwintr: swintr(p) requested"));
AUDIO_SET_SWINTR;
softintr_schedule(sc->sc_sicookie);
}
}
@ -466,13 +464,13 @@ am7930hwintr(v)
}
#endif /* AUDIO_C_HANDLER */
int
void
am7930swintr(sc0)
void *sc0;
{
struct audioamd_softc *sc = sc0;
struct auio *au;
int s, ret = 0;
int s;
DPRINTFN(1, ("audiointr: sc=%p\n", sc););
@ -480,17 +478,14 @@ am7930swintr(sc0)
s = splaudio();
if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) {
splx(s);
ret = 1;
(*sc->sc_rintr)(sc->sc_rarg);
s = splaudio();
}
if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) {
splx(s);
ret = 1;
(*sc->sc_pintr)(sc->sc_parg);
} else
splx(s);
return (ret);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: fd.c,v 1.96 2002/11/01 11:31:53 mrg Exp $ */
/* $NetBSD: fd.c,v 1.97 2002/12/09 16:11:50 pk Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -174,6 +174,8 @@ struct fdc_softc {
#define sc_nstat sc_io.fdcio_nstat
#define sc_status sc_io.fdcio_status
#define sc_intrcnt sc_io.fdcio_intrcnt
void *sc_sicookie; /* softintr(9) cookie */
};
extern struct fdcio *fdciop; /* I/O descriptor used in fdintr.s */
@ -302,7 +304,7 @@ void fdctimeout __P((void *arg));
void fdcpseudointr __P((void *arg));
int fdc_c_hwintr __P((void *));
void fdchwintr __P((void));
int fdcswintr __P((void *));
void fdcswintr __P((void *));
int fdcstate __P((struct fdc_softc *));
void fdcretry __P((struct fdc_softc *fdc));
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
@ -318,23 +320,6 @@ static void establish_chip_type __P((
bus_space_handle_t));
#if PIL_FDSOFT == 4
#define IE_FDSOFT IE_L4
#else
#error 4
#endif
#if defined(SUN4M)
#define FD_SET_SWINTR do { \
if (CPU_ISSUN4M) \
raise(0, PIL_FDSOFT); \
else \
ienab_bis(IE_L4); \
} while(0)
#else
#define FD_SET_SWINTR ienab_bis(IE_FDSOFT)
#endif /* defined(SUN4M) */
#define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd")
int
@ -624,8 +609,6 @@ fdcattach(fdc, pri)
code = '2';
}
printf(" softpri %d: chip 8207%c\n", PIL_FDSOFT, code);
/*
* Configure controller; enable FIFO, Implied seek, no POLL mode?.
* Note: CFG_EFIFO is active-low, initial threshold value: 8
@ -651,13 +634,13 @@ fdcattach(fdc, pri)
}
}
if (bus_intr_establish(fdc->sc_bustag, PIL_FDSOFT, IPL_BIO,
BUS_INTR_ESTABLISH_SOFTINTR,
fdcswintr, fdc) == NULL) {
printf("%s: cannot register interrupt handler\n",
fdc->sc_sicookie = softintr_establish(IPL_SOFTFDC, fdcswintr, fdc);
if (fdc->sc_sicookie == NULL) {
printf("\n%s: cannot register soft interrupt handler\n",
fdc->sc_dev.dv_xname);
return (-1);
}
printf(" softpri %d: chip 8207%c\n", IPL_SOFTFDC, code);
evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
fdc->sc_dev.dv_xname, "intr");
@ -1320,7 +1303,7 @@ fdc_c_hwintr(arg)
fdc->sc_istatus = FDC_ISTATUS_ERROR;
else
fdc->sc_istatus = FDC_ISTATUS_DONE;
FD_SET_SWINTR;
softintr_schedule(fdc->sc_sicookie);
return (1);
case FDC_ITASK_DMA:
/* Proceed with pseudo-dma below */
@ -1328,7 +1311,7 @@ fdc_c_hwintr(arg)
default:
printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask);
fdc->sc_istatus = FDC_ISTATUS_SPURIOUS;
FD_SET_SWINTR;
softintr_schedule(fdc->sc_sicookie);
return (1);
}
@ -1347,7 +1330,7 @@ fdc_c_hwintr(arg)
if ((msr & NE7_NDM) == 0) {
fdcresult(fdc);
fdc->sc_istatus = FDC_ISTATUS_DONE;
FD_SET_SWINTR;
softintr_schedule(fdc->sc_sicookie);
#ifdef FD_DEBUG
if (fdc_debug > 1)
printf("fdc: overrun: tc = %d\n", fdc->sc_tc);
@ -1368,14 +1351,14 @@ fdc_c_hwintr(arg)
fdc->sc_istatus = FDC_ISTATUS_DONE;
FTC_FLIP;
fdcresult(fdc);
FD_SET_SWINTR;
softintr_schedule(fdc->sc_sicookie);
break;
}
}
return (1);
}
int
void
fdcswintr(arg)
void *arg;
{
@ -1384,7 +1367,7 @@ fdcswintr(arg)
if (fdc->sc_istatus == FDC_ISTATUS_NONE)
/* This (software) interrupt is not for us */
return (0);
return;
switch (fdc->sc_istatus) {
case FDC_ISTATUS_ERROR:
@ -1398,7 +1381,7 @@ fdcswintr(arg)
s = splbio();
fdcstate(fdc);
splx(s);
return (1);
return;
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: zs.c,v 1.92 2002/10/09 08:56:25 jdc Exp $ */
/* $NetBSD: zs.c,v 1.93 2002/12/09 16:11:51 pk Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@ -96,19 +96,6 @@ int zs_def_cflag = (CREAD | CS8 | HUPCL);
*/
#define PCLK (9600 * 512) /* PCLK pin input clock rate */
/*
* Select software interrupt bit based on TTY ipl.
*/
#if PIL_TTY == 1
# define IE_ZSSOFT IE_L1
#elif PIL_TTY == 4
# define IE_ZSSOFT IE_L4
#elif PIL_TTY == 6
# define IE_ZSSOFT IE_L6
#else
# error "no suitable software interrupt bit"
#endif
#define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2))
/* The layout of this is hardware-dependent (padding, order). */
@ -192,9 +179,12 @@ CFATTACH_DECL(zs_obio, sizeof(struct zsc_softc),
extern struct cfdriver zs_cd;
/* softintr(9) cookie, shared by all instances of this driver */
static void *zs_sicookie;
/* Interrupt handlers. */
static int zshard __P((void *));
static int zssoft __P((void *));
static void zssoft __P((void *));
static int zs_get_speed __P((struct zs_chanstate *));
@ -435,7 +425,15 @@ zs_attach(zsc, zsd, pri)
return;
}
printf(" softpri %d\n", PIL_TTY);
if (!didintr) {
zs_sicookie = softintr_establish(IPL_SOFTSERIAL, zssoft, NULL);
if (zs_sicookie == NULL) {
printf("\n%s: cannot establish soft int handler\n",
zsc->zsc_dev.dv_xname);
return;
}
}
printf(" softpri %d\n", IPL_SOFTSERIAL);
/*
* Initialize software state for each channel.
@ -520,10 +518,6 @@ zs_attach(zsc, zsd, pri)
prevpri = pri;
bus_intr_establish(zsc->zsc_bustag, pri, IPL_SERIAL, 0,
zshard, NULL);
bus_intr_establish(zsc->zsc_bustag, PIL_TTY,
IPL_SOFTSERIAL,
BUS_INTR_ESTABLISH_SOFTINTR,
zssoft, NULL);
} else if (pri != prevpri)
panic("broken zs interrupt scheme");
@ -606,13 +600,8 @@ zshard(arg)
/* We are at splzs here, so no need to lock. */
if (softreq && (zssoftpending == 0)) {
zssoftpending = IE_ZSSOFT;
#if defined(SUN4M)
if (CPU_ISSUN4M)
raise(0, PIL_TTY);
else
#endif
ienab_bis(IE_ZSSOFT);
zssoftpending = 1;
softintr_schedule(zs_sicookie);
}
return (rval);
}
@ -620,7 +609,7 @@ zshard(arg)
/*
* Similar scheme as for zshard (look at all of them)
*/
static int
static void
zssoft(arg)
void *arg;
{
@ -629,7 +618,7 @@ zssoft(arg)
/* This is not the only ISR on this IPL. */
if (zssoftpending == 0)
return (0);
return;
/*
* The soft intr. bit will be set by zshard only if
@ -649,7 +638,6 @@ zssoft(arg)
(void)zsc_intr_soft(zsc);
}
splx(s);
return (1);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.4 2002/12/06 15:36:45 pk Exp $ */
/* $NetBSD: intr.h,v 1.5 2002/12/09 16:11:52 pk Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -60,10 +60,33 @@
#if defined(_KERNEL) && !defined(_LOCORE)
void *
softintr_establish __P((int level, void (*fun)(void *), void *arg));
softintr_establish(int level, void (*fun)(void *), void *arg);
void
softintr_disestablish __P((void *cookie));
softintr_disestablish(void *cookie);
#define softintr_schedule(cookie) setsoftint()
/*
* NB that softintr_schedule() casts the cookie to an int *.
* This is to get the sic_pilreq member of the softintr_cookie
* structure, which is otherwise internal to intr.c.
*/
#if defined(SUN4M) || defined(SUN4D)
extern void raise __P((int, int));
#if !(defined(SUN4) || defined(SUN4C))
#define softintr_schedule(cookie) raise(0, *((int *) (cookie)))
#else /* both defined */
#define softintr_schedule(cookie) do { \
if (CPU_ISSUN4M || CPU_ISSUN4D) \
raise(0, *((int *)(cookie))); \
else \
ienab_bis(*((int *)(cookie))); \
} while (0)
#endif /* SUN4 || SUN4C */
#else /* SUN4M || SUN4D */
#define softintr_schedule(cookie) ienab_bis(*((int *) (cookie)))
#endif /* SUN4M || SUN4D */
#if 0
void softintr_schedule(void *cookie);
#endif
#endif /* KERNEL && !_LOCORE */

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.c,v 1.61 2002/12/06 16:04:12 pk Exp $ */
/* $NetBSD: intr.c,v 1.62 2002/12/09 16:11:53 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@ -409,6 +409,41 @@ struct intrhand *intrhand[15] = {
NULL, /* 14 = counter 1 = profiling timer */
};
/*
* Soft interrupts use a separate set of handler chains.
* This is necessary since soft interrupt handlers do not return a value
* and therefore cannot be mixed with hardware interrupt handlers on a
* shared handler chain.
*/
struct intrhand *sintrhand[15] = { NULL };
static void ih_insert(struct intrhand **head, struct intrhand *ih)
{
struct intrhand **p, *q;
/*
* This is O(N^2) for long chains, but chains are never long
* and we do want to preserve order.
*/
for (p = head; (q = *p) != NULL; p = &q->ih_next)
continue;
*p = ih;
ih->ih_next = NULL;
}
static void ih_remove(struct intrhand **head, struct intrhand *ih)
{
struct intrhand **p, *q;
for (p = head; (q = *p) != ih; p = &q->ih_next)
continue;
if (q == NULL)
panic("intr_remove: intrhand %p fun %p arg %p",
ih, ih->ih_fun, ih->ih_arg);
*p = q->ih_next;
q->ih_next = NULL;
}
static int fastvec; /* marks fast vectors (see below) */
#ifdef DIAGNOSTIC
extern int sparc_interrupt4m[];
@ -425,7 +460,6 @@ intr_establish(level, classipl, ih)
int classipl;
struct intrhand *ih;
{
struct intrhand **p, *q;
#ifdef DIAGNOSTIC
struct trapvec *tv;
int displ;
@ -466,14 +500,7 @@ intr_establish(level, classipl, ih)
/* pre-shift to PIL field in %psr */
ih->ih_classipl = (classipl << 8) & PSR_PIL;
/*
* This is O(N^2) for long chains, but chains are never long
* and we do want to preserve order.
*/
for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next)
continue;
*p = ih;
ih->ih_next = NULL;
ih_insert(&intrhand[level], ih);
splx(s);
}
@ -482,16 +509,7 @@ intr_disestablish(level, ih)
int level;
struct intrhand *ih;
{
struct intrhand **p, *q;
for (p = &intrhand[level]; (q = *p) != ih; p = &q->ih_next)
continue;
if (q == NULL)
panic("intr_disestablish: level %d intrhand %p fun %p arg %p",
level, ih, ih->ih_fun, ih->ih_arg);
*p = q->ih_next;
q->ih_next = NULL;
ih_remove(&intrhand[level], ih);
}
/*
@ -544,6 +562,20 @@ intr_fasttrap(level, vec)
splx(s);
}
/*
* This is a softintr cookie. NB that sic_pilreq MUST be the
* first element in the struct, because the softintr_schedule()
* macro in intr.h casts cookies to int * to get it. On a
* sun4m, sic_pilreq is an actual processor interrupt level that
* is passed to raise(), and on a sun4 or sun4c sic_pilreq is a
* bit to set in the interrupt enable register with ienab_bis().
*/
struct softintr_cookie {
int sic_pilreq; /* MUST be first! */
int sic_level;
struct intrhand sic_hand;
};
/*
* softintr_init(): initialise the MI softintr system.
*/
@ -564,15 +596,47 @@ softintr_establish(level, fun, arg)
void (*fun) __P((void *));
void *arg;
{
struct softintr_cookie *sic;
struct intrhand *ih;
int pilreq;
ih = malloc(sizeof(*ih), M_DEVBUF, 0);
bzero(ih, sizeof(*ih));
/*
* On a sun4m, the processor interrupt level is stored
* in the softintr cookie to be passed to raise().
*
* On a sun4 or sun4c the appropriate bit to set
* in the interrupt enable register is stored in
* the softintr cookie to be passed to ienab_bis().
*/
pilreq = level;
if (CPU_ISSUN4 || CPU_ISSUN4C) {
/* Select the most suitable of three available softint levels */
if (level >= 1 && level < 4)
pilreq = IE_L1;
else if (level >= 4 && level < 6)
pilreq = IE_L4;
else {
pilreq = IE_L6;
}
}
sic = malloc(sizeof(*sic), M_DEVBUF, 0);
sic->sic_level = level;
sic->sic_pilreq = pilreq;
ih = &sic->sic_hand;
ih->ih_fun = (int (*) __P((void *)))fun;
ih->ih_arg = arg;
ih->ih_next = 0;
intr_establish(1, level, ih);
return (void *)ih;
/*
* Always run the handler at the requested level, which might
* be higher than the hardware can provide.
*
* pre-shift to PIL field in %psr
*/
ih->ih_classipl = (level << 8) & PSR_PIL;
ih_insert(&sintrhand[level], ih);
return (void *)sic;
}
/*
@ -583,11 +647,31 @@ void
softintr_disestablish(cookie)
void *cookie;
{
struct softintr_cookie *sic = cookie;
intr_disestablish(1, cookie);
ih_remove(&sintrhand[sic->sic_level], &sic->sic_hand);
free(cookie, M_DEVBUF);
}
#if 0
void
softintr_schedule(cookie)
void *cookie;
{
struct softintr_cookie *sic = cookie;
if (CPU_ISSUN4M || CPU_ISSUN4D) {
#if defined(SUN4M) || defined(SUN4D)
extern void raise(int,int);
raise(0, sic->sic_pilreq);
#endif
} else {
#if defined(SUN4) || defined(SUN4C)
ienab_bis(sic->sic_pilreq);
#endif
}
}
#endif
#ifdef MULTIPROCESSOR
/*
* Called by interrupt stubs, etc., to lock/unlock the kernel.