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