diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sparc/dev/amd7930.c | 68 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fd.c | 10 | ||||
-rw-r--r-- | sys/arch/sparc/include/cpu.h | 5 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/intr.c | 92 |
4 files changed, 145 insertions, 30 deletions
diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c index de17fca17c5..fabc158aedc 100644 --- a/sys/arch/sparc/dev/amd7930.c +++ b/sys/arch/sparc/dev/amd7930.c @@ -1,4 +1,4 @@ -/* $OpenBSD: amd7930.c,v 1.29 2005/07/09 22:23:13 miod Exp $ */ +/* $OpenBSD: amd7930.c,v 1.30 2005/08/14 10:58:33 miod Exp $ */ /* $NetBSD: amd7930.c,v 1.37 1998/03/30 14:23:40 pk Exp $ */ /* @@ -57,6 +57,11 @@ int amd7930debug = 0; #endif /* + * Define AUDIO_C_HANDLER to force using non-fast trap routines. + */ +/* #define AUDIO_C_HANDLER */ + +/* * Software state, per AMD79C30 audio chip. */ struct amd7930_softc { @@ -84,8 +89,6 @@ struct amd7930_softc { }; /* interrupt interfaces */ -#ifdef AUDIO_C_HANDLER -int amd7930hwintr(void *); #if defined(SUN4M) #define AUDIO_SET_SWINTR do { \ if (CPU_ISSUN4M) \ @@ -96,14 +99,17 @@ int amd7930hwintr(void *); #else #define AUDIO_SET_SWINTR ienab_bis(IE_L4) #endif /* defined(SUN4M) */ -#else + +#ifndef AUDIO_C_HANDLER struct auio *auiop; #endif /* AUDIO_C_HANDLER */ +int amd7930hwintr(void *); int amd7930swintr(void *); /* forward declarations */ void audio_setmap(volatile struct amd7930 *, struct mapreg *); static void init_amd(volatile struct amd7930 *); +int amd7930_shareintr(void *); /* autoconfiguration driver */ void amd7930attach(struct device *, struct device *, void *); @@ -294,17 +300,30 @@ amd7930attach(parent, self, args) init_amd(amd); + /* + * Register interrupt handlers. We'll prefer a fast trap (unless + * AUDIO_C_HANDLER is defined), with a sharing callback so that we + * can revert into a regular trap vector if necessary. + */ #ifndef AUDIO_C_HANDLER - auiop = &sc->sc_au; sc->sc_hwih.ih_vec = pri; - evcount_attach(&sc->sc_hwih.ih_count, sc->sc_dev.dv_xname, - &sc->sc_hwih.ih_vec, &evcount_intr); - intr_fasttrap(pri, amd7930_trap); + if (intr_fasttrap(pri, amd7930_trap, amd7930_shareintr, sc) == 0) { + auiop = &sc->sc_au; + evcount_attach(&sc->sc_hwih.ih_count, sc->sc_dev.dv_xname, + &sc->sc_hwih.ih_vec, &evcount_intr); + } else { +#ifdef AUDIO_DEBUG + printf("%s: unable to register fast trap handler\n", + self->dv_xname); +#endif #else - sc->sc_hwih.ih_fun = amd7930hwintr; - sc->sc_hwih.ih_arg = &sc->sc_au; - intr_establish(pri, &sc->sc_hwih, IPL_AUHARD, sc->sc_dev.dv_xname); + { #endif + sc->sc_hwih.ih_fun = amd7930hwintr; + sc->sc_hwih.ih_arg = &sc->sc_au; + intr_establish(pri, &sc->sc_hwih, IPL_AUHARD, + sc->sc_dev.dv_xname); + } sc->sc_swih.ih_fun = amd7930swintr; sc->sc_swih.ih_arg = sc; intr_establish(IPL_AUSOFT, &sc->sc_swih, IPL_AUSOFT, @@ -767,7 +786,6 @@ amd7930_query_devinfo(addr, dip) return (0); } -#ifdef AUDIO_C_HANDLER int amd7930hwintr(au0) void *au0; @@ -811,7 +829,6 @@ amd7930hwintr(au0) return (-1); } -#endif /* AUDIO_C_HANDLER */ int amd7930swintr(sc0) @@ -842,3 +859,28 @@ amd7930swintr(sc0) splx(s); return (ret); } + +#ifndef AUDIO_C_HANDLER +int +amd7930_shareintr(void *arg) +{ + struct amd7930_softc *sc = arg; + + /* + * We are invoked at splhigh(), so there is no need to prevent the chip + * from interrupting while we are messing with the handlers. We + * however need to properly untie the event counter from the chain, + * since it will be reused immediately by intr_establish()... + */ + + intr_fastuntrap(sc->sc_hwih.ih_vec); + evcount_detach(&sc->sc_hwih.ih_count); + + sc->sc_hwih.ih_fun = amd7930hwintr; + sc->sc_hwih.ih_arg = &sc->sc_au; + intr_establish(sc->sc_hwih.ih_vec, &sc->sc_hwih, IPL_AUHARD, + sc->sc_dev.dv_xname); + + return (0); +} +#endif diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c index bfbff8f15fa..2ad2d5fa5a1 100644 --- a/sys/arch/sparc/dev/fd.c +++ b/sys/arch/sparc/dev/fd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fd.c,v 1.41 2005/03/23 17:10:22 miod Exp $ */ +/* $OpenBSD: fd.c,v 1.42 2005/08/14 10:58:33 miod Exp $ */ /* $NetBSD: fd.c,v 1.51 1997/05/24 20:16:19 pk Exp $ */ /*- @@ -442,6 +442,7 @@ fdcattach(parent, self, aux) TAILQ_INIT(&fdc->sc_drives); pri = ca->ca_ra.ra_intr[0].int_pri; + printf(" pri %d, softpri %d: ", pri, IPL_FDSOFT); #ifdef FDC_C_HANDLER fdc->sc_hih.ih_fun = (void *)fdc_c_hwintr; fdc->sc_hih.ih_arg = fdc; @@ -449,9 +450,12 @@ fdcattach(parent, self, aux) #else fdciop = &fdc->sc_io; fdc->sc_hih.ih_vec = pri; + if (intr_fasttrap(pri, fdchwintr, NULL, NULL) != 0) { + printf("unable to register fast trap handler\n"); + return; + } evcount_attach(&fdc->sc_hih.ih_count, self->dv_xname, &fdc->sc_hih.ih_vec, &evcount_intr); - intr_fasttrap(pri, fdchwintr); #endif fdc->sc_sih.ih_fun = (void *)fdcswintr; fdc->sc_sih.ih_arg = fdc; @@ -500,7 +504,7 @@ fdcattach(parent, self, aux) printf(" CFGLOCK: unexpected response"); } - printf(" pri %d, softpri %d: chip 8207%c\n", pri, IPL_FDSOFT, code); + printf("chip 8207%c\n", code); /* * Controller and drives are represented by one and the same diff --git a/sys/arch/sparc/include/cpu.h b/sys/arch/sparc/include/cpu.h index 37ae52d7a88..6fa40683229 100644 --- a/sys/arch/sparc/include/cpu.h +++ b/sys/arch/sparc/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.24 2005/03/23 17:14:45 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.25 2005/08/14 10:58:36 miod Exp $ */ /* $NetBSD: cpu.h,v 1.24 1997/03/15 22:25:15 pk Exp $ */ /* @@ -173,7 +173,8 @@ void vmeintr_establish(int vec, int level, struct intrhand *, int, const char *) * interrupt vectors (vectors that are not shared and are handled in the * trap window). Such functions must be written in assembly. */ -void intr_fasttrap(int level, void (*vec)(void)); +int intr_fasttrap(int, void (*)(void), int (*)(void *), void *); +void intr_fastuntrap(int); /* auxreg.c */ void led_blink(void *); diff --git a/sys/arch/sparc/sparc/intr.c b/sys/arch/sparc/sparc/intr.c index e544aa33353..5b15030efb6 100644 --- a/sys/arch/sparc/sparc/intr.c +++ b/sys/arch/sparc/sparc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.27 2004/09/29 07:35:14 miod Exp $ */ +/* $OpenBSD: intr.c,v 1.28 2005/08/14 10:58:36 miod Exp $ */ /* $NetBSD: intr.c,v 1.20 1997/07/29 09:42:03 fair Exp $ */ /* @@ -244,6 +244,11 @@ struct intrhand *intrhand[15] = { }; static int fastvec; /* marks fast vectors (see below) */ +static struct { + int (*cb)(void *); + void *data; +} fastvec_share[15]; + #ifdef DIAGNOSTIC extern int sparc_interrupt4m[]; extern int sparc_interrupt44c[]; @@ -251,7 +256,7 @@ extern int sparc_interrupt44c[]; /* * Attach an interrupt handler to the vector chain for the given level. - * This is not possible if it has been taken away as a fast vector. + * This may not be possible if it has been taken away as a fast vector. */ void intr_establish(level, ih, ipl_block, name) @@ -294,9 +299,19 @@ intr_establish(level, ih, ipl_block, name) evcount_attach(&ih->ih_count, name, &ih->ih_vec, &evcount_intr); s = splhigh(); - if (fastvec & (1 << level)) - panic("intr_establish: level %d interrupt tied to fast vector", - level); + + /* + * Check if this interrupt is already being handled by a fast trap. + * If so, attempt to change it back to a regular (thus) shareable + * trap. + */ + if (fastvec & (1 << level)) { + if (fastvec_share[level].cb == NULL || + (*fastvec_share[level].cb)(fastvec_share[level].data) != 0) + panic("intr_establish: level %d interrupt tied to fast vector", + level); + } + #ifdef DIAGNOSTIC /* double check for legal hardware interrupt */ if ((level != 1 && level != 4 && level != 6) || CPU_ISSUN4M ) { @@ -329,11 +344,13 @@ intr_establish(level, ih, ipl_block, name) /* * Like intr_establish, but wires a fast trap vector. Only one such fast * trap is legal for any interrupt, and it must be a hardware interrupt. + * In case some other device wants to share the interrupt, we also register + * a callback which will be able to revert this and register a slower, but + * shareable trap vector if necessary (for example, to share int 13 between + * audioamd and stp). */ -void -intr_fasttrap(level, vec) - int level; - void (*vec)(void); +int +intr_fasttrap(int level, void (*vec)(void), int (*share)(void *), void *cbdata) { struct trapvec *tv; u_long hi22, lo10; @@ -349,9 +366,16 @@ intr_fasttrap(level, vec) hi22 = ((u_long)vec) >> 10; lo10 = ((u_long)vec) & 0x3ff; s = splhigh(); - if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL) - panic("intr_fasttrap: already handling level %d interrupts", - level); + + /* + * If this interrupt is already being handled, fail; the caller will + * either panic or try to register a slow (shareable) trap. + */ + if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL) { + splx(s); + return (EBUSY); + } + #ifdef DIAGNOSTIC displ = (CPU_ISSUN4M) ? &sparc_interrupt4m[0] - &tv->tv_instr[1] @@ -371,12 +395,56 @@ intr_fasttrap(level, vec) instr[1] = I_JMPLri(I_G0, I_L3, lo10); /* jmpl %l3+%lo(vec),%g0 */ instr[2] = I_RDPSR(I_L0); /* mov %psr, %l0 */ + fastvec_share[level].cb = share; + fastvec_share[level].data = cbdata; + tvp = (char *)tv->tv_instr; instrp = (char *)instr; for (i = 0; i < sizeof(int) * 3; i++, instrp++, tvp++) pmap_writetext(tvp, *instrp); fastvec |= 1 << level; splx(s); + + return (0); +} + +void +intr_fastuntrap(int level) +{ + struct trapvec *tv; + int i, s; + int displ; + int instr[3]; + char *instrp; + char *tvp; + + tv = &trapbase[T_L1INT - 1 + level]; + + /* restore to `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */ + displ = (CPU_ISSUN4M) + ? &sparc_interrupt4m[0] - &tv->tv_instr[1] + : &sparc_interrupt44c[0] - &tv->tv_instr[1]; + instr[0] = I_MOVi(I_L3, level); + instr[1] = I_BA(0, displ); + instr[2] = I_RDPSR(I_L0); + + s = splhigh(); + +#ifdef DIAGNOSTIC + if ((fastvec & (1 << level)) == 0) { + splx(s); + return; + } +#endif + + tvp = (char *)tv->tv_instr; + instrp = (char *)instr; + for (i = 0; i < sizeof(int) * 3; i++, instrp++, tvp++) + pmap_writetext(tvp, *instrp); + fastvec &= ~(1 << level); + fastvec_share[level].cb = NULL; + + splx(s); } #ifdef DIAGNOSTIC |