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:
committed by
Giacomo Travaglini
parent
4122649122
commit
9bcffd1e29
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user