xref: /openbmc/x86-power-control/src/power_control.cpp (revision b84e78935d8178dab56ab9cff11c5ee37a92fe11)
10d57f4e3SJason M. Bills /*
20d57f4e3SJason M. Bills // Copyright (c) 2018-2019 Intel Corporation
30d57f4e3SJason M. Bills //
40d57f4e3SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
50d57f4e3SJason M. Bills // you may not use this file except in compliance with the License.
60d57f4e3SJason M. Bills // You may obtain a copy of the License at
70d57f4e3SJason M. Bills //
80d57f4e3SJason M. Bills //      http://www.apache.org/licenses/LICENSE-2.0
90d57f4e3SJason M. Bills //
100d57f4e3SJason M. Bills // Unless required by applicable law or agreed to in writing, software
110d57f4e3SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
120d57f4e3SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130d57f4e3SJason M. Bills // See the License for the specific language governing permissions and
140d57f4e3SJason M. Bills // limitations under the License.
150d57f4e3SJason M. Bills */
1650fe8ee3SAndrei Kartashev #include "power_control.hpp"
1750fe8ee3SAndrei Kartashev 
180d57f4e3SJason M. Bills #include <sys/sysinfo.h>
190d57f4e3SJason M. Bills #include <systemd/sd-journal.h>
200d57f4e3SJason M. Bills 
21744e9a98SEd Tanous #include <boost/asio/io_context.hpp>
220d57f4e3SJason M. Bills #include <boost/asio/posix/stream_descriptor.hpp>
230d57f4e3SJason M. Bills #include <boost/asio/steady_timer.hpp>
240d57f4e3SJason M. Bills #include <boost/container/flat_map.hpp>
250d57f4e3SJason M. Bills #include <boost/container/flat_set.hpp>
260d57f4e3SJason M. Bills #include <gpiod.hpp>
270d57f4e3SJason M. Bills #include <nlohmann/json.hpp>
28c46ebb49SJason M. Bills #include <phosphor-logging/lg2.hpp>
290d57f4e3SJason M. Bills #include <sdbusplus/asio/object_server.hpp>
300d57f4e3SJason M. Bills 
310d57f4e3SJason M. Bills #include <filesystem>
320d57f4e3SJason M. Bills #include <fstream>
33ca47855dSZev Weiss #include <optional>
34ca47855dSZev Weiss #include <regex>
350d57f4e3SJason M. Bills #include <string_view>
360d57f4e3SJason M. Bills 
370d57f4e3SJason M. Bills namespace power_control
380d57f4e3SJason M. Bills {
39744e9a98SEd Tanous static boost::asio::io_context io;
400d57f4e3SJason M. Bills std::shared_ptr<sdbusplus::asio::connection> conn;
4150fe8ee3SAndrei Kartashev PersistentState appState;
4299e8f9dfSAndrei Kartashev PowerRestoreController powerRestore(io);
430d57f4e3SJason M. Bills 
440d57f4e3SJason M. Bills static std::string node = "0";
453efcf37bSAndrei Kartashev static const std::string appName = "power-control";
460d57f4e3SJason M. Bills 
470d57f4e3SJason M. Bills enum class DbusConfigType
480d57f4e3SJason M. Bills {
490d57f4e3SJason M. Bills     name = 1,
500d57f4e3SJason M. Bills     path,
510d57f4e3SJason M. Bills     interface,
520d57f4e3SJason M. Bills     property
530d57f4e3SJason M. Bills };
54ca47855dSZev Weiss 
55ca47855dSZev Weiss // Mandatory config parameters for dbus inputs
560d57f4e3SJason M. Bills boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
570d57f4e3SJason M. Bills     {DbusConfigType::name, "DbusName"},
580d57f4e3SJason M. Bills     {DbusConfigType::path, "Path"},
590d57f4e3SJason M. Bills     {DbusConfigType::interface, "Interface"},
600d57f4e3SJason M. Bills     {DbusConfigType::property, "Property"}};
610d57f4e3SJason M. Bills 
620d57f4e3SJason M. Bills enum class ConfigType
630d57f4e3SJason M. Bills {
640d57f4e3SJason M. Bills     GPIO = 1,
650d57f4e3SJason M. Bills     DBUS
660d57f4e3SJason M. Bills };
670d57f4e3SJason M. Bills 
680d57f4e3SJason M. Bills struct ConfigData
690d57f4e3SJason M. Bills {
700d57f4e3SJason M. Bills     std::string name;
710d57f4e3SJason M. Bills     std::string lineName;
720d57f4e3SJason M. Bills     std::string dbusName;
730d57f4e3SJason M. Bills     std::string path;
740d57f4e3SJason M. Bills     std::string interface;
75ca47855dSZev Weiss     std::optional<std::regex> matchRegex;
760d57f4e3SJason M. Bills     bool polarity;
770d57f4e3SJason M. Bills     ConfigType type;
780d57f4e3SJason M. Bills };
790d57f4e3SJason M. Bills 
800d57f4e3SJason M. Bills static ConfigData powerOutConfig;
810d57f4e3SJason M. Bills static ConfigData powerOkConfig;
820d57f4e3SJason M. Bills static ConfigData resetOutConfig;
830d57f4e3SJason M. Bills static ConfigData nmiOutConfig;
840d57f4e3SJason M. Bills static ConfigData sioPwrGoodConfig;
850d57f4e3SJason M. Bills static ConfigData sioOnControlConfig;
860d57f4e3SJason M. Bills static ConfigData sioS5Config;
870d57f4e3SJason M. Bills static ConfigData postCompleteConfig;
880d57f4e3SJason M. Bills static ConfigData powerButtonConfig;
890d57f4e3SJason M. Bills static ConfigData resetButtonConfig;
900d57f4e3SJason M. Bills static ConfigData idButtonConfig;
910d57f4e3SJason M. Bills static ConfigData nmiButtonConfig;
920d57f4e3SJason M. Bills static ConfigData slotPowerConfig;
93cfc4d25eSKonstantin Aladyshev static ConfigData hpmStbyEnConfig;
940d57f4e3SJason M. Bills 
950d57f4e3SJason M. Bills // map for storing list of gpio parameters whose config are to be read from x86
960d57f4e3SJason M. Bills // power control json config
970d57f4e3SJason M. Bills boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
980d57f4e3SJason M. Bills     {"PowerOut", &powerOutConfig},
990d57f4e3SJason M. Bills     {"PowerOk", &powerOkConfig},
1000d57f4e3SJason M. Bills     {"ResetOut", &resetOutConfig},
1010d57f4e3SJason M. Bills     {"NMIOut", &nmiOutConfig},
1020d57f4e3SJason M. Bills     {"SioPowerGood", &sioPwrGoodConfig},
1030d57f4e3SJason M. Bills     {"SioOnControl", &sioOnControlConfig},
1040d57f4e3SJason M. Bills     {"SIOS5", &sioS5Config},
1050d57f4e3SJason M. Bills     {"PostComplete", &postCompleteConfig},
1060d57f4e3SJason M. Bills     {"PowerButton", &powerButtonConfig},
1070d57f4e3SJason M. Bills     {"ResetButton", &resetButtonConfig},
1080d57f4e3SJason M. Bills     {"IdButton", &idButtonConfig},
1090d57f4e3SJason M. Bills     {"NMIButton", &nmiButtonConfig},
110cfc4d25eSKonstantin Aladyshev     {"SlotPower", &slotPowerConfig},
111cfc4d25eSKonstantin Aladyshev     {"HpmStbyEn", &hpmStbyEnConfig}};
1120d57f4e3SJason M. Bills 
1130d57f4e3SJason M. Bills static std::string hostDbusName = "xyz.openbmc_project.State.Host";
1140d57f4e3SJason M. Bills static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
1150d57f4e3SJason M. Bills static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
1160d57f4e3SJason M. Bills static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
1170d57f4e3SJason M. Bills static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
1180d57f4e3SJason M. Bills static std::string rstCauseDbusName =
1190d57f4e3SJason M. Bills     "xyz.openbmc_project.Control.Host.RestartCause";
1200d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
1210d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
1220d57f4e3SJason M. Bills #ifdef CHASSIS_SYSTEM_RESET
1230d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
1240d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
1250d57f4e3SJason M. Bills #endif
1260d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
1270d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
1280d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
1290d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
1300d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
1310d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
1320d57f4e3SJason M. Bills static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
1330d57f4e3SJason M. Bills 
1340d57f4e3SJason M. Bills static gpiod::line powerButtonMask;
1350d57f4e3SJason M. Bills static gpiod::line resetButtonMask;
1360d57f4e3SJason M. Bills static bool nmiButtonMasked = false;
13758e379d1SMatt Simmering #if IGNORE_SOFT_RESETS_DURING_POST
13858e379d1SMatt Simmering static bool ignoreNextSoftReset = false;
13958e379d1SMatt Simmering #endif
1400d57f4e3SJason M. Bills 
1410d57f4e3SJason M. Bills // This map contains all timer values that are to be read from json config
1420d57f4e3SJason M. Bills boost::container::flat_map<std::string, int> TimerMap = {
1430d57f4e3SJason M. Bills     {"PowerPulseMs", 200},
1440d57f4e3SJason M. Bills     {"ForceOffPulseMs", 15000},
1450d57f4e3SJason M. Bills     {"ResetPulseMs", 500},
1460d57f4e3SJason M. Bills     {"PowerCycleMs", 5000},
1470d57f4e3SJason M. Bills     {"SioPowerGoodWatchdogMs", 1000},
1480d57f4e3SJason M. Bills     {"PsPowerOKWatchdogMs", 8000},
1490d57f4e3SJason M. Bills     {"GracefulPowerOffS", (5 * 60)},
1500d57f4e3SJason M. Bills     {"WarmResetCheckMs", 500},
1510d57f4e3SJason M. Bills     {"PowerOffSaveMs", 7000},
152edd211e4SMichal Orzel     {"SlotPowerCycleMs", 200},
153edd211e4SMichal Orzel     {"DbusGetPropertyRetry", 1000}};
1540d57f4e3SJason M. Bills 
1550d57f4e3SJason M. Bills static bool nmiEnabled = true;
156d7ea283bSOlivier FAURAX static bool nmiWhenPoweredOff = true;
1570d57f4e3SJason M. Bills static bool sioEnabled = true;
1580d57f4e3SJason M. Bills 
1590d57f4e3SJason M. Bills // Timers
1600d57f4e3SJason M. Bills // Time holding GPIOs asserted
1610d57f4e3SJason M. Bills static boost::asio::steady_timer gpioAssertTimer(io);
1620d57f4e3SJason M. Bills // Time between off and on during a power cycle
1630d57f4e3SJason M. Bills static boost::asio::steady_timer powerCycleTimer(io);
1640d57f4e3SJason M. Bills // Time OS gracefully powering off
1650d57f4e3SJason M. Bills static boost::asio::steady_timer gracefulPowerOffTimer(io);
1660d57f4e3SJason M. Bills // Time the warm reset check
1670d57f4e3SJason M. Bills static boost::asio::steady_timer warmResetCheckTimer(io);
1680d57f4e3SJason M. Bills // Time power supply power OK assertion on power-on
1690d57f4e3SJason M. Bills static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
1700d57f4e3SJason M. Bills // Time SIO power good assertion on power-on
1710d57f4e3SJason M. Bills static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
1720d57f4e3SJason M. Bills // Time power-off state save for power loss tracking
1730d57f4e3SJason M. Bills static boost::asio::steady_timer powerStateSaveTimer(io);
1740d57f4e3SJason M. Bills // POH timer
1750d57f4e3SJason M. Bills static boost::asio::steady_timer pohCounterTimer(io);
1760d57f4e3SJason M. Bills // Time when to allow restart cause updates
1770d57f4e3SJason M. Bills static boost::asio::steady_timer restartCauseTimer(io);
1780d57f4e3SJason M. Bills static boost::asio::steady_timer slotPowerCycleTimer(io);
1790d57f4e3SJason M. Bills 
180edd211e4SMichal Orzel // Map containing timers used for D-Bus get-property retries
181edd211e4SMichal Orzel static boost::container::flat_map<std::string, boost::asio::steady_timer>
182edd211e4SMichal Orzel     dBusRetryTimers;
183edd211e4SMichal Orzel 
1840d57f4e3SJason M. Bills // GPIO Lines and Event Descriptors
1850d57f4e3SJason M. Bills static gpiod::line psPowerOKLine;
1860d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
1870d57f4e3SJason M. Bills static gpiod::line sioPowerGoodLine;
1880d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
1890d57f4e3SJason M. Bills static gpiod::line sioOnControlLine;
1900d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
1910d57f4e3SJason M. Bills static gpiod::line sioS5Line;
1920d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor sioS5Event(io);
1930d57f4e3SJason M. Bills static gpiod::line powerButtonLine;
1940d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor powerButtonEvent(io);
1950d57f4e3SJason M. Bills static gpiod::line resetButtonLine;
1960d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor resetButtonEvent(io);
1970d57f4e3SJason M. Bills static gpiod::line nmiButtonLine;
1980d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
1990d57f4e3SJason M. Bills static gpiod::line idButtonLine;
2000d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor idButtonEvent(io);
2010d57f4e3SJason M. Bills static gpiod::line postCompleteLine;
2020d57f4e3SJason M. Bills static boost::asio::posix::stream_descriptor postCompleteEvent(io);
2030d57f4e3SJason M. Bills static gpiod::line nmiOutLine;
2040d57f4e3SJason M. Bills static gpiod::line slotPowerLine;
2050d57f4e3SJason M. Bills 
2060d57f4e3SJason M. Bills static constexpr uint8_t beepPowerFail = 8;
2070d57f4e3SJason M. Bills 
beep(const uint8_t & beepPriority)2080d57f4e3SJason M. Bills static void beep(const uint8_t& beepPriority)
2090d57f4e3SJason M. Bills {
210c46ebb49SJason M. Bills     lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
211c46ebb49SJason M. Bills               beepPriority);
2120d57f4e3SJason M. Bills 
2130d57f4e3SJason M. Bills     conn->async_method_call(
2140d57f4e3SJason M. Bills         [](boost::system::error_code ec) {
2150d57f4e3SJason M. Bills             if (ec)
2160d57f4e3SJason M. Bills             {
217c46ebb49SJason M. Bills                 lg2::error(
218c46ebb49SJason M. Bills                     "beep returned error with async_method_call (ec = {ERROR_MSG})",
219c46ebb49SJason M. Bills                     "ERROR_MSG", ec.message());
2200d57f4e3SJason M. Bills                 return;
2210d57f4e3SJason M. Bills             }
2220d57f4e3SJason M. Bills         },
2230d57f4e3SJason M. Bills         "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
2240d57f4e3SJason M. Bills         "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
2250d57f4e3SJason M. Bills }
2260d57f4e3SJason M. Bills 
2278623918bSTim Lee enum class OperatingSystemStateStage
2288623918bSTim Lee {
2298623918bSTim Lee     Inactive,
2308623918bSTim Lee     Standby,
2318623918bSTim Lee };
23258e379d1SMatt Simmering static OperatingSystemStateStage operatingSystemState;
getOperatingSystemStateStage(const OperatingSystemStateStage stage)233*b84e7893SPatrick Williams static constexpr std::string_view getOperatingSystemStateStage(
234*b84e7893SPatrick Williams     const OperatingSystemStateStage stage)
2358623918bSTim Lee {
2368623918bSTim Lee     switch (stage)
2378623918bSTim Lee     {
2388623918bSTim Lee         case OperatingSystemStateStage::Inactive:
2398623918bSTim Lee             return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
2408623918bSTim Lee             break;
2418623918bSTim Lee         case OperatingSystemStateStage::Standby:
2428623918bSTim Lee             return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
2438623918bSTim Lee             break;
2448623918bSTim Lee         default:
2458623918bSTim Lee             return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
2468623918bSTim Lee             break;
2478623918bSTim Lee     }
2488623918bSTim Lee };
setOperatingSystemState(const OperatingSystemStateStage stage)2498623918bSTim Lee static void setOperatingSystemState(const OperatingSystemStateStage stage)
2508623918bSTim Lee {
25158e379d1SMatt Simmering     operatingSystemState = stage;
25258e379d1SMatt Simmering #if IGNORE_SOFT_RESETS_DURING_POST
25358e379d1SMatt Simmering     // If POST complete has asserted set ignoreNextSoftReset to false to avoid
25458e379d1SMatt Simmering     // masking soft resets after POST
25558e379d1SMatt Simmering     if (operatingSystemState == OperatingSystemStateStage::Standby)
25658e379d1SMatt Simmering     {
25758e379d1SMatt Simmering         ignoreNextSoftReset = false;
25858e379d1SMatt Simmering     }
25958e379d1SMatt Simmering #endif
2608623918bSTim Lee     osIface->set_property("OperatingSystemState",
2618623918bSTim Lee                           std::string(getOperatingSystemStateStage(stage)));
2628623918bSTim Lee 
2638623918bSTim Lee     lg2::info("Moving os state to {STATE} stage", "STATE",
2648623918bSTim Lee               getOperatingSystemStateStage(stage));
2658623918bSTim Lee }
2668623918bSTim Lee 
2670d57f4e3SJason M. Bills enum class PowerState
2680d57f4e3SJason M. Bills {
2690d57f4e3SJason M. Bills     on,
2700d57f4e3SJason M. Bills     waitForPSPowerOK,
2710d57f4e3SJason M. Bills     waitForSIOPowerGood,
2720d57f4e3SJason M. Bills     off,
2730d57f4e3SJason M. Bills     transitionToOff,
2740d57f4e3SJason M. Bills     gracefulTransitionToOff,
2750d57f4e3SJason M. Bills     cycleOff,
2760d57f4e3SJason M. Bills     transitionToCycleOff,
2770d57f4e3SJason M. Bills     gracefulTransitionToCycleOff,
2780d57f4e3SJason M. Bills     checkForWarmReset,
2790d57f4e3SJason M. Bills };
2800d57f4e3SJason M. Bills static PowerState powerState;
getPowerStateName(PowerState state)2810d57f4e3SJason M. Bills static std::string getPowerStateName(PowerState state)
2820d57f4e3SJason M. Bills {
2830d57f4e3SJason M. Bills     switch (state)
2840d57f4e3SJason M. Bills     {
2850d57f4e3SJason M. Bills         case PowerState::on:
2860d57f4e3SJason M. Bills             return "On";
2870d57f4e3SJason M. Bills             break;
2880d57f4e3SJason M. Bills         case PowerState::waitForPSPowerOK:
2890d57f4e3SJason M. Bills             return "Wait for Power Supply Power OK";
2900d57f4e3SJason M. Bills             break;
2910d57f4e3SJason M. Bills         case PowerState::waitForSIOPowerGood:
2920d57f4e3SJason M. Bills             return "Wait for SIO Power Good";
2930d57f4e3SJason M. Bills             break;
2940d57f4e3SJason M. Bills         case PowerState::off:
2950d57f4e3SJason M. Bills             return "Off";
2960d57f4e3SJason M. Bills             break;
2970d57f4e3SJason M. Bills         case PowerState::transitionToOff:
2980d57f4e3SJason M. Bills             return "Transition to Off";
2990d57f4e3SJason M. Bills             break;
3000d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToOff:
3010d57f4e3SJason M. Bills             return "Graceful Transition to Off";
3020d57f4e3SJason M. Bills             break;
3030d57f4e3SJason M. Bills         case PowerState::cycleOff:
3040d57f4e3SJason M. Bills             return "Power Cycle Off";
3050d57f4e3SJason M. Bills             break;
3060d57f4e3SJason M. Bills         case PowerState::transitionToCycleOff:
3070d57f4e3SJason M. Bills             return "Transition to Power Cycle Off";
3080d57f4e3SJason M. Bills             break;
3090d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToCycleOff:
3100d57f4e3SJason M. Bills             return "Graceful Transition to Power Cycle Off";
3110d57f4e3SJason M. Bills             break;
3120d57f4e3SJason M. Bills         case PowerState::checkForWarmReset:
3130d57f4e3SJason M. Bills             return "Check for Warm Reset";
3140d57f4e3SJason M. Bills             break;
3150d57f4e3SJason M. Bills         default:
3160d57f4e3SJason M. Bills             return "unknown state: " + std::to_string(static_cast<int>(state));
3170d57f4e3SJason M. Bills             break;
3180d57f4e3SJason M. Bills     }
3190d57f4e3SJason M. Bills }
logStateTransition(const PowerState state)3200d57f4e3SJason M. Bills static void logStateTransition(const PowerState state)
3210d57f4e3SJason M. Bills {
322c46ebb49SJason M. Bills     lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
323c46ebb49SJason M. Bills               getPowerStateName(state));
3240d57f4e3SJason M. Bills }
3250d57f4e3SJason M. Bills 
3260d57f4e3SJason M. Bills enum class Event
3270d57f4e3SJason M. Bills {
3280d57f4e3SJason M. Bills     psPowerOKAssert,
3290d57f4e3SJason M. Bills     psPowerOKDeAssert,
3300d57f4e3SJason M. Bills     sioPowerGoodAssert,
3310d57f4e3SJason M. Bills     sioPowerGoodDeAssert,
3320d57f4e3SJason M. Bills     sioS5Assert,
3330d57f4e3SJason M. Bills     sioS5DeAssert,
3340d57f4e3SJason M. Bills     pltRstAssert,
3350d57f4e3SJason M. Bills     pltRstDeAssert,
3360d57f4e3SJason M. Bills     postCompleteAssert,
3370d57f4e3SJason M. Bills     postCompleteDeAssert,
3380d57f4e3SJason M. Bills     powerButtonPressed,
3390d57f4e3SJason M. Bills     resetButtonPressed,
3400d57f4e3SJason M. Bills     powerCycleTimerExpired,
3410d57f4e3SJason M. Bills     psPowerOKWatchdogTimerExpired,
3420d57f4e3SJason M. Bills     sioPowerGoodWatchdogTimerExpired,
3430d57f4e3SJason M. Bills     gracefulPowerOffTimerExpired,
3440d57f4e3SJason M. Bills     powerOnRequest,
3450d57f4e3SJason M. Bills     powerOffRequest,
3460d57f4e3SJason M. Bills     powerCycleRequest,
3470d57f4e3SJason M. Bills     resetRequest,
3480d57f4e3SJason M. Bills     gracefulPowerOffRequest,
3490d57f4e3SJason M. Bills     gracefulPowerCycleRequest,
3500d57f4e3SJason M. Bills     warmResetDetected,
3510d57f4e3SJason M. Bills };
getEventName(Event event)3520d57f4e3SJason M. Bills static std::string getEventName(Event event)
3530d57f4e3SJason M. Bills {
3540d57f4e3SJason M. Bills     switch (event)
3550d57f4e3SJason M. Bills     {
3560d57f4e3SJason M. Bills         case Event::psPowerOKAssert:
3570d57f4e3SJason M. Bills             return "power supply power OK assert";
3580d57f4e3SJason M. Bills             break;
3590d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
3600d57f4e3SJason M. Bills             return "power supply power OK de-assert";
3610d57f4e3SJason M. Bills             break;
3620d57f4e3SJason M. Bills         case Event::sioPowerGoodAssert:
3630d57f4e3SJason M. Bills             return "SIO power good assert";
3640d57f4e3SJason M. Bills             break;
3650d57f4e3SJason M. Bills         case Event::sioPowerGoodDeAssert:
3660d57f4e3SJason M. Bills             return "SIO power good de-assert";
3670d57f4e3SJason M. Bills             break;
3680d57f4e3SJason M. Bills         case Event::sioS5Assert:
3690d57f4e3SJason M. Bills             return "SIO S5 assert";
3700d57f4e3SJason M. Bills             break;
3710d57f4e3SJason M. Bills         case Event::sioS5DeAssert:
3720d57f4e3SJason M. Bills             return "SIO S5 de-assert";
3730d57f4e3SJason M. Bills             break;
3740d57f4e3SJason M. Bills         case Event::pltRstAssert:
3750d57f4e3SJason M. Bills             return "PLT_RST assert";
3760d57f4e3SJason M. Bills             break;
3770d57f4e3SJason M. Bills         case Event::pltRstDeAssert:
3780d57f4e3SJason M. Bills             return "PLT_RST de-assert";
3790d57f4e3SJason M. Bills             break;
3800d57f4e3SJason M. Bills         case Event::postCompleteAssert:
3810d57f4e3SJason M. Bills             return "POST Complete assert";
3820d57f4e3SJason M. Bills             break;
3830d57f4e3SJason M. Bills         case Event::postCompleteDeAssert:
3840d57f4e3SJason M. Bills             return "POST Complete de-assert";
3850d57f4e3SJason M. Bills             break;
3860d57f4e3SJason M. Bills         case Event::powerButtonPressed:
3870d57f4e3SJason M. Bills             return "power button pressed";
3880d57f4e3SJason M. Bills             break;
3890d57f4e3SJason M. Bills         case Event::resetButtonPressed:
3900d57f4e3SJason M. Bills             return "reset button pressed";
3910d57f4e3SJason M. Bills             break;
3920d57f4e3SJason M. Bills         case Event::powerCycleTimerExpired:
3930d57f4e3SJason M. Bills             return "power cycle timer expired";
3940d57f4e3SJason M. Bills             break;
3950d57f4e3SJason M. Bills         case Event::psPowerOKWatchdogTimerExpired:
3960d57f4e3SJason M. Bills             return "power supply power OK watchdog timer expired";
3970d57f4e3SJason M. Bills             break;
3980d57f4e3SJason M. Bills         case Event::sioPowerGoodWatchdogTimerExpired:
3990d57f4e3SJason M. Bills             return "SIO power good watchdog timer expired";
4000d57f4e3SJason M. Bills             break;
4010d57f4e3SJason M. Bills         case Event::gracefulPowerOffTimerExpired:
4020d57f4e3SJason M. Bills             return "graceful power-off timer expired";
4030d57f4e3SJason M. Bills             break;
4040d57f4e3SJason M. Bills         case Event::powerOnRequest:
4050d57f4e3SJason M. Bills             return "power-on request";
4060d57f4e3SJason M. Bills             break;
4070d57f4e3SJason M. Bills         case Event::powerOffRequest:
4080d57f4e3SJason M. Bills             return "power-off request";
4090d57f4e3SJason M. Bills             break;
4100d57f4e3SJason M. Bills         case Event::powerCycleRequest:
4110d57f4e3SJason M. Bills             return "power-cycle request";
4120d57f4e3SJason M. Bills             break;
4130d57f4e3SJason M. Bills         case Event::resetRequest:
4140d57f4e3SJason M. Bills             return "reset request";
4150d57f4e3SJason M. Bills             break;
4160d57f4e3SJason M. Bills         case Event::gracefulPowerOffRequest:
4170d57f4e3SJason M. Bills             return "graceful power-off request";
4180d57f4e3SJason M. Bills             break;
4190d57f4e3SJason M. Bills         case Event::gracefulPowerCycleRequest:
4200d57f4e3SJason M. Bills             return "graceful power-cycle request";
4210d57f4e3SJason M. Bills             break;
4220d57f4e3SJason M. Bills         case Event::warmResetDetected:
4230d57f4e3SJason M. Bills             return "warm reset detected";
4240d57f4e3SJason M. Bills             break;
4250d57f4e3SJason M. Bills         default:
4260d57f4e3SJason M. Bills             return "unknown event: " + std::to_string(static_cast<int>(event));
4270d57f4e3SJason M. Bills             break;
4280d57f4e3SJason M. Bills     }
4290d57f4e3SJason M. Bills }
logEvent(const std::string_view stateHandler,const Event event)4300d57f4e3SJason M. Bills static void logEvent(const std::string_view stateHandler, const Event event)
4310d57f4e3SJason M. Bills {
432c46ebb49SJason M. Bills     lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
433c46ebb49SJason M. Bills               stateHandler, "EVENT", getEventName(event));
4340d57f4e3SJason M. Bills }
4350d57f4e3SJason M. Bills 
4360d57f4e3SJason M. Bills // Power state handlers
4370d57f4e3SJason M. Bills static void powerStateOn(const Event event);
4380d57f4e3SJason M. Bills static void powerStateWaitForPSPowerOK(const Event event);
4390d57f4e3SJason M. Bills static void powerStateWaitForSIOPowerGood(const Event event);
4400d57f4e3SJason M. Bills static void powerStateOff(const Event event);
4410d57f4e3SJason M. Bills static void powerStateTransitionToOff(const Event event);
4420d57f4e3SJason M. Bills static void powerStateGracefulTransitionToOff(const Event event);
4430d57f4e3SJason M. Bills static void powerStateCycleOff(const Event event);
4440d57f4e3SJason M. Bills static void powerStateTransitionToCycleOff(const Event event);
4450d57f4e3SJason M. Bills static void powerStateGracefulTransitionToCycleOff(const Event event);
4460d57f4e3SJason M. Bills static void powerStateCheckForWarmReset(const Event event);
4470d57f4e3SJason M. Bills 
getPowerStateHandler(PowerState state)4480d57f4e3SJason M. Bills static std::function<void(const Event)> getPowerStateHandler(PowerState state)
4490d57f4e3SJason M. Bills {
4500d57f4e3SJason M. Bills     switch (state)
4510d57f4e3SJason M. Bills     {
4520d57f4e3SJason M. Bills         case PowerState::on:
4530d57f4e3SJason M. Bills             return powerStateOn;
4540d57f4e3SJason M. Bills             break;
4550d57f4e3SJason M. Bills         case PowerState::waitForPSPowerOK:
4560d57f4e3SJason M. Bills             return powerStateWaitForPSPowerOK;
4570d57f4e3SJason M. Bills             break;
4580d57f4e3SJason M. Bills         case PowerState::waitForSIOPowerGood:
4590d57f4e3SJason M. Bills             return powerStateWaitForSIOPowerGood;
4600d57f4e3SJason M. Bills             break;
4610d57f4e3SJason M. Bills         case PowerState::off:
4620d57f4e3SJason M. Bills             return powerStateOff;
4630d57f4e3SJason M. Bills             break;
4640d57f4e3SJason M. Bills         case PowerState::transitionToOff:
4650d57f4e3SJason M. Bills             return powerStateTransitionToOff;
4660d57f4e3SJason M. Bills             break;
4670d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToOff:
4680d57f4e3SJason M. Bills             return powerStateGracefulTransitionToOff;
4690d57f4e3SJason M. Bills             break;
4700d57f4e3SJason M. Bills         case PowerState::cycleOff:
4710d57f4e3SJason M. Bills             return powerStateCycleOff;
4720d57f4e3SJason M. Bills             break;
4730d57f4e3SJason M. Bills         case PowerState::transitionToCycleOff:
4740d57f4e3SJason M. Bills             return powerStateTransitionToCycleOff;
4750d57f4e3SJason M. Bills             break;
4760d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToCycleOff:
4770d57f4e3SJason M. Bills             return powerStateGracefulTransitionToCycleOff;
4780d57f4e3SJason M. Bills             break;
4790d57f4e3SJason M. Bills         case PowerState::checkForWarmReset:
4800d57f4e3SJason M. Bills             return powerStateCheckForWarmReset;
4810d57f4e3SJason M. Bills             break;
4820d57f4e3SJason M. Bills         default:
4830d57f4e3SJason M. Bills             return nullptr;
4840d57f4e3SJason M. Bills             break;
4850d57f4e3SJason M. Bills     }
4860d57f4e3SJason M. Bills };
4870d57f4e3SJason M. Bills 
sendPowerControlEvent(const Event event)4880d57f4e3SJason M. Bills static void sendPowerControlEvent(const Event event)
4890d57f4e3SJason M. Bills {
4900d57f4e3SJason M. Bills     std::function<void(const Event)> handler = getPowerStateHandler(powerState);
4910d57f4e3SJason M. Bills     if (handler == nullptr)
4920d57f4e3SJason M. Bills     {
493c46ebb49SJason M. Bills         lg2::error("Failed to find handler for power state: {STATE}", "STATE",
494c46ebb49SJason M. Bills                    static_cast<int>(powerState));
4950d57f4e3SJason M. Bills         return;
4960d57f4e3SJason M. Bills     }
4970d57f4e3SJason M. Bills     handler(event);
4980d57f4e3SJason M. Bills }
4990d57f4e3SJason M. Bills 
getCurrentTimeMs()5000d57f4e3SJason M. Bills static uint64_t getCurrentTimeMs()
5010d57f4e3SJason M. Bills {
5020d57f4e3SJason M. Bills     struct timespec time = {};
5030d57f4e3SJason M. Bills 
5040d57f4e3SJason M. Bills     if (clock_gettime(CLOCK_REALTIME, &time) < 0)
5050d57f4e3SJason M. Bills     {
5060d57f4e3SJason M. Bills         return 0;
5070d57f4e3SJason M. Bills     }
5080d57f4e3SJason M. Bills     uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
5090d57f4e3SJason M. Bills     currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
5100d57f4e3SJason M. Bills 
5110d57f4e3SJason M. Bills     return currentTimeMs;
5120d57f4e3SJason M. Bills }
5130d57f4e3SJason M. Bills 
getHostState(const PowerState state)5140d57f4e3SJason M. Bills static constexpr std::string_view getHostState(const PowerState state)
5150d57f4e3SJason M. Bills {
5160d57f4e3SJason M. Bills     switch (state)
5170d57f4e3SJason M. Bills     {
5180d57f4e3SJason M. Bills         case PowerState::on:
5190d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToOff:
5200d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToCycleOff:
5210d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.HostState.Running";
5220d57f4e3SJason M. Bills             break;
5230d57f4e3SJason M. Bills         case PowerState::waitForPSPowerOK:
5240d57f4e3SJason M. Bills         case PowerState::waitForSIOPowerGood:
5250d57f4e3SJason M. Bills         case PowerState::off:
5260d57f4e3SJason M. Bills         case PowerState::transitionToOff:
5270d57f4e3SJason M. Bills         case PowerState::transitionToCycleOff:
5280d57f4e3SJason M. Bills         case PowerState::cycleOff:
5290d57f4e3SJason M. Bills         case PowerState::checkForWarmReset:
5300d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.HostState.Off";
5310d57f4e3SJason M. Bills             break;
5320d57f4e3SJason M. Bills         default:
5330d57f4e3SJason M. Bills             return "";
5340d57f4e3SJason M. Bills             break;
5350d57f4e3SJason M. Bills     }
5360d57f4e3SJason M. Bills };
getChassisState(const PowerState state)5370d57f4e3SJason M. Bills static constexpr std::string_view getChassisState(const PowerState state)
5380d57f4e3SJason M. Bills {
5390d57f4e3SJason M. Bills     switch (state)
5400d57f4e3SJason M. Bills     {
5410d57f4e3SJason M. Bills         case PowerState::on:
5420d57f4e3SJason M. Bills         case PowerState::transitionToOff:
5430d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToOff:
5440d57f4e3SJason M. Bills         case PowerState::transitionToCycleOff:
5450d57f4e3SJason M. Bills         case PowerState::gracefulTransitionToCycleOff:
5460d57f4e3SJason M. Bills         case PowerState::checkForWarmReset:
5470d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Chassis.PowerState.On";
5480d57f4e3SJason M. Bills             break;
5490d57f4e3SJason M. Bills         case PowerState::waitForPSPowerOK:
5500d57f4e3SJason M. Bills         case PowerState::waitForSIOPowerGood:
5510d57f4e3SJason M. Bills         case PowerState::off:
5520d57f4e3SJason M. Bills         case PowerState::cycleOff:
5530d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Chassis.PowerState.Off";
5540d57f4e3SJason M. Bills             break;
5550d57f4e3SJason M. Bills         default:
5560d57f4e3SJason M. Bills             return "";
5570d57f4e3SJason M. Bills             break;
5580d57f4e3SJason M. Bills     }
5590d57f4e3SJason M. Bills };
5600d57f4e3SJason M. Bills #ifdef CHASSIS_SYSTEM_RESET
5610d57f4e3SJason M. Bills enum class SlotPowerState
5620d57f4e3SJason M. Bills {
5630d57f4e3SJason M. Bills     on,
5640d57f4e3SJason M. Bills     off,
5650d57f4e3SJason M. Bills };
5660d57f4e3SJason M. Bills static SlotPowerState slotPowerState;
getSlotState(const SlotPowerState state)5670d57f4e3SJason M. Bills static constexpr std::string_view getSlotState(const SlotPowerState state)
5680d57f4e3SJason M. Bills {
5690d57f4e3SJason M. Bills     switch (state)
5700d57f4e3SJason M. Bills     {
5710d57f4e3SJason M. Bills         case SlotPowerState::on:
5720d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Chassis.PowerState.On";
5730d57f4e3SJason M. Bills             break;
5740d57f4e3SJason M. Bills         case SlotPowerState::off:
5750d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Chassis.PowerState.Off";
5760d57f4e3SJason M. Bills             break;
5770d57f4e3SJason M. Bills         default:
5780d57f4e3SJason M. Bills             return "";
5790d57f4e3SJason M. Bills             break;
5800d57f4e3SJason M. Bills     }
5810d57f4e3SJason M. Bills };
setSlotPowerState(const SlotPowerState state)5820d57f4e3SJason M. Bills static void setSlotPowerState(const SlotPowerState state)
5830d57f4e3SJason M. Bills {
5840d57f4e3SJason M. Bills     slotPowerState = state;
5850d57f4e3SJason M. Bills     chassisSlotIface->set_property("CurrentPowerState",
5860d57f4e3SJason M. Bills                                    std::string(getSlotState(slotPowerState)));
5870d57f4e3SJason M. Bills     chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
5880d57f4e3SJason M. Bills }
5890d57f4e3SJason M. Bills #endif
savePowerState(const PowerState state)5900d57f4e3SJason M. Bills static void savePowerState(const PowerState state)
5910d57f4e3SJason M. Bills {
5920d57f4e3SJason M. Bills     powerStateSaveTimer.expires_after(
5930d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
5940d57f4e3SJason M. Bills     powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
5950d57f4e3SJason M. Bills         if (ec)
5960d57f4e3SJason M. Bills         {
5970d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
5980d57f4e3SJason M. Bills             // completion.
5990d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
6000d57f4e3SJason M. Bills             {
601c46ebb49SJason M. Bills                 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
602c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
6030d57f4e3SJason M. Bills             }
6040d57f4e3SJason M. Bills             return;
6050d57f4e3SJason M. Bills         }
60650fe8ee3SAndrei Kartashev         appState.set(PersistentState::Params::PowerState,
60750fe8ee3SAndrei Kartashev                      std::string{getChassisState(state)});
6080d57f4e3SJason M. Bills     });
6090d57f4e3SJason M. Bills }
setPowerState(const PowerState state)6100d57f4e3SJason M. Bills static void setPowerState(const PowerState state)
6110d57f4e3SJason M. Bills {
6120d57f4e3SJason M. Bills     powerState = state;
6130d57f4e3SJason M. Bills     logStateTransition(state);
6140d57f4e3SJason M. Bills 
6150d57f4e3SJason M. Bills     hostIface->set_property("CurrentHostState",
6160d57f4e3SJason M. Bills                             std::string(getHostState(powerState)));
6170d57f4e3SJason M. Bills 
6180d57f4e3SJason M. Bills     chassisIface->set_property("CurrentPowerState",
6190d57f4e3SJason M. Bills                                std::string(getChassisState(powerState)));
6200d57f4e3SJason M. Bills     chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
6210d57f4e3SJason M. Bills 
6220d57f4e3SJason M. Bills     // Save the power state for the restore policy
6230d57f4e3SJason M. Bills     savePowerState(state);
6240d57f4e3SJason M. Bills }
6250d57f4e3SJason M. Bills 
6260d57f4e3SJason M. Bills enum class RestartCause
6270d57f4e3SJason M. Bills {
6280d57f4e3SJason M. Bills     command,
6290d57f4e3SJason M. Bills     resetButton,
6300d57f4e3SJason M. Bills     powerButton,
6310d57f4e3SJason M. Bills     watchdog,
6320d57f4e3SJason M. Bills     powerPolicyOn,
6330d57f4e3SJason M. Bills     powerPolicyRestore,
6340d57f4e3SJason M. Bills     softReset,
6350d57f4e3SJason M. Bills };
6360d57f4e3SJason M. Bills static boost::container::flat_set<RestartCause> causeSet;
getRestartCause(RestartCause cause)6370d57f4e3SJason M. Bills static std::string getRestartCause(RestartCause cause)
6380d57f4e3SJason M. Bills {
6390d57f4e3SJason M. Bills     switch (cause)
6400d57f4e3SJason M. Bills     {
6410d57f4e3SJason M. Bills         case RestartCause::command:
6420d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
6430d57f4e3SJason M. Bills             break;
6440d57f4e3SJason M. Bills         case RestartCause::resetButton:
6450d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
6460d57f4e3SJason M. Bills             break;
6470d57f4e3SJason M. Bills         case RestartCause::powerButton:
6480d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
6490d57f4e3SJason M. Bills             break;
6500d57f4e3SJason M. Bills         case RestartCause::watchdog:
6510d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
6520d57f4e3SJason M. Bills             break;
6530d57f4e3SJason M. Bills         case RestartCause::powerPolicyOn:
6540d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
6550d57f4e3SJason M. Bills             break;
6560d57f4e3SJason M. Bills         case RestartCause::powerPolicyRestore:
6570d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
6580d57f4e3SJason M. Bills             break;
6590d57f4e3SJason M. Bills         case RestartCause::softReset:
6600d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
6610d57f4e3SJason M. Bills             break;
6620d57f4e3SJason M. Bills         default:
6630d57f4e3SJason M. Bills             return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
6640d57f4e3SJason M. Bills             break;
6650d57f4e3SJason M. Bills     }
6660d57f4e3SJason M. Bills }
addRestartCause(const RestartCause cause)6670d57f4e3SJason M. Bills static void addRestartCause(const RestartCause cause)
6680d57f4e3SJason M. Bills {
6690d57f4e3SJason M. Bills     // Add this to the set of causes for this restart
6700d57f4e3SJason M. Bills     causeSet.insert(cause);
6710d57f4e3SJason M. Bills }
clearRestartCause()6720d57f4e3SJason M. Bills static void clearRestartCause()
6730d57f4e3SJason M. Bills {
6740d57f4e3SJason M. Bills     // Clear the set for the next restart
6750d57f4e3SJason M. Bills     causeSet.clear();
6760d57f4e3SJason M. Bills }
setRestartCauseProperty(const std::string & cause)6770d57f4e3SJason M. Bills static void setRestartCauseProperty(const std::string& cause)
6780d57f4e3SJason M. Bills {
679c46ebb49SJason M. Bills     lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
6800d57f4e3SJason M. Bills     restartCauseIface->set_property("RestartCause", cause);
6810d57f4e3SJason M. Bills }
6820d57f4e3SJason M. Bills 
68399e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
resetACBootProperty()6840d57f4e3SJason M. Bills static void resetACBootProperty()
6850d57f4e3SJason M. Bills {
6860d57f4e3SJason M. Bills     if ((causeSet.contains(RestartCause::command)) ||
6870d57f4e3SJason M. Bills         (causeSet.contains(RestartCause::softReset)))
6880d57f4e3SJason M. Bills     {
6890d57f4e3SJason M. Bills         conn->async_method_call(
6900d57f4e3SJason M. Bills             [](boost::system::error_code ec) {
6910d57f4e3SJason M. Bills                 if (ec)
6920d57f4e3SJason M. Bills                 {
693c46ebb49SJason M. Bills                     lg2::error("failed to reset ACBoot property");
6940d57f4e3SJason M. Bills                 }
6950d57f4e3SJason M. Bills             },
6960d57f4e3SJason M. Bills             "xyz.openbmc_project.Settings",
6970d57f4e3SJason M. Bills             "/xyz/openbmc_project/control/host0/ac_boot",
6980d57f4e3SJason M. Bills             "org.freedesktop.DBus.Properties", "Set",
6990d57f4e3SJason M. Bills             "xyz.openbmc_project.Common.ACBoot", "ACBoot",
7000d57f4e3SJason M. Bills             std::variant<std::string>{"False"});
7010d57f4e3SJason M. Bills     }
7020d57f4e3SJason M. Bills }
70399e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
7040d57f4e3SJason M. Bills 
setRestartCause()7050d57f4e3SJason M. Bills static void setRestartCause()
7060d57f4e3SJason M. Bills {
7070d57f4e3SJason M. Bills     // Determine the actual restart cause based on the set of causes
7080d57f4e3SJason M. Bills     std::string restartCause =
7090d57f4e3SJason M. Bills         "xyz.openbmc_project.State.Host.RestartCause.Unknown";
7100d57f4e3SJason M. Bills     if (causeSet.contains(RestartCause::watchdog))
7110d57f4e3SJason M. Bills     {
7120d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::watchdog);
7130d57f4e3SJason M. Bills     }
7140d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::command))
7150d57f4e3SJason M. Bills     {
7160d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::command);
7170d57f4e3SJason M. Bills     }
7180d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::resetButton))
7190d57f4e3SJason M. Bills     {
7200d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::resetButton);
7210d57f4e3SJason M. Bills     }
7220d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::powerButton))
7230d57f4e3SJason M. Bills     {
7240d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::powerButton);
7250d57f4e3SJason M. Bills     }
7260d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::powerPolicyOn))
7270d57f4e3SJason M. Bills     {
7280d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::powerPolicyOn);
7290d57f4e3SJason M. Bills     }
7300d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::powerPolicyRestore))
7310d57f4e3SJason M. Bills     {
7320d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::powerPolicyRestore);
7330d57f4e3SJason M. Bills     }
7340d57f4e3SJason M. Bills     else if (causeSet.contains(RestartCause::softReset))
7350d57f4e3SJason M. Bills     {
73658e379d1SMatt Simmering #if IGNORE_SOFT_RESETS_DURING_POST
73758e379d1SMatt Simmering         if (ignoreNextSoftReset)
73858e379d1SMatt Simmering         {
73958e379d1SMatt Simmering             ignoreNextSoftReset = false;
74058e379d1SMatt Simmering             return;
74158e379d1SMatt Simmering         }
74258e379d1SMatt Simmering #endif
7430d57f4e3SJason M. Bills         restartCause = getRestartCause(RestartCause::softReset);
7440d57f4e3SJason M. Bills     }
7450d57f4e3SJason M. Bills 
7460d57f4e3SJason M. Bills     setRestartCauseProperty(restartCause);
7470d57f4e3SJason M. Bills }
7480d57f4e3SJason M. Bills 
systemPowerGoodFailedLog()7490d57f4e3SJason M. Bills static void systemPowerGoodFailedLog()
7500d57f4e3SJason M. Bills {
7510d57f4e3SJason M. Bills     sd_journal_send(
7520d57f4e3SJason M. Bills         "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
7530d57f4e3SJason M. Bills         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7540d57f4e3SJason M. Bills         "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
7550d57f4e3SJason M. Bills         TimerMap["SioPowerGoodWatchdogMs"], NULL);
7560d57f4e3SJason M. Bills }
7570d57f4e3SJason M. Bills 
psPowerOKFailedLog()7580d57f4e3SJason M. Bills static void psPowerOKFailedLog()
7590d57f4e3SJason M. Bills {
7600d57f4e3SJason M. Bills     sd_journal_send(
7610d57f4e3SJason M. Bills         "MESSAGE=PowerControl: power supply power good failed to assert",
7620d57f4e3SJason M. Bills         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7630d57f4e3SJason M. Bills         "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
7640d57f4e3SJason M. Bills         TimerMap["PsPowerOKWatchdogMs"], NULL);
7650d57f4e3SJason M. Bills }
7660d57f4e3SJason M. Bills 
powerRestorePolicyLog()7670d57f4e3SJason M. Bills static void powerRestorePolicyLog()
7680d57f4e3SJason M. Bills {
7690d57f4e3SJason M. Bills     sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
7700d57f4e3SJason M. Bills                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7710d57f4e3SJason M. Bills                     "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
7720d57f4e3SJason M. Bills }
7730d57f4e3SJason M. Bills 
powerButtonPressLog()7740d57f4e3SJason M. Bills static void powerButtonPressLog()
7750d57f4e3SJason M. Bills {
7760d57f4e3SJason M. Bills     sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
7770d57f4e3SJason M. Bills                     LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7780d57f4e3SJason M. Bills                     "OpenBMC.0.1.PowerButtonPressed", NULL);
7790d57f4e3SJason M. Bills }
7800d57f4e3SJason M. Bills 
resetButtonPressLog()7810d57f4e3SJason M. Bills static void resetButtonPressLog()
7820d57f4e3SJason M. Bills {
7830d57f4e3SJason M. Bills     sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
7840d57f4e3SJason M. Bills                     LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7850d57f4e3SJason M. Bills                     "OpenBMC.0.1.ResetButtonPressed", NULL);
7860d57f4e3SJason M. Bills }
7870d57f4e3SJason M. Bills 
nmiButtonPressLog()7880d57f4e3SJason M. Bills static void nmiButtonPressLog()
7890d57f4e3SJason M. Bills {
7900d57f4e3SJason M. Bills     sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
7910d57f4e3SJason M. Bills                     LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7920d57f4e3SJason M. Bills                     "OpenBMC.0.1.NMIButtonPressed", NULL);
7930d57f4e3SJason M. Bills }
7940d57f4e3SJason M. Bills 
nmiDiagIntLog()7950d57f4e3SJason M. Bills static void nmiDiagIntLog()
7960d57f4e3SJason M. Bills {
7970d57f4e3SJason M. Bills     sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
7980d57f4e3SJason M. Bills                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
7990d57f4e3SJason M. Bills                     "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
8000d57f4e3SJason M. Bills }
8010d57f4e3SJason M. Bills 
PersistentState()80250fe8ee3SAndrei Kartashev PersistentState::PersistentState()
8030d57f4e3SJason M. Bills {
8040d57f4e3SJason M. Bills     // create the power control directory if it doesn't exist
8050d57f4e3SJason M. Bills     std::error_code ec;
8060d57f4e3SJason M. Bills     if (!(std::filesystem::create_directories(powerControlDir, ec)))
8070d57f4e3SJason M. Bills     {
8080d57f4e3SJason M. Bills         if (ec.value() != 0)
8090d57f4e3SJason M. Bills         {
810c46ebb49SJason M. Bills             lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
811c46ebb49SJason M. Bills                        powerControlDir.string(), "ERROR_MSG", ec.message());
81250fe8ee3SAndrei Kartashev             throw std::runtime_error("Failed to create state directory");
8130d57f4e3SJason M. Bills         }
8140d57f4e3SJason M. Bills     }
81550fe8ee3SAndrei Kartashev 
81650fe8ee3SAndrei Kartashev     // read saved state, it's ok, if the file doesn't exists
81750fe8ee3SAndrei Kartashev     std::ifstream appStateStream(powerControlDir / stateFile);
81850fe8ee3SAndrei Kartashev     if (!appStateStream.is_open())
8190d57f4e3SJason M. Bills     {
82050fe8ee3SAndrei Kartashev         lg2::info("Cannot open state file \'{PATH}\'", "PATH",
82150fe8ee3SAndrei Kartashev                   std::string(powerControlDir / stateFile));
82250fe8ee3SAndrei Kartashev         stateData = nlohmann::json({});
82350fe8ee3SAndrei Kartashev         return;
8240d57f4e3SJason M. Bills     }
82550fe8ee3SAndrei Kartashev     try
82650fe8ee3SAndrei Kartashev     {
82750fe8ee3SAndrei Kartashev         appStateStream >> stateData;
82850fe8ee3SAndrei Kartashev         if (stateData.is_discarded())
82950fe8ee3SAndrei Kartashev         {
83050fe8ee3SAndrei Kartashev             lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
83150fe8ee3SAndrei Kartashev                       std::string(powerControlDir / stateFile));
83250fe8ee3SAndrei Kartashev             stateData = nlohmann::json({});
83350fe8ee3SAndrei Kartashev             return;
83450fe8ee3SAndrei Kartashev         }
83550fe8ee3SAndrei Kartashev     }
83650fe8ee3SAndrei Kartashev     catch (const std::exception& ex)
83750fe8ee3SAndrei Kartashev     {
83850fe8ee3SAndrei Kartashev         lg2::info("Cannot read state file \'{PATH}\'", "PATH",
83950fe8ee3SAndrei Kartashev                   std::string(powerControlDir / stateFile));
84050fe8ee3SAndrei Kartashev         stateData = nlohmann::json({});
84150fe8ee3SAndrei Kartashev         return;
84250fe8ee3SAndrei Kartashev     }
84350fe8ee3SAndrei Kartashev }
~PersistentState()84450fe8ee3SAndrei Kartashev PersistentState::~PersistentState()
84550fe8ee3SAndrei Kartashev {
84650fe8ee3SAndrei Kartashev     saveState();
84750fe8ee3SAndrei Kartashev }
get(Params parameter)84850fe8ee3SAndrei Kartashev const std::string PersistentState::get(Params parameter)
84950fe8ee3SAndrei Kartashev {
85050fe8ee3SAndrei Kartashev     auto val = stateData.find(getName(parameter));
85150fe8ee3SAndrei Kartashev     if (val != stateData.end())
85250fe8ee3SAndrei Kartashev     {
85350fe8ee3SAndrei Kartashev         return val->get<std::string>();
85450fe8ee3SAndrei Kartashev     }
85550fe8ee3SAndrei Kartashev     return getDefault(parameter);
85650fe8ee3SAndrei Kartashev }
set(Params parameter,const std::string & value)85750fe8ee3SAndrei Kartashev void PersistentState::set(Params parameter, const std::string& value)
85850fe8ee3SAndrei Kartashev {
85950fe8ee3SAndrei Kartashev     stateData[getName(parameter)] = value;
86050fe8ee3SAndrei Kartashev     saveState();
86150fe8ee3SAndrei Kartashev }
86250fe8ee3SAndrei Kartashev 
getName(const Params parameter)86350fe8ee3SAndrei Kartashev const std::string PersistentState::getName(const Params parameter)
86450fe8ee3SAndrei Kartashev {
86550fe8ee3SAndrei Kartashev     switch (parameter)
86650fe8ee3SAndrei Kartashev     {
86750fe8ee3SAndrei Kartashev         case Params::PowerState:
86850fe8ee3SAndrei Kartashev             return "PowerState";
86950fe8ee3SAndrei Kartashev     }
87050fe8ee3SAndrei Kartashev     return "";
87150fe8ee3SAndrei Kartashev }
getDefault(const Params parameter)87250fe8ee3SAndrei Kartashev const std::string PersistentState::getDefault(const Params parameter)
87350fe8ee3SAndrei Kartashev {
87450fe8ee3SAndrei Kartashev     switch (parameter)
87550fe8ee3SAndrei Kartashev     {
87650fe8ee3SAndrei Kartashev         case Params::PowerState:
87750fe8ee3SAndrei Kartashev             return "xyz.openbmc_project.State.Chassis.PowerState.Off";
87850fe8ee3SAndrei Kartashev     }
87950fe8ee3SAndrei Kartashev     return "";
88050fe8ee3SAndrei Kartashev }
saveState()88150fe8ee3SAndrei Kartashev void PersistentState::saveState()
88250fe8ee3SAndrei Kartashev {
88350fe8ee3SAndrei Kartashev     std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
88450fe8ee3SAndrei Kartashev     if (!appStateStream.is_open())
88550fe8ee3SAndrei Kartashev     {
88650fe8ee3SAndrei Kartashev         lg2::error("Cannot write state file \'{PATH}\'", "PATH",
88750fe8ee3SAndrei Kartashev                    std::string(powerControlDir / stateFile));
88850fe8ee3SAndrei Kartashev         return;
88950fe8ee3SAndrei Kartashev     }
89050fe8ee3SAndrei Kartashev     appStateStream << stateData.dump(indentationSize);
8910d57f4e3SJason M. Bills }
8920d57f4e3SJason M. Bills 
89348aa1f05SPatrick Williams static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
89448aa1f05SPatrick Williams static constexpr const char* powerRestorePolicyIface =
89599e8f9dfSAndrei Kartashev     "xyz.openbmc_project.Control.Power.RestorePolicy";
89699e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
89748aa1f05SPatrick Williams static constexpr const char* powerACBootObject =
89899e8f9dfSAndrei Kartashev     "/xyz/openbmc_project/control/host0/ac_boot";
89948aa1f05SPatrick Williams static constexpr const char* powerACBootIface =
90099e8f9dfSAndrei Kartashev     "xyz.openbmc_project.Common.ACBoot";
90199e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
90299e8f9dfSAndrei Kartashev 
90399e8f9dfSAndrei Kartashev namespace match_rules = sdbusplus::bus::match::rules;
90499e8f9dfSAndrei Kartashev 
powerRestoreConfigHandler(sd_bus_message * m,void * context,sd_bus_error *)90599e8f9dfSAndrei Kartashev static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
90699e8f9dfSAndrei Kartashev                                      sd_bus_error*)
9070d57f4e3SJason M. Bills {
90899e8f9dfSAndrei Kartashev     if (context == nullptr || m == nullptr)
90999e8f9dfSAndrei Kartashev     {
91099e8f9dfSAndrei Kartashev         throw std::runtime_error("Invalid match");
91199e8f9dfSAndrei Kartashev     }
912439b9c3aSPatrick Williams     sdbusplus::message_t message(m);
91399e8f9dfSAndrei Kartashev     PowerRestoreController* powerRestore =
91499e8f9dfSAndrei Kartashev         static_cast<PowerRestoreController*>(context);
91599e8f9dfSAndrei Kartashev 
91699e8f9dfSAndrei Kartashev     if (std::string(message.get_member()) == "InterfacesAdded")
91799e8f9dfSAndrei Kartashev     {
91899e8f9dfSAndrei Kartashev         sdbusplus::message::object_path path;
91999e8f9dfSAndrei Kartashev         boost::container::flat_map<std::string, dbusPropertiesList> data;
92099e8f9dfSAndrei Kartashev 
92199e8f9dfSAndrei Kartashev         message.read(path, data);
92299e8f9dfSAndrei Kartashev 
92399e8f9dfSAndrei Kartashev         for (auto& [iface, properties] : data)
92499e8f9dfSAndrei Kartashev         {
92599e8f9dfSAndrei Kartashev             if ((iface == powerRestorePolicyIface)
92699e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
92799e8f9dfSAndrei Kartashev                 || (iface == powerACBootIface)
92899e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
92999e8f9dfSAndrei Kartashev             )
93099e8f9dfSAndrei Kartashev             {
93199e8f9dfSAndrei Kartashev                 powerRestore->setProperties(properties);
93299e8f9dfSAndrei Kartashev             }
93399e8f9dfSAndrei Kartashev         }
93499e8f9dfSAndrei Kartashev     }
93599e8f9dfSAndrei Kartashev     else if (std::string(message.get_member()) == "PropertiesChanged")
93699e8f9dfSAndrei Kartashev     {
93799e8f9dfSAndrei Kartashev         std::string interfaceName;
93899e8f9dfSAndrei Kartashev         dbusPropertiesList propertiesChanged;
93999e8f9dfSAndrei Kartashev 
94099e8f9dfSAndrei Kartashev         message.read(interfaceName, propertiesChanged);
94199e8f9dfSAndrei Kartashev 
94299e8f9dfSAndrei Kartashev         powerRestore->setProperties(propertiesChanged);
94399e8f9dfSAndrei Kartashev     }
94499e8f9dfSAndrei Kartashev     return 1;
9450d57f4e3SJason M. Bills }
9460d57f4e3SJason M. Bills 
run()94799e8f9dfSAndrei Kartashev void PowerRestoreController::run()
9480d57f4e3SJason M. Bills {
949a0a39f82SPatrick Williams     std::string powerRestorePolicyObject =
950a0a39f82SPatrick Williams         "/xyz/openbmc_project/control/host" + node + "/power_restore_policy";
95199e8f9dfSAndrei Kartashev     powerRestorePolicyLog();
95299e8f9dfSAndrei Kartashev     // this list only needs to be created once
95399e8f9dfSAndrei Kartashev     if (matches.empty())
95499e8f9dfSAndrei Kartashev     {
95599e8f9dfSAndrei Kartashev         matches.emplace_back(
95699e8f9dfSAndrei Kartashev             *conn,
95799e8f9dfSAndrei Kartashev             match_rules::interfacesAdded() +
95899e8f9dfSAndrei Kartashev                 match_rules::argNpath(0, powerRestorePolicyObject) +
95999e8f9dfSAndrei Kartashev                 match_rules::sender(setingsService),
96099e8f9dfSAndrei Kartashev             powerRestoreConfigHandler, this);
96199e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
96299e8f9dfSAndrei Kartashev         matches.emplace_back(*conn,
96399e8f9dfSAndrei Kartashev                              match_rules::interfacesAdded() +
96499e8f9dfSAndrei Kartashev                                  match_rules::argNpath(0, powerACBootObject) +
96599e8f9dfSAndrei Kartashev                                  match_rules::sender(setingsService),
96699e8f9dfSAndrei Kartashev                              powerRestoreConfigHandler, this);
96799e8f9dfSAndrei Kartashev         matches.emplace_back(*conn,
96899e8f9dfSAndrei Kartashev                              match_rules::propertiesChanged(powerACBootObject,
96999e8f9dfSAndrei Kartashev                                                             powerACBootIface) +
97099e8f9dfSAndrei Kartashev                                  match_rules::sender(setingsService),
97199e8f9dfSAndrei Kartashev                              powerRestoreConfigHandler, this);
97299e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
97399e8f9dfSAndrei Kartashev     }
97499e8f9dfSAndrei Kartashev 
97599e8f9dfSAndrei Kartashev     // Check if it's already on DBus
97699e8f9dfSAndrei Kartashev     conn->async_method_call(
97799e8f9dfSAndrei Kartashev         [this](boost::system::error_code ec,
97899e8f9dfSAndrei Kartashev                const dbusPropertiesList properties) {
97999e8f9dfSAndrei Kartashev             if (ec)
98099e8f9dfSAndrei Kartashev             {
98199e8f9dfSAndrei Kartashev                 return;
98299e8f9dfSAndrei Kartashev             }
98399e8f9dfSAndrei Kartashev             setProperties(properties);
98499e8f9dfSAndrei Kartashev         },
98599e8f9dfSAndrei Kartashev         setingsService, powerRestorePolicyObject,
98699e8f9dfSAndrei Kartashev         "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
98799e8f9dfSAndrei Kartashev 
98899e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
98999e8f9dfSAndrei Kartashev     // Check if it's already on DBus
99099e8f9dfSAndrei Kartashev     conn->async_method_call(
99199e8f9dfSAndrei Kartashev         [this](boost::system::error_code ec,
99299e8f9dfSAndrei Kartashev                const dbusPropertiesList properties) {
99399e8f9dfSAndrei Kartashev             if (ec)
99499e8f9dfSAndrei Kartashev             {
99599e8f9dfSAndrei Kartashev                 return;
99699e8f9dfSAndrei Kartashev             }
99799e8f9dfSAndrei Kartashev             setProperties(properties);
99899e8f9dfSAndrei Kartashev         },
99999e8f9dfSAndrei Kartashev         setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
100099e8f9dfSAndrei Kartashev         "GetAll", powerACBootIface);
100199e8f9dfSAndrei Kartashev #endif
100299e8f9dfSAndrei Kartashev }
100399e8f9dfSAndrei Kartashev 
setProperties(const dbusPropertiesList & props)100499e8f9dfSAndrei Kartashev void PowerRestoreController::setProperties(const dbusPropertiesList& props)
100599e8f9dfSAndrei Kartashev {
100699e8f9dfSAndrei Kartashev     for (auto& [property, propValue] : props)
100799e8f9dfSAndrei Kartashev     {
100899e8f9dfSAndrei Kartashev         if (property == "PowerRestorePolicy")
100999e8f9dfSAndrei Kartashev         {
101099e8f9dfSAndrei Kartashev             const std::string* value = std::get_if<std::string>(&propValue);
101199e8f9dfSAndrei Kartashev             if (value == nullptr)
101299e8f9dfSAndrei Kartashev             {
101399e8f9dfSAndrei Kartashev                 lg2::error("Unable to read Power Restore Policy");
101499e8f9dfSAndrei Kartashev                 continue;
101599e8f9dfSAndrei Kartashev             }
101699e8f9dfSAndrei Kartashev             powerRestorePolicy = *value;
101799e8f9dfSAndrei Kartashev         }
101899e8f9dfSAndrei Kartashev         else if (property == "PowerRestoreDelay")
101999e8f9dfSAndrei Kartashev         {
102099e8f9dfSAndrei Kartashev             const uint64_t* value = std::get_if<uint64_t>(&propValue);
102199e8f9dfSAndrei Kartashev             if (value == nullptr)
102299e8f9dfSAndrei Kartashev             {
102399e8f9dfSAndrei Kartashev                 lg2::error("Unable to read Power Restore Delay");
102499e8f9dfSAndrei Kartashev                 continue;
102599e8f9dfSAndrei Kartashev             }
102699e8f9dfSAndrei Kartashev             powerRestoreDelay = *value / 1000000; // usec to sec
102799e8f9dfSAndrei Kartashev         }
102899e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
102999e8f9dfSAndrei Kartashev         else if (property == "ACBoot")
103099e8f9dfSAndrei Kartashev         {
103199e8f9dfSAndrei Kartashev             const std::string* value = std::get_if<std::string>(&propValue);
103299e8f9dfSAndrei Kartashev             if (value == nullptr)
103399e8f9dfSAndrei Kartashev             {
103499e8f9dfSAndrei Kartashev                 lg2::error("Unable to read AC Boot status");
103599e8f9dfSAndrei Kartashev                 continue;
103699e8f9dfSAndrei Kartashev             }
103799e8f9dfSAndrei Kartashev             acBoot = *value;
103899e8f9dfSAndrei Kartashev         }
103999e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
104099e8f9dfSAndrei Kartashev     }
104199e8f9dfSAndrei Kartashev     invokeIfReady();
104299e8f9dfSAndrei Kartashev }
104399e8f9dfSAndrei Kartashev 
invokeIfReady()104499e8f9dfSAndrei Kartashev void PowerRestoreController::invokeIfReady()
104599e8f9dfSAndrei Kartashev {
104699e8f9dfSAndrei Kartashev     if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
104799e8f9dfSAndrei Kartashev     {
104899e8f9dfSAndrei Kartashev         return;
104999e8f9dfSAndrei Kartashev     }
105099e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
105199e8f9dfSAndrei Kartashev     if (acBoot.empty() || acBoot == "Unknown")
105299e8f9dfSAndrei Kartashev     {
105399e8f9dfSAndrei Kartashev         return;
105499e8f9dfSAndrei Kartashev     }
105599e8f9dfSAndrei Kartashev #endif
105699e8f9dfSAndrei Kartashev 
105799e8f9dfSAndrei Kartashev     matches.clear();
105899e8f9dfSAndrei Kartashev     if (!timerFired)
105999e8f9dfSAndrei Kartashev     {
106099e8f9dfSAndrei Kartashev         // Calculate the delay from now to meet the requested delay
106199e8f9dfSAndrei Kartashev         // Subtract the approximate uboot time
106299e8f9dfSAndrei Kartashev         static constexpr const int ubootSeconds = 20;
106399e8f9dfSAndrei Kartashev         int delay = powerRestoreDelay - ubootSeconds;
106499e8f9dfSAndrei Kartashev         // Subtract the time since boot
106599e8f9dfSAndrei Kartashev         struct sysinfo info = {};
106699e8f9dfSAndrei Kartashev         if (sysinfo(&info) == 0)
106799e8f9dfSAndrei Kartashev         {
106899e8f9dfSAndrei Kartashev             delay -= info.uptime;
106999e8f9dfSAndrei Kartashev         }
107099e8f9dfSAndrei Kartashev 
107199e8f9dfSAndrei Kartashev         if (delay > 0)
107299e8f9dfSAndrei Kartashev         {
107399e8f9dfSAndrei Kartashev             powerRestoreTimer.expires_after(std::chrono::seconds(delay));
107499e8f9dfSAndrei Kartashev             lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
107599e8f9dfSAndrei Kartashev                       delay);
1076a0a39f82SPatrick Williams             powerRestoreTimer.async_wait([this](const boost::system::error_code
1077a0a39f82SPatrick Williams                                                     ec) {
107899e8f9dfSAndrei Kartashev                 if (ec)
107999e8f9dfSAndrei Kartashev                 {
108099e8f9dfSAndrei Kartashev                     // operation_aborted is expected if timer is canceled before
108199e8f9dfSAndrei Kartashev                     // completion.
108299e8f9dfSAndrei Kartashev                     if (ec == boost::asio::error::operation_aborted)
108399e8f9dfSAndrei Kartashev                     {
108499e8f9dfSAndrei Kartashev                         return;
108599e8f9dfSAndrei Kartashev                     }
108699e8f9dfSAndrei Kartashev                     lg2::error(
108799e8f9dfSAndrei Kartashev                         "power restore policy async_wait failed: {ERROR_MSG}",
108899e8f9dfSAndrei Kartashev                         "ERROR_MSG", ec.message());
108999e8f9dfSAndrei Kartashev                 }
109099e8f9dfSAndrei Kartashev                 else
109199e8f9dfSAndrei Kartashev                 {
109299e8f9dfSAndrei Kartashev                     lg2::info("Power Restore delay timer expired");
109399e8f9dfSAndrei Kartashev                 }
109499e8f9dfSAndrei Kartashev                 invoke();
109599e8f9dfSAndrei Kartashev             });
109699e8f9dfSAndrei Kartashev             timerFired = true;
109799e8f9dfSAndrei Kartashev         }
109899e8f9dfSAndrei Kartashev         else
109999e8f9dfSAndrei Kartashev         {
110099e8f9dfSAndrei Kartashev             invoke();
110199e8f9dfSAndrei Kartashev         }
110299e8f9dfSAndrei Kartashev     }
110399e8f9dfSAndrei Kartashev }
110499e8f9dfSAndrei Kartashev 
invoke()110599e8f9dfSAndrei Kartashev void PowerRestoreController::invoke()
110699e8f9dfSAndrei Kartashev {
110799e8f9dfSAndrei Kartashev     // we want to run Power Restore only once
11080d57f4e3SJason M. Bills     if (policyInvoked)
11090d57f4e3SJason M. Bills     {
11100d57f4e3SJason M. Bills         return;
11110d57f4e3SJason M. Bills     }
11120d57f4e3SJason M. Bills     policyInvoked = true;
11130d57f4e3SJason M. Bills 
111499e8f9dfSAndrei Kartashev     lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
111599e8f9dfSAndrei Kartashev               powerRestorePolicy);
111699e8f9dfSAndrei Kartashev     if (powerRestorePolicy ==
11170d57f4e3SJason M. Bills         "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
11180d57f4e3SJason M. Bills     {
11190d57f4e3SJason M. Bills         sendPowerControlEvent(Event::powerOnRequest);
11200d57f4e3SJason M. Bills         setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
11210d57f4e3SJason M. Bills     }
112299e8f9dfSAndrei Kartashev     else if (powerRestorePolicy ==
11230d57f4e3SJason M. Bills              "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
11240d57f4e3SJason M. Bills     {
11250d57f4e3SJason M. Bills         if (wasPowerDropped())
11260d57f4e3SJason M. Bills         {
1127c46ebb49SJason M. Bills             lg2::info("Power was dropped, restoring Host On state");
11280d57f4e3SJason M. Bills             sendPowerControlEvent(Event::powerOnRequest);
11290d57f4e3SJason M. Bills             setRestartCauseProperty(
11300d57f4e3SJason M. Bills                 getRestartCause(RestartCause::powerPolicyRestore));
11310d57f4e3SJason M. Bills         }
11320d57f4e3SJason M. Bills         else
11330d57f4e3SJason M. Bills         {
1134c46ebb49SJason M. Bills             lg2::info("No power drop, restoring Host Off state");
11350d57f4e3SJason M. Bills         }
11360d57f4e3SJason M. Bills     }
11370d57f4e3SJason M. Bills     // We're done with the previous power state for the restore policy, so store
11380d57f4e3SJason M. Bills     // the current state
11390d57f4e3SJason M. Bills     savePowerState(powerState);
11400d57f4e3SJason M. Bills }
11410d57f4e3SJason M. Bills 
wasPowerDropped()114299e8f9dfSAndrei Kartashev bool PowerRestoreController::wasPowerDropped()
11430d57f4e3SJason M. Bills {
114499e8f9dfSAndrei Kartashev     std::string state = appState.get(PersistentState::Params::PowerState);
114599e8f9dfSAndrei Kartashev     return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
11460d57f4e3SJason M. Bills }
11470d57f4e3SJason M. Bills 
waitForGPIOEvent(const std::string & name,const std::function<void (bool)> & eventHandler,gpiod::line & line,boost::asio::posix::stream_descriptor & event)1148a0a39f82SPatrick Williams static void waitForGPIOEvent(
1149a0a39f82SPatrick Williams     const std::string& name, const std::function<void(bool)>& eventHandler,
1150a0a39f82SPatrick Williams     gpiod::line& line, boost::asio::posix::stream_descriptor& event)
11510d57f4e3SJason M. Bills {
1152a0a39f82SPatrick Williams     event.async_wait(
1153a0a39f82SPatrick Williams         boost::asio::posix::stream_descriptor::wait_read,
11540d57f4e3SJason M. Bills         [&name, eventHandler, &line,
11550d57f4e3SJason M. Bills          &event](const boost::system::error_code ec) {
11560d57f4e3SJason M. Bills             if (ec)
11570d57f4e3SJason M. Bills             {
1158a0a39f82SPatrick Williams                 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}",
1159a0a39f82SPatrick Williams                            "GPIO_NAME", name, "ERROR_MSG", ec.message());
1160c46ebb49SJason M. Bills                 // TODO: throw here to force power-control to
1161c46ebb49SJason M. Bills                 // restart?
11620d57f4e3SJason M. Bills                 return;
11630d57f4e3SJason M. Bills             }
11640d57f4e3SJason M. Bills             gpiod::line_event line_event = line.event_read();
1165a0a39f82SPatrick Williams             eventHandler(line_event.event_type ==
1166a0a39f82SPatrick Williams                          gpiod::line_event::RISING_EDGE);
11670d57f4e3SJason M. Bills             waitForGPIOEvent(name, eventHandler, line, event);
11680d57f4e3SJason M. Bills         });
11690d57f4e3SJason M. Bills }
11700d57f4e3SJason M. Bills 
requestGPIOEvents(const std::string & name,const std::function<void (bool)> & handler,gpiod::line & gpioLine,boost::asio::posix::stream_descriptor & gpioEventDescriptor)11710d57f4e3SJason M. Bills static bool requestGPIOEvents(
11720d57f4e3SJason M. Bills     const std::string& name, const std::function<void(bool)>& handler,
11730d57f4e3SJason M. Bills     gpiod::line& gpioLine,
11740d57f4e3SJason M. Bills     boost::asio::posix::stream_descriptor& gpioEventDescriptor)
11750d57f4e3SJason M. Bills {
11760d57f4e3SJason M. Bills     // Find the GPIO line
11770d57f4e3SJason M. Bills     gpioLine = gpiod::find_line(name);
11780d57f4e3SJason M. Bills     if (!gpioLine)
11790d57f4e3SJason M. Bills     {
1180c46ebb49SJason M. Bills         lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
11810d57f4e3SJason M. Bills         return false;
11820d57f4e3SJason M. Bills     }
11830d57f4e3SJason M. Bills 
11840d57f4e3SJason M. Bills     try
11850d57f4e3SJason M. Bills     {
11863efcf37bSAndrei Kartashev         gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
11870d57f4e3SJason M. Bills     }
1188c46ebb49SJason M. Bills     catch (const std::exception& e)
11890d57f4e3SJason M. Bills     {
1190c46ebb49SJason M. Bills         lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1191c46ebb49SJason M. Bills                    "GPIO_NAME", name, "ERROR", e);
11920d57f4e3SJason M. Bills         return false;
11930d57f4e3SJason M. Bills     }
11940d57f4e3SJason M. Bills 
11950d57f4e3SJason M. Bills     int gpioLineFd = gpioLine.event_get_fd();
11960d57f4e3SJason M. Bills     if (gpioLineFd < 0)
11970d57f4e3SJason M. Bills     {
1198c46ebb49SJason M. Bills         lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
11990d57f4e3SJason M. Bills         return false;
12000d57f4e3SJason M. Bills     }
12010d57f4e3SJason M. Bills 
12020d57f4e3SJason M. Bills     gpioEventDescriptor.assign(gpioLineFd);
12030d57f4e3SJason M. Bills 
12040d57f4e3SJason M. Bills     waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
12050d57f4e3SJason M. Bills     return true;
12060d57f4e3SJason M. Bills }
12070d57f4e3SJason M. Bills 
setGPIOOutput(const std::string & name,const int value,gpiod::line & gpioLine)12080d57f4e3SJason M. Bills static bool setGPIOOutput(const std::string& name, const int value,
12090d57f4e3SJason M. Bills                           gpiod::line& gpioLine)
12100d57f4e3SJason M. Bills {
12110d57f4e3SJason M. Bills     // Find the GPIO line
12120d57f4e3SJason M. Bills     gpioLine = gpiod::find_line(name);
12130d57f4e3SJason M. Bills     if (!gpioLine)
12140d57f4e3SJason M. Bills     {
1215c46ebb49SJason M. Bills         lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
12160d57f4e3SJason M. Bills         return false;
12170d57f4e3SJason M. Bills     }
12180d57f4e3SJason M. Bills 
12190d57f4e3SJason M. Bills     // Request GPIO output to specified value
12200d57f4e3SJason M. Bills     try
12210d57f4e3SJason M. Bills     {
12223efcf37bSAndrei Kartashev         gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
12233efcf37bSAndrei Kartashev                          value);
12240d57f4e3SJason M. Bills     }
1225c46ebb49SJason M. Bills     catch (const std::exception& e)
12260d57f4e3SJason M. Bills     {
1227c46ebb49SJason M. Bills         lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1228c46ebb49SJason M. Bills                    name, "ERROR", e);
12290d57f4e3SJason M. Bills         return false;
12300d57f4e3SJason M. Bills     }
12310d57f4e3SJason M. Bills 
1232c46ebb49SJason M. Bills     lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1233c46ebb49SJason M. Bills               "GPIO_VALUE", value);
12340d57f4e3SJason M. Bills     return true;
12350d57f4e3SJason M. Bills }
12360d57f4e3SJason M. Bills 
setMaskedGPIOOutputForMs(gpiod::line & maskedGPIOLine,const std::string & name,const int value,const int durationMs)12370d57f4e3SJason M. Bills static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
12380d57f4e3SJason M. Bills                                     const std::string& name, const int value,
12390d57f4e3SJason M. Bills                                     const int durationMs)
12400d57f4e3SJason M. Bills {
12410d57f4e3SJason M. Bills     // Set the masked GPIO line to the specified value
12420d57f4e3SJason M. Bills     maskedGPIOLine.set_value(value);
1243c46ebb49SJason M. Bills     lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1244c46ebb49SJason M. Bills               "GPIO_VALUE", value);
12450d57f4e3SJason M. Bills     gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1246c46ebb49SJason M. Bills     gpioAssertTimer.async_wait(
1247c46ebb49SJason M. Bills         [maskedGPIOLine, value, name](const boost::system::error_code ec) {
12480d57f4e3SJason M. Bills             // Set the masked GPIO line back to the opposite value
12490d57f4e3SJason M. Bills             maskedGPIOLine.set_value(!value);
1250c46ebb49SJason M. Bills             lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
12510d57f4e3SJason M. Bills             if (ec)
12520d57f4e3SJason M. Bills             {
12530d57f4e3SJason M. Bills                 // operation_aborted is expected if timer is canceled before
12540d57f4e3SJason M. Bills                 // completion.
12550d57f4e3SJason M. Bills                 if (ec != boost::asio::error::operation_aborted)
12560d57f4e3SJason M. Bills                 {
1257c46ebb49SJason M. Bills                     lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1258c46ebb49SJason M. Bills                                "GPIO_NAME", name, "ERROR_MSG", ec.message());
12590d57f4e3SJason M. Bills                 }
12600d57f4e3SJason M. Bills             }
12610d57f4e3SJason M. Bills         });
12620d57f4e3SJason M. Bills     return 0;
12630d57f4e3SJason M. Bills }
12640d57f4e3SJason M. Bills 
setGPIOOutputForMs(const ConfigData & config,const int value,const int durationMs)12650d57f4e3SJason M. Bills static int setGPIOOutputForMs(const ConfigData& config, const int value,
12660d57f4e3SJason M. Bills                               const int durationMs)
12670d57f4e3SJason M. Bills {
12680d57f4e3SJason M. Bills     // If the requested GPIO is masked, use the mask line to set the output
12690d57f4e3SJason M. Bills     if (powerButtonMask && config.lineName == powerOutConfig.lineName)
12700d57f4e3SJason M. Bills     {
12710d57f4e3SJason M. Bills         return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
12720d57f4e3SJason M. Bills                                         durationMs);
12730d57f4e3SJason M. Bills     }
12740d57f4e3SJason M. Bills     if (resetButtonMask && config.lineName == resetOutConfig.lineName)
12750d57f4e3SJason M. Bills     {
12760d57f4e3SJason M. Bills         return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
12770d57f4e3SJason M. Bills                                         durationMs);
12780d57f4e3SJason M. Bills     }
12790d57f4e3SJason M. Bills 
12800d57f4e3SJason M. Bills     // No mask set, so request and set the GPIO normally
12810d57f4e3SJason M. Bills     gpiod::line gpioLine;
12820d57f4e3SJason M. Bills     if (!setGPIOOutput(config.lineName, value, gpioLine))
12830d57f4e3SJason M. Bills     {
12840d57f4e3SJason M. Bills         return -1;
12850d57f4e3SJason M. Bills     }
12860d57f4e3SJason M. Bills     const std::string name = config.lineName;
12870d57f4e3SJason M. Bills 
12880d57f4e3SJason M. Bills     gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1289c46ebb49SJason M. Bills     gpioAssertTimer.async_wait(
1290c46ebb49SJason M. Bills         [gpioLine, value, name](const boost::system::error_code ec) {
12910d57f4e3SJason M. Bills             // Set the GPIO line back to the opposite value
12920d57f4e3SJason M. Bills             gpioLine.set_value(!value);
1293c46ebb49SJason M. Bills             lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
12940d57f4e3SJason M. Bills             if (ec)
12950d57f4e3SJason M. Bills             {
12960d57f4e3SJason M. Bills                 // operation_aborted is expected if timer is canceled before
12970d57f4e3SJason M. Bills                 // completion.
12980d57f4e3SJason M. Bills                 if (ec != boost::asio::error::operation_aborted)
12990d57f4e3SJason M. Bills                 {
1300c46ebb49SJason M. Bills                     lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1301c46ebb49SJason M. Bills                                "GPIO_NAME", name, "ERROR_MSG", ec.message());
13020d57f4e3SJason M. Bills                 }
13030d57f4e3SJason M. Bills             }
13040d57f4e3SJason M. Bills         });
13050d57f4e3SJason M. Bills     return 0;
13060d57f4e3SJason M. Bills }
13070d57f4e3SJason M. Bills 
assertGPIOForMs(const ConfigData & config,const int durationMs)13080d57f4e3SJason M. Bills static int assertGPIOForMs(const ConfigData& config, const int durationMs)
13090d57f4e3SJason M. Bills {
13100d57f4e3SJason M. Bills     return setGPIOOutputForMs(config, config.polarity, durationMs);
13110d57f4e3SJason M. Bills }
13120d57f4e3SJason M. Bills 
powerOn()13130d57f4e3SJason M. Bills static void powerOn()
13140d57f4e3SJason M. Bills {
13150d57f4e3SJason M. Bills     assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
13160d57f4e3SJason M. Bills }
13170d57f4e3SJason M. Bills #ifdef CHASSIS_SYSTEM_RESET
slotPowerOn()13180d57f4e3SJason M. Bills static int slotPowerOn()
13190d57f4e3SJason M. Bills {
13200d57f4e3SJason M. Bills     if (power_control::slotPowerState != power_control::SlotPowerState::on)
13210d57f4e3SJason M. Bills     {
13220d57f4e3SJason M. Bills         slotPowerLine.set_value(1);
13230d57f4e3SJason M. Bills 
13240d57f4e3SJason M. Bills         if (slotPowerLine.get_value() > 0)
13250d57f4e3SJason M. Bills         {
13260d57f4e3SJason M. Bills             setSlotPowerState(SlotPowerState::on);
1327c46ebb49SJason M. Bills             lg2::info("Slot Power is switched On\n");
13280d57f4e3SJason M. Bills         }
13290d57f4e3SJason M. Bills         else
13300d57f4e3SJason M. Bills         {
13310d57f4e3SJason M. Bills             return -1;
13320d57f4e3SJason M. Bills         }
13330d57f4e3SJason M. Bills     }
13340d57f4e3SJason M. Bills     else
13350d57f4e3SJason M. Bills     {
1336c46ebb49SJason M. Bills         lg2::info("Slot Power is already in 'On' state\n");
13370d57f4e3SJason M. Bills         return -1;
13380d57f4e3SJason M. Bills     }
13390d57f4e3SJason M. Bills     return 0;
13400d57f4e3SJason M. Bills }
slotPowerOff()13410d57f4e3SJason M. Bills static int slotPowerOff()
13420d57f4e3SJason M. Bills {
13430d57f4e3SJason M. Bills     if (power_control::slotPowerState != power_control::SlotPowerState::off)
13440d57f4e3SJason M. Bills     {
13450d57f4e3SJason M. Bills         slotPowerLine.set_value(0);
13460d57f4e3SJason M. Bills 
13470d57f4e3SJason M. Bills         if (!(slotPowerLine.get_value() > 0))
13480d57f4e3SJason M. Bills         {
13490d57f4e3SJason M. Bills             setSlotPowerState(SlotPowerState::off);
13500d57f4e3SJason M. Bills             setPowerState(PowerState::off);
1351c46ebb49SJason M. Bills             lg2::info("Slot Power is switched Off\n");
13520d57f4e3SJason M. Bills         }
13530d57f4e3SJason M. Bills         else
13540d57f4e3SJason M. Bills         {
13550d57f4e3SJason M. Bills             return -1;
13560d57f4e3SJason M. Bills         }
13570d57f4e3SJason M. Bills     }
13580d57f4e3SJason M. Bills     else
13590d57f4e3SJason M. Bills     {
1360c46ebb49SJason M. Bills         lg2::info("Slot Power is already in 'Off' state\n");
13610d57f4e3SJason M. Bills         return -1;
13620d57f4e3SJason M. Bills     }
13630d57f4e3SJason M. Bills     return 0;
13640d57f4e3SJason M. Bills }
slotPowerCycle()13650d57f4e3SJason M. Bills static void slotPowerCycle()
13660d57f4e3SJason M. Bills {
1367c46ebb49SJason M. Bills     lg2::info("Slot Power Cycle started\n");
13680d57f4e3SJason M. Bills     slotPowerOff();
13690d57f4e3SJason M. Bills     slotPowerCycleTimer.expires_after(
13700d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
13710d57f4e3SJason M. Bills     slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
13720d57f4e3SJason M. Bills         if (ec)
13730d57f4e3SJason M. Bills         {
13740d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
13750d57f4e3SJason M. Bills             {
1376c46ebb49SJason M. Bills                 lg2::error(
1377c46ebb49SJason M. Bills                     "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1378c46ebb49SJason M. Bills                     "ERROR_MSG", ec.message());
13790d57f4e3SJason M. Bills             }
1380c46ebb49SJason M. Bills             lg2::info("Slot Power cycle timer canceled\n");
13810d57f4e3SJason M. Bills             return;
13820d57f4e3SJason M. Bills         }
1383c46ebb49SJason M. Bills         lg2::info("Slot Power cycle timer completed\n");
13840d57f4e3SJason M. Bills         slotPowerOn();
1385c46ebb49SJason M. Bills         lg2::info("Slot Power Cycle Completed\n");
13860d57f4e3SJason M. Bills     });
13870d57f4e3SJason M. Bills }
13880d57f4e3SJason M. Bills #endif
gracefulPowerOff()13890d57f4e3SJason M. Bills static void gracefulPowerOff()
13900d57f4e3SJason M. Bills {
13910d57f4e3SJason M. Bills     assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
13920d57f4e3SJason M. Bills }
13930d57f4e3SJason M. Bills 
forcePowerOff()13940d57f4e3SJason M. Bills static void forcePowerOff()
13950d57f4e3SJason M. Bills {
13960d57f4e3SJason M. Bills     if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
13970d57f4e3SJason M. Bills     {
13980d57f4e3SJason M. Bills         return;
13990d57f4e3SJason M. Bills     }
14000d57f4e3SJason M. Bills 
14010d57f4e3SJason M. Bills     // If the force off timer expires, then the power-button override failed
14020d57f4e3SJason M. Bills     gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
14030d57f4e3SJason M. Bills         if (ec)
14040d57f4e3SJason M. Bills         {
14050d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
14060d57f4e3SJason M. Bills             // completion.
14070d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
14080d57f4e3SJason M. Bills             {
1409c46ebb49SJason M. Bills                 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1410c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
14110d57f4e3SJason M. Bills             }
14120d57f4e3SJason M. Bills             return;
14130d57f4e3SJason M. Bills         }
14140d57f4e3SJason M. Bills 
1415c46ebb49SJason M. Bills         lg2::error("Power-button override failed. Not sure what to do now.");
14160d57f4e3SJason M. Bills     });
14170d57f4e3SJason M. Bills }
14180d57f4e3SJason M. Bills 
reset()14190d57f4e3SJason M. Bills static void reset()
14200d57f4e3SJason M. Bills {
14210d57f4e3SJason M. Bills     assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
14220d57f4e3SJason M. Bills }
14230d57f4e3SJason M. Bills 
gracefulPowerOffTimerStart()14240d57f4e3SJason M. Bills static void gracefulPowerOffTimerStart()
14250d57f4e3SJason M. Bills {
1426c46ebb49SJason M. Bills     lg2::info("Graceful power-off timer started");
14270d57f4e3SJason M. Bills     gracefulPowerOffTimer.expires_after(
14280d57f4e3SJason M. Bills         std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
14290d57f4e3SJason M. Bills     gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
14300d57f4e3SJason M. Bills         if (ec)
14310d57f4e3SJason M. Bills         {
14320d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
14330d57f4e3SJason M. Bills             // completion.
14340d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
14350d57f4e3SJason M. Bills             {
1436c46ebb49SJason M. Bills                 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1437c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
14380d57f4e3SJason M. Bills             }
1439c46ebb49SJason M. Bills             lg2::info("Graceful power-off timer canceled");
14400d57f4e3SJason M. Bills             return;
14410d57f4e3SJason M. Bills         }
1442c46ebb49SJason M. Bills         lg2::info("Graceful power-off timer completed");
14430d57f4e3SJason M. Bills         sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
14440d57f4e3SJason M. Bills     });
14450d57f4e3SJason M. Bills }
14460d57f4e3SJason M. Bills 
powerCycleTimerStart()14470d57f4e3SJason M. Bills static void powerCycleTimerStart()
14480d57f4e3SJason M. Bills {
1449c46ebb49SJason M. Bills     lg2::info("Power-cycle timer started");
14500d57f4e3SJason M. Bills     powerCycleTimer.expires_after(
14510d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
14520d57f4e3SJason M. Bills     powerCycleTimer.async_wait([](const boost::system::error_code ec) {
14530d57f4e3SJason M. Bills         if (ec)
14540d57f4e3SJason M. Bills         {
14550d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
14560d57f4e3SJason M. Bills             // completion.
14570d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
14580d57f4e3SJason M. Bills             {
1459c46ebb49SJason M. Bills                 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1460c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
14610d57f4e3SJason M. Bills             }
1462c46ebb49SJason M. Bills             lg2::info("Power-cycle timer canceled");
14630d57f4e3SJason M. Bills             return;
14640d57f4e3SJason M. Bills         }
1465c46ebb49SJason M. Bills         lg2::info("Power-cycle timer completed");
14660d57f4e3SJason M. Bills         sendPowerControlEvent(Event::powerCycleTimerExpired);
14670d57f4e3SJason M. Bills     });
14680d57f4e3SJason M. Bills }
14690d57f4e3SJason M. Bills 
psPowerOKWatchdogTimerStart()14700d57f4e3SJason M. Bills static void psPowerOKWatchdogTimerStart()
14710d57f4e3SJason M. Bills {
1472c46ebb49SJason M. Bills     lg2::info("power supply power OK watchdog timer started");
14730d57f4e3SJason M. Bills     psPowerOKWatchdogTimer.expires_after(
14740d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
14750d57f4e3SJason M. Bills     psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
14760d57f4e3SJason M. Bills         if (ec)
14770d57f4e3SJason M. Bills         {
14780d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
14790d57f4e3SJason M. Bills             // completion.
14800d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
14810d57f4e3SJason M. Bills             {
1482c46ebb49SJason M. Bills                 lg2::error(
1483c46ebb49SJason M. Bills                     "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1484c46ebb49SJason M. Bills                     "ERROR_MSG", ec.message());
14850d57f4e3SJason M. Bills             }
1486c46ebb49SJason M. Bills             lg2::info("power supply power OK watchdog timer canceled");
14870d57f4e3SJason M. Bills             return;
14880d57f4e3SJason M. Bills         }
1489c46ebb49SJason M. Bills         lg2::info("power supply power OK watchdog timer expired");
14900d57f4e3SJason M. Bills         sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
14910d57f4e3SJason M. Bills     });
14920d57f4e3SJason M. Bills }
14930d57f4e3SJason M. Bills 
warmResetCheckTimerStart()14940d57f4e3SJason M. Bills static void warmResetCheckTimerStart()
14950d57f4e3SJason M. Bills {
1496c46ebb49SJason M. Bills     lg2::info("Warm reset check timer started");
14970d57f4e3SJason M. Bills     warmResetCheckTimer.expires_after(
14980d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
14990d57f4e3SJason M. Bills     warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
15000d57f4e3SJason M. Bills         if (ec)
15010d57f4e3SJason M. Bills         {
15020d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
15030d57f4e3SJason M. Bills             // completion.
15040d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
15050d57f4e3SJason M. Bills             {
1506c46ebb49SJason M. Bills                 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1507c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
15080d57f4e3SJason M. Bills             }
1509c46ebb49SJason M. Bills             lg2::info("Warm reset check timer canceled");
15100d57f4e3SJason M. Bills             return;
15110d57f4e3SJason M. Bills         }
1512c46ebb49SJason M. Bills         lg2::info("Warm reset check timer completed");
15130d57f4e3SJason M. Bills         sendPowerControlEvent(Event::warmResetDetected);
15140d57f4e3SJason M. Bills     });
15150d57f4e3SJason M. Bills }
15160d57f4e3SJason M. Bills 
pohCounterTimerStart()15170d57f4e3SJason M. Bills static void pohCounterTimerStart()
15180d57f4e3SJason M. Bills {
1519c46ebb49SJason M. Bills     lg2::info("POH timer started");
15200d57f4e3SJason M. Bills     // Set the time-out as 1 hour, to align with POH command in ipmid
15210d57f4e3SJason M. Bills     pohCounterTimer.expires_after(std::chrono::hours(1));
15220d57f4e3SJason M. Bills     pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
15230d57f4e3SJason M. Bills         if (ec)
15240d57f4e3SJason M. Bills         {
15250d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
15260d57f4e3SJason M. Bills             // completion.
15270d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
15280d57f4e3SJason M. Bills             {
1529c46ebb49SJason M. Bills                 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1530c46ebb49SJason M. Bills                            "ERROR_MSG", ec.message());
15310d57f4e3SJason M. Bills             }
1532c46ebb49SJason M. Bills             lg2::info("POH timer canceled");
15330d57f4e3SJason M. Bills             return;
15340d57f4e3SJason M. Bills         }
15350d57f4e3SJason M. Bills 
15360d57f4e3SJason M. Bills         if (getHostState(powerState) !=
15370d57f4e3SJason M. Bills             "xyz.openbmc_project.State.Host.HostState.Running")
15380d57f4e3SJason M. Bills         {
15390d57f4e3SJason M. Bills             return;
15400d57f4e3SJason M. Bills         }
15410d57f4e3SJason M. Bills 
15420d57f4e3SJason M. Bills         conn->async_method_call(
15430d57f4e3SJason M. Bills             [](boost::system::error_code ec,
15440d57f4e3SJason M. Bills                const std::variant<uint32_t>& pohCounterProperty) {
15450d57f4e3SJason M. Bills                 if (ec)
15460d57f4e3SJason M. Bills                 {
1547c46ebb49SJason M. Bills                     lg2::error("error getting poh counter");
15480d57f4e3SJason M. Bills                     return;
15490d57f4e3SJason M. Bills                 }
15500d57f4e3SJason M. Bills                 const uint32_t* pohCounter =
15510d57f4e3SJason M. Bills                     std::get_if<uint32_t>(&pohCounterProperty);
15520d57f4e3SJason M. Bills                 if (pohCounter == nullptr)
15530d57f4e3SJason M. Bills                 {
1554c46ebb49SJason M. Bills                     lg2::error("unable to read poh counter");
15550d57f4e3SJason M. Bills                     return;
15560d57f4e3SJason M. Bills                 }
15570d57f4e3SJason M. Bills 
15580d57f4e3SJason M. Bills                 conn->async_method_call(
15590d57f4e3SJason M. Bills                     [](boost::system::error_code ec) {
15600d57f4e3SJason M. Bills                         if (ec)
15610d57f4e3SJason M. Bills                         {
1562c46ebb49SJason M. Bills                             lg2::error("failed to set poh counter");
15630d57f4e3SJason M. Bills                         }
15640d57f4e3SJason M. Bills                     },
15650d57f4e3SJason M. Bills                     "xyz.openbmc_project.Settings",
15660d57f4e3SJason M. Bills                     "/xyz/openbmc_project/state/chassis0",
15670d57f4e3SJason M. Bills                     "org.freedesktop.DBus.Properties", "Set",
15680d57f4e3SJason M. Bills                     "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
15690d57f4e3SJason M. Bills                     std::variant<uint32_t>(*pohCounter + 1));
15700d57f4e3SJason M. Bills             },
15710d57f4e3SJason M. Bills             "xyz.openbmc_project.Settings",
15720d57f4e3SJason M. Bills             "/xyz/openbmc_project/state/chassis0",
15730d57f4e3SJason M. Bills             "org.freedesktop.DBus.Properties", "Get",
15740d57f4e3SJason M. Bills             "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
15750d57f4e3SJason M. Bills 
15760d57f4e3SJason M. Bills         pohCounterTimerStart();
15770d57f4e3SJason M. Bills     });
15780d57f4e3SJason M. Bills }
15790d57f4e3SJason M. Bills 
currentHostStateMonitor()15800d57f4e3SJason M. Bills static void currentHostStateMonitor()
15810d57f4e3SJason M. Bills {
15820d57f4e3SJason M. Bills     if (getHostState(powerState) ==
15830d57f4e3SJason M. Bills         "xyz.openbmc_project.State.Host.HostState.Running")
15840d57f4e3SJason M. Bills     {
15850d57f4e3SJason M. Bills         pohCounterTimerStart();
15860d57f4e3SJason M. Bills         // Clear the restart cause set for the next restart
15870d57f4e3SJason M. Bills         clearRestartCause();
15880d57f4e3SJason M. Bills     }
15890d57f4e3SJason M. Bills     else
15900d57f4e3SJason M. Bills     {
15910d57f4e3SJason M. Bills         pohCounterTimer.cancel();
15920d57f4e3SJason M. Bills         // Set the restart cause set for this restart
15930d57f4e3SJason M. Bills         setRestartCause();
15940d57f4e3SJason M. Bills     }
15950d57f4e3SJason M. Bills 
1596a0a39f82SPatrick Williams     static auto match = sdbusplus::bus::match_t(
1597a0a39f82SPatrick Williams         *conn,
15980d57f4e3SJason M. Bills         "type='signal',member='PropertiesChanged', "
15990d57f4e3SJason M. Bills         "interface='org.freedesktop.DBus.Properties', "
16000d57f4e3SJason M. Bills         "arg0='xyz.openbmc_project.State.Host'",
1601439b9c3aSPatrick Williams         [](sdbusplus::message_t& message) {
16020d57f4e3SJason M. Bills             std::string intfName;
16030d57f4e3SJason M. Bills             std::map<std::string, std::variant<std::string>> properties;
16040d57f4e3SJason M. Bills 
16050d57f4e3SJason M. Bills             try
16060d57f4e3SJason M. Bills             {
16070d57f4e3SJason M. Bills                 message.read(intfName, properties);
16080d57f4e3SJason M. Bills             }
16090d57f4e3SJason M. Bills             catch (const std::exception& e)
16100d57f4e3SJason M. Bills             {
1611c46ebb49SJason M. Bills                 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
16120d57f4e3SJason M. Bills                 return;
16130d57f4e3SJason M. Bills             }
16140d57f4e3SJason M. Bills             if (properties.empty())
16150d57f4e3SJason M. Bills             {
1616c46ebb49SJason M. Bills                 lg2::error("ERROR: Empty PropertiesChanged signal received");
16170d57f4e3SJason M. Bills                 return;
16180d57f4e3SJason M. Bills             }
16190d57f4e3SJason M. Bills 
16200d57f4e3SJason M. Bills             // We only want to check for CurrentHostState
16210d57f4e3SJason M. Bills             if (properties.begin()->first != "CurrentHostState")
16220d57f4e3SJason M. Bills             {
16230d57f4e3SJason M. Bills                 return;
16240d57f4e3SJason M. Bills             }
16250d57f4e3SJason M. Bills             std::string* currentHostState =
16260d57f4e3SJason M. Bills                 std::get_if<std::string>(&(properties.begin()->second));
16270d57f4e3SJason M. Bills             if (currentHostState == nullptr)
16280d57f4e3SJason M. Bills             {
1629c46ebb49SJason M. Bills                 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1630c46ebb49SJason M. Bills                            properties.begin()->first);
16310d57f4e3SJason M. Bills                 return;
16320d57f4e3SJason M. Bills             }
16330d57f4e3SJason M. Bills 
16340d57f4e3SJason M. Bills             if (*currentHostState ==
16350d57f4e3SJason M. Bills                 "xyz.openbmc_project.State.Host.HostState.Running")
16360d57f4e3SJason M. Bills             {
16370d57f4e3SJason M. Bills                 pohCounterTimerStart();
16380d57f4e3SJason M. Bills                 // Clear the restart cause set for the next restart
16390d57f4e3SJason M. Bills                 clearRestartCause();
1640a0a39f82SPatrick Williams                 sd_journal_send("MESSAGE=Host system DC power is on",
1641a0a39f82SPatrick Williams                                 "PRIORITY=%i", LOG_INFO,
1642a0a39f82SPatrick Williams                                 "REDFISH_MESSAGE_ID=%s",
16430d57f4e3SJason M. Bills                                 "OpenBMC.0.1.DCPowerOn", NULL);
16440d57f4e3SJason M. Bills             }
16450d57f4e3SJason M. Bills             else
16460d57f4e3SJason M. Bills             {
16470d57f4e3SJason M. Bills                 pohCounterTimer.cancel();
16480d57f4e3SJason M. Bills                 // POST_COMPLETE GPIO event is not working in some platforms
16490d57f4e3SJason M. Bills                 // when power state is changed to OFF. This resulted in
16500d57f4e3SJason M. Bills                 // 'OperatingSystemState' to stay at 'Standby', even though
16510d57f4e3SJason M. Bills                 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
16520d57f4e3SJason M. Bills                 // if HostState is trurned to OFF.
16538623918bSTim Lee                 setOperatingSystemState(OperatingSystemStateStage::Inactive);
16540d57f4e3SJason M. Bills 
16550d57f4e3SJason M. Bills                 // Set the restart cause set for this restart
16560d57f4e3SJason M. Bills                 setRestartCause();
165799e8f9dfSAndrei Kartashev #ifdef USE_ACBOOT
16580d57f4e3SJason M. Bills                 resetACBootProperty();
165999e8f9dfSAndrei Kartashev #endif // USE_ACBOOT
16600d57f4e3SJason M. Bills                 sd_journal_send("MESSAGE=Host system DC power is off",
1661a0a39f82SPatrick Williams                                 "PRIORITY=%i", LOG_INFO,
1662a0a39f82SPatrick Williams                                 "REDFISH_MESSAGE_ID=%s",
16630d57f4e3SJason M. Bills                                 "OpenBMC.0.1.DCPowerOff", NULL);
16640d57f4e3SJason M. Bills             }
16650d57f4e3SJason M. Bills         });
16660d57f4e3SJason M. Bills }
16670d57f4e3SJason M. Bills 
sioPowerGoodWatchdogTimerStart()16680d57f4e3SJason M. Bills static void sioPowerGoodWatchdogTimerStart()
16690d57f4e3SJason M. Bills {
1670c46ebb49SJason M. Bills     lg2::info("SIO power good watchdog timer started");
16710d57f4e3SJason M. Bills     sioPowerGoodWatchdogTimer.expires_after(
16720d57f4e3SJason M. Bills         std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
1673a0a39f82SPatrick Williams     sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1674a0a39f82SPatrick Williams                                                 ec) {
16750d57f4e3SJason M. Bills         if (ec)
16760d57f4e3SJason M. Bills         {
16770d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
16780d57f4e3SJason M. Bills             // completion.
16790d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
16800d57f4e3SJason M. Bills             {
1681c46ebb49SJason M. Bills                 lg2::error(
1682c46ebb49SJason M. Bills                     "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1683c46ebb49SJason M. Bills                     "ERROR_MSG", ec.message());
16840d57f4e3SJason M. Bills             }
1685c46ebb49SJason M. Bills             lg2::info("SIO power good watchdog timer canceled");
16860d57f4e3SJason M. Bills             return;
16870d57f4e3SJason M. Bills         }
1688c46ebb49SJason M. Bills         lg2::info("SIO power good watchdog timer completed");
16890d57f4e3SJason M. Bills         sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
16900d57f4e3SJason M. Bills     });
16910d57f4e3SJason M. Bills }
16920d57f4e3SJason M. Bills 
powerStateOn(const Event event)16930d57f4e3SJason M. Bills static void powerStateOn(const Event event)
16940d57f4e3SJason M. Bills {
16950d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
16960d57f4e3SJason M. Bills     switch (event)
16970d57f4e3SJason M. Bills     {
16980d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
16990d57f4e3SJason M. Bills             setPowerState(PowerState::off);
17000d57f4e3SJason M. Bills             // DC power is unexpectedly lost, beep
17010d57f4e3SJason M. Bills             beep(beepPowerFail);
17020d57f4e3SJason M. Bills             break;
17030d57f4e3SJason M. Bills         case Event::sioS5Assert:
17040d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToOff);
170558e379d1SMatt Simmering #if IGNORE_SOFT_RESETS_DURING_POST
170658e379d1SMatt Simmering             // Only recognize soft resets once host gets past POST COMPLETE
170758e379d1SMatt Simmering             if (operatingSystemState != OperatingSystemStateStage::Standby)
170858e379d1SMatt Simmering             {
170958e379d1SMatt Simmering                 ignoreNextSoftReset = true;
171058e379d1SMatt Simmering             }
171158e379d1SMatt Simmering #endif
17120d57f4e3SJason M. Bills             addRestartCause(RestartCause::softReset);
17130d57f4e3SJason M. Bills             break;
17140d57f4e3SJason M. Bills #if USE_PLT_RST
17150d57f4e3SJason M. Bills         case Event::pltRstAssert:
17160d57f4e3SJason M. Bills #else
17170d57f4e3SJason M. Bills         case Event::postCompleteDeAssert:
17180d57f4e3SJason M. Bills #endif
17190d57f4e3SJason M. Bills             setPowerState(PowerState::checkForWarmReset);
172058e379d1SMatt Simmering #if IGNORE_SOFT_RESETS_DURING_POST
172158e379d1SMatt Simmering             // Only recognize soft resets once host gets past POST COMPLETE
172258e379d1SMatt Simmering             if (operatingSystemState != OperatingSystemStateStage::Standby)
172358e379d1SMatt Simmering             {
172458e379d1SMatt Simmering                 ignoreNextSoftReset = true;
172558e379d1SMatt Simmering             }
172658e379d1SMatt Simmering #endif
17270d57f4e3SJason M. Bills             addRestartCause(RestartCause::softReset);
17280d57f4e3SJason M. Bills             warmResetCheckTimerStart();
17290d57f4e3SJason M. Bills             break;
17300d57f4e3SJason M. Bills         case Event::powerButtonPressed:
17310d57f4e3SJason M. Bills             setPowerState(PowerState::gracefulTransitionToOff);
17320d57f4e3SJason M. Bills             gracefulPowerOffTimerStart();
17330d57f4e3SJason M. Bills             break;
17340d57f4e3SJason M. Bills         case Event::powerOffRequest:
17350d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToOff);
17360d57f4e3SJason M. Bills             forcePowerOff();
17370d57f4e3SJason M. Bills             break;
17380d57f4e3SJason M. Bills         case Event::gracefulPowerOffRequest:
17390d57f4e3SJason M. Bills             setPowerState(PowerState::gracefulTransitionToOff);
17400d57f4e3SJason M. Bills             gracefulPowerOffTimerStart();
17410d57f4e3SJason M. Bills             gracefulPowerOff();
17420d57f4e3SJason M. Bills             break;
17430d57f4e3SJason M. Bills         case Event::powerCycleRequest:
17440d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToCycleOff);
17450d57f4e3SJason M. Bills             forcePowerOff();
17460d57f4e3SJason M. Bills             break;
17470d57f4e3SJason M. Bills         case Event::gracefulPowerCycleRequest:
17480d57f4e3SJason M. Bills             setPowerState(PowerState::gracefulTransitionToCycleOff);
17490d57f4e3SJason M. Bills             gracefulPowerOffTimerStart();
17500d57f4e3SJason M. Bills             gracefulPowerOff();
17510d57f4e3SJason M. Bills             break;
1752dc0bab92SJayanth Othayoth         case Event::resetButtonPressed:
1753dc0bab92SJayanth Othayoth             setPowerState(PowerState::checkForWarmReset);
1754dc0bab92SJayanth Othayoth             warmResetCheckTimerStart();
1755dc0bab92SJayanth Othayoth             break;
17560d57f4e3SJason M. Bills         case Event::resetRequest:
17570d57f4e3SJason M. Bills             reset();
17580d57f4e3SJason M. Bills             break;
17590d57f4e3SJason M. Bills         default:
1760c46ebb49SJason M. Bills             lg2::info("No action taken.");
17610d57f4e3SJason M. Bills             break;
17620d57f4e3SJason M. Bills     }
17630d57f4e3SJason M. Bills }
17640d57f4e3SJason M. Bills 
powerStateWaitForPSPowerOK(const Event event)17650d57f4e3SJason M. Bills static void powerStateWaitForPSPowerOK(const Event event)
17660d57f4e3SJason M. Bills {
17670d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
17680d57f4e3SJason M. Bills     switch (event)
17690d57f4e3SJason M. Bills     {
17700d57f4e3SJason M. Bills         case Event::psPowerOKAssert:
17710d57f4e3SJason M. Bills         {
17720d57f4e3SJason M. Bills             // Cancel any GPIO assertions held during the transition
17730d57f4e3SJason M. Bills             gpioAssertTimer.cancel();
17740d57f4e3SJason M. Bills             psPowerOKWatchdogTimer.cancel();
17750d57f4e3SJason M. Bills             if (sioEnabled == true)
17760d57f4e3SJason M. Bills             {
17770d57f4e3SJason M. Bills                 sioPowerGoodWatchdogTimerStart();
17780d57f4e3SJason M. Bills                 setPowerState(PowerState::waitForSIOPowerGood);
17790d57f4e3SJason M. Bills             }
17800d57f4e3SJason M. Bills             else
17810d57f4e3SJason M. Bills             {
17820d57f4e3SJason M. Bills                 setPowerState(PowerState::on);
17830d57f4e3SJason M. Bills             }
17840d57f4e3SJason M. Bills             break;
17850d57f4e3SJason M. Bills         }
17860d57f4e3SJason M. Bills         case Event::psPowerOKWatchdogTimerExpired:
17870d57f4e3SJason M. Bills             setPowerState(PowerState::off);
17880d57f4e3SJason M. Bills             psPowerOKFailedLog();
17890d57f4e3SJason M. Bills             break;
17900d57f4e3SJason M. Bills         case Event::sioPowerGoodAssert:
17910d57f4e3SJason M. Bills             psPowerOKWatchdogTimer.cancel();
17920d57f4e3SJason M. Bills             setPowerState(PowerState::on);
17930d57f4e3SJason M. Bills             break;
17940d57f4e3SJason M. Bills         default:
1795c46ebb49SJason M. Bills             lg2::info("No action taken.");
17960d57f4e3SJason M. Bills             break;
17970d57f4e3SJason M. Bills     }
17980d57f4e3SJason M. Bills }
17990d57f4e3SJason M. Bills 
powerStateWaitForSIOPowerGood(const Event event)18000d57f4e3SJason M. Bills static void powerStateWaitForSIOPowerGood(const Event event)
18010d57f4e3SJason M. Bills {
18020d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
18030d57f4e3SJason M. Bills     switch (event)
18040d57f4e3SJason M. Bills     {
18050d57f4e3SJason M. Bills         case Event::sioPowerGoodAssert:
18060d57f4e3SJason M. Bills             sioPowerGoodWatchdogTimer.cancel();
18070d57f4e3SJason M. Bills             setPowerState(PowerState::on);
18080d57f4e3SJason M. Bills             break;
18090d57f4e3SJason M. Bills         case Event::sioPowerGoodWatchdogTimerExpired:
18100d57f4e3SJason M. Bills             setPowerState(PowerState::off);
18110d57f4e3SJason M. Bills             systemPowerGoodFailedLog();
18120d57f4e3SJason M. Bills             break;
18130d57f4e3SJason M. Bills         default:
1814c46ebb49SJason M. Bills             lg2::info("No action taken.");
18150d57f4e3SJason M. Bills             break;
18160d57f4e3SJason M. Bills     }
18170d57f4e3SJason M. Bills }
18180d57f4e3SJason M. Bills 
powerStateOff(const Event event)18190d57f4e3SJason M. Bills static void powerStateOff(const Event event)
18200d57f4e3SJason M. Bills {
18210d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
18220d57f4e3SJason M. Bills     switch (event)
18230d57f4e3SJason M. Bills     {
18240d57f4e3SJason M. Bills         case Event::psPowerOKAssert:
18250d57f4e3SJason M. Bills         {
18260d57f4e3SJason M. Bills             if (sioEnabled == true)
18270d57f4e3SJason M. Bills             {
18280d57f4e3SJason M. Bills                 sioPowerGoodWatchdogTimerStart();
18290d57f4e3SJason M. Bills                 setPowerState(PowerState::waitForSIOPowerGood);
18300d57f4e3SJason M. Bills             }
18310d57f4e3SJason M. Bills             else
18320d57f4e3SJason M. Bills             {
18330d57f4e3SJason M. Bills                 setPowerState(PowerState::on);
18340d57f4e3SJason M. Bills             }
18350d57f4e3SJason M. Bills             break;
18360d57f4e3SJason M. Bills         }
18370d57f4e3SJason M. Bills         case Event::sioS5DeAssert:
1838fe159037SJason M. Bills             psPowerOKWatchdogTimerStart();
18390d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
18400d57f4e3SJason M. Bills             break;
18410d57f4e3SJason M. Bills         case Event::sioPowerGoodAssert:
18420d57f4e3SJason M. Bills             setPowerState(PowerState::on);
18430d57f4e3SJason M. Bills             break;
18440d57f4e3SJason M. Bills         case Event::powerButtonPressed:
18450d57f4e3SJason M. Bills             psPowerOKWatchdogTimerStart();
18460d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
18470d57f4e3SJason M. Bills             break;
18480d57f4e3SJason M. Bills         case Event::powerOnRequest:
18490d57f4e3SJason M. Bills             psPowerOKWatchdogTimerStart();
18500d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
18510d57f4e3SJason M. Bills             powerOn();
18520d57f4e3SJason M. Bills             break;
18530d57f4e3SJason M. Bills         default:
1854c46ebb49SJason M. Bills             lg2::info("No action taken.");
18550d57f4e3SJason M. Bills             break;
18560d57f4e3SJason M. Bills     }
18570d57f4e3SJason M. Bills }
18580d57f4e3SJason M. Bills 
powerStateTransitionToOff(const Event event)18590d57f4e3SJason M. Bills static void powerStateTransitionToOff(const Event event)
18600d57f4e3SJason M. Bills {
18610d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
18620d57f4e3SJason M. Bills     switch (event)
18630d57f4e3SJason M. Bills     {
18640d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
18650d57f4e3SJason M. Bills             // Cancel any GPIO assertions held during the transition
18660d57f4e3SJason M. Bills             gpioAssertTimer.cancel();
18670d57f4e3SJason M. Bills             setPowerState(PowerState::off);
18680d57f4e3SJason M. Bills             break;
18690d57f4e3SJason M. Bills         default:
1870c46ebb49SJason M. Bills             lg2::info("No action taken.");
18710d57f4e3SJason M. Bills             break;
18720d57f4e3SJason M. Bills     }
18730d57f4e3SJason M. Bills }
18740d57f4e3SJason M. Bills 
powerStateGracefulTransitionToOff(const Event event)18750d57f4e3SJason M. Bills static void powerStateGracefulTransitionToOff(const Event event)
18760d57f4e3SJason M. Bills {
18770d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
18780d57f4e3SJason M. Bills     switch (event)
18790d57f4e3SJason M. Bills     {
18800d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
18810d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
18820d57f4e3SJason M. Bills             setPowerState(PowerState::off);
18830d57f4e3SJason M. Bills             break;
18840d57f4e3SJason M. Bills         case Event::gracefulPowerOffTimerExpired:
18850d57f4e3SJason M. Bills             setPowerState(PowerState::on);
18860d57f4e3SJason M. Bills             break;
18870d57f4e3SJason M. Bills         case Event::powerOffRequest:
18880d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
18890d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToOff);
18900d57f4e3SJason M. Bills             forcePowerOff();
18910d57f4e3SJason M. Bills             break;
18920d57f4e3SJason M. Bills         case Event::powerCycleRequest:
18930d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
18940d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToCycleOff);
18950d57f4e3SJason M. Bills             forcePowerOff();
18960d57f4e3SJason M. Bills             break;
18970d57f4e3SJason M. Bills         case Event::resetRequest:
18980d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
18990d57f4e3SJason M. Bills             setPowerState(PowerState::on);
19000d57f4e3SJason M. Bills             reset();
19010d57f4e3SJason M. Bills             break;
19020d57f4e3SJason M. Bills         default:
1903c46ebb49SJason M. Bills             lg2::info("No action taken.");
19040d57f4e3SJason M. Bills             break;
19050d57f4e3SJason M. Bills     }
19060d57f4e3SJason M. Bills }
19070d57f4e3SJason M. Bills 
powerStateCycleOff(const Event event)19080d57f4e3SJason M. Bills static void powerStateCycleOff(const Event event)
19090d57f4e3SJason M. Bills {
19100d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
19110d57f4e3SJason M. Bills     switch (event)
19120d57f4e3SJason M. Bills     {
19130d57f4e3SJason M. Bills         case Event::psPowerOKAssert:
19140d57f4e3SJason M. Bills         {
19150d57f4e3SJason M. Bills             powerCycleTimer.cancel();
19160d57f4e3SJason M. Bills             if (sioEnabled == true)
19170d57f4e3SJason M. Bills             {
19180d57f4e3SJason M. Bills                 sioPowerGoodWatchdogTimerStart();
19190d57f4e3SJason M. Bills                 setPowerState(PowerState::waitForSIOPowerGood);
19200d57f4e3SJason M. Bills             }
19210d57f4e3SJason M. Bills             else
19220d57f4e3SJason M. Bills             {
19230d57f4e3SJason M. Bills                 setPowerState(PowerState::on);
19240d57f4e3SJason M. Bills             }
19250d57f4e3SJason M. Bills             break;
19260d57f4e3SJason M. Bills         }
19270d57f4e3SJason M. Bills         case Event::sioS5DeAssert:
19280d57f4e3SJason M. Bills             powerCycleTimer.cancel();
1929fe159037SJason M. Bills             psPowerOKWatchdogTimerStart();
19300d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
19310d57f4e3SJason M. Bills             break;
19320d57f4e3SJason M. Bills         case Event::powerButtonPressed:
19330d57f4e3SJason M. Bills             powerCycleTimer.cancel();
19340d57f4e3SJason M. Bills             psPowerOKWatchdogTimerStart();
19350d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
19360d57f4e3SJason M. Bills             break;
19370d57f4e3SJason M. Bills         case Event::powerCycleTimerExpired:
19380d57f4e3SJason M. Bills             psPowerOKWatchdogTimerStart();
19390d57f4e3SJason M. Bills             setPowerState(PowerState::waitForPSPowerOK);
19400d57f4e3SJason M. Bills             powerOn();
19410d57f4e3SJason M. Bills             break;
19420d57f4e3SJason M. Bills         default:
1943c46ebb49SJason M. Bills             lg2::info("No action taken.");
19440d57f4e3SJason M. Bills             break;
19450d57f4e3SJason M. Bills     }
19460d57f4e3SJason M. Bills }
19470d57f4e3SJason M. Bills 
powerStateTransitionToCycleOff(const Event event)19480d57f4e3SJason M. Bills static void powerStateTransitionToCycleOff(const Event event)
19490d57f4e3SJason M. Bills {
19500d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
19510d57f4e3SJason M. Bills     switch (event)
19520d57f4e3SJason M. Bills     {
19530d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
19540d57f4e3SJason M. Bills             // Cancel any GPIO assertions held during the transition
19550d57f4e3SJason M. Bills             gpioAssertTimer.cancel();
19560d57f4e3SJason M. Bills             setPowerState(PowerState::cycleOff);
19570d57f4e3SJason M. Bills             powerCycleTimerStart();
19580d57f4e3SJason M. Bills             break;
19590d57f4e3SJason M. Bills         default:
1960c46ebb49SJason M. Bills             lg2::info("No action taken.");
19610d57f4e3SJason M. Bills             break;
19620d57f4e3SJason M. Bills     }
19630d57f4e3SJason M. Bills }
19640d57f4e3SJason M. Bills 
powerStateGracefulTransitionToCycleOff(const Event event)19650d57f4e3SJason M. Bills static void powerStateGracefulTransitionToCycleOff(const Event event)
19660d57f4e3SJason M. Bills {
19670d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
19680d57f4e3SJason M. Bills     switch (event)
19690d57f4e3SJason M. Bills     {
19700d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
19710d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
19720d57f4e3SJason M. Bills             setPowerState(PowerState::cycleOff);
19730d57f4e3SJason M. Bills             powerCycleTimerStart();
19740d57f4e3SJason M. Bills             break;
19750d57f4e3SJason M. Bills         case Event::gracefulPowerOffTimerExpired:
19760d57f4e3SJason M. Bills             setPowerState(PowerState::on);
19770d57f4e3SJason M. Bills             break;
19780d57f4e3SJason M. Bills         case Event::powerOffRequest:
19790d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
19800d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToOff);
19810d57f4e3SJason M. Bills             forcePowerOff();
19820d57f4e3SJason M. Bills             break;
19830d57f4e3SJason M. Bills         case Event::powerCycleRequest:
19840d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
19850d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToCycleOff);
19860d57f4e3SJason M. Bills             forcePowerOff();
19870d57f4e3SJason M. Bills             break;
19880d57f4e3SJason M. Bills         case Event::resetRequest:
19890d57f4e3SJason M. Bills             gracefulPowerOffTimer.cancel();
19900d57f4e3SJason M. Bills             setPowerState(PowerState::on);
19910d57f4e3SJason M. Bills             reset();
19920d57f4e3SJason M. Bills             break;
19930d57f4e3SJason M. Bills         default:
1994c46ebb49SJason M. Bills             lg2::info("No action taken.");
19950d57f4e3SJason M. Bills             break;
19960d57f4e3SJason M. Bills     }
19970d57f4e3SJason M. Bills }
19980d57f4e3SJason M. Bills 
powerStateCheckForWarmReset(const Event event)19990d57f4e3SJason M. Bills static void powerStateCheckForWarmReset(const Event event)
20000d57f4e3SJason M. Bills {
20010d57f4e3SJason M. Bills     logEvent(__FUNCTION__, event);
20020d57f4e3SJason M. Bills     switch (event)
20030d57f4e3SJason M. Bills     {
20040d57f4e3SJason M. Bills         case Event::sioS5Assert:
20050d57f4e3SJason M. Bills             warmResetCheckTimer.cancel();
20060d57f4e3SJason M. Bills             setPowerState(PowerState::transitionToOff);
20070d57f4e3SJason M. Bills             break;
20080d57f4e3SJason M. Bills         case Event::warmResetDetected:
20090d57f4e3SJason M. Bills             setPowerState(PowerState::on);
20100d57f4e3SJason M. Bills             break;
20110d57f4e3SJason M. Bills         case Event::psPowerOKDeAssert:
20120d57f4e3SJason M. Bills             warmResetCheckTimer.cancel();
20130d57f4e3SJason M. Bills             setPowerState(PowerState::off);
20140d57f4e3SJason M. Bills             // DC power is unexpectedly lost, beep
20150d57f4e3SJason M. Bills             beep(beepPowerFail);
20160d57f4e3SJason M. Bills             break;
20170d57f4e3SJason M. Bills         default:
2018c46ebb49SJason M. Bills             lg2::info("No action taken.");
20190d57f4e3SJason M. Bills             break;
20200d57f4e3SJason M. Bills     }
20210d57f4e3SJason M. Bills }
20220d57f4e3SJason M. Bills 
psPowerOKHandler(bool state)20230d57f4e3SJason M. Bills static void psPowerOKHandler(bool state)
20240d57f4e3SJason M. Bills {
2025edc86f35SZev Weiss     Event powerControlEvent = (state == powerOkConfig.polarity)
2026edc86f35SZev Weiss                                   ? Event::psPowerOKAssert
202748aa1f05SPatrick Williams                                   : Event::psPowerOKDeAssert;
20280d57f4e3SJason M. Bills     sendPowerControlEvent(powerControlEvent);
20290d57f4e3SJason M. Bills }
20300d57f4e3SJason M. Bills 
sioPowerGoodHandler(bool state)20310d57f4e3SJason M. Bills static void sioPowerGoodHandler(bool state)
20320d57f4e3SJason M. Bills {
2033edc86f35SZev Weiss     Event powerControlEvent = (state == sioPwrGoodConfig.polarity)
2034edc86f35SZev Weiss                                   ? Event::sioPowerGoodAssert
203548aa1f05SPatrick Williams                                   : Event::sioPowerGoodDeAssert;
20360d57f4e3SJason M. Bills     sendPowerControlEvent(powerControlEvent);
20370d57f4e3SJason M. Bills }
20380d57f4e3SJason M. Bills 
sioOnControlHandler(bool state)20390d57f4e3SJason M. Bills static void sioOnControlHandler(bool state)
20400d57f4e3SJason M. Bills {
2041c46ebb49SJason M. Bills     lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2042c46ebb49SJason M. Bills               static_cast<int>(state));
20430d57f4e3SJason M. Bills }
20440d57f4e3SJason M. Bills 
sioS5Handler(bool state)20450d57f4e3SJason M. Bills static void sioS5Handler(bool state)
20460d57f4e3SJason M. Bills {
2047edc86f35SZev Weiss     Event powerControlEvent = (state == sioS5Config.polarity)
2048edc86f35SZev Weiss                                   ? Event::sioS5Assert
2049edc86f35SZev Weiss                                   : Event::sioS5DeAssert;
20500d57f4e3SJason M. Bills     sendPowerControlEvent(powerControlEvent);
20510d57f4e3SJason M. Bills }
20520d57f4e3SJason M. Bills 
powerButtonHandler(bool state)20530d57f4e3SJason M. Bills static void powerButtonHandler(bool state)
20540d57f4e3SJason M. Bills {
2055edc86f35SZev Weiss     bool asserted = state == powerButtonConfig.polarity;
2056edc86f35SZev Weiss     powerButtonIface->set_property("ButtonPressed", asserted);
2057edc86f35SZev Weiss     if (asserted)
20580d57f4e3SJason M. Bills     {
20590d57f4e3SJason M. Bills         powerButtonPressLog();
20600d57f4e3SJason M. Bills         if (!powerButtonMask)
20610d57f4e3SJason M. Bills         {
20620d57f4e3SJason M. Bills             sendPowerControlEvent(Event::powerButtonPressed);
20630d57f4e3SJason M. Bills             addRestartCause(RestartCause::powerButton);
20640d57f4e3SJason M. Bills         }
20650d57f4e3SJason M. Bills         else
20660d57f4e3SJason M. Bills         {
2067c46ebb49SJason M. Bills             lg2::info("power button press masked");
20680d57f4e3SJason M. Bills         }
20690d57f4e3SJason M. Bills     }
207005e8ea8eSRenze Nicolai #if USE_BUTTON_PASSTHROUGH
207105e8ea8eSRenze Nicolai     gpiod::line gpioLine;
207205e8ea8eSRenze Nicolai     bool outputState =
207305e8ea8eSRenze Nicolai         asserted ? powerOutConfig.polarity : (!powerOutConfig.polarity);
207405e8ea8eSRenze Nicolai     if (!setGPIOOutput(powerOutConfig.lineName, outputState, gpioLine))
207505e8ea8eSRenze Nicolai     {
207605e8ea8eSRenze Nicolai         lg2::error("{GPIO_NAME} power button passthrough failed", "GPIO_NAME",
207705e8ea8eSRenze Nicolai                    powerOutConfig.lineName);
207805e8ea8eSRenze Nicolai     }
207905e8ea8eSRenze Nicolai #endif
20800d57f4e3SJason M. Bills }
20810d57f4e3SJason M. Bills 
resetButtonHandler(bool state)20820d57f4e3SJason M. Bills static void resetButtonHandler(bool state)
20830d57f4e3SJason M. Bills {
2084edc86f35SZev Weiss     bool asserted = state == resetButtonConfig.polarity;
2085edc86f35SZev Weiss     resetButtonIface->set_property("ButtonPressed", asserted);
2086edc86f35SZev Weiss     if (asserted)
20870d57f4e3SJason M. Bills     {
20880d57f4e3SJason M. Bills         resetButtonPressLog();
20890d57f4e3SJason M. Bills         if (!resetButtonMask)
20900d57f4e3SJason M. Bills         {
20910d57f4e3SJason M. Bills             sendPowerControlEvent(Event::resetButtonPressed);
20920d57f4e3SJason M. Bills             addRestartCause(RestartCause::resetButton);
20930d57f4e3SJason M. Bills         }
20940d57f4e3SJason M. Bills         else
20950d57f4e3SJason M. Bills         {
2096c46ebb49SJason M. Bills             lg2::info("reset button press masked");
20970d57f4e3SJason M. Bills         }
20980d57f4e3SJason M. Bills     }
209905e8ea8eSRenze Nicolai #if USE_BUTTON_PASSTHROUGH
210005e8ea8eSRenze Nicolai     gpiod::line gpioLine;
210105e8ea8eSRenze Nicolai     bool outputState =
210205e8ea8eSRenze Nicolai         asserted ? resetOutConfig.polarity : (!resetOutConfig.polarity);
210305e8ea8eSRenze Nicolai     if (!setGPIOOutput(resetOutConfig.lineName, outputState, gpioLine))
210405e8ea8eSRenze Nicolai     {
210505e8ea8eSRenze Nicolai         lg2::error("{GPIO_NAME} reset button passthrough failed", "GPIO_NAME",
210605e8ea8eSRenze Nicolai                    resetOutConfig.lineName);
210705e8ea8eSRenze Nicolai     }
210805e8ea8eSRenze Nicolai #endif
21090d57f4e3SJason M. Bills }
21100d57f4e3SJason M. Bills 
21110d57f4e3SJason M. Bills #ifdef CHASSIS_SYSTEM_RESET
21120d57f4e3SJason M. Bills static constexpr auto systemdBusname = "org.freedesktop.systemd1";
21130d57f4e3SJason M. Bills static constexpr auto systemdPath = "/org/freedesktop/systemd1";
21140d57f4e3SJason M. Bills static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
21150d57f4e3SJason M. Bills static constexpr auto systemTargetName = "chassis-system-reset.target";
21160d57f4e3SJason M. Bills 
systemReset()21170d57f4e3SJason M. Bills void systemReset()
21180d57f4e3SJason M. Bills {
21190d57f4e3SJason M. Bills     conn->async_method_call(
21200d57f4e3SJason M. Bills         [](boost::system::error_code ec) {
21210d57f4e3SJason M. Bills             if (ec)
21220d57f4e3SJason M. Bills             {
2123c46ebb49SJason M. Bills                 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2124c46ebb49SJason M. Bills                            ec.message());
21250d57f4e3SJason M. Bills             }
21260d57f4e3SJason M. Bills         },
21270d57f4e3SJason M. Bills         systemdBusname, systemdPath, systemdInterface, "StartUnit",
21280d57f4e3SJason M. Bills         systemTargetName, "replace");
21290d57f4e3SJason M. Bills }
21300d57f4e3SJason M. Bills #endif
21310d57f4e3SJason M. Bills 
nmiSetEnableProperty(bool value)21320d57f4e3SJason M. Bills static void nmiSetEnableProperty(bool value)
21330d57f4e3SJason M. Bills {
21340d57f4e3SJason M. Bills     conn->async_method_call(
21350d57f4e3SJason M. Bills         [](boost::system::error_code ec) {
21360d57f4e3SJason M. Bills             if (ec)
21370d57f4e3SJason M. Bills             {
2138c46ebb49SJason M. Bills                 lg2::error("failed to set NMI source");
21390d57f4e3SJason M. Bills             }
21400d57f4e3SJason M. Bills         },
21410d57f4e3SJason M. Bills         "xyz.openbmc_project.Settings",
21420d57f4e3SJason M. Bills         "/xyz/openbmc_project/Chassis/Control/NMISource",
21430d57f4e3SJason M. Bills         "org.freedesktop.DBus.Properties", "Set",
21440d57f4e3SJason M. Bills         "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
21450d57f4e3SJason M. Bills         std::variant<bool>{value});
21460d57f4e3SJason M. Bills }
21470d57f4e3SJason M. Bills 
nmiReset(void)21480d57f4e3SJason M. Bills static void nmiReset(void)
21490d57f4e3SJason M. Bills {
21500d57f4e3SJason M. Bills     const static constexpr int nmiOutPulseTimeMs = 200;
21510d57f4e3SJason M. Bills 
2152c46ebb49SJason M. Bills     lg2::info("NMI out action");
2153461a166aSJian Zhang     nmiOutLine.set_value(nmiOutConfig.polarity);
2154c46ebb49SJason M. Bills     lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
2155461a166aSJian Zhang               nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
21560d57f4e3SJason M. Bills     gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
21570d57f4e3SJason M. Bills     gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
21580d57f4e3SJason M. Bills         // restore the NMI_OUT GPIO line back to the opposite value
2159461a166aSJian Zhang         nmiOutLine.set_value(!nmiOutConfig.polarity);
2160c46ebb49SJason M. Bills         lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
21610d57f4e3SJason M. Bills         if (ec)
21620d57f4e3SJason M. Bills         {
21630d57f4e3SJason M. Bills             // operation_aborted is expected if timer is canceled before
21640d57f4e3SJason M. Bills             // completion.
21650d57f4e3SJason M. Bills             if (ec != boost::asio::error::operation_aborted)
21660d57f4e3SJason M. Bills             {
2167c46ebb49SJason M. Bills                 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2168c46ebb49SJason M. Bills                            "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2169c46ebb49SJason M. Bills                            ec.message());
21700d57f4e3SJason M. Bills             }
21710d57f4e3SJason M. Bills         }
21720d57f4e3SJason M. Bills     });
21730d57f4e3SJason M. Bills     // log to redfish
21740d57f4e3SJason M. Bills     nmiDiagIntLog();
2175c46ebb49SJason M. Bills     lg2::info("NMI out action completed");
21760d57f4e3SJason M. Bills     // reset Enable Property
21770d57f4e3SJason M. Bills     nmiSetEnableProperty(false);
21780d57f4e3SJason M. Bills }
21790d57f4e3SJason M. Bills 
nmiSourcePropertyMonitor(void)21800d57f4e3SJason M. Bills static void nmiSourcePropertyMonitor(void)
21810d57f4e3SJason M. Bills {
2182c46ebb49SJason M. Bills     lg2::info("NMI Source Property Monitor");
21830d57f4e3SJason M. Bills 
2184439b9c3aSPatrick Williams     static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2185439b9c3aSPatrick Williams         std::make_unique<sdbusplus::bus::match_t>(
21860d57f4e3SJason M. Bills             *conn,
21870d57f4e3SJason M. Bills             "type='signal',interface='org.freedesktop.DBus.Properties',"
2188c46ebb49SJason M. Bills             "member='PropertiesChanged',"
2189c46ebb49SJason M. Bills             "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
2190439b9c3aSPatrick Williams             [](sdbusplus::message_t& msg) {
21910d57f4e3SJason M. Bills                 std::string interfaceName;
2192a0a39f82SPatrick Williams                 boost::container::flat_map<std::string,
2193a0a39f82SPatrick Williams                                            std::variant<bool, std::string>>
21940d57f4e3SJason M. Bills                     propertiesChanged;
21950d57f4e3SJason M. Bills                 std::string state;
21960d57f4e3SJason M. Bills                 bool value = true;
21970d57f4e3SJason M. Bills                 try
21980d57f4e3SJason M. Bills                 {
21990d57f4e3SJason M. Bills                     msg.read(interfaceName, propertiesChanged);
22000d57f4e3SJason M. Bills                     if (propertiesChanged.begin()->first == "Enabled")
22010d57f4e3SJason M. Bills                     {
2202a0a39f82SPatrick Williams                         value =
2203a0a39f82SPatrick Williams                             std::get<bool>(propertiesChanged.begin()->second);
2204a0a39f82SPatrick Williams                         lg2::info(
2205a0a39f82SPatrick Williams                             "NMI Enabled propertiesChanged value: {VALUE}",
2206c46ebb49SJason M. Bills                             "VALUE", value);
22070d57f4e3SJason M. Bills                         nmiEnabled = value;
22080d57f4e3SJason M. Bills                         if (nmiEnabled)
22090d57f4e3SJason M. Bills                         {
22100d57f4e3SJason M. Bills                             nmiReset();
22110d57f4e3SJason M. Bills                         }
22120d57f4e3SJason M. Bills                     }
22130d57f4e3SJason M. Bills                 }
22140d57f4e3SJason M. Bills                 catch (const std::exception& e)
22150d57f4e3SJason M. Bills                 {
2216a0a39f82SPatrick Williams                     lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2217a0a39f82SPatrick Williams                                e);
22180d57f4e3SJason M. Bills                     return;
22190d57f4e3SJason M. Bills                 }
22200d57f4e3SJason M. Bills             });
22210d57f4e3SJason M. Bills }
22220d57f4e3SJason M. Bills 
setNmiSource()22230d57f4e3SJason M. Bills static void setNmiSource()
22240d57f4e3SJason M. Bills {
22250d57f4e3SJason M. Bills     conn->async_method_call(
22260d57f4e3SJason M. Bills         [](boost::system::error_code ec) {
22270d57f4e3SJason M. Bills             if (ec)
22280d57f4e3SJason M. Bills             {
2229c46ebb49SJason M. Bills                 lg2::error("failed to set NMI source");
22300d57f4e3SJason M. Bills             }
22310d57f4e3SJason M. Bills         },
22320d57f4e3SJason M. Bills         "xyz.openbmc_project.Settings",
22330d57f4e3SJason M. Bills         "/xyz/openbmc_project/Chassis/Control/NMISource",
22340d57f4e3SJason M. Bills         "org.freedesktop.DBus.Properties", "Set",
22350d57f4e3SJason M. Bills         "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
22360d57f4e3SJason M. Bills         std::variant<std::string>{
22376af569fdSTim Lee             "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FrontPanelButton"});
22380d57f4e3SJason M. Bills     // set Enable Property
22390d57f4e3SJason M. Bills     nmiSetEnableProperty(true);
22400d57f4e3SJason M. Bills }
22410d57f4e3SJason M. Bills 
nmiButtonHandler(bool state)22420d57f4e3SJason M. Bills static void nmiButtonHandler(bool state)
22430d57f4e3SJason M. Bills {
2244d7ea283bSOlivier FAURAX     // Don't handle event if host not running and config doesn't force it
2245d7ea283bSOlivier FAURAX     if (!nmiWhenPoweredOff &&
2246d7ea283bSOlivier FAURAX         getHostState(powerState) !=
2247d7ea283bSOlivier FAURAX             "xyz.openbmc_project.State.Host.HostState.Running")
2248d7ea283bSOlivier FAURAX     {
2249d7ea283bSOlivier FAURAX         return;
2250d7ea283bSOlivier FAURAX     }
2251edc86f35SZev Weiss 
2252edc86f35SZev Weiss     bool asserted = state == nmiButtonConfig.polarity;
2253edc86f35SZev Weiss     nmiButtonIface->set_property("ButtonPressed", asserted);
2254edc86f35SZev Weiss     if (asserted)
22550d57f4e3SJason M. Bills     {
22560d57f4e3SJason M. Bills         nmiButtonPressLog();
22570d57f4e3SJason M. Bills         if (nmiButtonMasked)
22580d57f4e3SJason M. Bills         {
2259c46ebb49SJason M. Bills             lg2::info("NMI button press masked");
22600d57f4e3SJason M. Bills         }
22610d57f4e3SJason M. Bills         else
22620d57f4e3SJason M. Bills         {
22630d57f4e3SJason M. Bills             setNmiSource();
22640d57f4e3SJason M. Bills         }
22650d57f4e3SJason M. Bills     }
22660d57f4e3SJason M. Bills }
22670d57f4e3SJason M. Bills 
idButtonHandler(bool state)22680d57f4e3SJason M. Bills static void idButtonHandler(bool state)
22690d57f4e3SJason M. Bills {
2270edc86f35SZev Weiss     bool asserted = state == idButtonConfig.polarity;
2271edc86f35SZev Weiss     idButtonIface->set_property("ButtonPressed", asserted);
22720d57f4e3SJason M. Bills }
22730d57f4e3SJason M. Bills 
pltRstHandler(bool pltRst)22740d57f4e3SJason M. Bills static void pltRstHandler(bool pltRst)
22750d57f4e3SJason M. Bills {
22760d57f4e3SJason M. Bills     if (pltRst)
22770d57f4e3SJason M. Bills     {
22780d57f4e3SJason M. Bills         sendPowerControlEvent(Event::pltRstDeAssert);
22790d57f4e3SJason M. Bills     }
22800d57f4e3SJason M. Bills     else
22810d57f4e3SJason M. Bills     {
22820d57f4e3SJason M. Bills         sendPowerControlEvent(Event::pltRstAssert);
22830d57f4e3SJason M. Bills     }
22840d57f4e3SJason M. Bills }
22850d57f4e3SJason M. Bills 
hostMiscHandler(sdbusplus::message_t & msg)2286439b9c3aSPatrick Williams [[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
22870d57f4e3SJason M. Bills {
22880d57f4e3SJason M. Bills     std::string interfaceName;
22890d57f4e3SJason M. Bills     boost::container::flat_map<std::string, std::variant<bool>>
22900d57f4e3SJason M. Bills         propertiesChanged;
22910d57f4e3SJason M. Bills     try
22920d57f4e3SJason M. Bills     {
22930d57f4e3SJason M. Bills         msg.read(interfaceName, propertiesChanged);
22940d57f4e3SJason M. Bills     }
22950d57f4e3SJason M. Bills     catch (const std::exception& e)
22960d57f4e3SJason M. Bills     {
2297c46ebb49SJason M. Bills         lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
22980d57f4e3SJason M. Bills         return;
22990d57f4e3SJason M. Bills     }
23000d57f4e3SJason M. Bills     if (propertiesChanged.empty())
23010d57f4e3SJason M. Bills     {
2302c46ebb49SJason M. Bills         lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
23030d57f4e3SJason M. Bills         return;
23040d57f4e3SJason M. Bills     }
23050d57f4e3SJason M. Bills 
23060d57f4e3SJason M. Bills     for (auto& [property, value] : propertiesChanged)
23070d57f4e3SJason M. Bills     {
23080d57f4e3SJason M. Bills         if (property == "ESpiPlatformReset")
23090d57f4e3SJason M. Bills         {
23100d57f4e3SJason M. Bills             bool* pltRst = std::get_if<bool>(&value);
23110d57f4e3SJason M. Bills             if (pltRst == nullptr)
23120d57f4e3SJason M. Bills             {
2313c46ebb49SJason M. Bills                 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
23140d57f4e3SJason M. Bills                 return;
23150d57f4e3SJason M. Bills             }
23160d57f4e3SJason M. Bills             pltRstHandler(*pltRst);
23170d57f4e3SJason M. Bills         }
23180d57f4e3SJason M. Bills     }
23190d57f4e3SJason M. Bills }
23200d57f4e3SJason M. Bills 
postCompleteHandler(bool state)23210d57f4e3SJason M. Bills static void postCompleteHandler(bool state)
23220d57f4e3SJason M. Bills {
2323edc86f35SZev Weiss     bool asserted = state == postCompleteConfig.polarity;
2324edc86f35SZev Weiss     if (asserted)
23250d57f4e3SJason M. Bills     {
23260d57f4e3SJason M. Bills         sendPowerControlEvent(Event::postCompleteAssert);
23278623918bSTim Lee         setOperatingSystemState(OperatingSystemStateStage::Standby);
23280d57f4e3SJason M. Bills     }
23290d57f4e3SJason M. Bills     else
23300d57f4e3SJason M. Bills     {
23310d57f4e3SJason M. Bills         sendPowerControlEvent(Event::postCompleteDeAssert);
23328623918bSTim Lee         setOperatingSystemState(OperatingSystemStateStage::Inactive);
23330d57f4e3SJason M. Bills     }
23340d57f4e3SJason M. Bills }
23350d57f4e3SJason M. Bills 
loadConfigValues()23360d57f4e3SJason M. Bills static int loadConfigValues()
23370d57f4e3SJason M. Bills {
23380d57f4e3SJason M. Bills     const std::string configFilePath =
23390d57f4e3SJason M. Bills         "/usr/share/x86-power-control/power-config-host" + power_control::node +
23400d57f4e3SJason M. Bills         ".json";
23410d57f4e3SJason M. Bills     std::ifstream configFile(configFilePath.c_str());
23420d57f4e3SJason M. Bills     if (!configFile.is_open())
23430d57f4e3SJason M. Bills     {
2344c46ebb49SJason M. Bills         lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2345c46ebb49SJason M. Bills                    "PATH", configFilePath);
23460d57f4e3SJason M. Bills         return -1;
23470d57f4e3SJason M. Bills     }
23480d57f4e3SJason M. Bills     auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
23490d57f4e3SJason M. Bills 
23500d57f4e3SJason M. Bills     if (jsonData.is_discarded())
23510d57f4e3SJason M. Bills     {
2352c46ebb49SJason M. Bills         lg2::error("Power config readings JSON parser failure");
23530d57f4e3SJason M. Bills         return -1;
23540d57f4e3SJason M. Bills     }
23550d57f4e3SJason M. Bills     auto gpios = jsonData["gpio_configs"];
23560d57f4e3SJason M. Bills     auto timers = jsonData["timing_configs"];
23570d57f4e3SJason M. Bills 
23580d57f4e3SJason M. Bills     ConfigData* tempGpioData;
23590d57f4e3SJason M. Bills 
23600d57f4e3SJason M. Bills     for (nlohmann::json& gpioConfig : gpios)
23610d57f4e3SJason M. Bills     {
23620d57f4e3SJason M. Bills         if (!gpioConfig.contains("Name"))
23630d57f4e3SJason M. Bills         {
2364c46ebb49SJason M. Bills             lg2::error("The 'Name' field must be defined in Json file");
23650d57f4e3SJason M. Bills             return -1;
23660d57f4e3SJason M. Bills         }
23670d57f4e3SJason M. Bills 
23680d57f4e3SJason M. Bills         // Iterate through the powersignal map to check if the gpio json config
23690d57f4e3SJason M. Bills         // entry is valid
23700d57f4e3SJason M. Bills         std::string gpioName = gpioConfig["Name"];
23710d57f4e3SJason M. Bills         auto signalMapIter = powerSignalMap.find(gpioName);
23720d57f4e3SJason M. Bills         if (signalMapIter == powerSignalMap.end())
23730d57f4e3SJason M. Bills         {
2374c46ebb49SJason M. Bills             lg2::error(
2375c46ebb49SJason M. Bills                 "{GPIO_NAME} is not a recognized power-control signal name",
2376c46ebb49SJason M. Bills                 "GPIO_NAME", gpioName);
23770d57f4e3SJason M. Bills             return -1;
23780d57f4e3SJason M. Bills         }
23790d57f4e3SJason M. Bills 
23800d57f4e3SJason M. Bills         // assign the power signal name to the corresponding structure reference
23810d57f4e3SJason M. Bills         // from map then fillup the structure with coressponding json config
23820d57f4e3SJason M. Bills         // value
23830d57f4e3SJason M. Bills         tempGpioData = signalMapIter->second;
23840d57f4e3SJason M. Bills         tempGpioData->name = gpioName;
23850d57f4e3SJason M. Bills 
23860d57f4e3SJason M. Bills         if (!gpioConfig.contains("Type"))
23870d57f4e3SJason M. Bills         {
2388c46ebb49SJason M. Bills             lg2::error("The \'Type\' field must be defined in Json file");
23890d57f4e3SJason M. Bills             return -1;
23900d57f4e3SJason M. Bills         }
23910d57f4e3SJason M. Bills 
23920d57f4e3SJason M. Bills         std::string signalType = gpioConfig["Type"];
23930d57f4e3SJason M. Bills         if (signalType == "GPIO")
23940d57f4e3SJason M. Bills         {
23950d57f4e3SJason M. Bills             tempGpioData->type = ConfigType::GPIO;
23960d57f4e3SJason M. Bills         }
23970d57f4e3SJason M. Bills         else if (signalType == "DBUS")
23980d57f4e3SJason M. Bills         {
23990d57f4e3SJason M. Bills             tempGpioData->type = ConfigType::DBUS;
24000d57f4e3SJason M. Bills         }
24010d57f4e3SJason M. Bills         else
24020d57f4e3SJason M. Bills         {
2403c46ebb49SJason M. Bills             lg2::error("{TYPE} is not a recognized power-control signal type",
2404c46ebb49SJason M. Bills                        "TYPE", signalType);
24050d57f4e3SJason M. Bills             return -1;
24060d57f4e3SJason M. Bills         }
24070d57f4e3SJason M. Bills 
24080d57f4e3SJason M. Bills         if (tempGpioData->type == ConfigType::GPIO)
24090d57f4e3SJason M. Bills         {
24100d57f4e3SJason M. Bills             if (gpioConfig.contains("LineName"))
24110d57f4e3SJason M. Bills             {
24120d57f4e3SJason M. Bills                 tempGpioData->lineName = gpioConfig["LineName"];
24130d57f4e3SJason M. Bills             }
24140d57f4e3SJason M. Bills             else
24150d57f4e3SJason M. Bills             {
2416c46ebb49SJason M. Bills                 lg2::error(
24170d57f4e3SJason M. Bills                     "The \'LineName\' field must be defined for GPIO configuration");
24180d57f4e3SJason M. Bills                 return -1;
24190d57f4e3SJason M. Bills             }
24200d57f4e3SJason M. Bills             if (gpioConfig.contains("Polarity"))
24210d57f4e3SJason M. Bills             {
24220d57f4e3SJason M. Bills                 std::string polarity = gpioConfig["Polarity"];
24230d57f4e3SJason M. Bills                 if (polarity == "ActiveLow")
24240d57f4e3SJason M. Bills                 {
24250d57f4e3SJason M. Bills                     tempGpioData->polarity = false;
24260d57f4e3SJason M. Bills                 }
24270d57f4e3SJason M. Bills                 else if (polarity == "ActiveHigh")
24280d57f4e3SJason M. Bills                 {
24290d57f4e3SJason M. Bills                     tempGpioData->polarity = true;
24300d57f4e3SJason M. Bills                 }
24310d57f4e3SJason M. Bills                 else
24320d57f4e3SJason M. Bills                 {
2433c46ebb49SJason M. Bills                     lg2::error(
2434c46ebb49SJason M. Bills                         "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2435c46ebb49SJason M. Bills                         "POLARITY", polarity);
24360d57f4e3SJason M. Bills                     return -1;
24370d57f4e3SJason M. Bills                 }
24380d57f4e3SJason M. Bills             }
24390d57f4e3SJason M. Bills             else
24400d57f4e3SJason M. Bills             {
2441c46ebb49SJason M. Bills                 lg2::error("Polarity field not found for {GPIO_NAME}",
2442c46ebb49SJason M. Bills                            "GPIO_NAME", tempGpioData->lineName);
24430d57f4e3SJason M. Bills                 return -1;
24440d57f4e3SJason M. Bills             }
24450d57f4e3SJason M. Bills         }
24460d57f4e3SJason M. Bills         else
24470d57f4e3SJason M. Bills         {
24480d57f4e3SJason M. Bills             // if dbus based gpio config is defined read and update the dbus
24490d57f4e3SJason M. Bills             // params corresponding to the gpio config instance
24500d57f4e3SJason M. Bills             for (auto& [key, dbusParamName] : dbusParams)
24510d57f4e3SJason M. Bills             {
24520d57f4e3SJason M. Bills                 if (!gpioConfig.contains(dbusParamName))
24530d57f4e3SJason M. Bills                 {
2454c46ebb49SJason M. Bills                     lg2::error(
2455c46ebb49SJason M. Bills                         "The {DBUS_NAME} field must be defined for Dbus configuration ",
2456c46ebb49SJason M. Bills                         "DBUS_NAME", dbusParamName);
24570d57f4e3SJason M. Bills                     return -1;
24580d57f4e3SJason M. Bills                 }
24590d57f4e3SJason M. Bills             }
24600d57f4e3SJason M. Bills             tempGpioData->dbusName =
24610d57f4e3SJason M. Bills                 gpioConfig[dbusParams[DbusConfigType::name]];
24620d57f4e3SJason M. Bills             tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
24630d57f4e3SJason M. Bills             tempGpioData->interface =
24640d57f4e3SJason M. Bills                 gpioConfig[dbusParams[DbusConfigType::interface]];
24650d57f4e3SJason M. Bills             tempGpioData->lineName =
24660d57f4e3SJason M. Bills                 gpioConfig[dbusParams[DbusConfigType::property]];
2467ca47855dSZev Weiss 
2468d603dd1bSZev Weiss             // dbus-based inputs must be active-high.
2469d603dd1bSZev Weiss             tempGpioData->polarity = true;
2470d603dd1bSZev Weiss 
2471ca47855dSZev Weiss             // MatchRegex is optional
2472ca47855dSZev Weiss             auto item = gpioConfig.find("MatchRegex");
2473ca47855dSZev Weiss             if (item != gpioConfig.end())
2474ca47855dSZev Weiss             {
2475ca47855dSZev Weiss                 try
2476ca47855dSZev Weiss                 {
2477ca47855dSZev Weiss                     tempGpioData->matchRegex = std::regex(*item);
2478ca47855dSZev Weiss                 }
2479ca47855dSZev Weiss                 catch (const std::regex_error& e)
2480ca47855dSZev Weiss                 {
2481ca47855dSZev Weiss                     lg2::error("Invalid MatchRegex for {NAME}: {ERR}", "NAME",
2482ca47855dSZev Weiss                                gpioName, "ERR", e.what());
2483ca47855dSZev Weiss                     return -1;
2484ca47855dSZev Weiss                 }
2485ca47855dSZev Weiss             }
24860d57f4e3SJason M. Bills         }
24870d57f4e3SJason M. Bills     }
24880d57f4e3SJason M. Bills 
24890d57f4e3SJason M. Bills     // read and store the timer values from json config to Timer Map
24900d57f4e3SJason M. Bills     for (auto& [key, timerValue] : TimerMap)
24910d57f4e3SJason M. Bills     {
24920d57f4e3SJason M. Bills         if (timers.contains(key.c_str()))
24930d57f4e3SJason M. Bills         {
24940d57f4e3SJason M. Bills             timerValue = timers[key.c_str()];
24950d57f4e3SJason M. Bills         }
24960d57f4e3SJason M. Bills     }
24970d57f4e3SJason M. Bills 
2498891bbde7SJonathan Doman     // If "events_configs" key is not in json config, fallback to null
2499891bbde7SJonathan Doman     auto events = jsonData.value("event_configs",
2500891bbde7SJonathan Doman                                  nlohmann::json(nlohmann::json::value_t::null));
2501891bbde7SJonathan Doman     if (events.is_object())
2502d7ea283bSOlivier FAURAX     {
2503d7ea283bSOlivier FAURAX         nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2504d7ea283bSOlivier FAURAX     }
2505d7ea283bSOlivier FAURAX 
25060d57f4e3SJason M. Bills     return 0;
25070d57f4e3SJason M. Bills }
25080d57f4e3SJason M. Bills 
2509ca47855dSZev Weiss template <typename T>
getMessageValue(sdbusplus::message_t & msg,const std::string & name)2510*b84e7893SPatrick Williams static std::optional<T> getMessageValue(sdbusplus::message_t& msg,
2511*b84e7893SPatrick Williams                                         const std::string& name)
25120d57f4e3SJason M. Bills {
25130d57f4e3SJason M. Bills     std::string event;
2514ca47855dSZev Weiss     std::string thresholdInterface;
2515ca47855dSZev Weiss     boost::container::flat_map<std::string, std::variant<T>> propertiesChanged;
2516ca47855dSZev Weiss 
25170d57f4e3SJason M. Bills     msg.read(thresholdInterface, propertiesChanged);
25180d57f4e3SJason M. Bills     if (propertiesChanged.empty())
25190d57f4e3SJason M. Bills     {
2520ca47855dSZev Weiss         return std::nullopt;
25210d57f4e3SJason M. Bills     }
25220d57f4e3SJason M. Bills 
25230d57f4e3SJason M. Bills     event = propertiesChanged.begin()->first;
2524ca47855dSZev Weiss     if (event.empty() || event != name)
2525ca47855dSZev Weiss     {
2526ca47855dSZev Weiss         return std::nullopt;
2527ca47855dSZev Weiss     }
2528ca47855dSZev Weiss 
2529ca47855dSZev Weiss     return std::get<T>(propertiesChanged.begin()->second);
2530ca47855dSZev Weiss }
2531ca47855dSZev Weiss 
getDbusMsgGPIOState(sdbusplus::message_t & msg,const ConfigData & config,bool & value)2532ca47855dSZev Weiss static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
2533ca47855dSZev Weiss                                 const ConfigData& config, bool& value)
2534ca47855dSZev Weiss {
2535ca47855dSZev Weiss     try
2536ca47855dSZev Weiss     {
2537ca47855dSZev Weiss         if (config.matchRegex.has_value())
2538ca47855dSZev Weiss         {
2539ca47855dSZev Weiss             std::optional<std::string> s =
2540ca47855dSZev Weiss                 getMessageValue<std::string>(msg, config.lineName);
2541ca47855dSZev Weiss             if (!s.has_value())
25420d57f4e3SJason M. Bills             {
25430d57f4e3SJason M. Bills                 return false;
25440d57f4e3SJason M. Bills             }
25450d57f4e3SJason M. Bills 
2546ca47855dSZev Weiss             std::smatch m;
2547ca47855dSZev Weiss             value = std::regex_match(s.value(), m, config.matchRegex.value());
2548ca47855dSZev Weiss         }
2549ca47855dSZev Weiss         else
2550ca47855dSZev Weiss         {
2551ca47855dSZev Weiss             std::optional<bool> v = getMessageValue<bool>(msg, config.lineName);
2552ca47855dSZev Weiss             if (!v.has_value())
2553ca47855dSZev Weiss             {
2554ca47855dSZev Weiss                 return false;
2555ca47855dSZev Weiss             }
2556ca47855dSZev Weiss             value = v.value();
2557ca47855dSZev Weiss         }
25580d57f4e3SJason M. Bills         return true;
25590d57f4e3SJason M. Bills     }
25600d57f4e3SJason M. Bills     catch (const std::exception& e)
25610d57f4e3SJason M. Bills     {
2562c46ebb49SJason M. Bills         lg2::error(
2563c46ebb49SJason M. Bills             "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2564ca47855dSZev Weiss             "DBUS_NAME", config.lineName, "ERROR", e);
25650d57f4e3SJason M. Bills         return false;
25660d57f4e3SJason M. Bills     }
25670d57f4e3SJason M. Bills }
25680d57f4e3SJason M. Bills 
dbusGPIOMatcher(const ConfigData & cfg,std::function<void (bool)> onMatch)2569*b84e7893SPatrick Williams static sdbusplus::bus::match_t dbusGPIOMatcher(
2570*b84e7893SPatrick Williams     const ConfigData& cfg, std::function<void(bool)> onMatch)
25710d57f4e3SJason M. Bills {
2572a0a39f82SPatrick Williams     auto pulseEventMatcherCallback =
2573a0a39f82SPatrick Williams         [&cfg, onMatch](sdbusplus::message_t& msg) {
25740d57f4e3SJason M. Bills             bool value = false;
2575ca47855dSZev Weiss             if (!getDbusMsgGPIOState(msg, cfg, value))
25760d57f4e3SJason M. Bills             {
25770d57f4e3SJason M. Bills                 return;
25780d57f4e3SJason M. Bills             }
25790d57f4e3SJason M. Bills             onMatch(value);
25800d57f4e3SJason M. Bills         };
25810d57f4e3SJason M. Bills 
2582439b9c3aSPatrick Williams     return sdbusplus::bus::match_t(
2583439b9c3aSPatrick Williams         static_cast<sdbusplus::bus_t&>(*conn),
25840d57f4e3SJason M. Bills         "type='signal',interface='org.freedesktop.DBus.Properties',member='"
25850d57f4e3SJason M. Bills         "PropertiesChanged',arg0='" +
25861cc7921fSZev Weiss             cfg.interface + "',path='" + cfg.path + "',sender='" +
25871cc7921fSZev Weiss             cfg.dbusName + "'",
25880d57f4e3SJason M. Bills         std::move(pulseEventMatcherCallback));
25890d57f4e3SJason M. Bills }
25900d57f4e3SJason M. Bills 
2591edd211e4SMichal Orzel // D-Bus property read functions
2592edd211e4SMichal Orzel void reschedulePropertyRead(const ConfigData& configData);
2593edd211e4SMichal Orzel 
getProperty(const ConfigData & configData)2594edd211e4SMichal Orzel int getProperty(const ConfigData& configData)
2595edd211e4SMichal Orzel {
2596edd211e4SMichal Orzel     std::variant<bool> resp;
2597edd211e4SMichal Orzel 
2598edd211e4SMichal Orzel     try
25990d57f4e3SJason M. Bills     {
26000d57f4e3SJason M. Bills         auto method = conn->new_method_call(
26010d57f4e3SJason M. Bills             configData.dbusName.c_str(), configData.path.c_str(),
26020d57f4e3SJason M. Bills             "org.freedesktop.DBus.Properties", "Get");
2603edd211e4SMichal Orzel         method.append(configData.interface.c_str(),
2604edd211e4SMichal Orzel                       configData.lineName.c_str());
26050d57f4e3SJason M. Bills 
26060d57f4e3SJason M. Bills         auto reply = conn->call(method);
26070d57f4e3SJason M. Bills         if (reply.is_method_error())
26080d57f4e3SJason M. Bills         {
2609c46ebb49SJason M. Bills             lg2::error(
2610c46ebb49SJason M. Bills                 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2611edd211e4SMichal Orzel                 "PROPERTY", configData.lineName, "INTERFACE",
2612edd211e4SMichal Orzel                 configData.interface, "PATH", configData.path);
26130d57f4e3SJason M. Bills             return -1;
26140d57f4e3SJason M. Bills         }
2615edd211e4SMichal Orzel 
26160d57f4e3SJason M. Bills         reply.read(resp);
2617edd211e4SMichal Orzel     }
2618edd211e4SMichal Orzel     catch (const sdbusplus::exception_t& e)
2619edd211e4SMichal Orzel     {
2620edd211e4SMichal Orzel         lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2621edd211e4SMichal Orzel                    configData.lineName, "WHAT", e.what());
2622edd211e4SMichal Orzel         reschedulePropertyRead(configData);
2623edd211e4SMichal Orzel         return -1;
2624edd211e4SMichal Orzel     }
2625edd211e4SMichal Orzel 
262685e111edSLogananth Sundararaj     auto respValue = std::get_if<bool>(&resp);
26270d57f4e3SJason M. Bills     if (!respValue)
26280d57f4e3SJason M. Bills     {
2629c46ebb49SJason M. Bills         lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2630c46ebb49SJason M. Bills                    "PROPERTY", configData.lineName);
26310d57f4e3SJason M. Bills         return -1;
26320d57f4e3SJason M. Bills     }
26330d57f4e3SJason M. Bills     return (*respValue);
26340d57f4e3SJason M. Bills }
2635edd211e4SMichal Orzel 
setInitialValue(const ConfigData & configData,bool initialValue)2636edd211e4SMichal Orzel void setInitialValue(const ConfigData& configData, bool initialValue)
2637edd211e4SMichal Orzel {
2638edd211e4SMichal Orzel     if (configData.name == "PowerOk")
2639edd211e4SMichal Orzel     {
2640edd211e4SMichal Orzel         powerState = (initialValue ? PowerState::on : PowerState::off);
2641edd211e4SMichal Orzel         hostIface->set_property("CurrentHostState",
2642edd211e4SMichal Orzel                                 std::string(getHostState(powerState)));
2643edd211e4SMichal Orzel     }
2644edd211e4SMichal Orzel     else if (configData.name == "PowerButton")
2645edd211e4SMichal Orzel     {
2646edd211e4SMichal Orzel         powerButtonIface->set_property("ButtonPressed", !initialValue);
2647edd211e4SMichal Orzel     }
2648edd211e4SMichal Orzel     else if (configData.name == "ResetButton")
2649edd211e4SMichal Orzel     {
2650edd211e4SMichal Orzel         resetButtonIface->set_property("ButtonPressed", !initialValue);
2651edd211e4SMichal Orzel     }
2652edd211e4SMichal Orzel     else if (configData.name == "NMIButton")
2653edd211e4SMichal Orzel     {
2654edd211e4SMichal Orzel         nmiButtonIface->set_property("ButtonPressed", !initialValue);
2655edd211e4SMichal Orzel     }
2656edd211e4SMichal Orzel     else if (configData.name == "IdButton")
2657edd211e4SMichal Orzel     {
2658edd211e4SMichal Orzel         idButtonIface->set_property("ButtonPressed", !initialValue);
2659edd211e4SMichal Orzel     }
2660edd211e4SMichal Orzel     else if (configData.name == "PostComplete")
2661edd211e4SMichal Orzel     {
2662edd211e4SMichal Orzel         OperatingSystemStateStage osState =
2663c6d75656SJason M. Bills             (initialValue == postCompleteConfig.polarity
2664c6d75656SJason M. Bills                  ? OperatingSystemStateStage::Standby
2665c6d75656SJason M. Bills                  : OperatingSystemStateStage::Inactive);
2666edd211e4SMichal Orzel         setOperatingSystemState(osState);
2667edd211e4SMichal Orzel     }
2668edd211e4SMichal Orzel     else
2669edd211e4SMichal Orzel     {
2670edd211e4SMichal Orzel         lg2::error("Unknown name {NAME}", "NAME", configData.name);
2671edd211e4SMichal Orzel     }
2672edd211e4SMichal Orzel }
2673edd211e4SMichal Orzel 
reschedulePropertyRead(const ConfigData & configData)2674edd211e4SMichal Orzel void reschedulePropertyRead(const ConfigData& configData)
2675edd211e4SMichal Orzel {
2676edd211e4SMichal Orzel     auto item = dBusRetryTimers.find(configData.name);
2677edd211e4SMichal Orzel 
2678edd211e4SMichal Orzel     if (item == dBusRetryTimers.end())
2679edd211e4SMichal Orzel     {
2680edd211e4SMichal Orzel         auto newItem = dBusRetryTimers.insert(
2681edd211e4SMichal Orzel             {configData.name, boost::asio::steady_timer(io)});
2682edd211e4SMichal Orzel 
2683edd211e4SMichal Orzel         if (!newItem.second)
2684edd211e4SMichal Orzel         {
2685edd211e4SMichal Orzel             lg2::error("Failed to add new timer for {NAME}", "NAME",
2686edd211e4SMichal Orzel                        configData.name);
2687edd211e4SMichal Orzel             return;
2688edd211e4SMichal Orzel         }
2689edd211e4SMichal Orzel 
2690edd211e4SMichal Orzel         item = newItem.first;
2691edd211e4SMichal Orzel     }
2692edd211e4SMichal Orzel 
2693edd211e4SMichal Orzel     auto& timer = item->second;
2694edd211e4SMichal Orzel     timer.expires_after(
2695edd211e4SMichal Orzel         std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2696edd211e4SMichal Orzel     timer.async_wait([&configData](const boost::system::error_code ec) {
2697edd211e4SMichal Orzel         if (ec)
2698edd211e4SMichal Orzel         {
2699edd211e4SMichal Orzel             lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2700edd211e4SMichal Orzel                        configData.name, "MSG", ec.message());
2701edd211e4SMichal Orzel             dBusRetryTimers.erase(configData.name);
2702edd211e4SMichal Orzel             return;
2703edd211e4SMichal Orzel         }
2704edd211e4SMichal Orzel 
2705edd211e4SMichal Orzel         int property = getProperty(configData);
2706edd211e4SMichal Orzel 
2707edd211e4SMichal Orzel         if (property >= 0)
2708edd211e4SMichal Orzel         {
2709edd211e4SMichal Orzel             setInitialValue(configData, (property > 0));
2710edd211e4SMichal Orzel             dBusRetryTimers.erase(configData.name);
2711edd211e4SMichal Orzel         }
2712edd211e4SMichal Orzel     });
2713edd211e4SMichal Orzel }
27140d57f4e3SJason M. Bills } // namespace power_control
27150d57f4e3SJason M. Bills 
main(int argc,char * argv[])27160d57f4e3SJason M. Bills int main(int argc, char* argv[])
27170d57f4e3SJason M. Bills {
27180d57f4e3SJason M. Bills     using namespace power_control;
27190d57f4e3SJason M. Bills 
27200d57f4e3SJason M. Bills     if (argc > 1)
27210d57f4e3SJason M. Bills     {
27220d57f4e3SJason M. Bills         node = argv[1];
27230d57f4e3SJason M. Bills     }
2724c46ebb49SJason M. Bills     lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2725c46ebb49SJason M. Bills               node);
27260d57f4e3SJason M. Bills 
27270d57f4e3SJason M. Bills     conn = std::make_shared<sdbusplus::asio::connection>(io);
27280d57f4e3SJason M. Bills 
27290d57f4e3SJason M. Bills     // Load GPIO's through json config file
27300d57f4e3SJason M. Bills     if (loadConfigValues() == -1)
27310d57f4e3SJason M. Bills     {
2732c46ebb49SJason M. Bills         lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
27330d57f4e3SJason M. Bills     }
27340d57f4e3SJason M. Bills     /* Currently for single host based systems additional busname is added
27350d57f4e3SJason M. Bills     with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
27360d57f4e3SJason M. Bills     Going forward for single hosts the old bus name without zero numbering
27370d57f4e3SJason M. Bills     will be removed when all other applications adapted to the
27380d57f4e3SJason M. Bills     bus name with zero numbering (xyz.openbmc_project.State.Host0). */
27390d57f4e3SJason M. Bills 
27400d57f4e3SJason M. Bills     if (node == "0")
27410d57f4e3SJason M. Bills     {
27420d57f4e3SJason M. Bills         // Request all the dbus names
27430d57f4e3SJason M. Bills         conn->request_name(hostDbusName.c_str());
27440d57f4e3SJason M. Bills         conn->request_name(chassisDbusName.c_str());
27450d57f4e3SJason M. Bills         conn->request_name(osDbusName.c_str());
27460d57f4e3SJason M. Bills         conn->request_name(buttonDbusName.c_str());
27470d57f4e3SJason M. Bills         conn->request_name(nmiDbusName.c_str());
27480d57f4e3SJason M. Bills         conn->request_name(rstCauseDbusName.c_str());
27490d57f4e3SJason M. Bills     }
27500d57f4e3SJason M. Bills 
27510d57f4e3SJason M. Bills     hostDbusName += node;
27520d57f4e3SJason M. Bills     chassisDbusName += node;
27530d57f4e3SJason M. Bills     osDbusName += node;
27540d57f4e3SJason M. Bills     buttonDbusName += node;
27550d57f4e3SJason M. Bills     nmiDbusName += node;
27560d57f4e3SJason M. Bills     rstCauseDbusName += node;
27570d57f4e3SJason M. Bills 
27580d57f4e3SJason M. Bills     // Request all the dbus names
27590d57f4e3SJason M. Bills     conn->request_name(hostDbusName.c_str());
27600d57f4e3SJason M. Bills     conn->request_name(chassisDbusName.c_str());
27610d57f4e3SJason M. Bills     conn->request_name(osDbusName.c_str());
27620d57f4e3SJason M. Bills     conn->request_name(buttonDbusName.c_str());
27630d57f4e3SJason M. Bills     conn->request_name(nmiDbusName.c_str());
27640d57f4e3SJason M. Bills     conn->request_name(rstCauseDbusName.c_str());
27650d57f4e3SJason M. Bills 
27660d57f4e3SJason M. Bills     if (sioPwrGoodConfig.lineName.empty() ||
27670d57f4e3SJason M. Bills         sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
27680d57f4e3SJason M. Bills     {
27690d57f4e3SJason M. Bills         sioEnabled = false;
2770c46ebb49SJason M. Bills         lg2::info("SIO control GPIOs not defined, disable SIO support.");
27710d57f4e3SJason M. Bills     }
27720d57f4e3SJason M. Bills 
27730d57f4e3SJason M. Bills     // Request PS_PWROK GPIO events
27740d57f4e3SJason M. Bills     if (powerOkConfig.type == ConfigType::GPIO)
27750d57f4e3SJason M. Bills     {
27760d57f4e3SJason M. Bills         if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
27770d57f4e3SJason M. Bills                                psPowerOKLine, psPowerOKEvent))
27780d57f4e3SJason M. Bills         {
27790d57f4e3SJason M. Bills             return -1;
27800d57f4e3SJason M. Bills         }
27810d57f4e3SJason M. Bills     }
27820d57f4e3SJason M. Bills     else if (powerOkConfig.type == ConfigType::DBUS)
27830d57f4e3SJason M. Bills     {
2784439b9c3aSPatrick Williams         static sdbusplus::bus::match_t powerOkEventMonitor =
27850d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
27860d57f4e3SJason M. Bills     }
27870d57f4e3SJason M. Bills     else
27880d57f4e3SJason M. Bills     {
2789c46ebb49SJason M. Bills         lg2::error("PowerOk name should be configured from json config file");
27900d57f4e3SJason M. Bills         return -1;
27910d57f4e3SJason M. Bills     }
27920d57f4e3SJason M. Bills 
27930d57f4e3SJason M. Bills     if (sioEnabled == true)
27940d57f4e3SJason M. Bills     {
27950d57f4e3SJason M. Bills         // Request SIO_POWER_GOOD GPIO events
27960d57f4e3SJason M. Bills         if (sioPwrGoodConfig.type == ConfigType::GPIO)
27970d57f4e3SJason M. Bills         {
27980d57f4e3SJason M. Bills             if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
27990d57f4e3SJason M. Bills                                    sioPowerGoodHandler, sioPowerGoodLine,
28000d57f4e3SJason M. Bills                                    sioPowerGoodEvent))
28010d57f4e3SJason M. Bills             {
28020d57f4e3SJason M. Bills                 return -1;
28030d57f4e3SJason M. Bills             }
28040d57f4e3SJason M. Bills         }
28050d57f4e3SJason M. Bills         else if (sioPwrGoodConfig.type == ConfigType::DBUS)
28060d57f4e3SJason M. Bills         {
2807439b9c3aSPatrick Williams             static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
28080d57f4e3SJason M. Bills                 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
28090d57f4e3SJason M. Bills                                                sioPowerGoodHandler);
28100d57f4e3SJason M. Bills         }
28110d57f4e3SJason M. Bills         else
28120d57f4e3SJason M. Bills         {
2813c46ebb49SJason M. Bills             lg2::error(
28140d57f4e3SJason M. Bills                 "sioPwrGood name should be configured from json config file");
28150d57f4e3SJason M. Bills             return -1;
28160d57f4e3SJason M. Bills         }
28170d57f4e3SJason M. Bills 
28180d57f4e3SJason M. Bills         // Request SIO_ONCONTROL GPIO events
28190d57f4e3SJason M. Bills         if (sioOnControlConfig.type == ConfigType::GPIO)
28200d57f4e3SJason M. Bills         {
28210d57f4e3SJason M. Bills             if (!requestGPIOEvents(sioOnControlConfig.lineName,
28220d57f4e3SJason M. Bills                                    sioOnControlHandler, sioOnControlLine,
28230d57f4e3SJason M. Bills                                    sioOnControlEvent))
28240d57f4e3SJason M. Bills             {
28250d57f4e3SJason M. Bills                 return -1;
28260d57f4e3SJason M. Bills             }
28270d57f4e3SJason M. Bills         }
28280d57f4e3SJason M. Bills         else if (sioOnControlConfig.type == ConfigType::DBUS)
28290d57f4e3SJason M. Bills         {
2830439b9c3aSPatrick Williams             static sdbusplus::bus::match_t sioOnControlEventMonitor =
28310d57f4e3SJason M. Bills                 power_control::dbusGPIOMatcher(sioOnControlConfig,
28320d57f4e3SJason M. Bills                                                sioOnControlHandler);
28330d57f4e3SJason M. Bills         }
28340d57f4e3SJason M. Bills         else
28350d57f4e3SJason M. Bills         {
2836c46ebb49SJason M. Bills             lg2::error(
28370d57f4e3SJason M. Bills                 "sioOnControl name should be configured from jsonconfig file\n");
28380d57f4e3SJason M. Bills             return -1;
28390d57f4e3SJason M. Bills         }
28400d57f4e3SJason M. Bills 
28410d57f4e3SJason M. Bills         // Request SIO_S5 GPIO events
28420d57f4e3SJason M. Bills         if (sioS5Config.type == ConfigType::GPIO)
28430d57f4e3SJason M. Bills         {
28440d57f4e3SJason M. Bills             if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
28450d57f4e3SJason M. Bills                                    sioS5Line, sioS5Event))
28460d57f4e3SJason M. Bills             {
28470d57f4e3SJason M. Bills                 return -1;
28480d57f4e3SJason M. Bills             }
28490d57f4e3SJason M. Bills         }
28500d57f4e3SJason M. Bills         else if (sioS5Config.type == ConfigType::DBUS)
28510d57f4e3SJason M. Bills         {
2852439b9c3aSPatrick Williams             static sdbusplus::bus::match_t sioS5EventMonitor =
28530d57f4e3SJason M. Bills                 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
28540d57f4e3SJason M. Bills         }
28550d57f4e3SJason M. Bills         else
28560d57f4e3SJason M. Bills         {
2857c46ebb49SJason M. Bills             lg2::error("sioS5 name should be configured from json config file");
28580d57f4e3SJason M. Bills             return -1;
28590d57f4e3SJason M. Bills         }
28600d57f4e3SJason M. Bills     }
28610d57f4e3SJason M. Bills 
28620d57f4e3SJason M. Bills     // Request POWER_BUTTON GPIO events
28630d57f4e3SJason M. Bills     if (powerButtonConfig.type == ConfigType::GPIO)
28640d57f4e3SJason M. Bills     {
28650d57f4e3SJason M. Bills         if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
28660d57f4e3SJason M. Bills                                powerButtonLine, powerButtonEvent))
28670d57f4e3SJason M. Bills         {
28680d57f4e3SJason M. Bills             return -1;
28690d57f4e3SJason M. Bills         }
28700d57f4e3SJason M. Bills     }
28710d57f4e3SJason M. Bills     else if (powerButtonConfig.type == ConfigType::DBUS)
28720d57f4e3SJason M. Bills     {
2873439b9c3aSPatrick Williams         static sdbusplus::bus::match_t powerButtonEventMonitor =
28740d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(powerButtonConfig,
28750d57f4e3SJason M. Bills                                            powerButtonHandler);
28760d57f4e3SJason M. Bills     }
28770d57f4e3SJason M. Bills 
28780d57f4e3SJason M. Bills     // Request RESET_BUTTON GPIO events
28790d57f4e3SJason M. Bills     if (resetButtonConfig.type == ConfigType::GPIO)
28800d57f4e3SJason M. Bills     {
28810d57f4e3SJason M. Bills         if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
28820d57f4e3SJason M. Bills                                resetButtonLine, resetButtonEvent))
28830d57f4e3SJason M. Bills         {
28840d57f4e3SJason M. Bills             return -1;
28850d57f4e3SJason M. Bills         }
28860d57f4e3SJason M. Bills     }
28870d57f4e3SJason M. Bills     else if (resetButtonConfig.type == ConfigType::DBUS)
28880d57f4e3SJason M. Bills     {
2889439b9c3aSPatrick Williams         static sdbusplus::bus::match_t resetButtonEventMonitor =
28900d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(resetButtonConfig,
28910d57f4e3SJason M. Bills                                            resetButtonHandler);
28920d57f4e3SJason M. Bills     }
28930d57f4e3SJason M. Bills 
28940d57f4e3SJason M. Bills     // Request NMI_BUTTON GPIO events
28950d57f4e3SJason M. Bills     if (nmiButtonConfig.type == ConfigType::GPIO)
28960d57f4e3SJason M. Bills     {
28970d57f4e3SJason M. Bills         if (!nmiButtonConfig.lineName.empty())
28980d57f4e3SJason M. Bills         {
28990d57f4e3SJason M. Bills             requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
29000d57f4e3SJason M. Bills                               nmiButtonLine, nmiButtonEvent);
29010d57f4e3SJason M. Bills         }
29020d57f4e3SJason M. Bills     }
29030d57f4e3SJason M. Bills     else if (nmiButtonConfig.type == ConfigType::DBUS)
29040d57f4e3SJason M. Bills     {
2905439b9c3aSPatrick Williams         static sdbusplus::bus::match_t nmiButtonEventMonitor =
29060d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
29070d57f4e3SJason M. Bills     }
29080d57f4e3SJason M. Bills 
29090d57f4e3SJason M. Bills     // Request ID_BUTTON GPIO events
29100d57f4e3SJason M. Bills     if (idButtonConfig.type == ConfigType::GPIO)
29110d57f4e3SJason M. Bills     {
29120d57f4e3SJason M. Bills         if (!idButtonConfig.lineName.empty())
29130d57f4e3SJason M. Bills         {
29140d57f4e3SJason M. Bills             requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
29150d57f4e3SJason M. Bills                               idButtonLine, idButtonEvent);
29160d57f4e3SJason M. Bills         }
29170d57f4e3SJason M. Bills     }
29180d57f4e3SJason M. Bills     else if (idButtonConfig.type == ConfigType::DBUS)
29190d57f4e3SJason M. Bills     {
2920439b9c3aSPatrick Williams         static sdbusplus::bus::match_t idButtonEventMonitor =
29210d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
29220d57f4e3SJason M. Bills     }
29230d57f4e3SJason M. Bills 
29240d57f4e3SJason M. Bills #ifdef USE_PLT_RST
2925439b9c3aSPatrick Williams     sdbusplus::bus::match_t pltRstMatch(
29260d57f4e3SJason M. Bills         *conn,
29270d57f4e3SJason M. Bills         "type='signal',interface='org.freedesktop.DBus.Properties',member='"
29280d57f4e3SJason M. Bills         "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
29290d57f4e3SJason M. Bills         hostMiscHandler);
29300d57f4e3SJason M. Bills #endif
29310d57f4e3SJason M. Bills 
29320d57f4e3SJason M. Bills     // Request POST_COMPLETE GPIO events
29330d57f4e3SJason M. Bills     if (postCompleteConfig.type == ConfigType::GPIO)
29340d57f4e3SJason M. Bills     {
29350d57f4e3SJason M. Bills         if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
29360d57f4e3SJason M. Bills                                postCompleteLine, postCompleteEvent))
29370d57f4e3SJason M. Bills         {
29380d57f4e3SJason M. Bills             return -1;
29390d57f4e3SJason M. Bills         }
29400d57f4e3SJason M. Bills     }
29410d57f4e3SJason M. Bills     else if (postCompleteConfig.type == ConfigType::DBUS)
29420d57f4e3SJason M. Bills     {
2943439b9c3aSPatrick Williams         static sdbusplus::bus::match_t postCompleteEventMonitor =
29440d57f4e3SJason M. Bills             power_control::dbusGPIOMatcher(postCompleteConfig,
29450d57f4e3SJason M. Bills                                            postCompleteHandler);
29460d57f4e3SJason M. Bills     }
29470d57f4e3SJason M. Bills     else
29480d57f4e3SJason M. Bills     {
2949c46ebb49SJason M. Bills         lg2::error(
29500d57f4e3SJason M. Bills             "postComplete name should be configured from json config file");
29510d57f4e3SJason M. Bills         return -1;
29520d57f4e3SJason M. Bills     }
29530d57f4e3SJason M. Bills 
29540d57f4e3SJason M. Bills     // initialize NMI_OUT GPIO.
29550d57f4e3SJason M. Bills     if (!nmiOutConfig.lineName.empty())
29560d57f4e3SJason M. Bills     {
2957461a166aSJian Zhang         setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2958461a166aSJian Zhang                       nmiOutLine);
29590d57f4e3SJason M. Bills     }
29600d57f4e3SJason M. Bills 
29610d57f4e3SJason M. Bills     // Initialize POWER_OUT and RESET_OUT GPIO.
29620d57f4e3SJason M. Bills     gpiod::line line;
29630d57f4e3SJason M. Bills     if (!powerOutConfig.lineName.empty())
29640d57f4e3SJason M. Bills     {
29650d57f4e3SJason M. Bills         if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
29660d57f4e3SJason M. Bills                            line))
29670d57f4e3SJason M. Bills         {
29680d57f4e3SJason M. Bills             return -1;
29690d57f4e3SJason M. Bills         }
29700d57f4e3SJason M. Bills     }
29710d57f4e3SJason M. Bills     else
29720d57f4e3SJason M. Bills     {
2973c46ebb49SJason M. Bills         lg2::error("powerOut name should be configured from json config file");
29740d57f4e3SJason M. Bills         return -1;
29750d57f4e3SJason M. Bills     }
29760d57f4e3SJason M. Bills 
29770d57f4e3SJason M. Bills     if (!resetOutConfig.lineName.empty())
29780d57f4e3SJason M. Bills     {
29790d57f4e3SJason M. Bills         if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
29800d57f4e3SJason M. Bills                            line))
29810d57f4e3SJason M. Bills         {
29820d57f4e3SJason M. Bills             return -1;
29830d57f4e3SJason M. Bills         }
29840d57f4e3SJason M. Bills     }
29850d57f4e3SJason M. Bills     else
29860d57f4e3SJason M. Bills     {
2987c46ebb49SJason M. Bills         lg2::error("ResetOut name should be configured from json config file");
29880d57f4e3SJason M. Bills         return -1;
29890d57f4e3SJason M. Bills     }
29900d57f4e3SJason M. Bills     // Release line
29910d57f4e3SJason M. Bills     line.reset();
29920d57f4e3SJason M. Bills 
299358e379d1SMatt Simmering     // Initialize the power state and operating system state
29940d57f4e3SJason M. Bills     powerState = PowerState::off;
299558e379d1SMatt Simmering     operatingSystemState = OperatingSystemStateStage::Inactive;
29960d57f4e3SJason M. Bills     // Check power good
29970d57f4e3SJason M. Bills 
29980d57f4e3SJason M. Bills     if (powerOkConfig.type == ConfigType::GPIO)
29990d57f4e3SJason M. Bills     {
30000d57f4e3SJason M. Bills         if (psPowerOKLine.get_value() > 0 ||
30010d57f4e3SJason M. Bills             (sioEnabled &&
30020d57f4e3SJason M. Bills              (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
30030d57f4e3SJason M. Bills         {
30040d57f4e3SJason M. Bills             powerState = PowerState::on;
30050d57f4e3SJason M. Bills         }
30060d57f4e3SJason M. Bills     }
30070d57f4e3SJason M. Bills     else
30080d57f4e3SJason M. Bills     {
30090d57f4e3SJason M. Bills         if (getProperty(powerOkConfig))
30100d57f4e3SJason M. Bills         {
30110d57f4e3SJason M. Bills             powerState = PowerState::on;
30120d57f4e3SJason M. Bills         }
30130d57f4e3SJason M. Bills     }
30140d57f4e3SJason M. Bills     // Check if we need to start the Power Restore policy
301599e8f9dfSAndrei Kartashev     if (powerState != PowerState::on)
301699e8f9dfSAndrei Kartashev     {
301799e8f9dfSAndrei Kartashev         powerRestore.run();
301899e8f9dfSAndrei Kartashev     }
30190d57f4e3SJason M. Bills 
30200d57f4e3SJason M. Bills     if (nmiOutLine)
30210d57f4e3SJason M. Bills         nmiSourcePropertyMonitor();
30220d57f4e3SJason M. Bills 
3023c46ebb49SJason M. Bills     lg2::info("Initializing power state.");
30240d57f4e3SJason M. Bills     logStateTransition(powerState);
30250d57f4e3SJason M. Bills 
30260d57f4e3SJason M. Bills     // Power Control Service
30270d57f4e3SJason M. Bills     sdbusplus::asio::object_server hostServer =
30280d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
30290d57f4e3SJason M. Bills 
30300d57f4e3SJason M. Bills     // Power Control Interface
30310d57f4e3SJason M. Bills     hostIface =
30320d57f4e3SJason M. Bills         hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
30330d57f4e3SJason M. Bills                                  "xyz.openbmc_project.State.Host");
30340d57f4e3SJason M. Bills     // Interface for IPMI/Redfish initiated host state transitions
30350d57f4e3SJason M. Bills     hostIface->register_property(
30360d57f4e3SJason M. Bills         "RequestedHostTransition",
30370d57f4e3SJason M. Bills         std::string("xyz.openbmc_project.State.Host.Transition.Off"),
30380d57f4e3SJason M. Bills         [](const std::string& requested, std::string& resp) {
30390d57f4e3SJason M. Bills             if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
30400d57f4e3SJason M. Bills             {
30410d57f4e3SJason M. Bills                 // if power button is masked, ignore this
30420d57f4e3SJason M. Bills                 if (!powerButtonMask)
30430d57f4e3SJason M. Bills                 {
30440d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::gracefulPowerOffRequest);
30450d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
30460d57f4e3SJason M. Bills                 }
30470d57f4e3SJason M. Bills                 else
30480d57f4e3SJason M. Bills                 {
3049c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
30500d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
30510d57f4e3SJason M. Bills                     return 0;
30520d57f4e3SJason M. Bills                 }
30530d57f4e3SJason M. Bills             }
3054a0a39f82SPatrick Williams             else if (requested ==
3055a0a39f82SPatrick Williams                      "xyz.openbmc_project.State.Host.Transition.On")
30560d57f4e3SJason M. Bills             {
30570d57f4e3SJason M. Bills                 // if power button is masked, ignore this
30580d57f4e3SJason M. Bills                 if (!powerButtonMask)
30590d57f4e3SJason M. Bills                 {
30600d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::powerOnRequest);
30610d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
30620d57f4e3SJason M. Bills                 }
30630d57f4e3SJason M. Bills                 else
30640d57f4e3SJason M. Bills                 {
3065c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
30660d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
30670d57f4e3SJason M. Bills                     return 0;
30680d57f4e3SJason M. Bills                 }
30690d57f4e3SJason M. Bills             }
30700d57f4e3SJason M. Bills             else if (requested ==
30710d57f4e3SJason M. Bills                      "xyz.openbmc_project.State.Host.Transition.Reboot")
30720d57f4e3SJason M. Bills             {
30730d57f4e3SJason M. Bills                 // if power button is masked, ignore this
30740d57f4e3SJason M. Bills                 if (!powerButtonMask)
30750d57f4e3SJason M. Bills                 {
30760d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::powerCycleRequest);
30770d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
30780d57f4e3SJason M. Bills                 }
30790d57f4e3SJason M. Bills                 else
30800d57f4e3SJason M. Bills                 {
3081c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
30820d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
30830d57f4e3SJason M. Bills                     return 0;
30840d57f4e3SJason M. Bills                 }
30850d57f4e3SJason M. Bills             }
3086a0a39f82SPatrick Williams             else if (
3087a0a39f82SPatrick Williams                 requested ==
30880d57f4e3SJason M. Bills                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
30890d57f4e3SJason M. Bills             {
30900d57f4e3SJason M. Bills                 // if reset button is masked, ignore this
30910d57f4e3SJason M. Bills                 if (!resetButtonMask)
30920d57f4e3SJason M. Bills                 {
30930d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::gracefulPowerCycleRequest);
30940d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
30950d57f4e3SJason M. Bills                 }
30960d57f4e3SJason M. Bills                 else
30970d57f4e3SJason M. Bills                 {
3098c46ebb49SJason M. Bills                     lg2::info("Reset Button Masked.");
30990d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
31000d57f4e3SJason M. Bills                     return 0;
31010d57f4e3SJason M. Bills                 }
31020d57f4e3SJason M. Bills             }
3103a0a39f82SPatrick Williams             else if (
3104a0a39f82SPatrick Williams                 requested ==
31050d57f4e3SJason M. Bills                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
31060d57f4e3SJason M. Bills             {
31070d57f4e3SJason M. Bills                 // if reset button is masked, ignore this
31080d57f4e3SJason M. Bills                 if (!resetButtonMask)
31090d57f4e3SJason M. Bills                 {
31100d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::resetRequest);
31110d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
31120d57f4e3SJason M. Bills                 }
31130d57f4e3SJason M. Bills                 else
31140d57f4e3SJason M. Bills                 {
3115c46ebb49SJason M. Bills                     lg2::info("Reset Button Masked.");
31160d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
31170d57f4e3SJason M. Bills                     return 0;
31180d57f4e3SJason M. Bills                 }
31190d57f4e3SJason M. Bills             }
31200d57f4e3SJason M. Bills             else
31210d57f4e3SJason M. Bills             {
3122c46ebb49SJason M. Bills                 lg2::error("Unrecognized host state transition request.");
31230d57f4e3SJason M. Bills                 throw std::invalid_argument("Unrecognized Transition Request");
31240d57f4e3SJason M. Bills                 return 0;
31250d57f4e3SJason M. Bills             }
31260d57f4e3SJason M. Bills             resp = requested;
31270d57f4e3SJason M. Bills             return 1;
31280d57f4e3SJason M. Bills         });
31290d57f4e3SJason M. Bills     hostIface->register_property("CurrentHostState",
31300d57f4e3SJason M. Bills                                  std::string(getHostState(powerState)));
31310d57f4e3SJason M. Bills 
31320d57f4e3SJason M. Bills     hostIface->initialize();
31330d57f4e3SJason M. Bills 
31340d57f4e3SJason M. Bills     // Chassis Control Service
31350d57f4e3SJason M. Bills     sdbusplus::asio::object_server chassisServer =
31360d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
31370d57f4e3SJason M. Bills 
31380d57f4e3SJason M. Bills     // Chassis Control Interface
31390d57f4e3SJason M. Bills     chassisIface =
31400d57f4e3SJason M. Bills         chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
31410d57f4e3SJason M. Bills                                     "xyz.openbmc_project.State.Chassis");
31420d57f4e3SJason M. Bills 
31430d57f4e3SJason M. Bills     chassisIface->register_property(
31440d57f4e3SJason M. Bills         "RequestedPowerTransition",
31450d57f4e3SJason M. Bills         std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
31460d57f4e3SJason M. Bills         [](const std::string& requested, std::string& resp) {
31470d57f4e3SJason M. Bills             if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
31480d57f4e3SJason M. Bills             {
31490d57f4e3SJason M. Bills                 // if power button is masked, ignore this
31500d57f4e3SJason M. Bills                 if (!powerButtonMask)
31510d57f4e3SJason M. Bills                 {
31520d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::powerOffRequest);
31530d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
31540d57f4e3SJason M. Bills                 }
31550d57f4e3SJason M. Bills                 else
31560d57f4e3SJason M. Bills                 {
3157c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
31580d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
31590d57f4e3SJason M. Bills                     return 0;
31600d57f4e3SJason M. Bills                 }
31610d57f4e3SJason M. Bills             }
3162a0a39f82SPatrick Williams             else if (requested ==
3163a0a39f82SPatrick Williams                      "xyz.openbmc_project.State.Chassis.Transition.On")
31640d57f4e3SJason M. Bills             {
31650d57f4e3SJason M. Bills                 // if power button is masked, ignore this
31660d57f4e3SJason M. Bills                 if (!powerButtonMask)
31670d57f4e3SJason M. Bills                 {
31680d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::powerOnRequest);
31690d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
31700d57f4e3SJason M. Bills                 }
31710d57f4e3SJason M. Bills                 else
31720d57f4e3SJason M. Bills                 {
3173c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
31740d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
31750d57f4e3SJason M. Bills                     return 0;
31760d57f4e3SJason M. Bills                 }
31770d57f4e3SJason M. Bills             }
31780d57f4e3SJason M. Bills             else if (requested ==
31790d57f4e3SJason M. Bills                      "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
31800d57f4e3SJason M. Bills             {
31810d57f4e3SJason M. Bills                 // if power button is masked, ignore this
31820d57f4e3SJason M. Bills                 if (!powerButtonMask)
31830d57f4e3SJason M. Bills                 {
31840d57f4e3SJason M. Bills                     sendPowerControlEvent(Event::powerCycleRequest);
31850d57f4e3SJason M. Bills                     addRestartCause(RestartCause::command);
31860d57f4e3SJason M. Bills                 }
31870d57f4e3SJason M. Bills                 else
31880d57f4e3SJason M. Bills                 {
3189c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
31900d57f4e3SJason M. Bills                     throw std::invalid_argument("Transition Request Masked");
31910d57f4e3SJason M. Bills                     return 0;
31920d57f4e3SJason M. Bills                 }
31930d57f4e3SJason M. Bills             }
31940d57f4e3SJason M. Bills             else
31950d57f4e3SJason M. Bills             {
3196c46ebb49SJason M. Bills                 lg2::error("Unrecognized chassis state transition request.");
31970d57f4e3SJason M. Bills                 throw std::invalid_argument("Unrecognized Transition Request");
31980d57f4e3SJason M. Bills                 return 0;
31990d57f4e3SJason M. Bills             }
32000d57f4e3SJason M. Bills             resp = requested;
32010d57f4e3SJason M. Bills             return 1;
32020d57f4e3SJason M. Bills         });
32030d57f4e3SJason M. Bills     chassisIface->register_property("CurrentPowerState",
32040d57f4e3SJason M. Bills                                     std::string(getChassisState(powerState)));
32050d57f4e3SJason M. Bills     chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
32060d57f4e3SJason M. Bills 
32070d57f4e3SJason M. Bills     chassisIface->initialize();
32080d57f4e3SJason M. Bills 
32090d57f4e3SJason M. Bills #ifdef CHASSIS_SYSTEM_RESET
32100d57f4e3SJason M. Bills     // Chassis System Service
32110d57f4e3SJason M. Bills     sdbusplus::asio::object_server chassisSysServer =
32120d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
32130d57f4e3SJason M. Bills 
32140d57f4e3SJason M. Bills     // Chassis System Interface
32150d57f4e3SJason M. Bills     chassisSysIface = chassisSysServer.add_interface(
32160d57f4e3SJason M. Bills         "/xyz/openbmc_project/state/chassis_system0",
32170d57f4e3SJason M. Bills         "xyz.openbmc_project.State.Chassis");
32180d57f4e3SJason M. Bills 
32190d57f4e3SJason M. Bills     chassisSysIface->register_property(
32200d57f4e3SJason M. Bills         "RequestedPowerTransition",
32210d57f4e3SJason M. Bills         std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
32220d57f4e3SJason M. Bills         [](const std::string& requested, std::string& resp) {
32230d57f4e3SJason M. Bills             if (requested ==
32240d57f4e3SJason M. Bills                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
32250d57f4e3SJason M. Bills             {
32260d57f4e3SJason M. Bills                 systemReset();
32270d57f4e3SJason M. Bills                 addRestartCause(RestartCause::command);
32280d57f4e3SJason M. Bills             }
32290d57f4e3SJason M. Bills             else
32300d57f4e3SJason M. Bills             {
3231a0a39f82SPatrick Williams                 lg2::error(
3232a0a39f82SPatrick Williams                     "Unrecognized chassis system state transition request.");
32330d57f4e3SJason M. Bills                 throw std::invalid_argument("Unrecognized Transition Request");
32340d57f4e3SJason M. Bills                 return 0;
32350d57f4e3SJason M. Bills             }
32360d57f4e3SJason M. Bills             resp = requested;
32370d57f4e3SJason M. Bills             return 1;
32380d57f4e3SJason M. Bills         });
32390d57f4e3SJason M. Bills     chassisSysIface->register_property(
32400d57f4e3SJason M. Bills         "CurrentPowerState", std::string(getChassisState(powerState)));
32410d57f4e3SJason M. Bills     chassisSysIface->register_property("LastStateChangeTime",
32420d57f4e3SJason M. Bills                                        getCurrentTimeMs());
32430d57f4e3SJason M. Bills 
32440d57f4e3SJason M. Bills     chassisSysIface->initialize();
32450d57f4e3SJason M. Bills 
32460d57f4e3SJason M. Bills     if (!slotPowerConfig.lineName.empty())
32470d57f4e3SJason M. Bills     {
32480d57f4e3SJason M. Bills         if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
32490d57f4e3SJason M. Bills         {
32500d57f4e3SJason M. Bills             return -1;
32510d57f4e3SJason M. Bills         }
32520d57f4e3SJason M. Bills 
32530d57f4e3SJason M. Bills         slotPowerState = SlotPowerState::off;
32540d57f4e3SJason M. Bills         if (slotPowerLine.get_value() > 0)
32550d57f4e3SJason M. Bills         {
32560d57f4e3SJason M. Bills             slotPowerState = SlotPowerState::on;
32570d57f4e3SJason M. Bills         }
32580d57f4e3SJason M. Bills 
32590d57f4e3SJason M. Bills         chassisSlotIface = chassisSysServer.add_interface(
32600d57f4e3SJason M. Bills             "/xyz/openbmc_project/state/chassis_system" + node,
32610d57f4e3SJason M. Bills             "xyz.openbmc_project.State.Chassis");
32620d57f4e3SJason M. Bills         chassisSlotIface->register_property(
32630d57f4e3SJason M. Bills             "RequestedPowerTransition",
32640d57f4e3SJason M. Bills             std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
32650d57f4e3SJason M. Bills             [](const std::string& requested, std::string& resp) {
3266a0a39f82SPatrick Williams                 if (requested ==
3267a0a39f82SPatrick Williams                     "xyz.openbmc_project.State.Chassis.Transition.On")
32680d57f4e3SJason M. Bills                 {
32690d57f4e3SJason M. Bills                     slotPowerOn();
32700d57f4e3SJason M. Bills                 }
32710d57f4e3SJason M. Bills                 else if (requested ==
32720d57f4e3SJason M. Bills                          "xyz.openbmc_project.State.Chassis.Transition.Off")
32730d57f4e3SJason M. Bills                 {
32740d57f4e3SJason M. Bills                     slotPowerOff();
32750d57f4e3SJason M. Bills                 }
3276a0a39f82SPatrick Williams                 else if (
3277a0a39f82SPatrick Williams                     requested ==
32780d57f4e3SJason M. Bills                     "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
32790d57f4e3SJason M. Bills                 {
32800d57f4e3SJason M. Bills                     slotPowerCycle();
32810d57f4e3SJason M. Bills                 }
32820d57f4e3SJason M. Bills                 else
32830d57f4e3SJason M. Bills                 {
3284c46ebb49SJason M. Bills                     lg2::error(
32850d57f4e3SJason M. Bills                         "Unrecognized chassis system state transition request.\n");
3286a0a39f82SPatrick Williams                     throw std::invalid_argument(
3287a0a39f82SPatrick Williams                         "Unrecognized Transition Request");
32880d57f4e3SJason M. Bills                     return 0;
32890d57f4e3SJason M. Bills                 }
32900d57f4e3SJason M. Bills                 resp = requested;
32910d57f4e3SJason M. Bills                 return 1;
32920d57f4e3SJason M. Bills             });
32930d57f4e3SJason M. Bills         chassisSlotIface->register_property(
32940d57f4e3SJason M. Bills             "CurrentPowerState", std::string(getSlotState(slotPowerState)));
32950d57f4e3SJason M. Bills         chassisSlotIface->register_property("LastStateChangeTime",
32960d57f4e3SJason M. Bills                                             getCurrentTimeMs());
32970d57f4e3SJason M. Bills         chassisSlotIface->initialize();
32980d57f4e3SJason M. Bills     }
32990d57f4e3SJason M. Bills #endif
33000d57f4e3SJason M. Bills     // Buttons Service
33010d57f4e3SJason M. Bills     sdbusplus::asio::object_server buttonsServer =
33020d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
33030d57f4e3SJason M. Bills 
33040d57f4e3SJason M. Bills     if (!powerButtonConfig.lineName.empty())
33050d57f4e3SJason M. Bills     {
33060d57f4e3SJason M. Bills         // Power Button Interface
33070d57f4e3SJason M. Bills         power_control::powerButtonIface = buttonsServer.add_interface(
33080d57f4e3SJason M. Bills             "/xyz/openbmc_project/chassis/buttons/power",
33090d57f4e3SJason M. Bills             "xyz.openbmc_project.Chassis.Buttons");
33100d57f4e3SJason M. Bills 
33110d57f4e3SJason M. Bills         powerButtonIface->register_property(
3312d394c887SPatrick Williams             "ButtonMasked", false, [](const bool requested, bool& current) {
33130d57f4e3SJason M. Bills                 if (requested)
33140d57f4e3SJason M. Bills                 {
33150d57f4e3SJason M. Bills                     if (powerButtonMask)
33160d57f4e3SJason M. Bills                     {
33170d57f4e3SJason M. Bills                         return 1;
33180d57f4e3SJason M. Bills                     }
33190d57f4e3SJason M. Bills                     if (!setGPIOOutput(powerOutConfig.lineName,
3320a0a39f82SPatrick Williams                                        !powerOutConfig.polarity,
3321a0a39f82SPatrick Williams                                        powerButtonMask))
33220d57f4e3SJason M. Bills                     {
33230d57f4e3SJason M. Bills                         throw std::runtime_error("Failed to request GPIO");
33240d57f4e3SJason M. Bills                         return 0;
33250d57f4e3SJason M. Bills                     }
3326c46ebb49SJason M. Bills                     lg2::info("Power Button Masked.");
33270d57f4e3SJason M. Bills                 }
33280d57f4e3SJason M. Bills                 else
33290d57f4e3SJason M. Bills                 {
33300d57f4e3SJason M. Bills                     if (!powerButtonMask)
33310d57f4e3SJason M. Bills                     {
33320d57f4e3SJason M. Bills                         return 1;
33330d57f4e3SJason M. Bills                     }
3334c46ebb49SJason M. Bills                     lg2::info("Power Button Un-masked");
33350d57f4e3SJason M. Bills                     powerButtonMask.reset();
33360d57f4e3SJason M. Bills                 }
33370d57f4e3SJason M. Bills                 // Update the mask setting
33380d57f4e3SJason M. Bills                 current = requested;
33390d57f4e3SJason M. Bills                 return 1;
33400d57f4e3SJason M. Bills             });
33410d57f4e3SJason M. Bills 
33420d57f4e3SJason M. Bills         // Check power button state
33430d57f4e3SJason M. Bills         bool powerButtonPressed;
33440d57f4e3SJason M. Bills         if (powerButtonConfig.type == ConfigType::GPIO)
33450d57f4e3SJason M. Bills         {
33460d57f4e3SJason M. Bills             powerButtonPressed = powerButtonLine.get_value() == 0;
33470d57f4e3SJason M. Bills         }
33480d57f4e3SJason M. Bills         else
33490d57f4e3SJason M. Bills         {
33500d57f4e3SJason M. Bills             powerButtonPressed = getProperty(powerButtonConfig) == 0;
33510d57f4e3SJason M. Bills         }
33520d57f4e3SJason M. Bills 
33530d57f4e3SJason M. Bills         powerButtonIface->register_property("ButtonPressed",
33540d57f4e3SJason M. Bills                                             powerButtonPressed);
33550d57f4e3SJason M. Bills 
33560d57f4e3SJason M. Bills         powerButtonIface->initialize();
33570d57f4e3SJason M. Bills     }
33580d57f4e3SJason M. Bills 
33590d57f4e3SJason M. Bills     if (!resetButtonConfig.lineName.empty())
33600d57f4e3SJason M. Bills     {
33610d57f4e3SJason M. Bills         // Reset Button Interface
33620d57f4e3SJason M. Bills 
33630d57f4e3SJason M. Bills         resetButtonIface = buttonsServer.add_interface(
33640d57f4e3SJason M. Bills             "/xyz/openbmc_project/chassis/buttons/reset",
33650d57f4e3SJason M. Bills             "xyz.openbmc_project.Chassis.Buttons");
33660d57f4e3SJason M. Bills 
33670d57f4e3SJason M. Bills         resetButtonIface->register_property(
3368d394c887SPatrick Williams             "ButtonMasked", false, [](const bool requested, bool& current) {
33690d57f4e3SJason M. Bills                 if (requested)
33700d57f4e3SJason M. Bills                 {
33710d57f4e3SJason M. Bills                     if (resetButtonMask)
33720d57f4e3SJason M. Bills                     {
33730d57f4e3SJason M. Bills                         return 1;
33740d57f4e3SJason M. Bills                     }
33750d57f4e3SJason M. Bills                     if (!setGPIOOutput(resetOutConfig.lineName,
3376a0a39f82SPatrick Williams                                        !resetOutConfig.polarity,
3377a0a39f82SPatrick Williams                                        resetButtonMask))
33780d57f4e3SJason M. Bills                     {
33790d57f4e3SJason M. Bills                         throw std::runtime_error("Failed to request GPIO");
33800d57f4e3SJason M. Bills                         return 0;
33810d57f4e3SJason M. Bills                     }
3382c46ebb49SJason M. Bills                     lg2::info("Reset Button Masked.");
33830d57f4e3SJason M. Bills                 }
33840d57f4e3SJason M. Bills                 else
33850d57f4e3SJason M. Bills                 {
33860d57f4e3SJason M. Bills                     if (!resetButtonMask)
33870d57f4e3SJason M. Bills                     {
33880d57f4e3SJason M. Bills                         return 1;
33890d57f4e3SJason M. Bills                     }
3390c46ebb49SJason M. Bills                     lg2::info("Reset Button Un-masked");
33910d57f4e3SJason M. Bills                     resetButtonMask.reset();
33920d57f4e3SJason M. Bills                 }
33930d57f4e3SJason M. Bills                 // Update the mask setting
33940d57f4e3SJason M. Bills                 current = requested;
33950d57f4e3SJason M. Bills                 return 1;
33960d57f4e3SJason M. Bills             });
33970d57f4e3SJason M. Bills 
33980d57f4e3SJason M. Bills         // Check reset button state
33990d57f4e3SJason M. Bills         bool resetButtonPressed;
34000d57f4e3SJason M. Bills         if (resetButtonConfig.type == ConfigType::GPIO)
34010d57f4e3SJason M. Bills         {
34020d57f4e3SJason M. Bills             resetButtonPressed = resetButtonLine.get_value() == 0;
34030d57f4e3SJason M. Bills         }
34040d57f4e3SJason M. Bills         else
34050d57f4e3SJason M. Bills         {
34060d57f4e3SJason M. Bills             resetButtonPressed = getProperty(resetButtonConfig) == 0;
34070d57f4e3SJason M. Bills         }
34080d57f4e3SJason M. Bills 
34090d57f4e3SJason M. Bills         resetButtonIface->register_property("ButtonPressed",
34100d57f4e3SJason M. Bills                                             resetButtonPressed);
34110d57f4e3SJason M. Bills 
34120d57f4e3SJason M. Bills         resetButtonIface->initialize();
34130d57f4e3SJason M. Bills     }
34140d57f4e3SJason M. Bills 
34150d57f4e3SJason M. Bills     if (nmiButtonLine)
34160d57f4e3SJason M. Bills     {
34170d57f4e3SJason M. Bills         // NMI Button Interface
34180d57f4e3SJason M. Bills         nmiButtonIface = buttonsServer.add_interface(
34190d57f4e3SJason M. Bills             "/xyz/openbmc_project/chassis/buttons/nmi",
34200d57f4e3SJason M. Bills             "xyz.openbmc_project.Chassis.Buttons");
34210d57f4e3SJason M. Bills 
34220d57f4e3SJason M. Bills         nmiButtonIface->register_property(
34230d57f4e3SJason M. Bills             "ButtonMasked", false, [](const bool requested, bool& current) {
34240d57f4e3SJason M. Bills                 if (nmiButtonMasked == requested)
34250d57f4e3SJason M. Bills                 {
34260d57f4e3SJason M. Bills                     // NMI button mask is already set as requested, so no change
34270d57f4e3SJason M. Bills                     return 1;
34280d57f4e3SJason M. Bills                 }
34290d57f4e3SJason M. Bills                 if (requested)
34300d57f4e3SJason M. Bills                 {
3431c46ebb49SJason M. Bills                     lg2::info("NMI Button Masked.");
34320d57f4e3SJason M. Bills                     nmiButtonMasked = true;
34330d57f4e3SJason M. Bills                 }
34340d57f4e3SJason M. Bills                 else
34350d57f4e3SJason M. Bills                 {
3436c46ebb49SJason M. Bills                     lg2::info("NMI Button Un-masked.");
34370d57f4e3SJason M. Bills                     nmiButtonMasked = false;
34380d57f4e3SJason M. Bills                 }
34390d57f4e3SJason M. Bills                 // Update the mask setting
34400d57f4e3SJason M. Bills                 current = nmiButtonMasked;
34410d57f4e3SJason M. Bills                 return 1;
34420d57f4e3SJason M. Bills             });
34430d57f4e3SJason M. Bills 
34440d57f4e3SJason M. Bills         // Check NMI button state
34450d57f4e3SJason M. Bills         bool nmiButtonPressed;
34460d57f4e3SJason M. Bills         if (nmiButtonConfig.type == ConfigType::GPIO)
34470d57f4e3SJason M. Bills         {
34480d57f4e3SJason M. Bills             nmiButtonPressed = nmiButtonLine.get_value() == 0;
34490d57f4e3SJason M. Bills         }
34500d57f4e3SJason M. Bills         else
34510d57f4e3SJason M. Bills         {
34520d57f4e3SJason M. Bills             nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
34530d57f4e3SJason M. Bills         }
34540d57f4e3SJason M. Bills 
34550d57f4e3SJason M. Bills         nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
34560d57f4e3SJason M. Bills 
34570d57f4e3SJason M. Bills         nmiButtonIface->initialize();
34580d57f4e3SJason M. Bills     }
34590d57f4e3SJason M. Bills 
34600d57f4e3SJason M. Bills     if (nmiOutLine)
34610d57f4e3SJason M. Bills     {
34620d57f4e3SJason M. Bills         // NMI out Service
34630d57f4e3SJason M. Bills         sdbusplus::asio::object_server nmiOutServer =
34640d57f4e3SJason M. Bills             sdbusplus::asio::object_server(conn);
34650d57f4e3SJason M. Bills 
34660d57f4e3SJason M. Bills         // NMI out Interface
34670d57f4e3SJason M. Bills         nmiOutIface = nmiOutServer.add_interface(
34680d57f4e3SJason M. Bills             "/xyz/openbmc_project/control/host" + node + "/nmi",
34690d57f4e3SJason M. Bills             "xyz.openbmc_project.Control.Host.NMI");
34700d57f4e3SJason M. Bills         nmiOutIface->register_method("NMI", nmiReset);
34710d57f4e3SJason M. Bills         nmiOutIface->initialize();
34720d57f4e3SJason M. Bills     }
34730d57f4e3SJason M. Bills 
34740d57f4e3SJason M. Bills     if (idButtonLine)
34750d57f4e3SJason M. Bills     {
34760d57f4e3SJason M. Bills         // ID Button Interface
34770d57f4e3SJason M. Bills         idButtonIface = buttonsServer.add_interface(
34780d57f4e3SJason M. Bills             "/xyz/openbmc_project/chassis/buttons/id",
34790d57f4e3SJason M. Bills             "xyz.openbmc_project.Chassis.Buttons");
34800d57f4e3SJason M. Bills 
34810d57f4e3SJason M. Bills         // Check ID button state
34820d57f4e3SJason M. Bills         bool idButtonPressed;
34830d57f4e3SJason M. Bills         if (idButtonConfig.type == ConfigType::GPIO)
34840d57f4e3SJason M. Bills         {
34850d57f4e3SJason M. Bills             idButtonPressed = idButtonLine.get_value() == 0;
34860d57f4e3SJason M. Bills         }
34870d57f4e3SJason M. Bills         else
34880d57f4e3SJason M. Bills         {
34890d57f4e3SJason M. Bills             idButtonPressed = getProperty(idButtonConfig) == 0;
34900d57f4e3SJason M. Bills         }
34910d57f4e3SJason M. Bills 
34920d57f4e3SJason M. Bills         idButtonIface->register_property("ButtonPressed", idButtonPressed);
34930d57f4e3SJason M. Bills 
34940d57f4e3SJason M. Bills         idButtonIface->initialize();
34950d57f4e3SJason M. Bills     }
34960d57f4e3SJason M. Bills 
34970d57f4e3SJason M. Bills     // OS State Service
34980d57f4e3SJason M. Bills     sdbusplus::asio::object_server osServer =
34990d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
35000d57f4e3SJason M. Bills 
35010d57f4e3SJason M. Bills     // OS State Interface
35020d57f4e3SJason M. Bills     osIface = osServer.add_interface(
350333737913SPotin Lai         "/xyz/openbmc_project/state/host" + node,
35040d57f4e3SJason M. Bills         "xyz.openbmc_project.State.OperatingSystem.Status");
35050d57f4e3SJason M. Bills 
35060d57f4e3SJason M. Bills     // Get the initial OS state based on POST complete
3507c6d75656SJason M. Bills     //      Asserted, OS state is "Standby" (ready to boot)
3508c6d75656SJason M. Bills     //      De-Asserted, OS state is "Inactive"
35098623918bSTim Lee     OperatingSystemStateStage osState;
35100d57f4e3SJason M. Bills     if (postCompleteConfig.type == ConfigType::GPIO)
35110d57f4e3SJason M. Bills     {
3512c6d75656SJason M. Bills         osState = postCompleteLine.get_value() == postCompleteConfig.polarity
3513c6d75656SJason M. Bills                       ? OperatingSystemStateStage::Standby
3514c6d75656SJason M. Bills                       : OperatingSystemStateStage::Inactive;
35150d57f4e3SJason M. Bills     }
35160d57f4e3SJason M. Bills     else
35170d57f4e3SJason M. Bills     {
35188623918bSTim Lee         osState = getProperty(postCompleteConfig) > 0
3519c6d75656SJason M. Bills                       ? OperatingSystemStateStage::Standby
3520c6d75656SJason M. Bills                       : OperatingSystemStateStage::Inactive;
35210d57f4e3SJason M. Bills     }
35220d57f4e3SJason M. Bills 
35238623918bSTim Lee     osIface->register_property(
35248623918bSTim Lee         "OperatingSystemState",
35258623918bSTim Lee         std::string(getOperatingSystemStateStage(osState)));
35260d57f4e3SJason M. Bills 
35270d57f4e3SJason M. Bills     osIface->initialize();
35280d57f4e3SJason M. Bills 
35290d57f4e3SJason M. Bills     // Restart Cause Service
35300d57f4e3SJason M. Bills     sdbusplus::asio::object_server restartCauseServer =
35310d57f4e3SJason M. Bills         sdbusplus::asio::object_server(conn);
35320d57f4e3SJason M. Bills 
35330d57f4e3SJason M. Bills     // Restart Cause Interface
35340d57f4e3SJason M. Bills     restartCauseIface = restartCauseServer.add_interface(
35350d57f4e3SJason M. Bills         "/xyz/openbmc_project/control/host" + node + "/restart_cause",
35360d57f4e3SJason M. Bills         "xyz.openbmc_project.Control.Host.RestartCause");
35370d57f4e3SJason M. Bills 
35380d57f4e3SJason M. Bills     restartCauseIface->register_property(
35390d57f4e3SJason M. Bills         "RestartCause",
35400d57f4e3SJason M. Bills         std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
35410d57f4e3SJason M. Bills 
35420d57f4e3SJason M. Bills     restartCauseIface->register_property(
35430d57f4e3SJason M. Bills         "RequestedRestartCause",
35440d57f4e3SJason M. Bills         std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
35450d57f4e3SJason M. Bills         [](const std::string& requested, std::string& resp) {
35460d57f4e3SJason M. Bills             if (requested ==
35470d57f4e3SJason M. Bills                 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
35480d57f4e3SJason M. Bills             {
35490d57f4e3SJason M. Bills                 addRestartCause(RestartCause::watchdog);
35500d57f4e3SJason M. Bills             }
35510d57f4e3SJason M. Bills             else
35520d57f4e3SJason M. Bills             {
3553a0a39f82SPatrick Williams                 throw std::invalid_argument(
3554a0a39f82SPatrick Williams                     "Unrecognized RestartCause Request");
35550d57f4e3SJason M. Bills                 return 0;
35560d57f4e3SJason M. Bills             }
35570d57f4e3SJason M. Bills 
3558a0a39f82SPatrick Williams             lg2::info("RestartCause requested: {RESTART_CAUSE}",
3559a0a39f82SPatrick Williams                       "RESTART_CAUSE", requested);
35600d57f4e3SJason M. Bills             resp = requested;
35610d57f4e3SJason M. Bills             return 1;
35620d57f4e3SJason M. Bills         });
35630d57f4e3SJason M. Bills 
35640d57f4e3SJason M. Bills     restartCauseIface->initialize();
35650d57f4e3SJason M. Bills 
35660d57f4e3SJason M. Bills     currentHostStateMonitor();
35670d57f4e3SJason M. Bills 
3568cfc4d25eSKonstantin Aladyshev     if (!hpmStbyEnConfig.lineName.empty())
3569cfc4d25eSKonstantin Aladyshev     {
3570cfc4d25eSKonstantin Aladyshev         // Set to indicate BMC's power control module is ready to take
3571cfc4d25eSKonstantin Aladyshev         // the inputs [PWR_GOOD] from the HPM FPGA
3572cfc4d25eSKonstantin Aladyshev         gpiod::line hpmLine;
3573cfc4d25eSKonstantin Aladyshev         if (!setGPIOOutput(hpmStbyEnConfig.lineName, hpmStbyEnConfig.polarity,
3574cfc4d25eSKonstantin Aladyshev                            hpmLine))
3575cfc4d25eSKonstantin Aladyshev         {
3576cfc4d25eSKonstantin Aladyshev             return -1;
3577cfc4d25eSKonstantin Aladyshev         }
3578cfc4d25eSKonstantin Aladyshev     }
3579cfc4d25eSKonstantin Aladyshev 
35800d57f4e3SJason M. Bills     io.run();
35810d57f4e3SJason M. Bills 
35820d57f4e3SJason M. Bills     return 0;
35830d57f4e3SJason M. Bills }
3584