diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-16 00:40:59 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-16 00:40:59 +0000 |
commit | 65aeca4e8c04581896ff2d5844a33e63d17b5094 (patch) | |
tree | 7f90d4da2db923ee2adfaf712a0d2487adf49052 /sys/arch/amd64 | |
parent | df16ae3a02369ac5510d4e79a51b3239777001c7 (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.
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/amd64/intr.c | 10 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/vector.S | 10 | ||||
-rw-r--r-- | sys/arch/amd64/include/intr.h | 4 |
3 files changed, 19 insertions, 5 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); |