aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Krzeminski <marcin.krzeminski@nokia.com>2016-11-07 10:00:24 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-11-07 10:00:24 +0000
commit3bc4b52ccd7754de4fb177871f1c5eaaa61ec7ef (patch)
treec24d1e169d01bd8dc2e7cb02abb1f51994640486
parent6e29651c5e3a0e0336818574f273b3f6ecea491d (diff)
nvic: set pending status for not active interrupts
According to ARM DUI 0552A 4.2.10. NVIC set pending status also for disabled interrupts. Correct the logic for when interrupts are marked pending both on input level transition and when interrupts are dismissed, to match the NVIC behaviour rather than the 11MPCore GIC. Signed-off-by: Marcin Krzeminski <marcin.krzeminski@nokia.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/intc/arm_gic.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index b30cc91745..521aac3cc6 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -156,6 +156,17 @@ static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
}
}
+static void gic_set_irq_nvic(GICState *s, int irq, int level,
+ int cm, int target)
+{
+ if (level) {
+ GIC_SET_LEVEL(irq, cm);
+ GIC_SET_PENDING(irq, target);
+ } else {
+ GIC_CLEAR_LEVEL(irq, cm);
+ }
+}
+
static void gic_set_irq_generic(GICState *s, int irq, int level,
int cm, int target)
{
@@ -201,8 +212,10 @@ static void gic_set_irq(void *opaque, int irq, int level)
return;
}
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
+ if (s->revision == REV_11MPCORE) {
gic_set_irq_11mpcore(s, irq, level, cm, target);
+ } else if (s->revision == REV_NVIC) {
+ gic_set_irq_nvic(s, irq, level, cm, target);
} else {
gic_set_irq_generic(s, irq, level, cm, target);
}
@@ -568,7 +581,7 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
return; /* No active IRQ. */
}
- if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
+ if (s->revision == REV_11MPCORE) {
/* Mark level triggered interrupts as pending if they are still
raised. */
if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
@@ -576,6 +589,11 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
DPRINTF("Set %d pending mask %x\n", irq, cm);
GIC_SET_PENDING(irq, cm);
}
+ } else if (s->revision == REV_NVIC) {
+ if (GIC_TEST_LEVEL(irq, cm)) {
+ DPRINTF("Set nvic %d pending mask %x\n", irq, cm);
+ GIC_SET_PENDING(irq, cm);
+ }
}
group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);