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()
{
/** 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
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)
{
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
"from the power controller\n", tc->contextId());
clearStandByWfi(tc);
+ clearWakeRequest(tc);
// InitCPU
Reset().invoke(tc);
* @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
{
*/
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:
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
{
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
#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"
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
{
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;
}
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) {
}
}
- cpuInterface->update();
+ if (peInLowPowerState) {
+ if (cpuInterface->havePendingInterrupts()) {
+ cpuInterface->assertWakeRequest();
+ cpuInterface->clearPendingInterrupts();
+ }
+ } else {
+ cpuInterface->update();
+ }
}
uint8_t