summaryrefslogtreecommitdiff
path: root/hw/intc/arm_gic.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/arm_gic.c')
-rw-r--r--hw/intc/arm_gic.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 1c4a1143af..77519c0ad5 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -66,7 +66,7 @@ void gic_update(GICState *s)
best_prio = 0x100;
best_irq = 1023;
for (irq = 0; irq < s->num_irq; irq++) {
- if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
+ if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm)) {
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
best_prio = GIC_GET_PRIORITY(irq, cpu);
best_irq = irq;
@@ -89,14 +89,43 @@ void gic_set_pending_private(GICState *s, int cpu, int irq)
{
int cm = 1 << cpu;
- if (GIC_TEST_PENDING(irq, cm))
+ if (gic_test_pending(s, irq, cm)) {
return;
+ }
DPRINTF("Set %d pending cpu %d\n", irq, cpu);
GIC_SET_PENDING(irq, cm);
gic_update(s);
}
+static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
+ int cm, int target)
+{
+ if (level) {
+ GIC_SET_LEVEL(irq, cm);
+ if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
+ DPRINTF("Set %d pending mask %x\n", irq, target);
+ 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)
+{
+ if (level) {
+ GIC_SET_LEVEL(irq, cm);
+ DPRINTF("Set %d pending mask %x\n", irq, target);
+ if (GIC_TEST_EDGE_TRIGGER(irq)) {
+ GIC_SET_PENDING(irq, target);
+ }
+ } else {
+ GIC_CLEAR_LEVEL(irq, cm);
+ }
+}
+
/* Process a change in an external IRQ input. */
static void gic_set_irq(void *opaque, int irq, int level)
{
@@ -126,15 +155,12 @@ static void gic_set_irq(void *opaque, int irq, int level)
return;
}
- if (level) {
- GIC_SET_LEVEL(irq, cm);
- if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
- DPRINTF("Set %d pending mask %x\n", irq, target);
- GIC_SET_PENDING(irq, target);
- }
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
+ gic_set_irq_11mpcore(s, irq, level, cm, target);
} else {
- GIC_CLEAR_LEVEL(irq, cm);
+ gic_set_irq_generic(s, irq, level, cm, target);
}
+
gic_update(s);
}
@@ -195,14 +221,18 @@ void gic_complete_irq(GICState *s, int cpu, int irq)
}
if (s->running_irq[cpu] == 1023)
return; /* No active IRQ. */
- /* Mark level triggered interrupts as pending if they are still
- raised. */
- if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
- && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
- DPRINTF("Set %d pending mask %x\n", irq, cm);
- GIC_SET_PENDING(irq, cm);
- update = 1;
+
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
+ /* Mark level triggered interrupts as pending if they are still
+ raised. */
+ if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
+ && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
+ DPRINTF("Set %d pending mask %x\n", irq, cm);
+ GIC_SET_PENDING(irq, cm);
+ update = 1;
+ }
}
+
if (irq != s->running_irq[cpu]) {
/* Complete an IRQ that is not currently running. */
int tmp = s->running_irq[cpu];
@@ -273,7 +303,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
res = 0;
mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK;
for (i = 0; i < 8; i++) {
- if (GIC_TEST_PENDING(irq + i, mask)) {
+ if (gic_test_pending(s, irq + i, mask)) {
res |= (1 << i);
}
}