arch-arm, dev-arm: WakeRequest implementation
authorAdrian Herrera <adrian.herrera@arm.com>
Mon, 9 Dec 2019 20:13:55 +0000 (20:13 +0000)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Tue, 31 Mar 2020 13:30:16 +0000 (13:30 +0000)
This patch provides a GIC WakeRequest implementation based on GICv3 and
FVPBasePwrCtrl models. When GICR_WAKER.ProcessorSleep is set to 1 for a
certain PE, any pending interrupt coming from the Redistributor asserts
a WakeRequest signal; if PwrStatus.WEN is set, this brings up the PE.

Change-Id: I5e8b7f0e9f7706dfcc7d2e0857f4c3b86cdc04ca
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26810
Tested-by: Gem5 Cloud Project GCB service account <345032938727@cloudbuild.gserviceaccount.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>

src/arch/arm/system.cc
src/arch/arm/system.hh
src/dev/arm/fvp_base_pwr_ctrl.cc
src/dev/arm/fvp_base_pwr_ctrl.hh
src/dev/arm/gic_v3.cc
src/dev/arm/gic_v3.hh
src/dev/arm/gic_v3_cpu_interface.cc
src/dev/arm/gic_v3_cpu_interface.hh
src/dev/arm/gic_v3_redistributor.cc

index 5d261a7907ee7eefcb961d3ec40b280d3b822c8d..b03f0f5ae49a9969719cc8d539dc7b4486b1ae71 100644 (file)
@@ -214,6 +214,22 @@ ArmSystem::callClearStandByWfi(ThreadContext *tc)
         pwr_ctrl->clearStandByWfi(tc);
 }
 
+bool
+ArmSystem::callSetWakeRequest(ThreadContext *tc)
+{
+    if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
+        return pwr_ctrl->setWakeRequest(tc);
+    else
+        return true;
+}
+
+void
+ArmSystem::callClearWakeRequest(ThreadContext *tc)
+{
+    if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
+        pwr_ctrl->clearWakeRequest(tc);
+}
+
 ArmSystem *
 ArmSystemParams::create()
 {
index 364a804373c05eaeafd2221bf2fcba865def73c9..1339c1c7554b2dd52fe1c4f51aa6c274b2b7222a 100644 (file)
@@ -327,6 +327,16 @@ class ArmSystem : public System
 
     /** Make a call to notify the power controller of STANDBYWFI deassertion */
     static void callClearStandByWfi(ThreadContext *tc);
+
+    /**
+     * Notify the power controller of WAKEREQUEST assertion. Returns true
+     * if WAKEREQUEST is enabled as a power-on mechanism, and the core is now
+     * powered, false otherwise
+     */
+    static bool callSetWakeRequest(ThreadContext *tc);
+
+    /** Notify the power controller of WAKEREQUEST deassertion */
+    static void callClearWakeRequest(ThreadContext *tc);
 };
 
 #endif
index 88708bd865bbb65eb15ca4333db5d601db149f3c..a6650b893600317fea744a26027b80596e2f01fa 100644 (file)
@@ -91,6 +91,34 @@ FVPBasePwrCtrl::clearStandByWfi(ThreadContext *const tc)
     pwrs->pwfi = 0;
 }
 
+bool
+FVPBasePwrCtrl::setWakeRequest(ThreadContext *const tc)
+{
+    PwrStatus *pwrs = getCorePwrStatus(tc);
+
+    if (!pwrs->pwk)
+        DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::setWakeRequest: WakeRequest "
+                "asserted for core %d\n", tc->contextId());
+    pwrs->pwk = 1;
+    if (!pwrs->l0 && pwrs->wen) {
+        pwrs->wk = WK_GICWR;
+        powerCoreOn(tc, pwrs);
+        return true;
+    }
+    return false;
+}
+
+void
+FVPBasePwrCtrl::clearWakeRequest(ThreadContext *const tc)
+{
+    PwrStatus *pwrs = getCorePwrStatus(tc);
+
+    if (pwrs->pwk)
+        DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::clearWakeRequest: "
+                "WakeRequest deasserted for core %d\n", tc->contextId());
+    pwrs->pwk = 0;
+}
+
 Tick
 FVPBasePwrCtrl::read(PacketPtr pkt)
 {
@@ -276,6 +304,7 @@ FVPBasePwrCtrl::startCoreUp(ThreadContext *const tc)
     DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
             "from the power controller\n", tc->contextId());
     clearStandByWfi(tc);
+    clearWakeRequest(tc);
 
     // InitCPU
     Reset().invoke(tc);
index df0b686f674e666457fabd7cbab7523483d44c6d..aa446a8667d69a6fb0d6bc94a41bd05b5cc817ac 100644 (file)
@@ -51,11 +51,6 @@ class ThreadContext;
  * @file
  * This class implements the base power controller for FVP-based
  * platforms. Based on Fast Models version 11.8.
- *
- * Limitations:
- *     - Level 2 affinity is not implemented -> PSYSR.L2 is RAZ
- *     - WakeRequests are not modelled by GICv3 -> PSYSR.WEN is always 0
- *     - PSYSR.WK can only be 0b00 (Cold power-on) and 0b10 (Wake by PPONR)
  */
 class FVPBasePwrCtrl : public BasicPioDevice
 {
@@ -78,6 +73,21 @@ class FVPBasePwrCtrl : public BasicPioDevice
      */
     void clearStandByWfi(ThreadContext *const tc);
 
+    /**
+     * Triggered by the GIC when GICR_WAKER.ProcessorSleep is 1 and there are
+     * pending interrupts for the core
+     * @param tc Thread context representing the core
+     * @return true if the core is powered ON when PwrStatus.WEN is enabled,
+     * false otherwise
+     */
+    bool setWakeRequest(ThreadContext *const tc);
+
+    /**
+     * Triggered by the GIC when GICR_WAKER.ProcessorSleep becomes 0
+     * @param tc Thread context representing the core
+     */
+    void clearWakeRequest(ThreadContext *const tc);
+
     void init() override;
 
   protected:
index ede5f16ba2807b42b84dcb6353dc09f40a72fd48..2103c0e6c797699dac69ba9e627853b040ec59e1 100644 (file)
@@ -221,6 +221,18 @@ Gicv3::deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
     platform->intrctrl->clear(cpu, int_type, 0);
 }
 
