dev-arm: add FVP Base Power Controller model
authorAdrian Herrera <adrian.herrera@arm.com>
Fri, 25 Oct 2019 09:49:23 +0000 (10:49 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 12 Mar 2020 14:28:22 +0000 (14:28 +0000)
This is a reduced model of the FVP Base platforms Power Controller.
As of now it allows the following functions from software:
- Checking for core presence
- Reporting the power state of a core / cluster
- Explicitly powering off a core on WFI
- Explicitly powering off cores in a CPU cluster on WFI
- Explicitly powering on a core through writes to PPONR register

Change-Id: Ia1d4d3ae8e4bfb2d23b2c6077396a4d8500e2e30
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26463
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/isa/insts/misc.isa
src/arch/arm/system.cc
src/arch/arm/system.hh
src/dev/arm/RealView.py
src/dev/arm/SConscript
src/dev/arm/fvp_base_pwr_ctrl.cc [new file with mode: 0644]
src/dev/arm/fvp_base_pwr_ctrl.hh [new file with mode: 0644]
src/dev/arm/gic_v3.cc

index 0c6fdc31a521bd5dac5e25ce3171115a902733f5..03401ca3258460bde2a05fe086d01269fcae3cc7 100644 (file)
@@ -762,6 +762,7 @@ let {{
         fault = trapWFx(tc, cpsr, scr, false);
         if (fault == NoFault) {
             PseudoInst::quiesce(tc);
+            ArmSystem::callSetStandByWfi(tc);
         } else {
             PseudoInst::quiesceSkip(tc);
         }
index 6ecc75a6a1f767a5d12bb91a84642b16e382afd8..9053a5c7d06fae8814ce656126ea92ffb93be214 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited
+ * Copyright (c) 2010, 2012-2013, 2015,2017-2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -47,6 +47,7 @@
 #include "base/loader/object_file.hh"
 #include "base/loader/symtab.hh"
 #include "cpu/thread_context.hh"
+#include "dev/arm/fvp_base_pwr_ctrl.hh"
 #include "dev/arm/gic_v2.hh"
 #include "mem/fs_translating_port_proxy.hh"
 #include "mem/physical.hh"
@@ -62,6 +63,7 @@ ArmSystem::ArmSystem(Params *p)
       _haveCrypto(p->have_crypto),
       _genericTimer(nullptr),
       _gic(nullptr),
+      _pwrCtrl(nullptr),
       _highestELIs64(p->highest_el_is_64),
       _physAddrRange64(p->phys_addr_range_64),
       _haveLargeAsid64(p->have_large_asid_64),
@@ -197,6 +199,20 @@ ArmSystem::callSemihosting32(ThreadContext *tc,
     return sys->semihosting->call32(tc, op, param);
 }
 
+void
+ArmSystem::callSetStandByWfi(ThreadContext *tc)
+{
+    if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
+        pwr_ctrl->setStandByWfi(tc);
+}
+
+void
+ArmSystem::callClearStandByWfi(ThreadContext *tc)
+{
+    if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
+        pwr_ctrl->clearStandByWfi(tc);
+}
+
 ArmSystem *
 ArmSystemParams::create()
 {
index 0c75ad51d9bb5a1a585379e2587b06c8c4f19e38..d9268f09393f4f1827845d25ab0393a33abcc37f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2013, 2015-2019 ARM Limited
+ * Copyright (c) 2010, 2012-2013, 2015-2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -53,6 +53,7 @@
 
 class GenericTimer;
 class BaseGic;
+class FVPBasePwrCtrl;
 class ThreadContext;
 
 class ArmSystem : public System
@@ -84,6 +85,11 @@ class ArmSystem : public System
     GenericTimer *_genericTimer;
     BaseGic *_gic;
 
+    /**
+     * Pointer to the Power Controller (if any)
+     */
+    FVPBasePwrCtrl *_pwrCtrl;
+
     /**
      * Reset address (ARMv8)
      */
@@ -175,12 +181,21 @@ class ArmSystem : public System
     /** Sets the pointer to the GIC. */
     void setGIC(BaseGic *gic) { _gic = gic; }
 
+    /** Sets the pointer to the Power Controller */
+    void setPowerController(FVPBasePwrCtrl *pwr_ctrl)
+    {
+        _pwrCtrl = pwr_ctrl;
+    }
+
     /** Get a pointer to the system's generic timer model */
     GenericTimer *getGenericTimer() const { return _genericTimer; }
 
     /** Get a pointer to the system's GIC */
     BaseGic *getGIC() const { return _gic; }
 
+    /** Get a pointer to the system's power controller */
+    FVPBasePwrCtrl *getPowerController() const { return _pwrCtrl; }
+
     /** Returns true if the register width of the highest implemented exception
      * level is 64 bits (ARMv8) */
     bool highestELIs64() const { return _highestELIs64; }
@@ -305,6 +320,12 @@ class ArmSystem : public System
     /** Make a Semihosting call from aarch32 */
     static uint32_t callSemihosting32(ThreadContext *tc,
                                       uint32_t op, uint32_t param);
+
+    /** Make a call to notify the power controller of STANDBYWFI assertion */
+    static void callSetStandByWfi(ThreadContext *tc);
+
+    /** Make a call to notify the power controller of STANDBYWFI deassertion */
+    static void callClearStandByWfi(ThreadContext *tc);
 };
 
 #endif
index 68a69d3ff6577d7425cabd8e4c862899dc3fa5c4..40ed4684ec4c2cc1fb3d1a34b023ac1e35dfd415 100644 (file)
@@ -1159,3 +1159,14 @@ class VExpress_GEM5_V2(VExpress_GEM5_V2_Base):
         return super(VExpress_GEM5_V2,self)._on_chip_devices() + [
                 self.hdlcd,
             ]
+
+class FVPBasePwrCtrl(BasicPioDevice):
+    """
+Based on Fast Models Base_PowerController v11.8
+Reference:
+    Fast Models Reference Manual - Section 7.7.2 - Version 11.8
+    Document ID: 100964_1180_00_en
+    """
+
+    type = 'FVPBasePwrCtrl'
+    cxx_header = 'dev/arm/fvp_base_pwr_ctrl.hh'
index b264d05cfdb3b123de155f9eb5694668da211cb3..de5f8b74efdb0f1e83761e8582f46a9fa476c711 100644 (file)
@@ -1,6 +1,6 @@
 # -*- mode:python -*-
 
-# Copyright (c) 2009, 2012-2013 ARM Limited
+# Copyright (c) 2009, 2012-2013, 2020 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -92,6 +92,7 @@ if env['TARGET_ISA'] == 'arm':
     Source('vio_mmio.cc')
     Source('ufs_device.cc')
     Source('energy_ctrl.cc')
+    Source('fvp_base_pwr_ctrl.cc')
 
     DebugFlag('AMBA')
     DebugFlag('FlashDevice')
@@ -106,6 +107,7 @@ if env['TARGET_ISA'] == 'arm':
     DebugFlag('SMMUv3Hazard')
     DebugFlag('Sp805')
     DebugFlag('EnergyCtrl')
+    DebugFlag('FVPBasePwrCtrl')
     DebugFlag('UFSHostDevice')
     DebugFlag('VGIC')
     DebugFlag('NoMali')
diff --git a/src/dev/arm/fvp_base_pwr_ctrl.cc b/src/dev/arm/fvp_base_pwr_ctrl.cc
new file mode 100644 (file)
index 0000000..88708bd
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dev/arm/fvp_base_pwr_ctrl.hh"
+
+#include "arch/arm/faults.hh"
+#include "arch/arm/system.hh"
+#include "arch/arm/utility.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "debug/FVPBasePwrCtrl.hh"
+#include "mem/packet_access.hh"
+#include "params/FVPBasePwrCtrl.hh"
+#include "sim/system.hh"
+
+FVPBasePwrCtrl::FVPBasePwrCtrl(FVPBasePwrCtrlParams *const params)
+    : BasicPioDevice(params, 0x1000),
+      regs(),
+      system(*static_cast<ArmSystem *>(sys))
+{
+    warn_if(sys->multiThread,
+            "Base Power Controller does not support multi-threaded systems\n");
+    system.setPowerController(this);
+}
+
+void
+FVPBasePwrCtrl::init()
+{
+    // All cores are ON by default (PwrStatus.{l0,l1} = 0b1)
+    corePwrStatus.resize(sys->numContexts(), 0x60000000);
+    for (const auto &tc : sys->threadContexts)
+        poweredCoresPerCluster[tc->socketId()] += 1;
+    BasicPioDevice::init();
+}
+
+void
+FVPBasePwrCtrl::setStandByWfi(ThreadContext *const tc)
+{
+    PwrStatus *pwrs = getCorePwrStatus(tc);
+
+    if (!pwrs->pwfi)
+        DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::setStandByWfi: STANDBYWFI "
+                "asserted for core %d\n", tc->contextId());
+    pwrs->pwfi = 1;
+    if (pwrs->l0 && (pwrs->pp || pwrs->pc))
+        powerCoreOff(tc, pwrs);
+}
+
+void
+FVPBasePwrCtrl::clearStandByWfi(ThreadContext *const tc)
+{
+    PwrStatus *pwrs = getCorePwrStatus(tc);
+
+    if (pwrs->pwfi)
+        DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::clearStandByWfi: STANDBYWFI "
+                "deasserted for core %d\n", tc->contextId());
+    pwrs->pwfi = 0;
+}
+
+Tick
+FVPBasePwrCtrl::read(PacketPtr pkt)
+{
+    const Addr addr = pkt->getAddr() - pioAddr;
+    const size_t size = pkt->getSize();
+    panic_if(size != 4, "FVPBasePwrCtrl::read: Invalid size %i\n", size);
+
+    uint64_t resp = 0;
+    switch (addr) {
+      case PPOFFR:
+        resp = regs.ppoffr;
+        break;
+      case PPONR:
+        resp = regs.pponr;
+        break;
+      case PCOFFR:
+        resp = regs.pcoffr;
+        break;
+      case PWKUPR:
+        resp = regs.pwkupr;
+        break;
+      case PSYSR:
+        resp = regs.psysr;
+        break;
+      default:
+        warn("FVPBasePwrCtrl::read: Unexpected address (0x%x:%i), "
+             "assuming RAZ\n", addr, size);
+    }
+
+    DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::read: 0x%x<-0x%x(%i)\n", resp,
+            addr, size);
+
+    pkt->setUintX(resp, LittleEndianByteOrder);
+    pkt->makeResponse();
+    return pioDelay;
+}
+
+Tick
+FVPBasePwrCtrl::write(PacketPtr pkt)
+{
+    const Addr addr = pkt->getAddr() - pioAddr;
+    const size_t size = pkt->getSize();
+    panic_if(size != 4, "FVPBasePwrCtrl::write: Invalid size %i\n", size);
+
+    uint64_t data = pkt->getUintX(LittleEndianByteOrder);
+
+    // Software may use the power controller to check for core presence
+    // If core is not present, return an invalid MPID as notification
+    ThreadContext *tc = getThreadContextByMPID(data & MPID_MSK);
+    PwrStatus *pwrs = tc ? getCorePwrStatus(tc) : nullptr;
+    switch (addr) {
+      case PPOFFR:
+        if (!tc) {
+            regs.ppoffr = ~0;
+        } else if (pwrs->l0) {
+            // Set pending power off
+            pwrs->pp = 1;
+            regs.ppoffr = data & MPID_MSK;
+        } else {
+            regs.ppoffr = ~0 & MPID_MSK;
+        }
+        break;
+      case PPONR:
+        if (!tc) {
+            regs.pponr = ~0;
+        } else {
+            if (!pwrs->l0) {
+                pwrs->wk = WK_PPONR;
+                powerCoreOn(tc, pwrs);
+                startCoreUp(tc);
+                regs.pponr = data & MPID_MSK;
+            } else {
+                regs.pponr = ~0 & MPID_MSK;
+            }
+        }
+        break;
+      case PCOFFR:
+        if (!tc) {
+            regs.pcoffr = ~0;
+        } else if (pwrs->l0) {
+            // Power off all cores in the cluster
+            for (const auto &tco : sys->threadContexts) {
+                if (tc->socketId() == tco->socketId()) {
+                    PwrStatus *npwrs = getCorePwrStatus(tco);
+                    // Set pending cluster power off
+                    npwrs->pc = 1;
+                    if (npwrs->l0 && npwrs->pwfi)
+                        powerCoreOff(tco, npwrs);
+                }
+            }
+        } else {
+            regs.pcoffr = ~0 & MPID_MSK;
+        }
+        break;
+      case PWKUPR:
+        if (!tc) {
+            regs.pwkupr = ~0;
+        } else {
+            // Update WEN value
+            pwrs->wen = bits(data, 31);
+            // Power-on if there is any pending Wakeup Requests
+            if (!pwrs->l0 && pwrs->wen && pwrs->pwk) {
+                pwrs->wk = WK_GICWR;
+                powerCoreOn(tc, pwrs);
+                startCoreUp(tc);
+            }
+            regs.pwkupr = data & (MPID_MSK | (1 << 31));
+        }
+        break;
+      case PSYSR:
+        if (!tc)
+            regs.psysr = ~0;
+        else
+            regs.psysr = (data & MPID_MSK) | (((uint32_t) *pwrs) & ~MPID_MSK);
+        break;
+      default:
+        warn("FVPBasePwrCtrl::write: Unexpected address (0x%x:%i), "
+             "assuming WI\n", addr, size);
+    }
+
+    DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::write: 0x%x->0x%x(%i)\n", data,
+            addr, size);
+
+    pkt->makeResponse();
+    return pioDelay;
+}
+
+FVPBasePwrCtrl::PwrStatus *
+FVPBasePwrCtrl::getCorePwrStatus(ThreadContext *const tc)
+{
+    PwrStatus *pwrs = &corePwrStatus[tc->contextId()];
+    pwrs->l1 = poweredCoresPerCluster[tc->socketId()] > 0;
+    return pwrs;
+}
+
+ThreadContext *
+FVPBasePwrCtrl::getThreadContextByMPID(uint32_t mpid) const
+{
+    for (auto &tc : sys->threadContexts) {
+        if (mpid == ArmISA::getAffinity(&system, tc))
+            return tc;
+    }
+    return nullptr;
+}
+
+void
+FVPBasePwrCtrl::powerCoreOn(ThreadContext *const tc, PwrStatus *const pwrs)
+{
+    DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOn: Powering ON "
+            "core %d\n", tc->contextId());
+    pwrs->l0 = 1;
+    poweredCoresPerCluster[tc->socketId()]++;
+    // Clear pending power-offs to the core
+    pwrs->pp = 0;
+    // Clear pending power-offs to the core's cluster
+    for (const auto &tco : sys->threadContexts) {
+        if (tc->socketId() == tco->socketId()) {
+            PwrStatus *npwrs = getCorePwrStatus(tco);
+            npwrs->pc = 0;
+        }
+    }
+    tc->getCpuPtr()->pwrState(Enums::PwrState::ON);
+}
+
+void
+FVPBasePwrCtrl::powerCoreOff(ThreadContext *const tc, PwrStatus *const pwrs)
+{
+    DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOff: Powering OFF "
+            "core %d\n", tc->contextId());
+    pwrs->l0 = 0;
+    poweredCoresPerCluster[tc->socketId()]--;
+    // Clear pending power-offs to the core
+    pwrs->pp = 0;
+    pwrs->pc = 0;
+    // Clear power-on reason
+    pwrs->wk = 0;
+    tc->getCpuPtr()->pwrState(Enums::PwrState::OFF);
+}
+
+void
+FVPBasePwrCtrl::startCoreUp(ThreadContext *const tc)
+{
+    DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
+            "from the power controller\n", tc->contextId());
+    clearStandByWfi(tc);
+
+    // InitCPU
+    Reset().invoke(tc);
+    tc->activate();
+}
+
+FVPBasePwrCtrl *
+FVPBasePwrCtrlParams::create()
+{
+    return new FVPBasePwrCtrl(this);
+}
diff --git a/src/dev/arm/fvp_base_pwr_ctrl.hh b/src/dev/arm/fvp_base_pwr_ctrl.hh
new file mode 100644 (file)
index 0000000..df0b686
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
+#define __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
+
+#include <unordered_map>
+
+#include "base/bitunion.hh"
+#include "dev/io_device.hh"
+
+class ArmSystem;
+class FVPBasePwrCtrlParams;
+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
+{
+  public:
+    FVPBasePwrCtrl(FVPBasePwrCtrlParams *const params);
+
+    /**
+     * Triggered by the ISA when a WFI instruction is executed and (1) there
+     * are no pending interrupts and (2) it is not trapped. Core is set
+     * to quiescent state only if there is a pending power off
+     * @param tc Thread context representing the core
+     */
+    void setStandByWfi(ThreadContext *const tc);
+
+    /**
+     * Triggered when an interrupt is posted to the core. Core is brought up
+     * from quiescent state if it is suspended. The latter is done by
+     * BaseCPU::wakeup.
+     * @param tc Thread context representing the core
+     */
+    void clearStandByWfi(ThreadContext *const tc);
+
+    void init() override;
+
+  protected:
+    Tick read(PacketPtr pkt) override;
+    Tick write(PacketPtr pkt) override;
+
+  private:
+    BitUnion32(PwrStatus)
+        Bitfield<30> l1;
+        Bitfield<29> l0;
+        Bitfield<28> wen;
+        Bitfield<27> pc;
+        Bitfield<26> pp;
+        Bitfield<25,24> wk;
+        Bitfield<1> pwfi;
+        Bitfield<0> pwk;
+    EndBitUnion(PwrStatus)
+
+    enum Offset : Addr {
+        PPOFFR = 0x00,
+        PPONR  = 0x04,
+        PCOFFR = 0x08,
+        PWKUPR = 0x0c,
+        PSYSR  = 0x10
+    };
+
+    struct Registers {
+        uint32_t ppoffr;
+        uint32_t pponr;
+        uint32_t pcoffr;
+        uint32_t pwkupr;
+        uint32_t psysr;
+    } regs;
+
+    /** Mask for extracting the MPID from a 32-bit value */
+    static constexpr uint32_t MPID_MSK = 0x00ffffff;
+    /** Wake-up reasons */
+    enum { WK_COLD, WK_RESET, WK_PPONR, WK_GICWR };
+
+    /**
+     * Per-core power status. This is power related information for each core
+     * that is bound to this power controller functionality
+     */
+    std::vector<PwrStatus> corePwrStatus;
+
+    /** Number of powered cores per cluster. Helps keep track of PSYSR.L1 */
+    std::unordered_map<uint32_t, size_t> poweredCoresPerCluster;
+
+    /**
+     * Retrieves the power status of a certain core and resizes the entries
+     * if needed. This is a workaround for a limitation of the System object
+     * only exposing existing thread contexts after "init()"
+     * @param Thread (HW) context in the core
+     * @return Core power status
+     */
+    PwrStatus *getCorePwrStatus(ThreadContext *const tc);
+
+    /**
+     * Retrieves the thread context reference for a CPU core by MPID
+     * @param mpid ID provided by software
+     * @return valid thread context reference if valid MPID, nullptr otherwise
+     */
+    ThreadContext *getThreadContextByMPID(uint32_t mpid) const;
+
+    /**
+     * Powers on a core. A Reset fault is invoked in the core followed by
+     * an activation
+     * @param Thread (HW) context in the core
+     * @param Core power status
+     */
+    void powerCoreOn(ThreadContext *const tc, PwrStatus *const pwrs);
+
+    /**
+     * Powers off a core. The core enters into quiescent state until
+     * an explicit PPONR write or a WakeRequest from the GIC wakes it up
+     * @param Thread (HW) context in the core
+     * @param Core power status
+     */
+    void powerCoreOff(ThreadContext *const tc, PwrStatus *const pwrs);
+
+    /**
+     * Starts a core up. This invokes the reset vector to setup the wake-up
+     * entrypoint and activates the thread context. This covers cases when
+     * PSYSR.WEN is enabled or PPONR is written
+     * @param Thread (HW) context in the core
+     */
+    void startCoreUp(ThreadContext *const tc);
+
+    /** Reference to the arm system */
+    ArmSystem &system;
+};
+
+#endif // __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
index 3607f4f984d9e67b352d8e64c803d1febe0c1a09..ede5f16ba2807b42b84dcb6353dc09f40a72fd48 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
@@ -205,6 +205,7 @@ void
 Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
 {
     platform->intrctrl->post(cpu, int_type, 0);
+    ArmSystem::callClearStandByWfi(sys->getThreadContext(cpu));
 }
 
 bool