summaryrefslogtreecommitdiff
path: root/sys/arch/socppc/dev/ipic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/socppc/dev/ipic.c')
-rw-r--r--sys/arch/socppc/dev/ipic.c73
1 files changed, 57 insertions, 16 deletions
diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c
index 3512297db75..0bfec255649 100644
--- a/sys/arch/socppc/dev/ipic.c
+++ b/sys/arch/socppc/dev/ipic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipic.c,v 1.8 2009/06/09 01:12:38 deraadt Exp $ */
+/* $OpenBSD: ipic.c,v 1.9 2009/09/06 20:09:34 kettenis Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
@@ -24,6 +24,8 @@
#include <machine/autoconf.h>
#include <machine/intr.h>
+#include <dev/ofw/openfirm.h>
+
#define IPIC_SICFR 0x00
#define IPIC_SIVCR 0x04
#define IPIC_SIPNR_H 0x08
@@ -83,12 +85,20 @@ uint32_t ipic_simsr_h(int);
uint32_t ipic_simsr_l(int);
uint32_t ipic_semsr(int);
+void intr_calculatemasks(void);
void ext_intr(void);
void ipic_do_pending_int(void);
int
ipic_match(struct device *parent, void *cfdata, void *aux)
{
+ struct obio_attach_args *oa = aux;
+ char buf[32];
+
+ if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
+ strcmp(buf, "ipic") != 0)
+ return (0);
+
return (1);
}
@@ -97,6 +107,7 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
{
struct ipic_softc *sc = (void *)self;
struct obio_attach_args *oa = aux;
+ int ivec;
sc->sc_iot = oa->oa_iot;
if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) {
@@ -104,6 +115,32 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ /*
+ * Deal with pre-established interrupts.
+ */
+ for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
+ if (ipic_intrhand[ivec]) {
+ int level = ipic_intrhand[ivec]->ih_level;
+ uint32_t mask;
+
+ sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
+ sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
+ sc->sc_semsr[level] |= ipic_semsr(ivec);
+ intr_calculatemasks();
+
+ /* Unmask the interrupt. */
+ mask = ipic_read(sc, IPIC_SIMSR_H);
+ mask |= ipic_simsr_h(ivec);
+ ipic_write(sc, IPIC_SIMSR_H, mask);
+ mask = ipic_read(sc, IPIC_SIMSR_L);
+ mask |= ipic_simsr_l(ivec);
+ ipic_write(sc, IPIC_SIMSR_L, mask);
+ mask = ipic_read(sc, IPIC_SEMSR);
+ mask |= ipic_semsr(ivec);
+ ipic_write(sc, IPIC_SEMSR, mask);
+ }
+ }
+
ipic_sc = sc;
printf("\n");
}
@@ -176,7 +213,7 @@ ipic_semsr(int ivec)
return 0;
}
-static void
+void
intr_calculatemasks(void)
{
struct ipic_softc *sc = ipic_sc;
@@ -240,10 +277,12 @@ intr_establish(int ivec, int type, int level,
for (p = &ipic_intrhand[ivec]; (q = *p) != NULL; p = &q->ih_next)
;
- sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
- sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
- sc->sc_semsr[level] |= ipic_semsr(ivec);
- intr_calculatemasks();
+ if (sc) {
+ sc->sc_simsr_h[level] |= ipic_simsr_h(ivec);
+ sc->sc_simsr_l[level] |= ipic_simsr_l(ivec);
+ sc->sc_semsr[level] |= ipic_semsr(ivec);
+ intr_calculatemasks();
+ }
ih->ih_fun = ih_fun;
ih->ih_arg = ih_arg;
@@ -253,16 +292,18 @@ intr_establish(int ivec, int type, int level,
evcount_attach(&ih->ih_count, name, NULL, &evcount_intr);
*p = ih;
- /* Unmask the interrupt. */
- mask = ipic_read(sc, IPIC_SIMSR_H);
- mask |= ipic_simsr_h(ivec);
- ipic_write(sc, IPIC_SIMSR_H, mask);
- mask = ipic_read(sc, IPIC_SIMSR_L);
- mask |= ipic_simsr_l(ivec);
- ipic_write(sc, IPIC_SIMSR_L, mask);
- mask = ipic_read(sc, IPIC_SEMSR);
- mask |= ipic_semsr(ivec);
- ipic_write(sc, IPIC_SEMSR, mask);
+ if (sc) {
+ /* Unmask the interrupt. */
+ mask = ipic_read(sc, IPIC_SIMSR_H);
+ mask |= ipic_simsr_h(ivec);
+ ipic_write(sc, IPIC_SIMSR_H, mask);
+ mask = ipic_read(sc, IPIC_SIMSR_L);
+ mask |= ipic_simsr_l(ivec);
+ ipic_write(sc, IPIC_SIMSR_L, mask);
+ mask = ipic_read(sc, IPIC_SEMSR);
+ mask |= ipic_semsr(ivec);
+ ipic_write(sc, IPIC_SEMSR, mask);
+ }
return (ih);
}