summaryrefslogtreecommitdiff
path: root/sys/arch/hppa64
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2011-04-07 13:13:02 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2011-04-07 13:13:02 +0000
commit6093d78f79aa7f9e740f4257b4ee108f9da92ff6 (patch)
tree5e631dc8458548be4f6f66feaa289dfb93fe7337 /sys/arch/hppa64
parentd4e56ba26adadc4f7472c2f376d6b877a3cd26ce (diff)
Initial interrupt handling implementation for hppa64.
ok kettenis@
Diffstat (limited to 'sys/arch/hppa64')
-rw-r--r--sys/arch/hppa64/dev/cpu.c4
-rw-r--r--sys/arch/hppa64/hppa64/autoconf.c4
-rw-r--r--sys/arch/hppa64/hppa64/intr.c375
-rw-r--r--sys/arch/hppa64/hppa64/trap.c10
-rw-r--r--sys/arch/hppa64/include/autoconf.h9
-rw-r--r--sys/arch/hppa64/include/cpu.h7
-rw-r--r--sys/arch/hppa64/include/intr.h5
7 files changed, 389 insertions, 25 deletions
diff --git a/sys/arch/hppa64/dev/cpu.c b/sys/arch/hppa64/dev/cpu.c
index 13a664b0c6c..ae04948263a 100644
--- a/sys/arch/hppa64/dev/cpu.c
+++ b/sys/arch/hppa64/dev/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.4 2011/04/06 15:52:07 jsing Exp $ */
+/* $OpenBSD: cpu.c,v 1.5 2011/04/07 13:13:01 jsing Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@@ -187,5 +187,5 @@ cpuattach(struct device *parent, struct device *self, void *aux)
printf("%u %scoherent %sTLB\n",
pdc_cache.dt_size, pdc_cache.dt_conf.tc_cst? "" : "in", p);
-/* TODO spin up others */
+ cpu_intr_establish(IPL_CLOCK, 63, cpu_hardclock, NULL, "clock");
}
diff --git a/sys/arch/hppa64/hppa64/autoconf.c b/sys/arch/hppa64/hppa64/autoconf.c
index cac45da27df..bb5b1180c11 100644
--- a/sys/arch/hppa64/hppa64/autoconf.c
+++ b/sys/arch/hppa64/hppa64/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.13 2010/07/01 04:33:23 jsing Exp $ */
+/* $OpenBSD: autoconf.c,v 1.14 2011/04/07 13:13:01 jsing Exp $ */
/*
* Copyright (c) 1998-2005 Michael Shalayeff
@@ -107,7 +107,7 @@ cpu_configure(void)
if (config_rootfound("mainbus", &ca) == NULL)
panic("no mainbus found");
- mtctl(0xffffffffffffffffULL, CR_EIEM);
+ cpu_intr_init();
spl0();
if (cold_hook)
diff --git a/sys/arch/hppa64/hppa64/intr.c b/sys/arch/hppa64/hppa64/intr.c
index 038613617d3..64d0ff05d62 100644
--- a/sys/arch/hppa64/hppa64/intr.c
+++ b/sys/arch/hppa64/hppa64/intr.c
@@ -1,40 +1,385 @@
-/* $OpenBSD: intr.c,v 1.3 2011/04/05 15:30:45 jsing Exp $ */
+/* $OpenBSD: intr.c,v 1.4 2011/04/07 13:13:01 jsing Exp $ */
/*
- * Copyright (c) Joel Sing <jsing@openbsd.org>
+ * Copyright (c) 2002-2004 Michael Shalayeff
+ * All rights reserved.
*
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define INTRDEBUG
+
#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/malloc.h>
+
+#include <uvm/uvm_extern.h> /* for uvmexp */
+#include <machine/autoconf.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
#include <machine/intr.h>
+#include <machine/iomod.h>
+#include <machine/psl.h>
+#include <machine/reg.h>
+
+#ifdef DDB
+#include <machine/db_machdep.h>
+#endif
+
+#ifdef INTRDEBUG
+#include <ddb/db_output.h>
+#endif
+
+struct hppa_iv {
+ char pri;
+ char irq;
+ char flags;
+#define HPPA_IV_SOFT 0x01
+ char pad;
+ int pad2;
+ int (*handler)(void *);
+ void *arg;
+ u_int bit;
+ struct hppa_iv *share;
+ struct hppa_iv *next;
+ struct evcount *cnt;
+} __packed;
+
+struct hppa_iv *intr_list;
+struct hppa_iv intr_table[CPU_NINTS] __attribute__ ((aligned(64))) = {
+ { IPL_SOFTCLOCK, 0, HPPA_IV_SOFT, 0, 0, NULL },
+ { IPL_SOFTNET , 0, HPPA_IV_SOFT, 0, 0, NULL },
+ { 0 },
+ { 0 },
+ { IPL_SOFTTTY , 0, HPPA_IV_SOFT, 0, 0, NULL }
+};
+
+volatile u_long imask[NIPL] = {
+ 1 << (IPL_SOFTCLOCK - 1),
+ 1 << (IPL_SOFTNET - 1),
+ 0,
+ 0,
+ 1 << (IPL_SOFTTTY - 1)
+};
+
+void
+cpu_intr_init(void)
+{
+ u_long mask;
+ int level;
+
+ for (level = NIPL - 1; level > 0; level--) {
+ imask[level - 1] |= imask[level];
+#ifdef INTRDEBUG
+ printf("IPL %i 0x%lx\n", level - 1, imask[level - 1]);
+#endif
+ }
+
+ /* Prevent hardclock from happening early. */
+ mask = mfctl(CR_ITMR);
+ mtctl(mask - 1, CR_ITMR);
+
+ /* Clear unwanted interrupts. */
+ mask = mfctl(CR_EIRR);
+ mtctl(mask & (1UL << 63), CR_EIRR);
+
+ /* Time to enable interrupts. */
+ curcpu()->ci_psw |= PSL_I;
+ ssm(PSL_I, mask);
+}
+
+int
+cpu_intr_findirq(void)
+{
+ int irq;
+
+ for (irq = 0; irq < CPU_NINTS; irq++)
+ if (intr_table[irq].handler == NULL &&
+ intr_table[irq].pri == 0)
+ return irq;
+
+ return -1;
+}
+
+void *
+cpu_intr_map(void *v, int pri, int irq, int (*handler)(void *), void *arg,
+ const char *name)
+{
+ struct hppa_iv *iv, *pv = v, *ivb = pv->next;
+ struct evcount *cnt;
+
+ if (irq < 0 || irq >= CPU_NINTS)
+ return (NULL);
+
+ cnt = (struct evcount *)malloc(sizeof *cnt, M_DEVBUF, M_NOWAIT);
+ if (!cnt)
+ return (NULL);
+
+ iv = &ivb[irq];
+ if (iv->handler) {
+ if (!pv->share) {
+ free(cnt, M_DEVBUF);
+ return (NULL);
+ } else {
+ iv = pv->share;
+ pv->share = iv->share;
+ iv->share = ivb[irq].share;
+ ivb[irq].share = iv;
+ }
+ }
+
+ evcount_attach(cnt, name, NULL);
+ iv->pri = pri;
+ iv->irq = irq;
+ iv->flags = 0;
+ iv->handler = handler;
+ iv->arg = arg;
+ iv->cnt = cnt;
+ iv->next = intr_list;
+ intr_list = iv;
+
+ return (iv);
+}
+
+void *
+cpu_intr_establish(int pri, int irq, int (*handler)(void *), void *arg,
+ const char *name)
+{
+ struct hppa_iv *iv;
+ struct evcount *cnt;
+
+ if (irq < 0 || irq >= CPU_NINTS || intr_table[irq].handler)
+ return (NULL);
+
+ if ((intr_table[irq].flags & HPPA_IV_SOFT) != 0)
+ return (NULL);
+
+ cnt = (struct evcount *)malloc(sizeof *cnt, M_DEVBUF, M_NOWAIT);
+ if (!cnt)
+ return (NULL);
+
+ imask[pri] |= (1UL << irq);
+
+ iv = &intr_table[irq];
+ iv->pri = pri;
+ iv->irq = irq;
+ iv->bit = 1 << irq;
+ iv->flags = 0;
+ iv->handler = handler;
+ iv->arg = arg;
+ iv->cnt = cnt;
+ iv->next = NULL;
+ iv->share = NULL;
+
+ evcount_attach(cnt, name, NULL);
+
+ return (iv);
+}
+
+int fls(u_long mask);
+
+int
+fls(u_long mask)
+{
+ int bit = 64;
+
+ if (!(mask & 0xffffffff00000000)) {
+ bit -= 32;
+ mask <<= 32;
+ }
+
+ if (!(mask & 0xffff000000000000)) {
+ bit -= 16;
+ mask <<= 16;
+ }
+
+ if (!(mask & 0xff00000000000000)) {
+ bit -= 8;
+ mask <<= 8;
+ }
+
+ if (!(mask & 0xf000000000000000)) {
+ bit -= 4;
+ mask <<= 4;
+ }
+
+ if (!(mask & 0xc000000000000000)) {
+ bit -= 2;
+ mask <<= 2;
+ }
+
+ if (!(mask & 0x8000000000000000)) {
+ bit -= 1;
+ mask <<= 1;
+ }
+
+ return mask ? bit : 0;
+}
+
+void
+cpu_intr(void *v)
+{
+ struct cpu_info *ci = curcpu();
+ struct trapframe *frame = v;
+ struct hppa_iv *iv;
+ int pri, r, s, bit;
+ u_long mask;
+ void *arg;
+
+ ci->ci_ipending |= mfctl(CR_EIRR);
+
+ s = ci->ci_cpl;
+ if (ci->ci_in_intr++)
+ frame->tf_flags |= TFF_INTR;
+
+ /* Process higher priority interrupts first. */
+ for (pri = NIPL - 1; pri > s; pri--) {
+
+ mask = imask[pri] ^ imask[pri - 1];
+
+ while (ci->ci_ipending & mask) {
-volatile u_long imask[NIPL];
+ bit = fls(ci->ci_ipending & mask) - 1;
+ iv = &intr_table[bit];
+
+ ci->ci_ipending &= ~(1UL << bit);
+ mtctl(1UL << bit, CR_EIRR);
+ ci->ci_ipending |= mfctl(CR_EIRR);
+
+ uvmexp.intrs++;
+ if (iv->flags & HPPA_IV_SOFT)
+ uvmexp.softs++;
+
+ ci->ci_cpl = iv->pri;
+ mtctl(imask[ci->ci_cpl], CR_EIEM);
+ ssm(PSL_I, mask);
+
+ for (r = iv->flags & HPPA_IV_SOFT;
+ iv && iv->handler; iv = iv->next) {
+ /* No arg means pass the frame. */
+ arg = iv->arg ? iv->arg : v;
+ if ((iv->handler)(arg) == 1) {
+ if (iv->cnt)
+ iv->cnt->ec_count++;
+ r |= 1;
+ }
+ }
+
+ rsm(PSL_I, mask);
+ }
+ }
+ ci->ci_in_intr--;
+ ci->ci_cpl = s;
+
+#ifdef INTRDEBUG
+ if (uvmexp.intrs % 10000)
+ db_printf(".");
+ if (uvmexp.softs % 10000)
+ db_printf("+");
+#endif
+
+ mtctl(imask[ci->ci_cpl], CR_EIEM);
+ ssm(PSL_I, mask);
+}
void *
softintr_establish(int pri, void (*handler)(void *), void *arg)
{
- return (void *)1;
+ struct hppa_iv *iv;
+ int irq;
+
+ if (pri == IPL_TTY)
+ pri = IPL_SOFTTTY;
+
+ irq = pri - 1;
+ iv = &intr_table[irq];
+ if ((iv->flags & HPPA_IV_SOFT) == 0 || iv->pri != pri)
+ return (NULL);
+
+ if (iv->handler) {
+ struct hppa_iv *nv;
+
+ nv = malloc(sizeof *iv, M_DEVBUF, M_NOWAIT);
+ if (!nv)
+ return (NULL);
+ while (iv->next)
+ iv = iv->next;
+ iv->next = nv;
+ iv = nv;
+ } else
+ imask[pri] |= (1 << irq);
+
+ iv->pri = pri;
+ iv->irq = 0;
+ iv->bit = 1 << irq;
+ iv->flags = HPPA_IV_SOFT;
+ iv->handler = (int (*)(void *))handler; /* XXX */
+ iv->arg = arg;
+ iv->cnt = NULL;
+ iv->next = NULL;
+ iv->share = NULL;
+
+ return (iv);
}
void
softintr_disestablish(void *cookie)
{
+ struct hppa_iv *iv = cookie;
+ int irq = iv->pri - 1;
+
+ if (&intr_table[irq] == cookie) {
+ if (iv->next) {
+ struct hppa_iv *nv = iv->next;
+
+ iv->handler = nv->handler;
+ iv->arg = nv->arg;
+ iv->next = nv->next;
+ free(nv, M_DEVBUF);
+ return;
+ } else {
+ iv->handler = NULL;
+ iv->arg = NULL;
+ return;
+ }
+ }
+
+ for (iv = &intr_table[irq]; iv; iv = iv->next) {
+ if (iv->next == cookie) {
+ iv->next = iv->next->next;
+ free(cookie, M_DEVBUF);
+ return;
+ }
+ }
}
void
softintr_schedule(void *cookie)
{
-}
+ struct hppa_iv *iv = cookie;
+ softintr(1 << (iv->pri - 1));
+}
diff --git a/sys/arch/hppa64/hppa64/trap.c b/sys/arch/hppa64/hppa64/trap.c
index c57327376dd..d04013fcbfb 100644
--- a/sys/arch/hppa64/hppa64/trap.c
+++ b/sys/arch/hppa64/hppa64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.17 2011/04/06 14:45:23 jsing Exp $ */
+/* $OpenBSD: trap.c,v 1.18 2011/04/07 13:13:01 jsing Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@@ -33,6 +33,7 @@
#include <uvm/uvm.h>
#include <machine/autoconf.h>
+#include <machine/cpufunc.h>
#include <machine/psl.h>
#ifdef DDB
@@ -177,6 +178,7 @@ trap(int type, struct trapframe *frame)
#ifdef DIAGNOSTIC
long oldcpl = curcpu()->ci_cpl;
#endif
+ u_long mask;
trapnum = type & ~T_USER;
opcode = frame->tf_iir;
@@ -225,7 +227,8 @@ trap(int type, struct trapframe *frame)
#endif
if (trapnum != T_INTERRUPT) {
uvmexp.traps++;
- /* TODO mtctl(frame->tf_eiem, CR_EIEM); */
+ mtctl(frame->tf_eiem, CR_EIEM);
+ ssm(PSL_I, mask);
}
switch (type) {
@@ -479,8 +482,7 @@ printf("here\n");
case T_INTERRUPT:
case T_INTERRUPT | T_USER:
-/* cpu_intr(frame); */
-printf("eirr 0x%08x\n", mfctl(CR_EIRR));
+ cpu_intr(frame);
break;
case T_CONDITION:
diff --git a/sys/arch/hppa64/include/autoconf.h b/sys/arch/hppa64/include/autoconf.h
index 14495bd005b..748359d28e2 100644
--- a/sys/arch/hppa64/include/autoconf.h
+++ b/sys/arch/hppa64/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.h,v 1.2 2005/05/22 01:38:09 mickey Exp $ */
+/* $OpenBSD: autoconf.h,v 1.3 2011/04/07 13:13:01 jsing Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@@ -51,4 +51,11 @@ const char *hppa_mod_info(int, int);
void pdc_scan(struct device *, struct confargs *);
int mbprint(void *, const char *);
+int cpu_intr_findirq(void);
+void *cpu_intr_map(void *v, int pri, int irq, int (*handler)(void *),
+ void *arg, const char *name);
+void *cpu_intr_establish(int pri, int irq, int (*handler)(void *),
+ void *arg, const char *name);
+int clock_intr(void *);
+
void dumpconf(void);
diff --git a/sys/arch/hppa64/include/cpu.h b/sys/arch/hppa64/include/cpu.h
index e988c564e86..948f2fb968c 100644
--- a/sys/arch/hppa64/include/cpu.h
+++ b/sys/arch/hppa64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.22 2011/04/06 14:45:23 jsing Exp $ */
+/* $OpenBSD: cpu.h,v 1.23 2011/04/07 13:13:01 jsing Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@@ -73,6 +73,8 @@
/*
* Interrupts stuff
*/
+#define CPU_NINTS 64
+
#define IPL_NONE 0
#define IPL_SOFTCLOCK 1
#define IPL_SOFTNET 2
@@ -126,6 +128,9 @@ struct cpu_info {
volatile int ci_psw;
volatile int ci_cpl;
+ volatile u_long ci_ipending;
+ volatile int ci_in_intr;
+
struct proc *ci_curproc;
struct pcb *ci_cpcb;
struct cpu_info *ci_next;
diff --git a/sys/arch/hppa64/include/intr.h b/sys/arch/hppa64/include/intr.h
index 94f104cb629..4d088f2925f 100644
--- a/sys/arch/hppa64/include/intr.h
+++ b/sys/arch/hppa64/include/intr.h
@@ -18,6 +18,11 @@
#define _MACHINE_INTR_H_
#if !defined(_LOCORE) && defined(_KERNEL)
+#define softintr(mask) atomic_setbits_long(&curcpu()->ci_ipending, mask)
+
+void cpu_intr_init(void);
+void cpu_intr(void *);
+
void *softintr_establish(int, void (*)(void *), void *);
void softintr_disestablish(void *);
void softintr_schedule(void *);