diff options
author | raj <raj@FreeBSD.org> | 2008-09-11 12:36:13 +0000 |
---|---|---|
committer | raj <raj@FreeBSD.org> | 2008-09-11 12:36:13 +0000 |
commit | df986188e9cc833240ca7eb2dd62a649ea5dc33a (patch) | |
tree | 42c4a1699b503244b7e33f5a53810449a27be094 | |
parent | 30165fb1e191c6ee2d68f8621f73d606ae402ebd (diff) | |
download | FreeBSD-src-df986188e9cc833240ca7eb2dd62a649ea5dc33a.zip FreeBSD-src-df986188e9cc833240ca7eb2dd62a649ea5dc33a.tar.gz |
ARM interrupts improvements.
- Fix nexus_setup_intr() abuse of setting up multiple IRQs in one go. Calling
arm_setup_irqhandler() in loop is bogus, as there's just one cookie given
from the caller and it is overwritten in each iteration so that only the
last handler's cookie value prevails.
- Proper intr masking/unmasking handling: the IRQ source is masked at PIC level
only after the last handler has been removed from the list.
Reviewed by: cognet, imp, sam, stass
Obtained from: Grzegorz Bernacki gjb ! semihalf dot com
-rw-r--r-- | sys/arm/arm/intr.c | 14 | ||||
-rw-r--r-- | sys/arm/arm/nexus.c | 14 | ||||
-rw-r--r-- | sys/arm/include/intr.h | 2 |
3 files changed, 16 insertions, 14 deletions
diff --git a/sys/arm/arm/intr.c b/sys/arm/arm/intr.c index 0787b88..85c2fd8 100644 --- a/sys/arm/arm/intr.c +++ b/sys/arm/arm/intr.c @@ -92,9 +92,19 @@ arm_setup_irqhandler(const char *name, driver_filter_t *filt, } int -arm_remove_irqhandler(void *cookie) +arm_remove_irqhandler(int irq, void *cookie) { - return (intr_event_remove_handler(cookie)); + struct intr_event *event; + int error; + + event = intr_events[irq]; + arm_mask_irq(irq); + + error = intr_event_remove_handler(cookie); + + if (!TAILQ_EMPTY(&event->ie_handlers)) + arm_unmask_irq(irq); + return (error); } void dosoftints(void); diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c index 0be9ec1..ca9c587 100644 --- a/sys/arm/arm/nexus.c +++ b/sys/arm/arm/nexus.c @@ -120,34 +120,26 @@ nexus_probe(device_t dev) panic("nexus_probe mem_rman"); return (0); - return bus_generic_probe(dev); } static int nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { - int i; if ((rman_get_flags(res) & RF_SHAREABLE) == 0) flags |= INTR_EXCL; - for (i = rman_get_start(res); i <= rman_get_end(res); i++) - arm_setup_irqhandler(device_get_nameunit(child), - filt, intr, arg, i, flags, cookiep); + arm_setup_irqhandler(device_get_nameunit(child), + filt, intr, arg, rman_get_start(res), flags, cookiep); return (0); } static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { - int error; - int i; - for (i = rman_get_start(r); i <= rman_get_end(r); i++) - arm_mask_irq(i); - error = arm_remove_irqhandler(ih); - return (error); + return (arm_remove_irqhandler(rman_get_start(r), ih)); } static int diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h index a41b214..bf2bf6d 100644 --- a/sys/arm/include/intr.h +++ b/sys/arm/include/intr.h @@ -57,6 +57,6 @@ void arm_mask_irq(uintptr_t); void arm_unmask_irq(uintptr_t); void arm_setup_irqhandler(const char *, int (*)(void*), void (*)(void*), void *, int, int, void **); -int arm_remove_irqhandler(void *); +int arm_remove_irqhandler(int, void *); extern void (*arm_post_filter)(void *); #endif /* _MACHINE_INTR_H */ |