diff options
author | Luc MICHEL <luc.michel@git.antfield.fr> | 2018-01-25 11:45:29 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-01-25 11:45:29 +0000 |
commit | 91f4e18d9550a19ccb33fdac37ab0caf084549c0 (patch) | |
tree | c0445869d414d71c7dc60bdda1245b29369650fb /hw/intc | |
parent | 55faa21273151259de38da271c8a2f2b37d6c250 (diff) |
hw/intc/arm_gic: Prevent the GIC from signaling an IRQ when it's "active and pending"
In the GIC, when an IRQ is acknowledged, its state goes from "pending"
to:
- "active" if the corresponding IRQ pin has been de-asserted
- "active and pending" otherwise.
The GICv2 manual states that when a IRQ becomes active (or active and
pending), the GIC should either signal another (higher priority) IRQ to
the CPU if there is one, or de-assert the CPU IRQ pin.
The current implementation of the GIC in QEMU does not check if the
IRQ is already active when looking for pending interrupts with
sufficient priority in gic_update(). This can lead to signaling an
interrupt that is already active.
This usually happens when splitting priority drop and interrupt
deactivation. On priority drop, the IRQ stays active until deactivation.
If it becomes pending again, chances are that it will be incorrectly
selected as best_irq in gic_update().
This commit fixes this by checking if the IRQ is not already active when
looking for best_irq in gic_update().
Note that regarding the ARM11MPCore GIC version, the corresponding
manual is not clear on that point, but it has has no priority
drop/interrupt deactivation separation, so this case should not happen.
Signed-off-by: Luc MICHEL <luc.michel@git.antfield.fr>
Message-id: 20180119145756.7629-3-luc.michel@greensocs.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc')
-rw-r--r-- | hw/intc/arm_gic.c | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index d701e49ff9..dad383ea12 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -93,6 +93,7 @@ void gic_update(GICState *s) best_irq = 1023; for (irq = 0; irq < s->num_irq; irq++) { if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && + (!GIC_TEST_ACTIVE(irq, cm)) && (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { best_prio = GIC_GET_PRIORITY(irq, cpu); |