summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2012-04-17 15:22:02 +0000
committermiod <miod@openbsd.org>2012-04-17 15:22:02 +0000
commitb540ef5c5421f18b7977fad4a36d1566daf963f3 (patch)
treee17f383b7863b947d3af77568b5e09ba04cac594
parentRemove "#define _POSIX_THREADS" line before include <pthread.h>. (diff)
downloadwireguard-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.c28
-rw-r--r--sys/arch/sgi/hpc/hpcvar.h5
-rw-r--r--sys/arch/sgi/localbus/int.c131
-rw-r--r--sys/arch/sgi/localbus/intvar.h5
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);