+void
+Gicv3::deassertAll(uint32_t cpu)
+{
+    platform->intrctrl->clearAll(cpu);
+}
+
+bool
+Gicv3::haveAsserted(uint32_t cpu) const
+{
+    return platform->intrctrl->havePosted(cpu);
+}
+
 Gicv3Redistributor *
 Gicv3::getRedistributorByAffinity(uint32_t affinity) const
 {
index 82bd4682fffff95a0ff06627e84ce7c836433098..1df08868381bbd3ca5c3098e3d878cfb3faf2e1a 100644 (file)
@@ -129,6 +129,8 @@ class Gicv3 : public BaseGic
 
     Gicv3(const Params * p);
     void deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type);
+    void deassertAll(uint32_t cpu);
+    bool haveAsserted(uint32_t cpu) const;
 
     inline Gicv3CPUInterface *
     getCPUInterface(int cpu_id) const
index b77fd3a7bad0d2eb624f38d43d1b178efdd26e31..73bd3bc6647b89413ccb5ffbee8de69cf722e06a 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "dev/arm/gic_v3_cpu_interface.hh"
 
+#include "arch/arm/faults.hh"
 #include "arch/arm/isa.hh"
 #include "debug/GIC.hh"
 #include "dev/arm/gic_v3.hh"
@@ -2570,6 +2571,36 @@ Gicv3CPUInterface::bpr1(Gicv3::GroupId group)
     return bpr;
 }
 
+bool
+Gicv3CPUInterface::havePendingInterrupts() const
+{
+    return gic->haveAsserted(cpuId) || hppi.prio != 0xff;
+}
+
+void
+Gicv3CPUInterface::clearPendingInterrupts()
+{
+    gic->deassertAll(cpuId);
+    resetHppi(hppi.intid);
+}
+
+void
+Gicv3CPUInterface::assertWakeRequest()
+{
+    ThreadContext *tc = gic->getSystem()->getThreadContext(cpuId);
+    if (ArmSystem::callSetWakeRequest(tc)) {
+        Reset().invoke(tc);
+        tc->activate();
+    }
+}
+
+void
+Gicv3CPUInterface::deassertWakeRequest()
+{
+    ThreadContext *tc = gic->getSystem()->getThreadContext(cpuId);
+    ArmSystem::callClearWakeRequest(tc);
+}
+
 void
 Gicv3CPUInterface::serialize(CheckpointOut & cp) const
 {
index 849f551d9e1157951061b5349d27c06f86e7ed27..d1e38022ce57f41337991d78c4d640172401c4f5 100644 (file)
@@ -335,6 +335,10 @@ class Gicv3CPUInterface : public ArmISA::BaseISADevice, public Serializable
     bool virtualIsEOISplitMode() const;
     void virtualUpdate();
     RegVal bpr1(Gicv3::GroupId group);
+    bool havePendingInterrupts(void) const;
+    void clearPendingInterrupts(void);
+    void assertWakeRequest(void);
+    void deassertWakeRequest(void);
 
     RegVal readBankedMiscReg(MiscRegIndex misc_reg) const;
     void setBankedMiscReg(MiscRegIndex misc_reg, RegVal val) const;
index a9b3f93a538bb6a2121ce68d2a700b814b1ad421..7408949470b4fc13ae5075d795dcee9d95dfc456 100644 (file)
@@ -417,22 +417,25 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
       }
 
       case GICR_WAKER: // Wake Register
+      {
         if (!distributor->DS && !is_secure_access) {
             // RAZ/WI for non-secure accesses
             return;
         }
 
-        if (not peInLowPowerState and
-            (data & GICR_WAKER_ProcessorSleep)) {
+        bool pe_was_low_power = peInLowPowerState;
+        peInLowPowerState = data & GICR_WAKER_ProcessorSleep;
+        if (!pe_was_low_power && peInLowPowerState) {
             DPRINTF(GIC, "Gicv3Redistributor::write(): "
                     "PE entering in low power state\n");
-        } else if (peInLowPowerState and
-                   not(data & GICR_WAKER_ProcessorSleep)) {
+            updateDistributor();
+        } else if (pe_was_low_power && !peInLowPowerState) {
             DPRINTF(GIC, "Gicv3Redistributor::write(): powering up PE\n");
+            cpuInterface->deassertWakeRequest();
+            updateDistributor();
         }
-
-        peInLowPowerState = data & GICR_WAKER_ProcessorSleep;
         break;
+      }
 
       case GICR_IGROUPR0: // Interrupt Group Register 0
         if (!distributor->DS && !is_secure_access) {
@@ -850,7 +853,14 @@ Gicv3Redistributor::update()
         }
     }
 
-    cpuInterface->update();
+    if (peInLowPowerState) {
+        if (cpuInterface->havePendingInterrupts()) {
+            cpuInterface->assertWakeRequest();
+            cpuInterface->clearPendingInterrupts();
+        }
+    } else {
+        cpuInterface->update();
+    }
 }
 
 uint8_t