summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorraj <raj@FreeBSD.org>2008-09-11 12:36:13 +0000
committerraj <raj@FreeBSD.org>2008-09-11 12:36:13 +0000
commitdf986188e9cc833240ca7eb2dd62a649ea5dc33a (patch)
tree42c4a1699b503244b7e33f5a53810449a27be094 /sys/arm
parent30165fb1e191c6ee2d68f8621f73d606ae402ebd (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/intr.c14
-rw-r--r--sys/arm/arm/nexus.c14
-rw-r--r--sys/arm/include/intr.h2
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 */
OpenPOWER on IntegriCloud