summaryrefslogtreecommitdiff
path: root/sys/arch/socppc
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2011-08-29 20:21:45 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2011-08-29 20:21:45 +0000
commit1a9161e19576a182bd9ae248258881711c63d5ed (patch)
tree74d3ef47c413b75f1037e9ffb1400a5eca09165a /sys/arch/socppc
parent45eb37d7c1c3cec88a07d2930a46f4ef74354a3e (diff)
Return of the long missing powerpc interrupt rewrite. Was working for
several weeks before release on macppc, socppc bugs just fixed.
Diffstat (limited to 'sys/arch/socppc')
-rw-r--r--sys/arch/socppc/dev/ipic.c180
-rw-r--r--sys/arch/socppc/socppc/clock.c4
-rw-r--r--sys/arch/socppc/socppc/machdep.c62
3 files changed, 130 insertions, 116 deletions
diff --git a/sys/arch/socppc/dev/ipic.c b/sys/arch/socppc/dev/ipic.c
index 6e250257176..c7a07965969 100644
--- a/sys/arch/socppc/dev/ipic.c
+++ b/sys/arch/socppc/dev/ipic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipic.c,v 1.14 2011/01/08 18:10:22 deraadt Exp $ */
+/* $OpenBSD: ipic.c,v 1.15 2011/08/29 20:21:44 drahn Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
@@ -65,8 +65,9 @@ struct ipic_softc {
};
uint32_t ipic_imask;
-struct intrhand *ipic_intrhand[IPIC_NVEC];
+struct intrq ipic_handler[IPIC_NVEC];
struct ipic_softc *ipic_sc;
+int ipic_preinit_done; /* defaults to 0 - not initialized */
int ipic_match(struct device *, void *, void *);
void ipic_attach(struct device *, struct device *, void *);
@@ -79,15 +80,34 @@ struct cfdriver ipic_cd = {
NULL, "ipic", DV_DULL
};
+void ipic_preinit(void);
uint32_t ipic_read(struct ipic_softc *, bus_addr_t);
void ipic_write(struct ipic_softc *, bus_addr_t, uint32_t);
uint32_t ipic_simsr_h(int);
uint32_t ipic_simsr_l(int);
uint32_t ipic_semsr(int);
+void ipic_calc_masks(void);
-void intr_calculatemasks(void);
void ext_intr(void);
-void ipic_do_pending_int(void);
+
+ppc_splraise_t ipic_splraise;
+ppc_spllower_t ipic_spllower;
+ppc_splx_t ipic_splx;
+
+void ipic_setipl(int);
+
+void
+ipic_preinit(void)
+{
+ int i;
+ struct intrq *iq;
+
+ for (i = 0; i < IPIC_NVEC; i++) {
+ iq = &ipic_handler[i];
+ TAILQ_INIT(&iq->iq_list);
+ }
+ ipic_preinit_done = 1;
+}
int
ipic_match(struct device *parent, void *cfdata, void *aux)
@@ -108,6 +128,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;
+ struct intrq *iq;
sc->sc_iot = oa->oa_iot;
if (bus_space_map(sc->sc_iot, oa->oa_offset, 128, 0, &sc->sc_ioh)) {
@@ -117,18 +138,23 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
ipic_sc = sc;
+ /* if ipic_preinit has not happened, do it here */
+ if (ipic_preinit_done == 0)
+ ipic_preinit();
+
/*
* Deal with pre-established interrupts.
*/
for (ivec = 0; ivec < IPIC_NVEC; ivec++) {
- if (ipic_intrhand[ivec]) {
- int level = ipic_intrhand[ivec]->ih_level;
+ iq = &ipic_handler[ivec];
+ if (!TAILQ_EMPTY(&iq->iq_list)) {
+ int level = TAILQ_FIRST(&iq->iq_list)->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();
+ ipic_calc_masks();
/* Unmask the interrupt. */
mask = ipic_read(sc, IPIC_SIMSR_H);
@@ -143,6 +169,11 @@ ipic_attach(struct device *parent, struct device *self, void *aux)
}
}
+ ppc_smask_init();
+ ppc_intr_func.raise = ipic_splraise;
+ ppc_intr_func.lower = ipic_spllower;
+ ppc_intr_func.x = ipic_splx;
+
printf("\n");
}
@@ -217,31 +248,9 @@ ipic_semsr(int ivec)
}
void
-intr_calculatemasks(void)
+ipic_calc_masks(void)
{
struct ipic_softc *sc = ipic_sc;
- int level;
-
- for (level = IPL_NONE; level < IPL_NUM; level++)
- cpu_imask[level] = SINT_ALLMASK | (1 << level);
-
- /*
- * There are tty, network and disk drivers that use free() at interrupt
- * time, so vm > (tty | net | bio).
- *
- * Enforce a hierarchy that gives slow devices a better chance at not
- * dropping data.
- */
- cpu_imask[IPL_NET] |= cpu_imask[IPL_BIO];
- cpu_imask[IPL_TTY] |= cpu_imask[IPL_NET];
- cpu_imask[IPL_VM] |= cpu_imask[IPL_TTY];
- cpu_imask[IPL_CLOCK] |= cpu_imask[IPL_VM] | SPL_CLOCKMASK;
-
- /*
- * These are pseudo-levels.
- */
- cpu_imask[IPL_NONE] = 0x00000000;
- cpu_imask[IPL_HIGH] = 0xffffffff;
sc->sc_simsr_h[IPL_NET] |= sc->sc_simsr_h[IPL_BIO];
sc->sc_simsr_h[IPL_TTY] |= sc->sc_simsr_h[IPL_NET];
@@ -267,36 +276,47 @@ intr_establish(int ivec, int type, int level,
int (*ih_fun)(void *), void *ih_arg, const char *name)
{
struct ipic_softc *sc = ipic_sc;
- struct intrhand **p, *q, *ih;
+ struct intrhand *ih;
+ struct intrq *iq;
uint32_t mask;
+ int s;
+
+ if (ipic_preinit_done == 0)
+ ipic_preinit();
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
if (ih == NULL)
panic("%s: malloc failed", __func__);
+ iq = &ipic_handler[ivec];
if (ivec < 0 || ivec >= IPIC_NVEC)
panic("%s: invalid vector %d", __func__, ivec);
- for (p = &ipic_intrhand[ivec]; (q = *p) != NULL; p = &q->ih_next)
- ;
-
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;
- ih->ih_next = NULL;
ih->ih_level = level;
ih->ih_irq = ivec;
- evcount_attach(&ih->ih_count, name, NULL);
- *p = ih;
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+ /*
+ * Append handler to end of list
+ */
+ s = ppc_intr_disable();
+
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+ ipic_calc_masks();
+
+ ppc_intr_enable(s);
+
+ /* Unmask the interrupt. */
if (sc) {
- /* Unmask the interrupt. */
mask = ipic_read(sc, IPIC_SIMSR_H);
mask |= ipic_simsr_h(ivec);
ipic_write(sc, IPIC_SIMSR_H, mask);
@@ -317,31 +337,22 @@ ext_intr(void)
struct cpu_info *ci = curcpu();
struct ipic_softc *sc = ipic_sc;
struct intrhand *ih;
- uint32_t simsr_h, simsr_l, semsr;
- int pcpl, ocpl;
+ struct intrq *iq;
+ int pcpl;
int ivec;
pcpl = ci->ci_cpl;
ivec = ipic_read(sc, IPIC_SIVCR) & 0x7f;
- simsr_h = ipic_read(sc, IPIC_SIMSR_H);
- simsr_l = ipic_read(sc, IPIC_SIMSR_L);
- semsr = ipic_read(sc, IPIC_SEMSR);
- ipic_write(sc, IPIC_SIMSR_H, simsr_h & ~ipic_simsr_h(ivec));
- ipic_write(sc, IPIC_SIMSR_L, simsr_l & ~ipic_simsr_l(ivec));
- ipic_write(sc, IPIC_SEMSR, semsr & ~ipic_semsr(ivec));
-
- ih = ipic_intrhand[ivec];
- while (ih) {
- if (ci->ci_cpl & (1 << ih->ih_level)) {
- ci->ci_ipending |= (1 << ih->ih_level);
- return;
+ iq = &ipic_handler[ivec];
+ TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
+ if (ih->ih_level <= pcpl) {
+ panic("irq handler called at wrong level %d %d",
+ ih->ih_level, pcpl);
+ continue;
}
- ipic_write(sc, IPIC_SIMSR_H, sc->sc_simsr_h[ih->ih_level]);
- ipic_write(sc, IPIC_SIMSR_L, sc->sc_simsr_l[ih->ih_level]);
- ipic_write(sc, IPIC_SEMSR, sc->sc_semsr[ih->ih_level]);
- ocpl = splraise(cpu_imask[ih->ih_level]);
+ ipic_splraise(ih->ih_level);
ppc_intr_enable(1);
KERNEL_LOCK();
@@ -350,40 +361,61 @@ ext_intr(void)
KERNEL_UNLOCK();
ppc_intr_disable();
- ci->ci_cpl = ocpl;
- ih = ih->ih_next;
}
- ipic_write(sc, IPIC_SIMSR_H, simsr_h);
- ipic_write(sc, IPIC_SIMSR_L, simsr_l);
- ipic_write(sc, IPIC_SEMSR, semsr);
splx(pcpl);
}
-static __inline int
-cntlzw(int x)
+int
+ipic_splraise(int newcpl)
{
- int a;
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ if (ocpl > newcpl)
+ newcpl = ocpl;
+
+ ipic_setipl(newcpl);
+
+ return (ocpl);
+}
- __asm __volatile("cntlzw %0,%1" : "=r"(a) : "r"(x));
+int
+ipic_spllower(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int ocpl = ci->ci_cpl;
+
+ ipic_splx(newcpl);
+
+ return (ocpl);
+}
+
+void
+ipic_splx(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
- return a;
+ ipic_setipl(newcpl);
+ if (ci->ci_ipending & ppc_smask[newcpl])
+ do_pending_int();
}
void
-ipic_do_pending_int(void)
+ipic_setipl(int ipl)
{
struct cpu_info *ci = curcpu();
struct ipic_softc *sc = ipic_sc;
uint32_t mask;
- int level;
+ int s;
- ci->ci_ipending &= SINT_ALLMASK;
- level = cntlzw(31 - (ci->ci_cpl & ~(SPL_CLOCKMASK|SINT_ALLMASK)));
- mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[level];
+ s = ppc_intr_disable();
+ ci->ci_cpl = ipl;
+ mask = sc->sc_simsr_h[IPL_HIGH] & ~sc->sc_simsr_h[ipl];
ipic_write(sc, IPIC_SIMSR_H, mask);
- mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[level];
+ mask = sc->sc_simsr_l[IPL_HIGH] & ~sc->sc_simsr_l[ipl];
ipic_write(sc, IPIC_SIMSR_L, mask);
- mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[level];
+ mask = sc->sc_semsr[IPL_HIGH] & ~sc->sc_semsr[ipl];
ipic_write(sc, IPIC_SEMSR, mask);
+ ppc_intr_enable(s);
}
diff --git a/sys/arch/socppc/socppc/clock.c b/sys/arch/socppc/socppc/clock.c
index d063e72bfd1..159aed44769 100644
--- a/sys/arch/socppc/socppc/clock.c
+++ b/sys/arch/socppc/socppc/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.8 2010/09/20 06:33:48 matthew Exp $ */
+/* $OpenBSD: clock.c,v 1.9 2011/08/29 20:21:44 drahn Exp $ */
/* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */
/*
@@ -202,7 +202,7 @@ decr_intr(struct clockframe *frame)
*/
ppc_mtdec(nextevent - tb);
- if (curcpu()->ci_cpl & SPL_CLOCKMASK) {
+ if (ci->ci_cpl >= IPL_CLOCK) {
ci->ci_statspending += nstats;
} else {
KERNEL_LOCK();
diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c
index 665343b48af..27348935a7a 100644
--- a/sys/arch/socppc/socppc/machdep.c
+++ b/sys/arch/socppc/socppc/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.32 2011/07/05 04:48:02 guenther Exp $ */
+/* $OpenBSD: machdep.c,v 1.33 2011/08/29 20:21:44 drahn Exp $ */
/* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */
/*
@@ -1095,59 +1095,41 @@ boot(int howto)
while(1) /* forever */;
}
-extern void ipic_do_pending_int(void);
-
void
do_pending_int(void)
{
struct cpu_info *ci = curcpu();
- int pcpl, s;
-
- if (ci->ci_iactive)
- return;
-
- ci->ci_iactive = 1;
+ int pcpl = ci->ci_cpl; /* XXX */
+ int s;
s = ppc_intr_disable();
- pcpl = ci->ci_cpl;
-
- ipic_do_pending_int();
+ if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
+ ppc_intr_enable(s);
+ return;
+ }
+ atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
do {
- if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
- ci->ci_ipending &= ~SINT_CLOCK;
- ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY;
- ppc_intr_enable(1);
- KERNEL_LOCK();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
+ (pcpl < IPL_SOFTCLOCK)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
softintr_dispatch(SI_SOFTCLOCK);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
- }
- if((ci->ci_ipending & SINT_NET) & ~pcpl) {
- ci->ci_ipending &= ~SINT_NET;
- ci->ci_cpl = SINT_NET|SINT_TTY;
- ppc_intr_enable(1);
- KERNEL_LOCK();
+ }
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
+ (pcpl < IPL_SOFTNET)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
softintr_dispatch(SI_SOFTNET);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
}
- if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
- ci->ci_ipending &= ~SINT_TTY;
- ci->ci_cpl = SINT_TTY;
- ppc_intr_enable(1);
- KERNEL_LOCK();
+ if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
+ (pcpl < IPL_SOFTTTY)) {
+ ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
softintr_dispatch(SI_SOFTTTY);
- KERNEL_UNLOCK();
- ppc_intr_disable();
- continue;
}
- } while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
- ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
- ci->ci_iactive = 0;
+ } while (ci->ci_ipending & ppc_smask[pcpl]);
+ splx(pcpl);
ppc_intr_enable(s);
+
+ atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
}
/*