monitor: Fill in EpowPowerOff action
This action does the following:
1) Starts a service mode timer, which would allow the system to be
serviced before anything happens.
2) On the expiration of that timer, it will:
a) Set the thermal fault alert D-Bus property. This will be used
to send an EPOW alert to the host on IBM systems.
b) Start the meltdown timer.
3) On the expiration of the meltdown timer, a hard power off will
occur. This timer cannot be canceled even if fans start behaving.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I9434699b816b23b68c6d9d1e97283b4ab9befe4f
diff --git a/monitor/power_interface.hpp b/monitor/power_interface.hpp
index 1a339c5..e0a802d 100644
--- a/monitor/power_interface.hpp
+++ b/monitor/power_interface.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "types.hpp"
+
namespace phosphor::fan::monitor
{
@@ -28,6 +30,13 @@
* @brief Perform a hard power off
*/
virtual void hardPowerOff() = 0;
+
+ /**
+ * @brief Sets the thermal alert D-Bus property
+ *
+ * @param[in] alert - The alert value
+ */
+ virtual void thermalAlert(bool alert) = 0;
};
/**
@@ -38,7 +47,7 @@
class PowerInterface : public PowerInterfaceBase
{
public:
- PowerInterface() = default;
+ PowerInterface() = delete;
~PowerInterface() = default;
PowerInterface(const PowerInterface&) = delete;
PowerInterface& operator=(const PowerInterface&) = delete;
@@ -46,6 +55,15 @@
PowerInterface& operator=(PowerInterface&&) = delete;
/**
+ * @brief Constructor
+ *
+ * @param[in] ThermalAlertObject& - The thermal alert D-Bus object
+ */
+ explicit PowerInterface(ThermalAlertObject& alertObject) :
+ _alert(alertObject)
+ {}
+
+ /**
* @brief Perform a soft power off
*/
void softPowerOff() override;
@@ -54,6 +72,22 @@
* @brief Perform a hard power off
*/
void hardPowerOff() override;
+
+ /**
+ * @brief Sets the thermal alert D-Bus property
+ *
+ * @param[in] alert - The alert value
+ */
+ void thermalAlert(bool alert) override
+ {
+ _alert.enabled(alert);
+ }
+
+ private:
+ /**
+ * @brief Reference to the thermal alert D-Bus object
+ */
+ ThermalAlertObject& _alert;
};
} // namespace phosphor::fan::monitor
diff --git a/monitor/power_off_action.hpp b/monitor/power_off_action.hpp
index f815a3b..f0e7531 100644
--- a/monitor/power_off_action.hpp
+++ b/monitor/power_off_action.hpp
@@ -302,9 +302,14 @@
/**
* @class EpowPowerOff
*
- * Still TODO, but has a cancelable service mode delay followed
- * by an uncancelable meltdown delay followed by a hard power off, with
- * some sort of EPOW alert in there as well.
+ * This class is derived from the PowerOffAction class and does the following:
+ * 1) On start, the service mode timer is started. This timer can be
+ * canceled if the cause is no longer satisfied (fans work again).
+ * 2) When this timer expires:
+ * a) The thermal alert D-Bus property is set, this can be used as
+ * an EPOW alert to the host that a power off is imminent.
+ * b) The meltdown timer is started. This timer cannot be canceled,
+ * and on expiration a hard power off occurs.
*/
class EpowPowerOff : public PowerOffAction
{
@@ -316,28 +321,133 @@
EpowPowerOff(EpowPowerOff&&) = delete;
EpowPowerOff& operator=(EpowPowerOff&&) = delete;
+ /**
+ * @brief Constructor
+ *
+ * @param[in] serviceModeDelay - The service mode timeout.
+ * @param[in] meltdownDelay - The meltdown delay timeout.
+ * @param[in] powerInterface - The object to use to do the power off
+ * @param[in] func - A function to call right before the power
+ * off occurs (after the delay). May be
+ * empty if no function is necessary.
+ */
EpowPowerOff(uint32_t serviceModeDelay, uint32_t meltdownDelay,
std::shared_ptr<PowerInterfaceBase> powerInterface,
PrePowerOffFunc func) :
PowerOffAction("EPOW Power Off: " + std::to_string(serviceModeDelay) +
"s/" + std::to_string(meltdownDelay) + "s",
powerInterface, func),
- _serviceModeDelay(serviceModeDelay), _meltdownDelay(meltdownDelay)
+ _serviceModeDelay(serviceModeDelay), _meltdownDelay(meltdownDelay),
+ _serviceModeTimer(
+ _event,
+ std::bind(std::mem_fn(&EpowPowerOff::serviceModeTimerExpired),
+ this)),
+ _meltdownTimer(
+ _event,
+ std::bind(std::mem_fn(&EpowPowerOff::meltdownTimerExpired), this))
{}
+ /**
+ * @brief Starts the service mode timer.
+ */
void start() override
{
- // TODO
+ getLogger().log(
+ fmt::format("Action {}: Starting service mode timer", name()));
+
+ _serviceModeTimer.restartOnce(_serviceModeDelay);
}
- bool cancel(bool) override
+ /**
+ * @brief Called when the service mode timer expires.
+ *
+ * Sets the thermal alert D-Bus property and starts the
+ * meltdown timer.
+ */
+ void serviceModeTimerExpired()
{
- // TODO
+ getLogger().log(fmt::format(
+ "Action {}: Service mode timer expired, starting meltdown timer",
+ name()));
+
+ _powerIface->thermalAlert(true);
+ _meltdownTimer.restartOnce(_meltdownDelay);
+ }
+
+ /**
+ * @brief Called when the meltdown timer expires.
+ *
+ * Executes a hard power off.
+ */
+ void meltdownTimerExpired()
+ {
+ getLogger().log(fmt::format(
+ "Action {}: Meltdown timer expired, executing hard power off",
+ name()));
+
+ if (_prePowerOffFunc)
+ {
+ _prePowerOffFunc();
+ }
+
+ _powerIface->hardPowerOff();
+ }
+
+ /**
+ * @brief Attempts to cancel the action
+ *
+ * The service mode timer can be canceled. The meltdown
+ * timer cannot.
+ *
+ * @param[in] force - To force the cancel (like if the
+ * system powers off).
+ *
+ * @return bool - If the cancel was successful
+ */
+ bool cancel(bool force) override
+ {
+ if (_serviceModeTimer.isEnabled())
+ {
+ _serviceModeTimer.setEnabled(false);
+ }
+
+ if (_meltdownTimer.isEnabled())
+ {
+ if (force)
+ {
+ _meltdownTimer.setEnabled(false);
+ }
+ else
+ {
+ getLogger().log("Cannot cancel running meltdown timer");
+ return false;
+ }
+ }
return true;
}
private:
+ /**
+ * @brief The number of seconds to wait until starting the uncancelable
+ * meltdown timer.
+ */
std::chrono::seconds _serviceModeDelay;
+
+ /**
+ * @brief The number of seconds to wait after the service mode
+ * timer expires before a hard power off will occur.
+ */
std::chrono::seconds _meltdownDelay;
+
+ /**
+ * @brief The service mode timer.
+ */
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>
+ _serviceModeTimer;
+
+ /**
+ * @brief The meltdown timer.
+ */
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _meltdownTimer;
};
} // namespace phosphor::fan::monitor
diff --git a/monitor/system.cpp b/monitor/system.cpp
index dbb9b73..4c30f9f 100644
--- a/monitor/system.cpp
+++ b/monitor/system.cpp
@@ -189,7 +189,7 @@
{
#ifdef MONITOR_USE_JSON
std::shared_ptr<PowerInterfaceBase> powerInterface =
- std::make_shared<PowerInterface>();
+ std::make_shared<PowerInterface>(_thermalAlert);
PowerOffAction::PrePowerOffFunc func =
std::bind(std::mem_fn(&System::logShutdownError), this);
diff --git a/monitor/test/mock_power_interface.hpp b/monitor/test/mock_power_interface.hpp
index c070182..6801751 100644
--- a/monitor/test/mock_power_interface.hpp
+++ b/monitor/test/mock_power_interface.hpp
@@ -12,6 +12,7 @@
public:
MOCK_METHOD(void, softPowerOff, (), (override));
MOCK_METHOD(void, hardPowerOff, (), (override));
+ MOCK_METHOD(void, thermalAlert, (bool), (override));
};
} // namespace phosphor::fan::monitor