arch-arm, dev-arm: WakeRequest implementation

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>
This commit is contained in:
Adrian Herrera
2019-12-09 20:13:55 +00:00
committed by Giacomo Travaglini
parent 4122649122
commit 9bcffd1e29
9 changed files with 136 additions and 12 deletions

View 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()
{

View 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

View 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);

View 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:

View 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
{

View 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

View 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
{

View 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;

View 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