summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2011-02-08 01:49:30 +0000
committermarcel <marcel@FreeBSD.org>2011-02-08 01:49:30 +0000
commitcdf278387fe97643c1feb5180b4fc3cb872286a0 (patch)
tree9ae70996177c0fdf14967aec6602bc77db736bde /sys/arm
parentcc3f43e6b293dc0a254297a634a8e49d67f14df5 (diff)
downloadFreeBSD-src-cdf278387fe97643c1feb5180b4fc3cb872286a0.zip
FreeBSD-src-cdf278387fe97643c1feb5180b4fc3cb872286a0.tar.gz
In arm_get_next_irq(), use the last IRQ argument in order to prevent
a hard hang due to an interrupt storm or stuck interrupt pin. We return the next IRQ that is larger than the last one returned and in doing so give all interrupts a fair chance of being handled. Consequently, we're able to break into the kernel debugger in such an event.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/mv/ic.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/sys/arm/mv/ic.c b/sys/arm/mv/ic.c
index 83d43a1..14c6b7b 100644
--- a/sys/arm/mv/ic.c
+++ b/sys/arm/mv/ic.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/ktr.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <machine/bus.h>
@@ -143,27 +144,38 @@ static devclass_t mv_ic_devclass;
DRIVER_MODULE(ic, simplebus, mv_ic_driver, mv_ic_devclass, 0, 0);
int
-arm_get_next_irq(int last __unused)
+arm_get_next_irq(int last)
{
- int irq;
+ u_int filt, irq;
+ int next;
+ filt = ~((last >= 0) ? (2 << last) - 1 : 0);
irq = mv_ic_get_cause() & mv_ic_get_mask();
- if (irq)
- return (ffs(irq) - 1);
-
+ if (irq & filt) {
+ next = ffs(irq & filt) - 1;
+ goto out;
+ }
if (mv_ic_sc->ic_high_regs) {
+ filt = ~((last >= 32) ? (2 << (last - 32)) - 1 : 0);
irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi();
- if (irq)
- return (ffs(irq) + 31);
+ if (irq & filt) {
+ next = ffs(irq & filt) + 31;
+ goto out;
+ }
}
-
if (mv_ic_sc->ic_error_regs) {
+ filt = ~((last >= 64) ? (2 << (last - 64)) - 1 : 0);
irq = mv_ic_get_cause_error() & mv_ic_get_mask_error();
- if (irq)
- return (ffs(irq) + 63);
+ if (irq & filt) {
+ next = ffs(irq & filt) + 63;
+ goto out;
+ }
}
+ next = -1;
- return (-1);
+ out:
+ CTR3(KTR_INTR, "%s: last=%d, next=%d", __func__, last, next);
+ return (next);
}
static void
OpenPOWER on IntegriCloud