summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-15 20:40:08 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-15 20:40:08 +0000
commit6c79978cbce731e6dd4f90352a13cdd25a500eeb (patch)
treeaff1016153e9c8e9c986a3263124aaef9a489b73 /sys
parent54d01755e0c490f3abfc0ae79a651eac257ad0cf (diff)
More than a decade ago, interrupt handlers on sparc started returning 0
(interrupt was not for me), 1 (positive interrupt was for me), or -1 (i am not sure...). We have continued with this practice in as many drivers as possible, throughout the tree. This makes some of the architectures use that information in their interrupt handler calling code -- if 1 is returned (and we know this specific machine does not have edge-shared interrupts), we finish servicing other possible handlers on the same pin. If the interrupt pin remains asserted (from a different device), we will end up back in the interrupt servicing code of course... but this is cheaper than calling all the chained interrupts on a pin. This does of course count on shared level interrupts being properly sorted by IPL. There have been some concerns about starvation of drivers which incorrectly return 1. Those drivers should be hunted down so that they return -1. (other architectures will follow) ok kettenis drahn dlg miod
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/alpha/alpha/interrupt.c8
-rw-r--r--sys/arch/alpha/dev/shared_intr.c10
-rw-r--r--sys/arch/alpha/include/intr.h4
-rw-r--r--sys/arch/alpha/pci/sio_pic.c4
-rw-r--r--sys/arch/landisk/landisk/intr.c4
-rw-r--r--sys/arch/loongson/loongson/generic2e_machdep.c9
-rw-r--r--sys/arch/loongson/loongson/yeeloong_machdep.c9
-rw-r--r--sys/arch/mvmeppc/dev/openpic.c6
-rw-r--r--sys/arch/sgi/sgi/intr_template.c9
9 files changed, 46 insertions, 17 deletions
diff --git a/sys/arch/alpha/alpha/interrupt.c b/sys/arch/alpha/alpha/interrupt.c
index 3390277aba1..4fff2042e1e 100644
--- a/sys/arch/alpha/alpha/interrupt.c
+++ b/sys/arch/alpha/alpha/interrupt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interrupt.c,v 1.30 2010/12/21 14:56:23 claudio Exp $ */
+/* $OpenBSD: interrupt.c,v 1.31 2011/04/15 20:40:03 deraadt Exp $ */
/* $NetBSD: interrupt.c,v 1.46 2000/06/03 20:47:36 thorpej Exp $ */
/*-
@@ -101,6 +101,12 @@ struct scbvec scb_iovectab[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)];
void scb_stray(void *, u_long);
+/*
+ * True if the system has any non-level interrupts which are shared
+ * on the same pin.
+ */
+int intr_shared_edge;
+
void
scb_init(void)
{
diff --git a/sys/arch/alpha/dev/shared_intr.c b/sys/arch/alpha/dev/shared_intr.c
index a0fdb4ca9b6..847541c8a9a 100644
--- a/sys/arch/alpha/dev/shared_intr.c
+++ b/sys/arch/alpha/dev/shared_intr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: shared_intr.c,v 1.17 2010/09/20 06:33:46 matthew Exp $ */
+/* $OpenBSD: shared_intr.c,v 1.18 2011/04/15 20:40:05 deraadt Exp $ */
/* $NetBSD: shared_intr.c,v 1.13 2000/03/19 01:46:18 thorpej Exp $ */
/*
@@ -104,10 +104,12 @@ alpha_shared_intr_dispatch(intr, num)
* -1: This interrupt might have been for me, but I can't say
* for sure.
*/
- if ((rv = (*ih->ih_fn)(ih->ih_arg)))
+ rv = (*ih->ih_fn)(ih->ih_arg);
+ if (rv)
ih->ih_count.ec_count++;
-
handled = handled || (rv != 0);
+ if (intr_shared_edge == 0 && rv == 1)
+ break;
}
return (handled);
@@ -142,6 +144,8 @@ alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename)
switch (intr[num].intr_sharetype) {
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type == intr[num].intr_sharetype)
break;
diff --git a/sys/arch/alpha/include/intr.h b/sys/arch/alpha/include/intr.h
index 29eae0d7006..03af2a9e156 100644
--- a/sys/arch/alpha/include/intr.h
+++ b/sys/arch/alpha/include/intr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.h,v 1.38 2011/03/23 16:54:34 pirofti Exp $ */
+/* $OpenBSD: intr.h,v 1.39 2011/04/15 20:40:05 deraadt Exp $ */
/* $NetBSD: intr.h,v 1.26 2000/06/03 20:47:41 thorpej Exp $ */
/*-
@@ -235,6 +235,8 @@ struct alpha_shared_intr {
((asi)[num].intr_maxstrays != 0 && \
(asi)[num].intr_nstrays == (asi)[num].intr_maxstrays)
+extern int intr_shared_edge;
+
/*
* simulated software interrupt register
*/
diff --git a/sys/arch/alpha/pci/sio_pic.c b/sys/arch/alpha/pci/sio_pic.c
index 8b65a4638b3..9ae639cf39d 100644
--- a/sys/arch/alpha/pci/sio_pic.c
+++ b/sys/arch/alpha/pci/sio_pic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sio_pic.c,v 1.31 2009/09/30 20:16:31 miod Exp $ */
+/* $OpenBSD: sio_pic.c,v 1.32 2011/04/15 20:40:05 deraadt Exp $ */
/* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */
/*-
@@ -586,6 +586,8 @@ sio_intr_alloc(v, mask, type, irq)
return (0);
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type != sio_intr[i].intr_sharetype)
continue;
diff --git a/sys/arch/landisk/landisk/intr.c b/sys/arch/landisk/landisk/intr.c
index 59f35869a99..1410089540e 100644
--- a/sys/arch/landisk/landisk/intr.c
+++ b/sys/arch/landisk/landisk/intr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.c,v 1.6 2010/09/20 06:33:47 matthew Exp $ */
+/* $OpenBSD: intr.c,v 1.7 2011/04/15 20:40:07 deraadt Exp $ */
/* $NetBSD: intr.c,v 1.1 2006/09/01 21:26:18 uwe Exp $ */
/*-
@@ -360,6 +360,8 @@ extintr_intr_handler(void *arg)
r = (*ih->ih_fun)(ih->ih_arg);
if (__predict_true(r != 0)) {
ih->ih_count.ec_count++;
+ if (r == 1)
+ break;
}
}
}
diff --git a/sys/arch/loongson/loongson/generic2e_machdep.c b/sys/arch/loongson/loongson/generic2e_machdep.c
index e08ccb1b260..f98d7ae034d 100644
--- a/sys/arch/loongson/loongson/generic2e_machdep.c
+++ b/sys/arch/loongson/loongson/generic2e_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: generic2e_machdep.c,v 1.1 2010/05/08 21:59:56 miod Exp $ */
+/* $OpenBSD: generic2e_machdep.c,v 1.2 2011/04/15 20:40:06 deraadt Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -239,7 +239,7 @@ generic2e_isa_intr(uint32_t hwpend, struct trap_frame *frame)
{
struct intrhand *ih;
uint64_t isr, mask = 0;
- int rc, irq;
+ int rc, irq, ret;
uint8_t ocw1, ocw2;
extern uint loongson_isaimr;
@@ -283,7 +283,8 @@ generic2e_isa_intr(uint32_t hwpend, struct trap_frame *frame)
ih = ih->ih_next) {
splraise(ih->ih_level);
- if ((*ih->ih_fun)(ih->ih_arg) != 0) {
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret) {
rc = 1;
ih->ih_count.ec_count++;
}
@@ -291,6 +292,8 @@ generic2e_isa_intr(uint32_t hwpend, struct trap_frame *frame)
__asm__ (".set noreorder\n");
curcpu()->ci_ipl = frame->ipl;
__asm__ ("sync\n\t.set reorder\n");
+ if (ret == 1)
+ break;
}
/* Send a specific EOI to the 8259. */
diff --git a/sys/arch/loongson/loongson/yeeloong_machdep.c b/sys/arch/loongson/loongson/yeeloong_machdep.c
index 17481469c93..eca1b5ce4d7 100644
--- a/sys/arch/loongson/loongson/yeeloong_machdep.c
+++ b/sys/arch/loongson/loongson/yeeloong_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: yeeloong_machdep.c,v 1.15 2010/10/14 21:23:04 pirofti Exp $ */
+/* $OpenBSD: yeeloong_machdep.c,v 1.16 2011/04/15 20:40:06 deraadt Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
@@ -346,7 +346,7 @@ lemote_isa_intr(uint32_t hwpend, struct trap_frame *frame)
* Now process allowed interrupts.
*/
if (isr != 0) {
- int lvl, bitno;
+ int lvl, bitno, ret;
uint64_t tmpisr;
/* Service higher level interrupts first */
@@ -365,13 +365,16 @@ lemote_isa_intr(uint32_t hwpend, struct trap_frame *frame)
for (ih = bonito_intrhand[BONITO_ISA_IRQ(bitno)];
ih != NULL; ih = ih->ih_next) {
splraise(ih->ih_level);
- if ((*ih->ih_fun)(ih->ih_arg) != 0) {
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret) {
rc = 1;
ih->ih_count.ec_count++;
}
__asm__ (".set noreorder\n");
curcpu()->ci_ipl = frame->ipl;
__asm__ ("sync\n\t.set reorder\n");
+ if (ret == 1)
+ break;
}
if (rc == 0)
printf("spurious isa interrupt %d\n",
diff --git a/sys/arch/mvmeppc/dev/openpic.c b/sys/arch/mvmeppc/dev/openpic.c
index b4220d0e07a..9fb92603221 100644
--- a/sys/arch/mvmeppc/dev/openpic.c
+++ b/sys/arch/mvmeppc/dev/openpic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: openpic.c,v 1.23 2010/09/20 06:33:47 matthew Exp $ */
+/* $OpenBSD: openpic.c,v 1.24 2011/04/15 20:40:06 deraadt Exp $ */
/*-
* Copyright (c) 1995 Per Fogelstrom
@@ -291,6 +291,8 @@ i8259_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
switch (intrtype[irq]) {
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type == intrtype[irq])
break;
@@ -374,6 +376,8 @@ openpic_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
switch (intrtype[irq]) {
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type == intrtype[irq])
break;
diff --git a/sys/arch/sgi/sgi/intr_template.c b/sys/arch/sgi/sgi/intr_template.c
index 1bec1c095a6..2f9f6e95b3e 100644
--- a/sys/arch/sgi/sgi/intr_template.c
+++ b/sys/arch/sgi/sgi/intr_template.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr_template.c,v 1.10 2010/01/18 17:01:14 miod Exp $ */
+/* $OpenBSD: intr_template.c,v 1.11 2011/04/15 20:40:06 deraadt Exp $ */
/*
* Copyright (c) 2009 Miodrag Vallat.
@@ -103,7 +103,7 @@ INTR_FUNCTIONNAME(uint32_t hwpend, struct trap_frame *frame)
int ipl;
int bit;
struct intrhand *ih;
- int rc;
+ int rc, ret;
INTR_LOCAL_DECLS
INTR_GETMASKS;
@@ -166,7 +166,8 @@ INTR_FUNCTIONNAME(uint32_t hwpend, struct trap_frame *frame)
__mp_lock(&kernel_lock);
}
#endif
- if ((*ih->ih_fun)(ih->ih_arg) != 0) {
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret != 0) {
rc = 1;
atomic_add_uint64(&ih->ih_count.ec_count, 1);
}
@@ -180,6 +181,8 @@ INTR_FUNCTIONNAME(uint32_t hwpend, struct trap_frame *frame)
__asm__ (".set noreorder\n");
ci->ci_ipl = ipl;
__asm__ ("sync\n\t.set reorder\n");
+ if (ret == 1)
+ break;
}
if (rc == 0)
INTR_SPURIOUS(bitno);