From df986188e9cc833240ca7eb2dd62a649ea5dc33a Mon Sep 17 00:00:00 2001 From: raj Date: Thu, 11 Sep 2008 12:36:13 +0000 Subject: 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 --- sys/arm/arm/intr.c | 14 ++++++++++++-- sys/arm/arm/nexus.c | 14 +++----------- sys/arm/include/intr.h | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'sys/arm') 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 */ -- cgit v1.1