diff options
author | 2012-04-17 15:22:02 +0000 | |
---|---|---|
committer | 2012-04-17 15:22:02 +0000 | |
commit | b540ef5c5421f18b7977fad4a36d1566daf963f3 (patch) | |
tree | e17f383b7863b947d3af77568b5e09ba04cac594 | |
parent | Remove "#define _POSIX_THREADS" line before include <pthread.h>. (diff) | |
download | wireguard-openbsd-b540ef5c5421f18b7977fad4a36d1566daf963f3.tar.xz wireguard-openbsd-b540ef5c5421f18b7977fad4a36d1566daf963f3.zip |
Infrastructure to allow an interrupt handler to request its interrupt to be
temporarily disabled (and then reenabled later). Will be necessary for the
next driver commit.
-rw-r--r-- | sys/arch/sgi/hpc/hpc.c | 28 | ||||
-rw-r--r-- | sys/arch/sgi/hpc/hpcvar.h | 5 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/int.c | 131 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/intvar.h | 5 |
4 files changed, 143 insertions, 26 deletions
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c index d3ff1b7323d..62879b201cc 100644 --- a/sys/arch/sgi/hpc/hpc.c +++ b/sys/arch/sgi/hpc/hpc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hpc.c,v 1.8 2012/04/15 20:50:32 miod Exp $ */ +/* $OpenBSD: hpc.c,v 1.9 2012/04/17 15:22:02 miod Exp $ */ /* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */ /* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */ @@ -112,9 +112,9 @@ struct hpc_device { int hd_sysmask; }; -#define HPCDEV_IP20 (1U << 1) /* Indigo R4k */ -#define HPCDEV_IP22 (1U << 2) /* Indigo2 */ -#define HPCDEV_IP24 (1U << 3) /* Indy, Challenge S */ +#define HPCDEV_IP20 (1U << 1) /* Indigo R4k */ +#define HPCDEV_IP22 (1U << 2) /* Indigo2 */ +#define HPCDEV_IP24 (1U << 3) /* Indy, Challenge S */ #define HPCDEV_IP24_INDY (1U << 4) /* Indy only */ /* @@ -188,7 +188,7 @@ static const struct hpc_device hpc3_onboard[] = { HPC_BASE_ADDRESS_0, IOC_BASE + IOC_PANEL, 0, INT2_L1_INTR(INT2_L1_IP22_PANEL), - HPCDEV_IP24 }, + HPCDEV_IP22 | HPCDEV_IP24 }, { NULL } }; @@ -793,6 +793,24 @@ hpc_intr_establish(int irq, int level, int (*handler)(void *), void *arg, return int2_intr_establish(irq, level, handler, arg, what); } +int +hpc_is_intr_pending(int irq) +{ + return int2_is_intr_pending(irq); +} + +void +hpc_intr_disable(void *v) +{ + int2_intr_disable(v); +} + +void +hpc_intr_enable(void *v) +{ + int2_intr_enable(v); +} + /* * bus_space_barrier() function for HPC3 (which have a write buffer) */ diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h index 7f688ca9ea0..9e2c988d2a8 100644 --- a/sys/arch/sgi/hpc/hpcvar.h +++ b/sys/arch/sgi/hpc/hpcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hpcvar.h,v 1.5 2012/04/15 20:50:32 miod Exp $ */ +/* $OpenBSD: hpcvar.h,v 1.6 2012/04/17 15:22:02 miod Exp $ */ /* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */ /* @@ -106,5 +106,8 @@ struct hpc_attach_args { void *hpc_intr_establish(int, int, int (*)(void *), void *, const char *); +int hpc_is_intr_pending(int); +void hpc_intr_disable(void *); +void hpc_intr_enable(void *); extern bus_space_t hpc3bus_tag; diff --git a/sys/arch/sgi/localbus/int.c b/sys/arch/sgi/localbus/int.c index e521bce3c69..ad141ed2a3c 100644 --- a/sys/arch/sgi/localbus/int.c +++ b/sys/arch/sgi/localbus/int.c @@ -1,4 +1,4 @@ -/* $OpenBSD: int.c,v 1.2 2012/04/15 20:44:52 miod Exp $ */ +/* $OpenBSD: int.c,v 1.3 2012/04/17 15:22:04 miod Exp $ */ /* $NetBSD: int.c,v 1.24 2011/07/01 18:53:46 dyoung Exp $ */ /* @@ -84,8 +84,14 @@ paddr_t int2_get_base(void); * registered on both cascaded interrupts. */ +struct int2_intrhand { + struct intrhand ih; + uint32_t flags; +#define IH_FL_DISABLED 0x01 +}; + #define INT2_NINTS (8 + 8 + 2 * 8) -struct intrhand *int2_intrhand[INT2_NINTS]; +struct int2_intrhand *int2_intrhand[INT2_NINTS]; uint32_t int2_intem; uint8_t int2_l0imask[NIPLS], int2_l1imask[NIPLS]; @@ -116,15 +122,19 @@ save_l0isr = isr; save_l0imr = imr; save_l0ipl = frame->ipl; \ #define INTR_MASKPENDING \ int2_write(INT2_LOCAL0_MASK, imr & ~isr) #define INTR_IMASK(ipl) int2_l0imask[ipl] -#define INTR_HANDLER(bit) int2_intrhand[bit + 0] +#define INTR_HANDLER(bit) (struct intrhand *)int2_intrhand[bit + 0] #define INTR_SPURIOUS(bit) \ do { \ printf("spurious int2 interrupt %d\n", bit); \ } while (0) +/* explicit masking with int2_intem to cope with handlers disabling themselves */ #define INTR_MASKRESTORE \ - int2_write(INT2_LOCAL0_MASK, imr) + int2_write(INT2_LOCAL0_MASK, int2_intem & imr) #define INTR_MASKSIZE 8 +#define INTR_HANDLER_SKIP(ih) \ + (((struct int2_intrhand *)(ih))->flags /* & IH_FL_DISABLED */) + #include <sgi/sgi/intr_template.c> /* @@ -147,22 +157,26 @@ save_l1isr = isr; save_l1imr = imr; save_l1ipl = frame->ipl; \ #define INTR_MASKPENDING \ int2_write(INT2_LOCAL1_MASK, imr & ~isr) #define INTR_IMASK(ipl) int2_l1imask[ipl] -#define INTR_HANDLER(bit) int2_intrhand[bit + 8] +#define INTR_HANDLER(bit) (struct intrhand *)int2_intrhand[bit + 8] #define INTR_SPURIOUS(bit) \ do { \ printf("spurious int2 interrupt %d\n", bit + 8); \ } while (0) +/* explicit masking with int2_intem to cope with handlers disabling themselves */ #define INTR_MASKRESTORE \ - int2_write(INT2_LOCAL1_MASK, imr) + int2_write(INT2_LOCAL1_MASK, (int2_intem >> 8) & imr) #define INTR_MASKSIZE 8 +#define INTR_HANDLER_SKIP(ih) \ + (((struct int2_intrhand *)(ih))->flags /* & IH_FL_DISABLED */) + #include <sgi/sgi/intr_template.c> void * int2_intr_establish(int irq, int level, int (*ih_fun) (void *), void *ih_arg, const char *ih_what) { - struct intrhand **p, *q, *ih; + struct int2_intrhand **p, *q, *ih; int s; #ifdef DIAGNOSTIC @@ -177,18 +191,20 @@ int2_intr_establish(int irq, int level, int (*ih_fun) (void *), if (ih == NULL) return NULL; - ih->ih_next = NULL; - ih->ih_fun = ih_fun; - ih->ih_arg = ih_arg; - ih->ih_level = level; - ih->ih_irq = irq; + ih->ih.ih_next = NULL; + ih->ih.ih_fun = ih_fun; + ih->ih.ih_arg = ih_arg; + ih->ih.ih_level = level; + ih->ih.ih_irq = irq; if (ih_what != NULL) - evcount_attach(&ih->ih_count, ih_what, &ih->ih_irq); + evcount_attach(&ih->ih.ih_count, ih_what, &ih->ih.ih_irq); + ih->flags = 0; s = splhigh(); - for (p = &int2_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) - ; + for (p = &int2_intrhand[irq]; (q = *p) != NULL; + p = (struct int2_intrhand **)&q->ih.ih_next) + continue; *p = ih; int2_intem |= 1 << irq; @@ -248,7 +264,7 @@ int2_mappable_intr(void *arg) vaddr_t imrreg; uint64_t imr, isr; uint i, intnum; - struct intrhand *ih; + struct int2_intrhand *ih; int rc, ret; imrreg = which == 0 ? INT2_IP22_MAP_MASK0 : INT2_IP22_MAP_MASK1; @@ -270,11 +286,13 @@ int2_mappable_intr(void *arg) if (isr & (1 << i)) { rc = 0; for (ih = int2_intrhand[intnum]; ih != NULL; - ih = ih->ih_next) { - ret = (*ih->ih_fun)(ih->ih_arg); + ih = (struct int2_intrhand *)ih->ih.ih_next) { + if (ih->flags /* & IH_FL_DISABLED */) + continue; + ret = (*ih->ih.ih_fun)(ih->ih.ih_arg); if (ret != 0) { rc = 1; - atomic_add_uint64(&ih->ih_count.ec_count, + atomic_add_uint64(&ih->ih.ih_count.ec_count, 1); } if (ret == 1) @@ -369,6 +387,81 @@ int2_get_base(void) } /* + * Returns nonzero if the given interrupt source is pending. + */ +int +int2_is_intr_pending(int irq) +{ + paddr_t reg; + + if (int2_base == 0) + int2_base = int2_get_base(); + switch (irq >> 3) { + case 0: + reg = INT2_LOCAL0_STATUS; + break; + case 1: + reg = INT2_LOCAL1_STATUS; + break; + case 2: + case 3: + reg = INT2_IP22_MAP_STATUS; + break; + default: + return 0; + } + + return int2_read(reg) & (1 << (irq & 7)); +} + +/* + * Temporarily disable an interrupt handler. Note that disable/enable + * calls can not be stacked. + * + * The interrupt source will become masked if it is the only handler. + * (This is intended for panel(4) which is not supposed to be a shared + * interrupt) + */ +void +int2_intr_disable(void *v) +{ + struct int2_intrhand *ih = (struct int2_intrhand *)v; + int s; + + s = splhigh(); + if ((ih->flags & IH_FL_DISABLED) == 0) { + ih->flags |= IH_FL_DISABLED; + if (ih == int2_intrhand[ih->ih.ih_irq] && + ih->ih.ih_next == NULL) { + /* disable interrupt source */ + int2_intem &= ~(1 << ih->ih.ih_irq); + } + } + splx(s); +} + +/* + * Reenable an interrupt handler. + */ +void +int2_intr_enable(void *v) +{ + struct int2_intrhand *ih = (struct int2_intrhand *)v; + int s; + + s = splhigh(); + if ((ih->flags & IH_FL_DISABLED) != 0) { + ih->flags &= ~IH_FL_DISABLED; + if (ih == int2_intrhand[ih->ih.ih_irq] && + ih->ih.ih_next == NULL) { + /* reenable interrupt source */ + int2_intem |= 1 << ih->ih.ih_irq; + } + } + splx(s); +} + +/* * Wait for the FIFO Full interrupt condition (Local 0 bit 0) to clear. */ void diff --git a/sys/arch/sgi/localbus/intvar.h b/sys/arch/sgi/localbus/intvar.h index c8f6a133862..4bebab52526 100644 --- a/sys/arch/sgi/localbus/intvar.h +++ b/sys/arch/sgi/localbus/intvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $OpenBSD: intvar.h,v 1.2 2012/04/17 15:22:04 miod Exp $ */ /* $NetBSD: int2var.h,v 1.3 2008/08/23 17:25:54 tsutsui Exp $ */ /* @@ -30,5 +30,8 @@ void *int2_intr_establish(int, int, int (*)(void *), void *, const char *); +int int2_is_intr_pending(int); +void int2_intr_disable(void *); +void int2_intr_enable(void *); void int2_wait_fifo(uint32_t); |