hw/intc/arm_gic: Add grouping support to gic_update()
authorPeter Maydell <peter.maydell@linaro.org>
Tue, 12 May 2015 10:57:18 +0000 (11:57 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Tue, 12 May 2015 10:57:18 +0000 (11:57 +0100)
Add support to gic_update() for determining the current IRQ
and FIQ status when interrupt grouping is supported. This
simply requires that instead of always raising IRQ we
check the group of the highest priority pending interrupt
and the GICC_CTLR.FIQEn bit to see whether we should raise
IRQ or FIQ.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 1430502643-25909-15-git-send-email-peter.maydell@linaro.org

hw/intc/arm_gic.c

index 6abdb143792584e4a667fe29c4091604ee766254..c1d2e704ec511307c30484eaaad5497c11b4185f 100644 (file)
@@ -60,7 +60,7 @@ void gic_update(GICState *s)
     int best_irq;
     int best_prio;
     int irq;
-    int level;
+    int irq_level, fiq_level;
     int cpu;
     int cm;
 
@@ -70,6 +70,7 @@ void gic_update(GICState *s)
         if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1))
             || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) {
             qemu_irq_lower(s->parent_irq[cpu]);
+            qemu_irq_lower(s->parent_fiq[cpu]);
             return;
         }
         best_prio = 0x100;
@@ -83,15 +84,31 @@ void gic_update(GICState *s)
                 }
             }
         }
-        level = 0;
+
+        irq_level = fiq_level = 0;
+
         if (best_prio < s->priority_mask[cpu]) {
             s->current_pending[cpu] = best_irq;
             if (best_prio < s->running_priority[cpu]) {
-                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
-                level = 1;
+                int group = GIC_TEST_GROUP(best_irq, cm);
+
+                if (extract32(s->ctlr, group, 1) &&
+                    extract32(s->cpu_ctlr[cpu], group, 1)) {
+                    if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) {
+                        DPRINTF("Raised pending FIQ %d (cpu %d)\n",
+                                best_irq, cpu);
+                        fiq_level = 1;
+                    } else {
+                        DPRINTF("Raised pending IRQ %d (cpu %d)\n",
+                                best_irq, cpu);
+                        irq_level = 1;
+                    }
+                }
             }
         }
-        qemu_set_irq(s->parent_irq[cpu], level);
+
+        qemu_set_irq(s->parent_irq[cpu], irq_level);
+        qemu_set_irq(s->parent_fiq[cpu], fiq_level);
     }
 }