summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-16 00:40:59 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-16 00:40:59 +0000
commit65aeca4e8c04581896ff2d5844a33e63d17b5094 (patch)
tree7f90d4da2db923ee2adfaf712a0d2487adf49052
parentdf16ae3a02369ac5510d4e79a51b3239777001c7 (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. ok and help from various people. In snaps for about a week now.
-rw-r--r--sys/arch/amd64/amd64/intr.c10
-rw-r--r--sys/arch/amd64/amd64/vector.S10
-rw-r--r--sys/arch/amd64/include/intr.h4
-rw-r--r--sys/arch/i386/i386/apicvec.s12
-rw-r--r--sys/arch/i386/i386/ioapic.c4
-rw-r--r--sys/arch/i386/i386/machdep.c8
-rw-r--r--sys/arch/i386/i386/vector.s8
-rw-r--r--sys/arch/i386/include/psl.h4
-rw-r--r--sys/arch/i386/isa/isa_machdep.c4
9 files changed, 50 insertions, 14 deletions
diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
index 44ba2669fc1..97784f1e518 100644
--- a/sys/arch/amd64/amd64/intr.c
+++ b/sys/arch/amd64/amd64/intr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.c,v 1.26 2010/12/27 20:22:23 guenther Exp $ */
+/* $OpenBSD: intr.c,v 1.27 2011/04/16 00:40:56 deraadt Exp $ */
/* $NetBSD: intr.c,v 1.3 2003/03/03 22:16:20 fvdl Exp $ */
/*
@@ -351,6 +351,12 @@ found:
return 0;
}
+/*
+ * True if the system has any non-level interrupts which are shared
+ * on the same pin.
+ */
+int intr_shared_edge;
+
void *
intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
int (*handler)(void *), void *arg, const char *what)
@@ -405,6 +411,8 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
source->is_type = type;
break;
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (source->is_type == type)
break;
diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index c79afcabb0c..b5350c52be8 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: vector.S,v 1.28 2011/04/01 22:51:45 guenther Exp $ */
+/* $OpenBSD: vector.S,v 1.29 2011/04/16 00:40:56 deraadt Exp $ */
/* $NetBSD: vector.S,v 1.5 2004/06/28 09:13:11 fvdl Exp $ */
/*
@@ -483,8 +483,12 @@ IDTVEC(intr_##name##num) ;\
8: movl %r12d,CPUVAR(ILEVEL) ;\
call *IH_FUN(%rbx) /* call it */ ;\
orq %rax,%rax /* should it be counted? */ ;\
- jz 4f ;\
- incq IH_COUNT(%rbx) ;\
+ jz 4f /* no, skip it */ ;\
+ incq IH_COUNT(%rbx) /* count the intrs */ ;\
+ cmpl $0,_C_LABEL(intr_shared_edge) ;\
+ jne 4f /* if no shared edges ... */ ;\
+ orq %rax,%rax /* 1 means stop trying */ ;\
+ jns 5f ;\
4: movq IH_NEXT(%rbx),%rbx /* next handler in chain */ ;\
testq %rbx,%rbx ;\
jnz 6b ;\
diff --git a/sys/arch/amd64/include/intr.h b/sys/arch/amd64/include/intr.h
index 5a6212ffcdf..fdb6d236b44 100644
--- a/sys/arch/amd64/include/intr.h
+++ b/sys/arch/amd64/include/intr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.h,v 1.22 2011/03/23 16:54:34 pirofti Exp $ */
+/* $OpenBSD: intr.h,v 1.23 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: intr.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */
/*-
@@ -191,6 +191,8 @@ extern struct intrstub ioapic_level_stubs[];
struct cpu_info;
+extern int intr_shared_edge;
+
extern char idt_allocmap[];
void intr_default_setup(void);
diff --git a/sys/arch/i386/i386/apicvec.s b/sys/arch/i386/i386/apicvec.s
index 8e30149aff3..9c55a9afaca 100644
--- a/sys/arch/i386/i386/apicvec.s
+++ b/sys/arch/i386/i386/apicvec.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: apicvec.s,v 1.22 2010/12/21 14:56:23 claudio Exp $ */
+/* $OpenBSD: apicvec.s,v 1.23 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: apicvec.s,v 1.1.2.2 2000/02/21 21:54:01 sommerfeld Exp $ */
/*-
@@ -302,8 +302,14 @@ _C_LABEL(Xintr_##name##num): \
jz 4f ;\
addl $1,IH_COUNT(%ebx) /* count the intrs */ ;\
adcl $0,IH_COUNT+4(%ebx) ;\
-4: \
- UNLOCK_KERNEL(IF_PPL(%esp)) ;\
+ cmp $0,_C_LABEL(intr_shared_edge) ;\
+ jne 4f /* if no shared edges ... */ ;\
+ orl %eax,%eax /* ... 1 means stop trying */ ;\
+ js 4f ;\
+1: UNLOCK_KERNEL(IF_PPL(%esp)) ;\
+ decl CPUVAR(IDEPTH) ;\
+ jmp 8f ;\
+4: UNLOCK_KERNEL(IF_PPL(%esp)) ;\
decl CPUVAR(IDEPTH) ;\
movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\
testl %ebx,%ebx ;\
diff --git a/sys/arch/i386/i386/ioapic.c b/sys/arch/i386/i386/ioapic.c
index 5e61bab1aa5..7ab93fc2e46 100644
--- a/sys/arch/i386/i386/ioapic.c
+++ b/sys/arch/i386/i386/ioapic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ioapic.c,v 1.25 2010/09/20 06:33:47 matthew Exp $ */
+/* $OpenBSD: ioapic.c,v 1.26 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: ioapic.c,v 1.7 2003/07/14 22:32:40 lukem Exp $ */
/*-
@@ -694,6 +694,8 @@ apic_intr_establish(int irq, int type, int level, int (*ih_fun)(void *),
pin->ip_type = type;
break;
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type == pin->ip_type)
break;
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 679b6dffb53..0700d4fdc87 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.490 2011/04/15 04:52:39 guenther Exp $ */
+/* $OpenBSD: machdep.c,v 1.491 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -3780,6 +3780,12 @@ i386_softintunlock(void)
#endif
/*
+ * True if the system has any non-level interrupts which are shared
+ * on the same pin.
+ */
+int intr_shared_edge;
+
+/*
* Software interrupt registration
*
* We hand-code this to ensure that it's atomic.
diff --git a/sys/arch/i386/i386/vector.s b/sys/arch/i386/i386/vector.s
index 60437b77380..5e043b06e12 100644
--- a/sys/arch/i386/i386/vector.s
+++ b/sys/arch/i386/i386/vector.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: vector.s,v 1.14 2009/08/10 16:40:50 oga Exp $ */
+/* $OpenBSD: vector.s,v 1.15 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: vector.s,v 1.32 1996/01/07 21:29:47 mycroft Exp $ */
/*
@@ -137,10 +137,14 @@ _C_LABEL(Xintr_##name##num): ;\
jz 5f /* no, skip it */ ;\
addl $1,IH_COUNT(%ebx) /* count the intrs */ ;\
adcl $0,IH_COUNT+4(%ebx) ;\
+ cmp $0,_C_LABEL(intr_shared_edge) ;\
+ jne 5f /* if no shared edges ... */ ;\
+ orl %eax,%eax /* ... 1 means stop trying */ ;\
+ jns 8f ;\
5: movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\
testl %ebx,%ebx ;\
jnz 7b ;\
- UNLOCK_KERNEL(IF_PPL(%esp)) ;\
+8: UNLOCK_KERNEL(IF_PPL(%esp)) ;\
decl CPUVAR(IDEPTH) ;\
STRAY_TEST(name,num) /* see if it's a stray */ ;\
6: unmask(num) /* unmask it in hardware */ ;\
diff --git a/sys/arch/i386/include/psl.h b/sys/arch/i386/include/psl.h
index 39b93d748d7..ad7101c3c3e 100644
--- a/sys/arch/i386/include/psl.h
+++ b/sys/arch/i386/include/psl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: psl.h,v 1.17 2011/03/23 16:54:35 pirofti Exp $ */
+/* $OpenBSD: psl.h,v 1.18 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: psl.h,v 1.30 1996/05/13 01:28:05 mycroft Exp $ */
/*-
@@ -91,6 +91,8 @@ struct intrhand {
struct evcount ih_count;
};
+extern int intr_shared_edge; /* This system has shared edge interrupts */
+
#endif /* _LOCORE */
#endif /* _KERNEL */
diff --git a/sys/arch/i386/isa/isa_machdep.c b/sys/arch/i386/isa/isa_machdep.c
index 678bf709f1b..5457f2ddd1d 100644
--- a/sys/arch/i386/isa/isa_machdep.c
+++ b/sys/arch/i386/isa/isa_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: isa_machdep.c,v 1.71 2010/11/20 20:58:51 miod Exp $ */
+/* $OpenBSD: isa_machdep.c,v 1.72 2011/04/16 00:40:58 deraadt Exp $ */
/* $NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $ */
/*-
@@ -514,6 +514,8 @@ isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level,
intrtype[irq] = type;
break;
case IST_EDGE:
+ intr_shared_edge = 1;
+ /* FALLTHROUGH */
case IST_LEVEL:
if (type == intrtype[irq])
break;