summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/sparc/dev/amd7930.c68
-rw-r--r--sys/arch/sparc/dev/fd.c10
-rw-r--r--sys/arch/sparc/include/cpu.h5
-rw-r--r--sys/arch/sparc/sparc/intr.c92
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