Initial commit

This commit is contained in:
Your Name
2026-04-23 17:07:55 +08:00
commit b7e39e063b
16725 changed files with 1625565 additions and 0 deletions
@@ -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
@@ -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