summaryrefslogtreecommitdiff
path: root/sys/arch/hp300/dev/frodo.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/hp300/dev/frodo.c')
-rw-r--r--sys/arch/hp300/dev/frodo.c104
1 files changed, 84 insertions, 20 deletions
diff --git a/sys/arch/hp300/dev/frodo.c b/sys/arch/hp300/dev/frodo.c
index 6cae385aef2..e2ee8bfbb9c 100644
--- a/sys/arch/hp300/dev/frodo.c
+++ b/sys/arch/hp300/dev/frodo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frodo.c,v 1.9 2007/01/06 20:09:12 miod Exp $ */
+/* $OpenBSD: frodo.c,v 1.10 2007/01/06 20:17:43 miod Exp $ */
/* $NetBSD: frodo.c,v 1.5 1999/07/31 21:15:20 thorpej Exp $ */
/*-
@@ -83,12 +83,14 @@
#include <hp300/dev/frodoreg.h>
#include <hp300/dev/frodovar.h>
+#include "isabr.h"
+
struct frodo_softc {
struct device sc_dev; /* generic device glue */
volatile u_int8_t *sc_regs; /* register base */
struct isr *sc_intr[FRODO_NINTR]; /* interrupt handlers */
struct isr sc_isr; /* main interrupt handler */
- int sc_refcnt; /* number of interrupt refs */
+ u_int sc_refcnt; /* number of interrupt refs */
};
int frodomatch(struct device *, void *, void *);
@@ -98,6 +100,7 @@ int frodoprint(void *, const char *);
int frodosubmatch(struct device *, void *, void *);
int frodointr(void *);
+void frodo_state(struct frodo_softc *);
void frodo_imask(struct frodo_softc *, u_int16_t, u_int16_t);
@@ -114,6 +117,7 @@ struct frodo_attach_args frodo_subdevs[] = {
{ "apci", NULL, FRODO_APCI_OFFSET(1), FRODO_INTR_APCI1 },
{ "apci", NULL, FRODO_APCI_OFFSET(2), FRODO_INTR_APCI2 },
{ "apci", NULL, FRODO_APCI_OFFSET(3), FRODO_INTR_APCI3 },
+ { "isabr", NULL, 0, 0 },
{ NULL, NULL, 0, 0 },
};
@@ -184,11 +188,17 @@ frodoattach(parent, self, aux)
FRODO_WRITE(sc, FRODO_PIC_PU, 0xff);
FRODO_WRITE(sc, FRODO_PIC_PL, 0xff);
- /* Set interrupt polarities. */
+ /* Set interrupt polarities... */
FRODO_WRITE(sc, FRODO_PIO_IPR, 0x10);
- /* ...and configure for edge triggering. */
- FRODO_WRITE(sc, FRODO_PIO_IELR, 0xcf);
+ /* ...and configure 1-5 for edge triggering. */
+ FRODO_WRITE(sc, FRODO_PIO_IELR, 0xc1);
+
+ /* Initialize IVR high half to zero so we don't need to mask it later */
+ FRODO_WRITE(sc, FRODO_PIC_IVR, 0x00);
+
+ /* Mask ISA interrupts until an ISA interrupt handler is registered. */
+ FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80);
/*
* We defer hooking up our interrupt handler until
@@ -240,7 +250,7 @@ frodoprint(aux, pnp)
return (UNCONF);
}
-void
+int
frodo_intr_establish(struct device *frdev, int line, struct isr *isr,
const char *name)
{
@@ -252,8 +262,11 @@ frodo_intr_establish(struct device *frdev, int line, struct isr *isr,
sc->sc_dev.dv_xname, line);
}
if (sc->sc_intr[line] != NULL) {
- panic("%s: interrupt line %d already used",
+#ifdef DEBUG
+ printf("%s: interrupt line %d already used\n",
sc->sc_dev.dv_xname, line);
+#endif
+ return (EPERM);
}
/*
@@ -279,7 +292,15 @@ frodo_intr_establish(struct device *frdev, int line, struct isr *isr,
sc->sc_intr[line] = isr;
/* Enable the interrupt line. */
- frodo_imask(sc, (1 << line), 0);
+ frodo_imask(sc, FRODO_INTR_BIT(line), 0);
+
+#if NISABR > 0
+ /* Unmask ISA interrupts if necessary. */
+ if (FRODO_INTR_ISA(line))
+ FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x00);
+#endif
+
+ return (0);
}
void
@@ -290,13 +311,26 @@ frodo_intr_disestablish(frdev, line)
struct frodo_softc *sc = (struct frodo_softc *)frdev;
int newpri;
+#ifdef DIAGNOSTIC
if (sc->sc_intr[line] == NULL) {
- panic("%s: no handler for line %d",
- sc->sc_dev.dv_xname, line);
+ printf("%s(%s): no handler for line %d",
+ sc->sc_dev.dv_xname, __func__, line);
+ return;
}
+#endif
sc->sc_intr[line] = NULL;
- frodo_imask(sc, 0, (1 << line));
+ frodo_imask(sc, 0, FRODO_INTR_BIT(line));
+
+#if NISABR > 0
+ /* Mask ISA interrupts if necessary. */
+ if (FRODO_INTR_ISA(line)) {
+ if (sc->sc_intr[FRODO_INTR_ILOW] == NULL &&
+ sc->sc_intr[FRODO_INTR_IMID] == NULL &&
+ sc->sc_intr[FRODO_INTR_IHIGH] == NULL)
+ FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80);
+ }
+#endif
/* If this was the last, unhook ourselves. */
if (sc->sc_refcnt-- == 1) {
@@ -326,21 +360,29 @@ frodointr(arg)
{
struct frodo_softc *sc = arg;
struct isr *fisr;
- int line, taken = 0;
+ int pending, line, rc = 0;
+
+#ifdef DEBUG
+ frodo_state(sc);
+#endif
/* Any interrupts pending? */
- if (FRODO_GETPEND(sc) == 0)
- return (0);
+ while ((pending = FRODO_GETPEND(sc)) != 0) {
+ rc++;
- do {
/*
* Get pending interrupt; this also clears it for us.
*/
- line = FRODO_IPEND(sc);
+ line = FRODO_READ(sc, FRODO_PIC_ACK) /* & 0x0f */;
+
fisr = sc->sc_intr[line];
if (fisr == NULL) {
printf("%s: unhandled interrupt on line %d\n",
sc->sc_dev.dv_xname, line);
+#ifdef DEBUG
+ /* Disable interrupt source */
+ frodo_imask(sc, 0, FRODO_INTR_BIT(line));
+#endif
} else {
if ((*fisr->isr_func)(fisr->isr_arg) != 0) {
fisr->isr_count.ec_count++;
@@ -349,11 +391,17 @@ frodointr(arg)
sc->sc_dev.dv_xname, line);
}
}
- if (taken++ > 100)
- panic("frodointr: looping, line %d fisr %p", line, fisr);
- } while (FRODO_GETPEND(sc) != 0);
- return (1);
+ if (rc > 100)
+ panic("frodointr: looping, pending %x line %d fisr %p",
+ pending, line, fisr);
+
+#ifdef DEBUG
+ frodo_state(sc);
+#endif
+ }
+
+ return (rc);
}
void
@@ -370,3 +418,19 @@ frodo_imask(sc, set, clear)
FRODO_SETMASK(sc, imask);
}
+
+#ifdef DEBUG
+void
+frodo_state(struct frodo_softc *sc)
+{
+ int i;
+
+ printf("%s state:", sc->sc_dev.dv_xname);
+ for (i = 0xc0; i < 0x100; i += 4) {
+ printf(" %02x", FRODO_READ(sc, i));
+ if (i == 0xcc || i == 0xdc || i == 0xec)
+ printf(" /");
+ }
+ printf("\n");
+}
+#endif