dev-arm: Implement LevelSensitive PPIs in GICv3
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Fri, 17 Jul 2020 12:40:01 +0000 (13:40 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 23 Jul 2020 16:51:03 +0000 (16:51 +0000)
Change-Id: I7f28408eff7d502427c4486518c83506893f4a7a
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31516
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/dev/arm/gic_v3.cc
src/dev/arm/gic_v3_redistributor.cc
src/dev/arm/gic_v3_redistributor.hh

index 8e75b1c5bad5f17886d072b10d841c6c9c54b072..83f2c83219281dd01361e692aeae41d6b1c31868 100644 (file)
@@ -193,8 +193,12 @@ Gicv3::sendPPInt(uint32_t int_id, uint32_t cpu)
 }
 
 void
-Gicv3::clearPPInt(uint32_t num, uint32_t cpu)
+Gicv3::clearPPInt(uint32_t int_id, uint32_t cpu)
 {
+    panic_if(cpu >= redistributors.size(), "Invalid cpuID clearing PPI!");
+    DPRINTF(Interrupt, "Gicv3::clearPPInt(): received PPI %d cpuTarget %#x\n",
+            int_id, cpu);
+    redistributors[cpu]->clearPPInt(int_id);
 }
 
 void
index 5fceed573eeeee4fe909e52b85636f1b6bae97dd..339039308fec80463bcccacf78ef61b0fa94785e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019-2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -58,6 +58,7 @@ Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id)
       irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0),
       irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
       irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
+      irqPendingIspendr(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
       irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
       irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0),
       irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX, Gicv3::INT_EDGE_TRIGGERED),
@@ -509,6 +510,7 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
                         "(GICR_ISPENDR0): int_id %d (PPI) "
                         "pending bit set\n", int_id);
                 irqPending[int_id] = true;
+                irqPendingIspendr[int_id] = true;
             }
         }
 
@@ -526,7 +528,7 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
 
             bool clear = data & (1 << int_id) ? 1 : 0;
 
-            if (clear) {
+            if (clear && treatAsEdgeTriggered(int_id)) {
                 irqPending[int_id] = false;
             }
         }
@@ -710,11 +712,23 @@ Gicv3Redistributor::sendPPInt(uint32_t int_id)
     assert((int_id >= Gicv3::SGI_MAX) &&
            (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
     irqPending[int_id] = true;
+    irqPendingIspendr[int_id] = false;
     DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
             "int_id %d (PPI) pending bit set\n", int_id);
     updateDistributor();
 }
 
+void
+Gicv3Redistributor::clearPPInt(uint32_t int_id)
+{
+    assert((int_id >= Gicv3::SGI_MAX) &&
+           (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
+
+    if (isLevelSensitive(int_id)) {
+        irqPending[int_id] = false;
+    }
+}
+
 void
 Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
 {
@@ -747,6 +761,7 @@ Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
     if (!forward) return;
 
     irqPending[int_id] = true;
+    irqPendingIspendr[int_id] = false;
     DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
             "int_id %d (SGI) pending bit set\n", int_id);
     updateDistributor();
@@ -977,7 +992,9 @@ Gicv3Redistributor::getIntGroup(int int_id) const
 void
 Gicv3Redistributor::activateIRQ(uint32_t int_id)
 {
-    irqPending[int_id] = false;
+    if (treatAsEdgeTriggered(int_id)) {
+        irqPending[int_id] = false;
+    }
     irqActive[int_id] = true;
 }
 
@@ -1037,6 +1054,7 @@ Gicv3Redistributor::serialize(CheckpointOut & cp) const
     SERIALIZE_CONTAINER(irqGroup);
     SERIALIZE_CONTAINER(irqEnabled);
     SERIALIZE_CONTAINER(irqPending);
+    SERIALIZE_CONTAINER(irqPendingIspendr);
     SERIALIZE_CONTAINER(irqActive);
     SERIALIZE_CONTAINER(irqPriority);
     SERIALIZE_CONTAINER(irqConfig);
@@ -1058,6 +1076,7 @@ Gicv3Redistributor::unserialize(CheckpointIn & cp)
     UNSERIALIZE_CONTAINER(irqGroup);
     UNSERIALIZE_CONTAINER(irqEnabled);
     UNSERIALIZE_CONTAINER(irqPending);
+    UNSERIALIZE_CONTAINER(irqPendingIspendr);
     UNSERIALIZE_CONTAINER(irqActive);
     UNSERIALIZE_CONTAINER(irqPriority);
     UNSERIALIZE_CONTAINER(irqConfig);
index ee92bc792f2afc286038c5394f35c8142a461de8..7def1a285c6f2b135908800af76291c6b6434d09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019-2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -153,6 +153,7 @@ class Gicv3Redistributor : public Serializable
     std::vector <uint8_t> irqGroup;
     std::vector <bool> irqEnabled;
     std::vector <bool> irqPending;
+    std::vector <bool> irqPendingIspendr;
     std::vector <bool> irqActive;
     std::vector <uint8_t> irqPriority;
     std::vector <Gicv3::IntTriggerType> irqConfig;
@@ -221,6 +222,29 @@ class Gicv3Redistributor : public Serializable
     void update();
     void updateDistributor();
 
+  protected:
+
+    bool isLevelSensitive(uint32_t int_id) const
+    {
+        return irqConfig[int_id] == Gicv3::INT_LEVEL_SENSITIVE;
+    }
+
+    /**
+     * This helper is used to check if an interrupt should be treated as
+     * edge triggered in the following scenarios:
+     *
+     * a) While activating the interrupt
+     * b) While clearing an interrupt via ICPENDR
+     *
+     * In fact, in these two situations, a level sensitive interrupt
+     * which had been made pending via a write to ISPENDR, will be
+     * treated as it if was edge triggered.
+     */
+    bool treatAsEdgeTriggered(uint32_t int_id) const
+    {
+        return !isLevelSensitive(int_id) || irqPendingIspendr[int_id];
+    }
+
   public:
 
     Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id);
@@ -228,6 +252,7 @@ class Gicv3Redistributor : public Serializable
     void init();
     uint64_t read(Addr addr, size_t size, bool is_secure_access);
     void sendPPInt(uint32_t int_id);
+    void clearPPInt(uint32_t int_id);
     void write(Addr addr, uint64_t data, size_t size, bool is_secure_access);
 };