dev-arm: Enable FIQ signaling for Group0 interrupts in GICv2
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Tue, 11 Sep 2018 12:39:00 +0000 (13:39 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 1 Oct 2018 08:28:51 +0000 (08:28 +0000)
Change-Id: Iafaf26344a26eade60c08dd2c0d716af14d9b328
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/12948
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/dev/arm/gic_v2.cc
src/dev/arm/gic_v2.hh

index 7bbc89e7498e061417e79d49c31272e1fb0202ae..99124b08c5af82c213d8bbab7942551353f5ad85 100644 (file)
@@ -364,7 +364,7 @@ GicV2::readCpu(ContextID ctx, Addr daddr)
                     ctx, iar.ack_id, iar.cpu_id, iar);
             cpuHighestInt[ctx] = SPURIOUS_INT;
             updateIntState(-1);
-            platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
+            clearInt(ctx, active_int);
             return iar;
         } else {
              return SPURIOUS_INT;
@@ -802,7 +802,7 @@ GicV2::updateIntState(int hint)
             if (isLevelSensitive(cpu, prev_highest)) {
 
                 DPRINTF(Interrupt, "Clear IRQ for cpu%d\n", cpu);
-                platform->intrctrl->clear(cpu, ArmISA::INT_IRQ, 0);
+                clearInt(cpu, prev_highest);
             }
             continue;
         }
@@ -816,7 +816,12 @@ GicV2::updateIntState(int hint)
 
             DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
                     cpu);
-            postInt(cpu, curTick() + intLatency);
+
+            if (isFiq(cpu, highest_int)) {
+                postFiq(cpu, curTick() + intLatency);
+            } else {
+                postInt(cpu, curTick() + intLatency);
+            }
         }
     }
 }
@@ -901,6 +906,16 @@ GicV2::clearPPInt(uint32_t num, uint32_t cpu)
     updateIntState(intNumToWord(num));
 }
 
+void
+GicV2::clearInt(ContextID ctx, uint32_t int_num)
+{
+    if (isFiq(ctx, int_num)) {
+        platform->intrctrl->clear(ctx, ArmISA::INT_FIQ, 0);
+    } else {
+        platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
+    }
+}
+
 void
 GicV2::postInt(uint32_t cpu, Tick when)
 {
index 4f30b00e6177e35202bd70c8d93116beea7c5f00..c9c1a4715b7fed57ce1622c9db527beeebd58371 100644 (file)
@@ -334,7 +334,35 @@ class GicV2 : public BaseGic, public BaseGicRegisters
         }
     }
 
-    /** CPU enabled */
+    bool isGroup0(ContextID ctx, uint32_t int_num) {
+        const uint32_t group_reg = getIntGroup(ctx, intNumToWord(int_num));
+        return bits(group_reg, intNumToBit(int_num));
+    }
+
+    /**
+     * This method checks if an interrupt ID must be signaled or has been
+     * signaled as a FIQ to the cpu. It does that by reading:
+     *
+     * 1) GICD_IGROUPR: controls if the interrupt is part of group0 or
+     * group1. Only group0 interrupts can be signaled as FIQs.
+     *
+     * 2) GICC_CTLR.FIQEn: controls whether the CPU interface signals Group 0
+     * interrupts to a target processor using the FIQ or the IRQ signal
+     */
+    bool isFiq(ContextID ctx, uint32_t int_num) {
+        const bool is_group0 = isGroup0(ctx, int_num);
+        const bool use_fiq = cpuControl[ctx].fiqEn;
+
+        if (is_group0 && use_fiq) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /** CPU enabled:
+     * Checks if GICC_CTLR.EnableGrp0 or EnableGrp1 are set
+     */
     bool cpuEnabled(ContextID ctx) const {
         return cpuControl[ctx].enableGrp0 ||
                cpuControl[ctx].enableGrp1;
@@ -393,6 +421,9 @@ class GicV2 : public BaseGic, public BaseGicRegisters
     int intNumToWord(int num) const { return num >> 5; }
     int intNumToBit(int num) const { return num % 32; }
 
+    /** Clears a cpu IRQ or FIQ signal */
+    void clearInt(ContextID ctx, uint32_t int_num);
+
     /**
      * Post an interrupt to a CPU with a delay
      */