summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2004-09-24 20:50:50 +0000
committerJason Wright <jason@cvs.openbsd.org>2004-09-24 20:50:50 +0000
commit2e5c92cd70327e660f4b8cc52b1569ed79dbe7b9 (patch)
treee0bc90932f047088398b7e8256b88bf9134611fc
parentcde3b380a82416aafd21d7917073a5e2924b706f (diff)
setup interrupt handling for fhc attached devices
-rw-r--r--sys/arch/sparc64/dev/fhc.c97
-rw-r--r--sys/arch/sparc64/dev/fhcvar.h4
2 files changed, 98 insertions, 3 deletions
diff --git a/sys/arch/sparc64/dev/fhc.c b/sys/arch/sparc64/dev/fhc.c
index c803c2abbc6..ca2e9031a9a 100644
--- a/sys/arch/sparc64/dev/fhc.c
+++ b/sys/arch/sparc64/dev/fhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fhc.c,v 1.2 2004/09/23 16:26:59 jason Exp $ */
+/* $OpenBSD: fhc.c,v 1.3 2004/09/24 20:50:49 jason Exp $ */
/*
* Copyright (c) 2004 Jason L. Wright (jason@thought.net)
@@ -39,7 +39,9 @@
#include <machine/autoconf.h>
#include <machine/openfirm.h>
+#include <sparc64/dev/fhcreg.h>
#include <sparc64/dev/fhcvar.h>
+#include <sparc64/dev/iommureg.h>
struct cfdriver fhc_cd = {
NULL, "fhc", DV_DULL
@@ -50,6 +52,11 @@ int fhc_print(void *, const char *);
bus_space_tag_t fhc_alloc_bus_tag(struct fhc_softc *);
int _fhc_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t, bus_size_t,
int, bus_space_handle_t *);
+void *fhc_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
+ int (*)(void *), void *, const char *);
+bus_space_handle_t *fhc_find_intr_handle(struct fhc_softc *, int);
+bus_space_handle_t *fhc_try_intr_handle(struct fhc_softc *,
+ bus_space_handle_t *, bus_size_t, int);
void
fhc_attach(struct fhc_softc *sc)
@@ -78,6 +85,8 @@ fhc_attach(struct fhc_softc *sc)
}
getprop(node, "reg", sizeof(struct fhc_reg),
&fa.fa_nreg, (void **)&fa.fa_reg);
+ getprop(node, "interrupts", sizeof(int),
+ &fa.fa_nintr, (void **)&fa.fa_intr);
(void)config_found(&sc->sc_dv, (void *)&fa, fhc_print);
@@ -85,6 +94,8 @@ fhc_attach(struct fhc_softc *sc)
free(fa.fa_name, M_DEVBUF);
if (fa.fa_reg != NULL)
free(fa.fa_reg, M_DEVBUF);
+ if (fa.fa_nintr != NULL)
+ free(fa.fa_intr, M_DEVBUF);
}
}
@@ -138,7 +149,7 @@ fhc_alloc_bus_tag(struct fhc_softc *sc)
bt->sasi = bt->parent->sasi;
bt->sparc_bus_map = _fhc_bus_map;
/* XXX bt->sparc_bus_mmap = fhc_bus_mmap; */
- /* XXX bt->sparc_intr_establish = upa_intr_establish; */
+ bt->sparc_intr_establish = fhc_intr_establish;
return (bt);
}
@@ -176,3 +187,85 @@ _fhc_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t addr,
return (EINVAL);
}
+
+bus_space_handle_t *
+fhc_try_intr_handle(struct fhc_softc *sc, bus_space_handle_t *hp,
+ bus_size_t off, int val)
+{
+ u_int64_t r;
+
+ r = bus_space_read_8(sc->sc_bt, *hp, off);
+ if (INTINO(r) == INTINO(val))
+ return (hp);
+ return (NULL);
+}
+
+bus_space_handle_t *
+fhc_find_intr_handle(struct fhc_softc *sc, int val)
+{
+ bus_space_handle_t *hp;
+
+ hp = fhc_try_intr_handle(sc, &sc->sc_freg, FHC_F_IMAP, val);
+ if (hp != NULL)
+ return (hp);
+ hp = fhc_try_intr_handle(sc, &sc->sc_sreg, FHC_S_IMAP, val);
+ if (hp != NULL)
+ return (hp);
+ hp = fhc_try_intr_handle(sc, &sc->sc_ureg, FHC_U_IMAP, val);
+ if (hp != NULL)
+ return (hp);
+ hp = fhc_try_intr_handle(sc, &sc->sc_treg, FHC_T_IMAP, val);
+ if (hp != NULL)
+ return (hp);
+ return (NULL);
+}
+
+void *
+fhc_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
+ int level, int flags, int (*handler)(void *), void *arg, const char *what)
+{
+ struct fhc_softc *sc = t->cookie;
+ volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
+ struct intrhand *ih;
+
+ if (level == IPL_NONE)
+ level = INTLEV(ihandle);
+ if (level == IPL_NONE) {
+ printf(": no IPL, setting IPL 2.\n");
+ level = 2;
+ }
+
+ if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
+ bus_space_handle_t *hp;
+ struct fhc_intr_reg *intrregs;
+
+ hp = fhc_find_intr_handle(sc, ihandle);
+ if (hp == NULL) {
+ printf(": can't find intr handle\n");
+ return (NULL);
+ }
+
+ intrregs = bus_space_vaddr(sc->sc_bt, *hp);
+ intrmapptr = &intrregs->imap;
+ intrclrptr = &intrregs->iclr;
+ }
+
+ ih = bus_intr_allocate(t0, handler, arg, INTINO(ihandle), level,
+ intrmapptr, intrclrptr, what);
+ if (ih == NULL)
+ return (NULL);
+
+ intr_establish(ih->ih_pil, ih);
+
+ if (intrmapptr != NULL) {
+ u_int64_t r;
+
+ r = *intrmapptr;
+ r |= INTMAP_V;
+ *intrmapptr = r;
+ r = *intrmapptr;
+ ih->ih_number |= r & INTMAP_INR;
+ }
+
+ return (ih);
+}
diff --git a/sys/arch/sparc64/dev/fhcvar.h b/sys/arch/sparc64/dev/fhcvar.h
index 879614eb55b..f00c999d4bc 100644
--- a/sys/arch/sparc64/dev/fhcvar.h
+++ b/sys/arch/sparc64/dev/fhcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fhcvar.h,v 1.1 2004/09/22 21:44:45 jason Exp $ */
+/* $OpenBSD: fhcvar.h,v 1.2 2004/09/24 20:50:49 jason Exp $ */
/*
* Copyright (c) 2004 Jason L. Wright (jason@thought.net).
@@ -62,6 +62,8 @@ struct fhc_attach_args {
char *fa_name;
int fa_node;
int fa_nreg;
+ int fa_nintr;
+ int *fa_intr;
struct fhc_reg *fa_reg;
bus_space_tag_t fa_bustag;
};