Initial commit
This commit is contained in:
+350
@@ -0,0 +1,350 @@
|
||||
From 84f3e76efb5ecba117bea7b0ad477c92042c9829 Mon Sep 17 00:00:00 2001
|
||||
From: James Feist <james.feist@linux.intel.com>
|
||||
Date: Mon, 17 Jun 2019 12:00:58 -0700
|
||||
Subject: [PATCH] Customize phosphor-watchdog for Intel platforms
|
||||
|
||||
This patch adds various changes to phosphor-watchdog that are
|
||||
required for compatibility with Intel platforms.
|
||||
|
||||
1. Add Redfish messages for watchdog timeout and pre-interrupt
|
||||
2. Use dbus properties for power control insted of service files
|
||||
3. Use host status to enable/disable watchdog
|
||||
4. Set preTimeoutInterruptOccurFlag
|
||||
5. Assign watchdog cause for correct reset cause reporting
|
||||
6. Add NMI Pre-Interrupt support for IPMI watchdog timer.
|
||||
|
||||
Signed-off-by: James Feist <james.feist@linux.intel.com>
|
||||
Signed-off-by: Ren Yu <yux.ren@intel.com>
|
||||
Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
|
||||
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
|
||||
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
|
||||
Signed-off-by: Sunita Kumari <sunitax.kumari@intel.com>
|
||||
Upstream-Status: Pending
|
||||
---
|
||||
src/watchdog.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++++---
|
||||
src/watchdog.hpp | 23 ++++-
|
||||
2 files changed, 242 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/src/watchdog.cpp b/src/watchdog.cpp
|
||||
index 90a840e..ae9f4e3 100644
|
||||
--- a/src/watchdog.cpp
|
||||
+++ b/src/watchdog.cpp
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "watchdog.hpp"
|
||||
|
||||
+#include <systemd/sd-journal.h>
|
||||
+
|
||||
#include <phosphor-logging/elog.hpp>
|
||||
#include <phosphor-logging/log.hpp>
|
||||
#include <sdbusplus/exception.hpp>
|
||||
#include <xyz/openbmc_project/Common/error.hpp>
|
||||
+#include <xyz/openbmc_project/State/Host/server.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
@@ -19,10 +22,86 @@ using namespace phosphor::logging;
|
||||
|
||||
using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
|
||||
|
||||
-// systemd service to kick start a target.
|
||||
-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
|
||||
-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
|
||||
-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
|
||||
+const static constexpr char* currentHostState = "CurrentHostState";
|
||||
+const static constexpr char* hostStatusOff =
|
||||
+ "xyz.openbmc_project.State.Host.HostState.Off";
|
||||
+
|
||||
+const static constexpr char* actionDescription = " due to Watchdog timeout";
|
||||
+const static constexpr char* hardResetDescription = "Hard Reset - System reset";
|
||||
+const static constexpr char* powerOffDescription =
|
||||
+ "Power Down - System power down";
|
||||
+const static constexpr char* powerCycleDescription =
|
||||
+ "Power Cycle - System power cycle";
|
||||
+const static constexpr char* timerExpiredDescription = "Timer expired";
|
||||
+
|
||||
+const static constexpr char* preInterruptActionNone =
|
||||
+ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None";
|
||||
+
|
||||
+const static constexpr char* preInterruptDescriptionSMI = "SMI";
|
||||
+const static constexpr char* preInterruptDescriptionNMI = "NMI";
|
||||
+const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt";
|
||||
+
|
||||
+const static constexpr char* reservedDescription = "Reserved";
|
||||
+
|
||||
+const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2";
|
||||
+const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST";
|
||||
+const static constexpr char* timerUseDescriptionOSLoad = "OSLoad";
|
||||
+const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS";
|
||||
+const static constexpr char* timerUseDescriptionOEM = "OEM";
|
||||
+
|
||||
+namespace restart
|
||||
+{
|
||||
+static constexpr const char* busName =
|
||||
+ "xyz.openbmc_project.Control.Host.RestartCause";
|
||||
+static constexpr const char* path =
|
||||
+ "/xyz/openbmc_project/control/host0/restart_cause";
|
||||
+static constexpr const char* interface =
|
||||
+ "xyz.openbmc_project.Control.Host.RestartCause";
|
||||
+static constexpr const char* property = "RequestedRestartCause";
|
||||
+} // namespace restart
|
||||
+
|
||||
+// chassis state manager service
|
||||
+namespace chassis
|
||||
+{
|
||||
+static constexpr const char* busName = "xyz.openbmc_project.State.Chassis";
|
||||
+static constexpr const char* path = "/xyz/openbmc_project/state/chassis0";
|
||||
+static constexpr const char* interface = "xyz.openbmc_project.State.Chassis";
|
||||
+static constexpr const char* request = "RequestedPowerTransition";
|
||||
+} // namespace chassis
|
||||
+
|
||||
+namespace host
|
||||
+{
|
||||
+static constexpr const char* busName = "xyz.openbmc_project.State.Host";
|
||||
+static constexpr const char* path = "/xyz/openbmc_project/state/host0";
|
||||
+static constexpr const char* interface = "xyz.openbmc_project.State.Host";
|
||||
+static constexpr const char* request = "RequestedHostTransition";
|
||||
+} // namespace host
|
||||
+
|
||||
+namespace nmi
|
||||
+{
|
||||
+static constexpr const char* busName = "xyz.openbmc_project.Control.Host.NMI";
|
||||
+static constexpr const char* path = "/xyz/openbmc_project/control/host0/nmi";
|
||||
+static constexpr const char* interface = "xyz.openbmc_project.Control.Host.NMI";
|
||||
+static constexpr const char* request = "NMI";
|
||||
+
|
||||
+} // namespace nmi
|
||||
+
|
||||
+void Watchdog::powerStateChangedHandler(
|
||||
+ const std::map<std::string, std::variant<std::string>>& props)
|
||||
+{
|
||||
+ const auto iter = props.find(currentHostState);
|
||||
+ if (iter != props.end())
|
||||
+ {
|
||||
+ const std::string* powerState = std::get_if<std::string>(&iter->second);
|
||||
+ if (powerState && (*powerState == hostStatusOff))
|
||||
+ {
|
||||
+ if (timerEnabled())
|
||||
+ {
|
||||
+ enabled(false);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
void Watchdog::resetTimeRemaining(bool enableWatchdog)
|
||||
{
|
||||
@@ -108,13 +187,111 @@ uint64_t Watchdog::interval(uint64_t value)
|
||||
// Optional callback function on timer expiration
|
||||
void Watchdog::timeOutHandler()
|
||||
{
|
||||
+ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt();
|
||||
+ std::string preInterruptActionMessageArgs{};
|
||||
+
|
||||
Action action = expireAction();
|
||||
+ std::string actionMessageArgs{};
|
||||
+
|
||||
+ expiredTimerUse(currentTimerUse());
|
||||
+
|
||||
+ TimerUse timeUser = expiredTimerUse();
|
||||
+ std::string timeUserMessage{};
|
||||
+
|
||||
if (!this->enabled())
|
||||
{
|
||||
action = fallback->action;
|
||||
}
|
||||
|
||||
- expiredTimerUse(currentTimerUse());
|
||||
+ switch (timeUser)
|
||||
+ {
|
||||
+ case Watchdog::TimerUse::BIOSFRB2:
|
||||
+ timeUserMessage = timerUseDescriptionBIOSFRB2;
|
||||
+ break;
|
||||
+ case Watchdog::TimerUse::BIOSPOST:
|
||||
+ timeUserMessage = timerUseDescriptionBIOSPOST;
|
||||
+ break;
|
||||
+ case Watchdog::TimerUse::OSLoad:
|
||||
+ timeUserMessage = timerUseDescriptionOSLoad;
|
||||
+ break;
|
||||
+ case Watchdog::TimerUse::SMSOS:
|
||||
+ timeUserMessage = timerUseDescriptionSMSOS;
|
||||
+ break;
|
||||
+ case Watchdog::TimerUse::OEM:
|
||||
+ timeUserMessage = timerUseDescriptionOEM;
|
||||
+ break;
|
||||
+ default:
|
||||
+ timeUserMessage = reservedDescription;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ switch (action)
|
||||
+ {
|
||||
+ case Watchdog::Action::HardReset:
|
||||
+ actionMessageArgs = std::string(hardResetDescription) +
|
||||
+ std::string(actionDescription);
|
||||
+ break;
|
||||
+ case Watchdog::Action::PowerOff:
|
||||
+ actionMessageArgs = std::string(powerOffDescription) +
|
||||
+ std::string(actionDescription);
|
||||
+ break;
|
||||
+ case Watchdog::Action::PowerCycle:
|
||||
+ actionMessageArgs = std::string(powerCycleDescription) +
|
||||
+ std::string(actionDescription);
|
||||
+ break;
|
||||
+ case Watchdog::Action::None:
|
||||
+ actionMessageArgs = timerExpiredDescription;
|
||||
+ break;
|
||||
+ default:
|
||||
+ actionMessageArgs = reservedDescription;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ // Log into redfish event log
|
||||
+ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s",
|
||||
+ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO,
|
||||
+ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog",
|
||||
+ "REDFISH_MESSAGE_ARGS=%s. timer use: %s",
|
||||
+ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL);
|
||||
+
|
||||
+ switch (preTimeoutInterruptAction)
|
||||
+ {
|
||||
+ case Watchdog::PreTimeoutInterruptAction::SMI:
|
||||
+ preInterruptActionMessageArgs = preInterruptDescriptionSMI;
|
||||
+ break;
|
||||
+ case Watchdog::PreTimeoutInterruptAction::NMI:
|
||||
+ preInterruptActionMessageArgs = preInterruptDescriptionNMI;
|
||||
+ break;
|
||||
+ case Watchdog::PreTimeoutInterruptAction::MI:
|
||||
+ preInterruptActionMessageArgs = preInterruptDescriptionMI;
|
||||
+ break;
|
||||
+ default:
|
||||
+ preInterruptActionMessageArgs = reservedDescription;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction))
|
||||
+ {
|
||||
+ preTimeoutInterruptOccurFlag(true);
|
||||
+
|
||||
+ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s",
|
||||
+ convertForMessage(preTimeoutInterruptAction).c_str(),
|
||||
+ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
|
||||
+ "OpenBMC.0.1.IPMIWatchdog",
|
||||
+ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to "
|
||||
+ "Watchdog timeout. timer use: %s",
|
||||
+ preInterruptActionMessageArgs.c_str(),
|
||||
+ timeUserMessage.c_str(), NULL);
|
||||
+
|
||||
+ if (preTimeoutInterruptAction ==
|
||||
+ Watchdog::PreTimeoutInterruptAction::NMI)
|
||||
+ {
|
||||
+ sdbusplus::message::message preTimeoutInterruptHandler;
|
||||
+ preTimeoutInterruptHandler = bus.new_method_call(
|
||||
+ nmi::busName, nmi::path, nmi::interface, nmi::request);
|
||||
+ bus.call_noreply(preTimeoutInterruptHandler);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
auto target = actionTargetMap.find(action);
|
||||
if (target == actionTargetMap.end())
|
||||
@@ -134,12 +311,45 @@ void Watchdog::timeOutHandler()
|
||||
|
||||
try
|
||||
{
|
||||
- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
|
||||
- SYSTEMD_INTERFACE, "StartUnit");
|
||||
- method.append(target->second);
|
||||
- method.append("replace");
|
||||
+ sdbusplus::message::message method;
|
||||
+ if (action == Watchdog::Action::HardReset)
|
||||
+ {
|
||||
+ auto method = bus.new_method_call(
|
||||
+ restart::busName, restart::path,
|
||||
+ "org.freedesktop.DBus.Properties", "Set");
|
||||
+ method.append(
|
||||
+ restart::interface, restart::property,
|
||||
+ std::variant<std::string>("xyz.openbmc_project.State.Host."
|
||||
+ "RestartCause.WatchdogTimer"));
|
||||
+ bus.call_noreply(method);
|
||||
|
||||
- bus.call_noreply(method);
|
||||
+ method = bus.new_method_call(host::busName, host::path,
|
||||
+ "org.freedesktop.DBus.Properties",
|
||||
+ "Set");
|
||||
+ method.append(host::interface, host::request,
|
||||
+ std::variant<std::string>(target->second));
|
||||
+ bus.call_noreply(method);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (action == Watchdog::Action::PowerCycle)
|
||||
+ {
|
||||
+ auto method = bus.new_method_call(
|
||||
+ restart::busName, restart::path,
|
||||
+ "org.freedesktop.DBus.Properties", "Set");
|
||||
+ method.append(restart::interface, restart::property,
|
||||
+ std::variant<std::string>(
|
||||
+ "xyz.openbmc_project.State.Host."
|
||||
+ "RestartCause.WatchdogTimer"));
|
||||
+ bus.call_noreply(method);
|
||||
+ }
|
||||
+ method = bus.new_method_call(chassis::busName, chassis::path,
|
||||
+ "org.freedesktop.DBus.Properties",
|
||||
+ "Set");
|
||||
+ method.append(chassis::interface, chassis::request,
|
||||
+ std::variant<std::string>(target->second));
|
||||
+ bus.call_noreply(method);
|
||||
+ }
|
||||
}
|
||||
catch (const sdbusplus::exception_t& e)
|
||||
{
|
||||
diff --git a/src/watchdog.hpp b/src/watchdog.hpp
|
||||
index da1e05a..0e88b50 100644
|
||||
--- a/src/watchdog.hpp
|
||||
+++ b/src/watchdog.hpp
|
||||
@@ -75,7 +75,18 @@ class Watchdog : public WatchdogInherits
|
||||
bus(bus), actionTargetMap(std::move(actionTargetMap)),
|
||||
fallback(fallback), minInterval(minInterval),
|
||||
timer(event, std::bind(&Watchdog::timeOutHandler, this)),
|
||||
- objPath(objPath), exitAfterTimeout(exitAfterTimeout)
|
||||
+ objPath(objPath), exitAfterTimeout(exitAfterTimeout),
|
||||
+ powerStateChangedSignal(
|
||||
+ bus,
|
||||
+ sdbusplus::bus::match::rules::propertiesChanged(
|
||||
+ "/xyz/openbmc_project/state/host0",
|
||||
+ "xyz.openbmc_project.State.Host"),
|
||||
+ [this](sdbusplus::message::message& msg) {
|
||||
+ std::string objectName;
|
||||
+ std::map<std::string, std::variant<std::string>> props;
|
||||
+ msg.read(objectName, props);
|
||||
+ powerStateChangedHandler(props);
|
||||
+ })
|
||||
{
|
||||
// Use default if passed in otherwise just use default that comes
|
||||
// with object
|
||||
@@ -92,6 +103,12 @@ class Watchdog : public WatchdogInherits
|
||||
tryFallbackOrDisable();
|
||||
}
|
||||
|
||||
+ /** @brief Disable watchdog when power status change meet
|
||||
+ * the specific requirement
|
||||
+ */
|
||||
+ void powerStateChangedHandler(
|
||||
+ const std::map<std::string, std::variant<std::string>>& props);
|
||||
+
|
||||
/** @brief Resets the TimeRemaining to the configured Interval
|
||||
* Optionally enables the watchdog.
|
||||
*
|
||||
@@ -180,6 +197,10 @@ class Watchdog : public WatchdogInherits
|
||||
/** @brief Contained timer object */
|
||||
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
|
||||
|
||||
+ /** @brief Optional Callback handler when power status change meet
|
||||
+ * the specific requirement */
|
||||
+ sdbusplus::bus::match_t powerStateChangedSignal;
|
||||
+
|
||||
/** @brief Optional Callback handler on timer expirartion */
|
||||
void timeOutHandler();
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Phosphor Watchdog
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \
|
||||
--path=/xyz/openbmc_project/watchdog/host0 \
|
||||
--action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Host.Transition.ForceWarmReboot \
|
||||
--action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \
|
||||
--action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle
|
||||
|
||||
BusName=xyz.openbmc_project.Watchdog
|
||||
Type=dbus
|
||||
|
||||
[Install]
|
||||
WantedBy=basic.target
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
FILESEXTRAPATHS:append := ":${THISDIR}/${PN}"
|
||||
|
||||
# Enable downstream autobump
|
||||
# The URI is required for the autobump script but keep it commented
|
||||
# to not override the upstream value
|
||||
# SRC_URI = "git://github.com/openbmc/phosphor-watchdog;branch=master;protocol=https"
|
||||
SRCREV = "6072942ee9b13e441f2dc34ce7e93465248e30be"
|
||||
|
||||
SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \
|
||||
"
|
||||
|
||||
# Remove the override to keep service running after DC cycle
|
||||
SYSTEMD_OVERRIDE:${PN}:remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf"
|
||||
SYSTEMD_SERVICE:${PN} = "phosphor-watchdog.service"
|
||||
@@ -0,0 +1,11 @@
|
||||
SUMMARY = "System watchdog"
|
||||
DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \
|
||||
when unrecoverable events occurs"
|
||||
|
||||
inherit allarch
|
||||
inherit obmc-phosphor-systemd
|
||||
|
||||
LICENSE = "CLOSED"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += "system-watchdog.service"
|
||||
SYSTEMD_ENVIRONMENT_FILE:${PN} += "obmc/system-watchdog/system-watchdog.conf"
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
TIMEOUT=60
|
||||
INTERVAL=10
|
||||
DEVICE=/dev/watchdog1
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=BMC Hardware Watchdog Daemon
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf
|
||||
ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}}
|
||||
KillSignal=SIGTERM
|
||||
|
||||
[Install]
|
||||
WantedBy=basic.target
|
||||
|
||||
Reference in New Issue
Block a user