diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2011-04-07 13:13:02 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2011-04-07 13:13:02 +0000 |
commit | 6093d78f79aa7f9e740f4257b4ee108f9da92ff6 (patch) | |
tree | 5e631dc8458548be4f6f66feaa289dfb93fe7337 /sys/arch/hppa64 | |
parent | d4e56ba26adadc4f7472c2f376d6b877a3cd26ce (diff) |
Initial interrupt handling implementation for hppa64.
ok kettenis@
Diffstat (limited to 'sys/arch/hppa64')
-rw-r--r-- | sys/arch/hppa64/dev/cpu.c | 4 | ||||
-rw-r--r-- | sys/arch/hppa64/hppa64/autoconf.c | 4 | ||||
-rw-r--r-- | sys/arch/hppa64/hppa64/intr.c | 375 | ||||
-rw-r--r-- | sys/arch/hppa64/hppa64/trap.c | 10 | ||||
-rw-r--r-- | sys/arch/hppa64/include/autoconf.h | 9 | ||||
-rw-r--r-- | sys/arch/hppa64/include/cpu.h | 7 | ||||
-rw-r--r-- | sys/arch/hppa64/include/intr.h | 5 |
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 *); |