From 9bcffd1e29087c664ac70dbea48eacf148f2078b Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Mon, 9 Dec 2019 20:13:55 +0000 Subject: [PATCH] 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 Reviewed-by: Nikos Nikoleris Maintainer: Nikos Nikoleris --- src/arch/arm/system.cc | 16 +++++++++++++++ src/arch/arm/system.hh | 10 ++++++++++ src/dev/arm/fvp_base_pwr_ctrl.cc | 29 +++++++++++++++++++++++++++ src/dev/arm/fvp_base_pwr_ctrl.hh | 20 ++++++++++++++----- src/dev/arm/gic_v3.cc | 12 +++++++++++ src/dev/arm/gic_v3.hh | 2 ++ src/dev/arm/gic_v3_cpu_interface.cc | 31 +++++++++++++++++++++++++++++ src/dev/arm/gic_v3_cpu_interface.hh | 4 ++++ src/dev/arm/gic_v3_redistributor.cc | 24 +++++++++++++++------- 9 files changed, 136 insertions(+), 12 deletions(-) diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc index 5d261a790..b03f0f5ae 100644 --- a/src/arch/arm/system.cc +++ b/src/arch/arm/system.cc @@ -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() { diff --git a/src/arch/arm/system.hh b/src/arch/arm/system.hh index 364a80437..1339c1c75 100644 --- a/src/arch/arm/system.hh +++ b/src/arch/arm/system.hh @@ -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 diff --git a/src/dev/arm/fvp_base_pwr_ctrl.cc b/src/dev/arm/fvp_base_pwr_ctrl.cc index 88708bd86..a6650b893 100644 --- a/src/dev/arm/fvp_base_pwr_ctrl.cc +++ b/src/dev/arm/fvp_base_pwr_ctrl.cc @@ -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); diff --git a/src/dev/arm/fvp_base_pwr_ctrl.hh b/src/dev/arm/fvp_base_pwr_ctrl.hh index df0b686f6..aa446a866 100644 --- a/src/dev/arm/fvp_base_pwr_ctrl.hh +++ b/src/dev/arm/fvp_base_pwr_ctrl.hh @@ -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: diff --git a/src/dev/arm/gic_v3.cc b/src/dev/arm/gic_v3.cc index ede5f16ba..2103c0e6c 100644 --- a/src/dev/arm/gic_v3.cc +++ b/src/dev/arm/gic_v3.cc @@ -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 { diff --git a/src/dev/arm/gic_v3.hh b/src/dev/arm/gic_v3.hh index 82bd4682f..1df088683 100644 --- a/src/dev/arm/gic_v3.hh +++ b/src/dev/arm/gic_v3.hh @@ -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 diff --git a/src/dev/arm/gic_v3_cpu_interface.cc b/src/dev/arm/gic_v3_cpu_interface.cc index b77fd3a7b..73bd3bc66 100644 --- a/src/dev/arm/gic_v3_cpu_interface.cc +++ b/src/dev/arm/gic_v3_cpu_interface.cc @@ -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 { diff --git a/src/dev/arm/gic_v3_cpu_interface.hh b/src/dev/arm/gic_v3_cpu_interface.hh index 849f551d9..d1e38022c 100644 --- a/src/dev/arm/gic_v3_cpu_interface.hh +++ b/src/dev/arm/gic_v3_cpu_interface.hh @@ -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; diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc index a9b3f93a5..740894947 100644 --- a/src/dev/arm/gic_v3_redistributor.cc +++ b/src/dev/arm/gic_v3_redistributor.cc @@ -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 -- 2.30.2